1. VFS 概述
VFS (Virtual File System) 是 Linux 内核的文件系统抽象层,它为用户空间提供统一的文件系统接口,同时支持多种不同的文件系统。
1.1 VFS 的作用
2. 核心数据结构
2.1 超级块 (super_block)
超级块存储文件系统的元数据:
// include/linux/fs.hstructsuper_block{// 设备信息dev_ts_dev;// 设备号unsignedlongs_blocksize;// 块大小unsignedchars_blocksize_bits;// 块大小位数// 文件系统类型structfile_system_type*s_type;// 超级块操作structsuper_operations*s_op;// 根目录structdentry*s_root;// 挂载选项char*s_options;// 标志unsignedlongs_flags;// 锁structrw_semaphores_umount;// 引用计数atomic_ts_active;// 私有数据void*s_fs_info;// 链表structlist_heads_list;};2.2 索引节点 (inode)
inode 存储文件的元数据:
// include/linux/fs.hstructinode{// 索引号unsignedlongi_ino;// 设备号dev_ti_rdev;// 文件类型和权限umode_ti_mode;// 链接数unsignedinti_nlink;// 用户/组 IDuid_ti_uid;gid_ti_gid;// 文件大小loff_ti_size;// 时间戳structtimespec64i_atime;// 访问时间structtimespec64i_mtime;// 修改时间structtimespec64i_ctime;// 创建时间// 块计数unsignedinti_blocks;// 所属超级块structsuper_block*i_sb;// inode 操作structinode_operations*i_op;// 文件操作structfile_operations*i_fop;// 地址空间 (页缓存)structaddress_space*i_mapping;// 私有数据void*i_private;// 链表structlist_headi_sb_list;structlist_headi_dentry;// 引用计数atomic_ti_count;};2.3 目录项 (dentry)
dentry 用于路径解析和目录缓存:
// include/linux/dcache.hstructdentry{// 目录项状态unsignedintd_flags;// 哈希值unsignedintd_hash;// 父目录structdentry*d_parent;// 文件名structqstrd_name;// inodestructinode*d_inode;// 别名链表structlist_headd_alias;// 子目录链表structlist_headd_child;// 父目录链表structlist_headd_subdirs;// 操作structdentry_operations*d_op;// 超级块structsuper_block*d_sb;// 私有数据void*d_fsdata;// 引用计数atomic_td_count;};2.4 文件描述符 (file)
file 是用户空间文件描述符的内核表示:
// include/linux/fs.hstructfile{// 路径structpathf_path;// 文件操作structfile_operations*f_op;// 锁spinlock_tf_lock;structmutexf_pos_lock;// 文件偏移loff_tf_pos;// 标志unsignedintf_flags;// 模式fmode_tf_mode;// 引用计数atomic_tf_count;// 私有数据void*private_data;// 地址空间structaddress_space*f_mapping;};3. 文件系统注册与挂载
3.1 注册文件系统
// fs/super.c// 文件系统类型structfile_system_type{constchar*name;// 文件系统名称intfs_flags;// 标志structdentry*(*mount)(structfile_system_type*,int,constchar*,void*);void(*kill_sb)(structsuper_block*);structmodule*owner;structlist_headfs_supers;// 私有数据void*fs_info;};// 注册文件系统intregister_filesystem(structfile_system_type*fs){// 添加到文件系统链表list_add(&fs->fs_supers,&file_systems);return0;}3.2 挂载文件系统
// fs/namespace.c// mount 系统调用SYSCALL_DEFINE5(mount,constchar__user*,dev_name,constchar__user*,dir_name,constchar__user*,type,unsignedlong,flags,constvoid__user*,data){// 解析路径path=user_path(dir_name);// 解析文件系统类型fstype=get_fs_type(type);// 调用文件系统的 mount 方法mnt=fstype->mount(fstype,flags,dev_name,data);// 将挂载添加到命名空间mntput(mnt);}4. 文件操作
4.1 打开文件
// fs/open.c// open 系统调用SYSCALL_DEFINE3(open,constchar__user*,filename,int,flags,umode_t,mode){returndo_sys_open(AT_FDCWD,filename,flags,mode);}longdo_sys_open(intdfd,constchar__user*filename,intflags,umode_tmode){structfile*f;structfilename*name;intfd;// 获取文件名name=getname(filename);// 分配文件描述符fd=get_unused_fd_flags(flags);if(fd<0)returnfd;// 打开文件f=do_filp_open(dfd,name,&op);if(IS_ERR(f)){put_unused_fd(fd);returnPTR_ERR(f);}// 关联到文件描述符表fdinstall(fd,f);returnfd;}// 实际打开文件structfile*do_filp_open(intdfd,structfilename*pathname,conststructopen_flags*op){structdentry*dentry;structfile*filp;// 路径解析dentry=path_lookupat(dfd,pathname,LOOKUP_PARENT,&path);if(IS_ERR(dentry))returnERR_CAST(dentry);// 创建 file 结构filp=alloc_file(&path,flags,&open_file_operations);returnfilp;}4.2 读取文件
// fs/read_write.c// read 系统调用SYSCALL_DEFINE3(read,int,fd,char__user*,buf,size_t,count){structfdf=fdget_pos(fd);ssize_tret=-EBADF;if(f.file){// 获取当前偏移loff_tpos=file_pos_read(f.file);// 调用 VFS 读取ret=vfs_read(f.file,buf,count,&pos);// 更新偏移if(ret>=0)file_pos_write(f.file,pos);fdput_pos(f);}returnret;}// VFS 读取ssize_tvfs_read(structfile*file,char__user*buf,size_tcount,loff_t*pos){ssize_tret;// 检查权限if(!(file->f_mode&FMODE_READ))return-EBADF;// 检查偏移if(unlikely(!access_ok(buf,count)))return-EFAULT;// 调用文件操作if(file->f_op->read)ret=file->f_op->read(file,buf,count,pos);elseret=do_sync_read(file,buf,count,pos);returnret;}4.3 写入文件
// fs/read_write.c// write 系统调用SYSCALL_DEFINE3(write,int,fd,constchar__user*,buf,size_t,count){structfdf=fdget_pos(fd);ssize_tret=-EBADF;if(f.file){loff_tpos=file_pos_read(f.file);ret=vfs_write(f.file,buf,count,&pos);if(ret>=0)file_pos_write(f.file,pos);fdput_pos(f);}returnret;}// VFS 写入ssize_tvfs_write(structfile*file,constchar__user*buf,size_tcount,loff_t*pos){ssize_tret;if(!(file->f_mode&FMODE_WRITE))return-EBADF;if(unlikely(!access_ok(buf,count)))return-EFAULT;if(file->f_op->write)ret=file->f_op->write(file,buf,count,pos);elseret=do_sync_write(file,buf,count,pos);returnret;}5. 路径解析
5.1 路径查找
// fs/namei.c// 路径解析structdentry*path_lookupat(intdfd,constchar*name,unsignedintflags,structpath*path){structdentry*dentry;constchar*s;// 处理绝对路径和相对路径if(*name=='/'){// 从根目录开始dentry=dget(current->fs->root.dentry);}elseif(dfd==AT_FDCWD){// 从当前目录开始dentry=dget(current->fs->pwd.dentry);}else{// 从指定目录开始dentry=get_fd(dfd);}// 逐级解析while(*name){// 跳过分隔符name=skip_name(name,&this);// 检查权限err=inode_permission(dentry->d_inode,MAY_EXEC);if(err)gotofail;// 查找子目录dentry=lookup_one_len(name,dentry,len);if(IS_ERR(dentry))gotofail;// 移动到下一级name+=len;}*path=dentry;returnNULL;}6. 目录项缓存 (dentry cache)
6.1 dentry 缓存
Linux 使用 dentry 缓存加速路径解析:
// fs/dcache.c// 哈希表staticstructhlist_bl_head*dentry_hashtable;staticLIST_HEAD(dentry_unused);// 添加到缓存voidd_add(structdentry*entry,structinode*inode){// 设置 inodeentry->d_inode=inode;// 哈希d_hash(entry);// 添加到哈希表hlist_bl_add_head(&entry->d_hash,&dentry_hashtable[hash]);// 添加到 LRU 链表list_add(&entry->d_lru,&dentry_unused);// 增加引用计数atomic_inc(&inode->i_count);}// 查找structdentry*d_lookup(structdentry*parent,structqstr*name){structhlist_bl_head*head;structdentry*dentry;// 计算哈希hash=full_name_hash(parent,name->name,name->len);head=&dentry_hashtable[hash&D_HASHMASK];// 遍历链表hlist_bl_for_each_entry(dentry,head,d_hash){if(dentry->d_parent!=parent)continue;if(dentry->d_name.hash!=hash)continue;if(!dentry_cmp(dentry,name))returndentry;}returnNULL;}7. 总结
VFS 是 Linux 文件系统的核心抽象:
- 统一接口- 为所有文件系统提供相同 API
- 核心数据结构- super_block, inode, dentry, file
- 路径解析- 高效的目录项缓存
- 文件操作- open, read, write, close 等
理解 VFS 是深入学习文件系统的基础。
下一节:通用块设备层