OS / linux 内核 read 操作源代码分析
read 操作是任何操作系統里的基本操作,我們來看一下在 linux 內核里,read 文件是怎樣實現的。
read 函數在用戶空間是由 read 系統調用實現的,由編譯器編譯成軟中斷 int 0x80 來進入內核空間,然后在中斷門上進入函數 sys_read,從而進入內核空間執行 read 操作。
sys_read 函數定義在 fs / read_write.c 文件,定義如下
asmlinkage ssize_t sys_read(unsigned int fd, char __user *buf, size_t count) {struct file *file; /*文件指針*/ssize_t ret = -EBADF;int fput_needed;/*輕量級的由文件描述符得到文件指針函數*/file = fget_light(fd, &fput_needed);if (file){/*file 結構體里的指示文件讀寫位置的 int 變量讀取*/loff_t pos = file_pos_read(file);/*vfs 虛擬文件系統實現 read 操作的地方*/ret = vfs_read(file, buf, count, &pos);/*file 結構體里的指示文件讀寫位置的 int 變量寫入*/file_pos_write(file, pos);/*釋放 file 結構體指針*/fput_light(file, fput_needed);}return ret; }首先看看 file_pos_read 和 file_pos_write 函數吧,定義如下
static inline loff_t file_pos_read(struct file *file) {return file->f_pos; } static inline void file_pos_write(struct file *file, loff_t pos) {file->f_pos = pos; }定義很簡單,讀取的時候就是讀出 file 結構體的 f_pos,寫入的時候就是寫到對應變量。指示文件的讀寫位置的變量就是在 file 結構體里。
然后看一下 fget_light 和 fput_light 函數,定義如下?
struct file fastcall *fget_light(unsigned int fd, int *fput_needed) {struct file *file;/*得到當前進程的 task_struct 的打開的 files 指針*/struct files_struct *files = current->files;*fput_needed = 0;/*如果只有一個進程使用這個結構體,就不必考慮鎖,否則要先得到鎖才可以讀取*/if (likely((atomic_read(&files->count) == 1))){/*從 files 結構體的 fd 數組上得到 file 結構體*/file = fcheck_files(files, fd);}else{/*先上鎖,在得到對應結構體*/rcu_read_lock();file = fcheck_files(files, fd);if (file){if (atomic_inc_not_zero(&file->f_count))*fput_needed = 1;else/* Didn't get the reference, someone's freed */file = NULL;}rcu_read_unlock();}return file; } static inline void fput_light(struct file *file, int fput_needed) { /*釋放并減少使用計數*/if (unlikely(fput_needed))fput(file); }然后返回來看我們最重要的 vfs_read 函數,vfs_read 函數定義在 fs / read_write.c,定義如下
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) {ssize_t ret;/*首先檢查文件是否可以讀取,否則返回壞的文件描述符標記*/if (!(file->f_mode & FMODE_READ))return -EBADF;/*如果沒有對應的文件操作函數集合,也返回錯誤*/if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))return -EINVAL;/*檢查有沒有權限*/if (unlikely(!access_ok(VERIFY_WRITE, buf, count)))return -EFAULT;/*檢查當前寫入的地方有沒有被上鎖,是否可讀寫*/ret = rw_verify_area(READ, file, pos, count);if (ret >= 0){count = ret;/*安全操作*/ret = security_file_permission(file, MAY_READ);if (!ret){/*如果 file 結構體里有 read 函數,就調用*/if (file->f_op->read)ret = file->f_op->read(file, buf, count, pos);else/*否則就調用異步讀取的*/ret = do_sync_read(file, buf, count, pos);if (ret > 0){/*成功讀取以后,通知父目錄已經讀取,并在當前進程結構體上記錄*/fsnotify_access(file->f_path.dentry);add_rchar(current, ret);}inc_syscr(current);}}return ret; }然后我們在進入 do_sync_read 函數看一看異步讀取是怎么實現的,do_sync_read 函數定義在 fs / read_write.c,定義如下
???
ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) {struct iovec iov = {.iov_base = buf, .iov_len = len};struct kiocb kiocb;ssize_t ret;/*初始化讀寫控制塊*/init_sync_kiocb(&kiocb, filp);kiocb.ki_pos = *ppos;kiocb.ki_left = len;/*調用 file_operation 結構體的異步讀取函數*/for (;;){ret = filp->f_op->aio_read(&kiocb, &iov, 1, kiocb.ki_pos);if (ret != -EIOCBRETRY)break;wait_on_retry_sync_kiocb(&kiocb);}/*如果沒結束,就等待*/if (-EIOCBQUEUED == ret)ret = wait_on_sync_kiocb(&kiocb);*ppos = kiocb.ki_pos;return ret; }至此,linux 內核的 read 操作就算 ok 了,linux 內核的 sys_write 和 read 很相似哦,只要弄明白 read,write 也一定是可以搞明白的。
?
轉載于:https://blog.csdn.net/sanwenyublog/article/details/50811957
?
(SAW:Game Over!)
總結
以上是生活随笔為你收集整理的OS / linux 内核 read 操作源代码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: wireshark 常用命令
- 下一篇: c/c++ / printf 实现