文件系统在操作系统中扮演着关键角色,为用户和应用程序提供了对文件进行操作的基础能力。
在linux内核中,进程管理、内存管理、网络协议栈、文件系统被视为内核的四大核心模块。文件系统在内核中分为vfs(虚拟文件系统)和实际文件系统(如ext4)。vfs作为一种工厂设计模式的抽象层,向外提供标准的posix语义层;而实际文件系统则实现了特定文件功能的磁盘文件系统。具体结构如下图所示:
文件系统的IO协议栈中,应用程序如果以dio方式读写文件,请求首先经过内核的vfs,然后到达实际文件系统的处理函数,接着请求进入设备映射,最后传递到块设备的IO层。在这里,调度算法和IO优化也会进行处理。块设备IO层处理完毕后,请求直接到达磁盘的驱动层,这一层通过调用IO命令对磁盘进行读写操作。
在Linux中,设计理念是“一切皆文件”,这种理念在文件系统设计中得到了充分体现。内核将目录视为文件来处理。文件的inode中存储的是文件对应的数据块索引和数据,而目录的inode则存储该目录下的文件的inode和文件名称,虽然都是inode,但存储的数据不同。文件系统中的所有目录名称和文件名称存在于vfs层(仅为内存结构展示),这个结构以struct dentry表示,而文件或目录以struct inode表示。
每个打开的文件在内核进程中以文件描述符存在,每个进程维护一个数组,这个数组的下标就是返回给应用的文件描述符,数组中的每个元素对应的是struct file。struct file中保存了struct dentry,而struct dentry中包含文件的inode信息。具体关系如下:
vfs层提供标准文件操作的函数接口,具体的文件操作函数由实际文件系统提供。针对应用程序访问文件系统,比如执行echo "aaa" > 1.txt命令,cat命令会先根据服务目录查找文件,然后读取1.txt的文件数据,这涉及到部分POSIX函数。整个echo命令在文件系统层面(vfs和实际文件系统)会经历lookup->open->write->close的过程。接下来将重点分析write语义的函数,以内核4.18为例进行分析。
实际文件系统会定义针对文件或目录的相关操作函数,每个inode会有const struct inode_operations *i_op和const struct file_operations *i_fop,实际文件系统的相关操作函数会在__ext4_iget中为对应的inode进行赋值。以下是针对ext4本地文件系统的示例代码:
文心一言
文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。
1008 查看详情
// 这里是以 ext4本地文件系统为例const struct inode_operations ext4_dir_inode_operations = { // 文件创建函数 .create = ext4_create, // 查找函数 .lookup = ext4_lookup, /****** 省略其他的定义的函数*****/};const struct file_operations ext4_file_operations = {.llseek = ext4_llseek,// 读函数.read_iter = ext4_file_read_iter,// 写函数.write_iter = ext4_file_write_iter,.unlocked_ioctl = ext4_ioctl,
ifdef CONFIG_COMPAT
.compat_ioctl = ext4_compat_ioctl,#endif.mmap = ext4_file_mmap,.mmap_supported_flags = MAP_SYNC,// open函数对应实际文件系统的函数.open = ext4_file_open,.release = ext4_release_file,.fsync = ext4_sync_file,.get_unmapped_area = thp_get_unmapped_area,.splice_read = generic_file_splice_read,.splice_write = iter_file_splice_write,.fallocate = ext4_fallocate,
};
当用户程序发起write的POSIX语义时,请求会进入内核的ksys_write->vfs_write->ext4_file_write_iter来完成这个write操作。整体流程如下:
以下是ksys_write、vfs_write和vfs_write的示例代码:
// write函数进入内核态的ksys_write// fd是已经打开的文件描述符,buf是需要写入的数据,count是写入的长度ssize_t ksys_write(unsigned int fd, const char user *buf, size_t count) {// f 代表打开的文件和打开文件的flagstruct fd f = fdget_pos(fd);ssize_t ret = -EBADF;// 如果打开的文件为空,则退出if (f.file) {// 获取文件读写的位置loff_t pos = file_pos_read(f.file);// 进入vfs_write的函数,接着处理文件写操作ret = vfs_write(f.file, buf, count, &pos);if (ret >= 0)file_pos_write(f.file, pos);fdput_pos(f);}return ret;}// vfs_write包装了ext4_file_write_iter 函数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_mode & FMODE_CAN_WRITE))return -EINVAL;if (unlikely(!access_ok(VERIFY_READ, buf, count)))return -EFAULT;// 检查文件系统可写区域以及锁检查ret = rw_verify_area(WRITE, file, pos, count);if (!ret) {if (count > MAX_RW_COUNT)count = MAX_RW_COUNT;file_start_write(file);// 调用ext4_file_write_iter 开始写数据ret = __vfs_write(file, buf, count, pos);if (ret > 0) {fsnotify_modify(file);add_wchar(current, ret);}inc_syscw(current);file_end_write(file);}return ret;}
// vfs_write是包装函数ssize_t vfs_write(struct file file, const char __user p, size_t count, loff_t *pos) {if (file->f_op->write)return file->f_op->write(file, p, count, pos);else if (file->f_op->write_iter)return new_sync_write(file, p, count, pos);elsereturn -EINVAL;}
// 把用户需要写入的数据封装为struct iovec,然后把这个iovec和fd对应的struct file,传递给时间文件系统的函数,进行文件写入。static ssize_t new_sync_write(struct file filp, const char __user buf, size_t len, loff_t ppos) {struct iovec iov = { .iov_base = (void __user )buf, .iov_len = len };struct kiocb kiocb;struct iov_iter iter;ssize_t ret;
init_sync_kiocb(&kiocb, filp);kiocb.ki_pos = *ppos;iov_iter_init(&iter, WRITE, &iov, 1, len);ret = call_write_iter(filp, &kiocb, &iter);BUG_ON(ret == -EIOCBQUEUED);if (ret > 0) *ppos = kiocb.ki_pos;return ret;
}
// call_write_iter是直接调用f_op->write_iter函数,这里对应的是 ext4_file_write_iter,到了这里虚拟文件系统层基本已经结束,进入实际文件系统的调用过程。static inline ssize_t call_write_iter(struct file file, struct kiocb kio, struct iov_iter *iter) {return file->f_op->write_iter(kio, iter);}
以上就是聊聊文件系统的原理的详细内容,更多请关注创想鸟其它相关文章!
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/466000.html
微信扫一扫
支付宝扫一扫