linux内核read操作源代码分析
2016-03-06 09:08
627 查看
read操作是任何操作系统里的基本操作,我们来看一下在linux内核里,read文件是怎样实现的。
read函数在用户空间是由read系统调用实现的,由编译器编译成软中断int 0x80来进入内核空间,然后在中端门上进入函数sys_read,从而进入内核空间执行read操作。
sys_read函数定义在fs/read_write.c文件,定义如下
首先看看file_pos_read和file_pos_write函数吧,定义如下
定义很简单,读取的时候就是读出file结构体的f_pos,写入的时候就是写到对应变量。指示文件的读写位置的变量就是在file结构体里。
然后看一下fget_light和fput_light函数,定义如下
然后返回来看我们最重要的vfs_read函数,vfs_read函数定义在fs/read_write.c,定义如下
然后我们在进入do_sync_read函数看一看异步读取是怎么实现的,do_sync_read函数定义在fs/read_write.c,定义如下
至此,linux内核的read操作就算ok了,linux内核的sys_write和read很相似哦,只要弄明白read,write也一定是可以搞明白的。
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也一定是可以搞明白的。
相关文章推荐