Linux VFS文件系统之读写(read/write)文件
来源:互联网 发布:腾讯云阿里云市场份额 编辑:程序博客网 时间:2024/05/16 16:22
------------------------------------------------
其中关键的一个函数为fcheck_files() ,看看代码:
函数files_fdtable(),就是去读取当前进程的文件描述表 , rcu_dereference()会根据文件描述符fd取得文件描述表中的file.
上面的代码实现很简单,在做了一些条件判断以后 ,如果该文件索引节点inode定义了文件的读实现方法的话,就调用此方法. Linux下特殊文件读往往是用此方法, 一些伪文件系统如:proc,sysfs等,读写文件也是用此方法 . 而如果没有定义此方法就会调用通用文件模型的读写方法.它最终就是读内存,或者需要从存储介质中去读数据.
可以看出这个函数和vfs_read()都是差不多的,只是调用的文件操作方法不同而已(file->f_op->write) ,如果没有定义file->f_op->write ,同样也需要do_sync_write()调用同样文件写操作, 首先把数据写到内存中,然后在适当的时候把数据同步到具体的存储介质中去.
#纯属个人理解,如有问题敬请谅解!
#kernel version: 2.6.26
#Author: andy wang
-------------------------------------------------
一: 概述
在上文中讨论了VFS层是如何打开一个文件的,本文就来讨论VFS读写文件的通用接口.
还是根据这个图来看一下VFS读写的流程. VFS会根据文件描述符fd的值在当前进程的文件描述表中找到对应的file ,然后找到f_op指向的索引节点inode文件操作方法,最后调用inode指向的文件读写函数完成文件的读写 ,此时VFS层读写文件的工作就完成了.
二: VFS read的实现流程
首先看看read/write的软件流程图:
从软件流程图中可以看出来, VFS处理文件的读写流程基本都是一样的.
首先按照这个流程看看read 具体是如何实现的:
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); //获取file if (file) { loff_t pos = file_pos_read(file); //读取文件读写位置 ret = vfs_read(file, buf, count, &pos); //VFS 读文件 file_pos_write(file, pos); //回写文件读写位置 fput_light(file, fput_needed); } return ret;}
因为在我们在open文件时就把文件相关的信息放在了文件描述表的file结构中(见上文) ,所以在读一个文件前,我们需要在当前进程的文件描述表中找到这个file结构 ,那么这个file结构是如何找到的呢?
那么就来看看 fget_light()代码是如何实现的:
struct file *fget_light(unsigned int fd, int *fput_needed){ struct file *file; struct files_struct *files = current->files; //取得当前进程的files_struct ,我们需要找到文件描述表 *fput_needed = 0; if (likely((atomic_read(&files->count) == 1))) { file = fcheck_files(files, fd); // 由fd值, 取得 file } 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;}
其中关键的一个函数为fcheck_files() ,看看代码:
static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd){ struct file * file = NULL; struct fdtable *fdt = files_fdtable(files); if (fd < fdt->max_fds) file = rcu_dereference(fdt->fd[fd]); return file;}
函数files_fdtable(),就是去读取当前进程的文件描述表 , rcu_dereference()会根据文件描述符fd取得文件描述表中的file.
接下来获取文件读写位置file->f_pos ,这个值可以通过系统调用llseek修改.
既然我们已经在当前进程的文件描述表中找到了file , 下面就需要调用保存在file中的文件操作方法(open时初始化) .
看看下面的代码就很清楚了:
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; 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;}
上面的代码实现很简单,在做了一些条件判断以后 ,如果该文件索引节点inode定义了文件的读实现方法的话,就调用此方法. Linux下特殊文件读往往是用此方法, 一些伪文件系统如:proc,sysfs等,读写文件也是用此方法 . 而如果没有定义此方法就会调用通用文件模型的读写方法.它最终就是读内存,或者需要从存储介质中去读数据.
三: VFS write的实现流程
其实VFS写文件的流程和读文件是一样的,只是调用文件操作方法不同而已 .
我们只需要看看vfs_write()的代码就可以了:
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos){ ssize_t ret; if (!(file->f_mode & FMODE_WRITE)) return -EBADF; if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write)) return -EINVAL; if (unlikely(!access_ok(VERIFY_READ, buf, count))) return -EFAULT; ret = rw_verify_area(WRITE, file, pos, count); if (ret >= 0) { count = ret; if (file->f_op->write) ret = file->f_op->write(file, buf, count, pos); else ret = do_sync_write(file, buf, count, pos); if (ret > 0) { fsnotify_modify(file->f_path.dentry); add_wchar(current, ret); } inc_syscw(current); } return ret;}
可以看出这个函数和vfs_read()都是差不多的,只是调用的文件操作方法不同而已(file->f_op->write) ,如果没有定义file->f_op->write ,同样也需要do_sync_write()调用同样文件写操作, 首先把数据写到内存中,然后在适当的时候把数据同步到具体的存储介质中去.
四: 小结
其实到这里我们已经可以深深领会到linux VFS的重要性了, 它就是为文件系统提供一个通用的接口模型,是linux文件系统的奠基石.VFS也是一个比较大的系统,要想清楚的知道其中的来龙去脉,还的要去潜心研究代码了..
- Linux VFS文件系统之读写(read/write)文件
- Linux VFS文件系统之读写(read/write)文件
- sys_read()/vfs_read()/vfs_write() Linux VFS文件系统之读写(read/write)文件
- sys_read()/vfs_read()/vfs_write() Linux VFS文件系统之读写(read/write)文件
- Linux VFS 之 write/read系统调用(kernel 3.4)
- linux kernel read write file 读写文件
- 读写文件read/write
- Linux VFS文件系统之打开(Open)文件
- Linux文件编程之虚拟文件系统(VFS)
- Linux VFS文件系统之创建文件
- Linux文件编程之虚拟文件系统(VFS)
- Linux VFS文件系统之创建文件
- Linux VFS文件系统之打开(Open)文件
- linux文件系统之VFS
- 【Linux】使用read、write、lseek函数实现文件读写操作
- read write 调用过程 文件读写 分析
- linux vfs 解析 之 mount 文件系统
- linux vfs 解析 之 mount 文件系统
- 陌陌、米聊、微博、微信看IT人士对交际的重视
- hdu 2141 纯水题
- poj2607 Fire Station
- android SDK升级后, 模拟器不能横屏的解决方法
- 对邮件发送系统的深刻解析(一般程序员都不一定搞的懂)
- Linux VFS文件系统之读写(read/write)文件
- 我的面试经验总结
- datawindow导出到word
- C++中的运算符重载问题
- 清除SNV用户记录
- 日期格式化
- java中io各种流的关闭顺序
- 初入 Java 反编译
- ERROR:Application requires API version 12.Device API version is 11 (Android 3.0)