vfscore 1. linux——vfs虚拟文件系统
虚拟文件系统VFS (1) 是具体文件系统和上层应用的接口层 (2) 只存在于内存中,不存在任何外存空间 (3) 在系统启动时建立,系统关闭时消亡 (4) 由超级块、inode, dentry, vfsmont等信息组成
具体文件系统 (1) 如 minix ext1/2/3/4 sysfs等 (2) 实现代码被组织成模块形式,向vfs注册回调 (3) 处理和具体文件系统相关的细节
1.1 vfs各个对象之间的关系
file_system_type 用于描述某种文件系统类型,一个file_system_type相当于一个类,用于定义一个具体的文件系统实例,某个file_system_type对象(具体的某个文件系统)与特定的 super_block关联,所有的文件系统都通过next组成单链表
super_block 用于描述整个文件系统的元数据,它与根inode,根dentry关联,同时也与挂载实例vfsmount相关联,它通过s_list链入全局链表super_blocks;通过s_instances连入file_system_type的fs_supers哈希表中
dentry 用于描述文件和目录的层级关系,dentry与父dentry和子dentry形成dentry树;近期没有使用的dentry通过d_lru链接入super block的s_dentry_lru链表;dentry通过d_u.d_alias连入inode的i_dentry哈希链表,通过d_inode指向所属的inode,通过dentry可以查找到对应的inode。为了查找某一个文件,它与vfsmount构成<vfsmount, dentry>二元组。图中的dentry如果它的d_parent为它自身则为root dentry
inode 所有的inode通过链表链接起来,通过i_sb_list指针连入super_block的s_inodes链表,它的i_sb指向所属文件系统的super block; 近期没有使用的inode通过i_lru链接入super block的s_inode_lru链表
每个inode节点的大小,一般是128字节或256字节。inode节点的总数,在格式化时就给定(现代OS可以动态变化),一般每2KB就设置一个inode。
一般文件系统中很少有文件小于2KB的,所以预定按照2KB分,一般inode是用不完的。所以inode在文件系统安装的时候会有一个默认数量,后期会根据实际的需要发生变化。
注意inode号:inode号是唯一的,表示不同的文件。其实在Linux内部的时候,访问文件都是通过inode号来进行的,所谓文件名仅仅是给用户容易使用的。
当我们打开一个文件的时候,首先,系统找到这个文件名对应的inode号;然后,通过inode号,得到inode信息,最后,由inode找到文件数据所在的block,现在可以处理文件数据了。
vfsmount 每一个装载实例都对应一个vfsmount,vfsmount与待装载文件系统(非被装载)的root dentry,super_block关联.
mount mount是vfsmount的封装,所有的mount链接成一张链表,mount代表待装载文件系统, 它的装载点指明了挂载到哪个dentry。可以为一个文件系统创建多个装载实例vfsmount,挂载到不同的挂载点上。图中的mount如果它的mnt_parent为它自身则为root mount,代表的是rootfs
1.2 VFS与具体文件系统的关联 1.2.1 VFS与具体文件系统的超级块
从图中可以看出VFS中在内存构建了一个通用的超级块实例,它通过s_fs_info来指向具体文件系统的内存超级块,而具体文件系统的超级块又来源于具体文件系统在磁盘上的超级块。
1.2.2 VFS和具体文件系统的inode
可以看出inode具有三种形态: 磁盘上的inode;具体文件系统的inode;VFS的inode vfs的inode往往作为具体文件系统的inode的一个成员变量 vfs的inode的i_private一般指向了具体文件系统的inode
1.2.3 vfs与具体文件系统的dentry
一般dentry只存在于VFS中
1.3 具体文件系统磁盘布局
以minix文件系统为例,文件系统在磁盘布局包含如下部分:
引导块
在文件系统开头,通常是一个扇区,存放引导程序,用于读入并启动操作系统
超级块
存放文件系统结构信息,并说明各部分大小
i节点位图
说明i节点使用情况,如果inode已经使用,则对应的bit置1
逻辑块位图
描述磁盘上每个逻辑块的使用情况,如果逻辑块被使用则置1
i节点
反应文件的元数据,一般是描述了文件由哪些逻辑块组成
逻辑块
保存了文件的数据
1.4 路径查找总体过程
根据文件名查找目录文件,目录文件是特殊文件,保存了文件名和i节点的对应关系,找到对应的目录项,目录项包含了inode号,找到对应的inode
进入inode节点找到对应的逻辑块
读取逻辑块读取相关文件内容
2. 源码分析 文件目录结构如下图:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 vfscore ├─ Config.uk ├─ dentry.c ├─ eventpoll.c ├─ exportsyms.uk ├─ extra.ld ├─ fd.c ├─ file.c ├─ fops.c ├─ include │ ├─ sys │ │ └─ vfs.h │ └─ vfscore │ ├─ dentry.h │ ├─ eventpoll.h │ ├─ file.h │ ├─ fs.h │ ├─ mount.h │ ├─ prex.h │ ├─ uio.h │ └─ vnode.h ├─ lookup.c ├─ main.c ├─ Makefile.uk ├─ mount.c ├─ pipe.c ├─ rootfs.c ├─ stdio.c ├─ subr_uio.c ├─ syscalls.c ├─ task.c ├─ vfs.h └─ vnode.c
2.1 vnode.h [The Sun VFS/Vnode Architecture - UNIX Filesystems: Evolution, Design, and Implementation Book] (oreilly.com)
编号
Inode
Vnode
1.
Inodes有与文件内容无关的文件元数据
vnode包含在文件生命周期内不会更改的属性
2.
Inode是一种磁盘上的结构,它从磁盘的角度解释文件的存储
Vnode是inode的内存结构抽象
3.
Inode不是内核的数据结构
Vnode是inode的内核表示。
4.
它可以快速访问
它比Inode需要更多的访问时间
5.
inode总是有效的
Vnode不一定总是有效的
6.
它包含了总是需要的信息(例如保护、管理权力)
Vnode只在打开文件时才存在
7.
Inode与分区内的唯一编号相关联
Vnode在分区中没有唯一的编号
8.
然而,它是UNIX操作系统中的一种数据结构
Vnode是内核内存中的一个对象,它代表UNIX文件接口
vnode负责记录文件存储的位置指针以及文件的属性等等,它具体包含以下几个属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 struct vnode { uint64_t v_ino; struct uk_list_head v_link ; struct mount *v_mount ; struct vnops *v_op ; int v_refcnt; int v_type; int v_flags; mode_t v_mode; off_t v_size; struct uk_mutex v_lock ; struct uk_list_head v_names ; void *v_data; };
v_ino: 对应inode的数字号,即索引节点号
v_link: 一个双向链表的节点,表示所有hash值相同的vnode的链表,用于快速查找
*v_mount: vfs挂载的指针
*v_op: vnode的操作指针
v_refcnt: 引用计数,当为0时即可以删除
v_type: vnode的类型,大致分为无类型、常规文件、目录、块设备(例如硬盘)、字符设备(例如键盘、打印机,一次处理一个字符)、软链接(删除的时候计数-1)、socket、FIFO管道(进程通信)
v_flags: vnode的标志,有三类-> VROOT 指文件系统的root节点;VISTTY 指设备是tty(Teletype)指终端设备;VPROTDEV指被保护的设备。
v_mode: 文件的访问权限
v_size: 文件的大小
v_lock: 互斥锁,保证在一个时间里只有一个线程能访问
v_name: 这个节点所在目录项的链表
*v_data: 存储的文件的指针
除了以上几个属性,vnode自身还包括以下几个属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 struct vattr { unsigned int va_mask; enum vtype va_type ; mode_t va_mode; nlink_t va_nlink; uid_t va_uid; gid_t va_gid; dev_t va_fsid; ino_t va_nodeid; struct timespec va_atime ; struct timespec va_mtime ; struct timespec va_ctime ; dev_t va_rdev; uint64_t va_nblocks; off_t va_size; };
va_mask: 表示vnode属性的掩码,一共17位,每一位代表一个属性
va-type: 表示vnode的类型,同上v-type
va-mode: 表示文件的访问模式
va-nlink: 硬链接数。当该vnode描述一个目录时,这个值至少为2,代表.和..的数目
va-uid: vnode所属文件的拥有者的id
va-gid: vnode所属文件所在组的id
va-fsid: 底层文件系统的id
va-nodeid: 索引节点号
va-atime: 文件最近一次被访问的时间
va-mtime: 文件最近一次被修改的时间
va-ctime: 文件最近一次被修改的时间,比起内容更强调文件属性
va-rdev: 如果该节点描述的是一个设备文件,则该值为设备号
va-nblocks: 文件使用的块的个数
va-size: 文件的大小
vattr结构体主要用于合并多种类型的文件属性,以便将它们作为函数参数进行传递。
vnode的操作函数有以下几个:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 struct vnops { vnop_open_t vop_open; vnop_close_t vop_close; vnop_read_t vop_read; vnop_write_t vop_write; vnop_seek_t vop_seek; vnop_ioctl_t vop_ioctl; vnop_fsync_t vop_fsync; vnop_readdir_t vop_readdir; vnop_lookup_t vop_lookup; vnop_create_t vop_create; vnop_remove_t vop_remove; vnop_rename_t vop_rename; vnop_mkdir_t vop_mkdir; vnop_rmdir_t vop_rmdir; vnop_getattr_t vop_getattr; vnop_setattr_t vop_setattr; vnop_inactive_t vop_inactive; vnop_truncate_t vop_truncate; vnop_link_t vop_link; vnop_cache_t vop_cache; vnop_fallocate_t vop_fallocate; vnop_readlink_t vop_readlink; vnop_symlink_t vop_symlink; vnop_poll_t vop_poll; };
2.2 dentry.h dentry即directory entry目录项,用于描述文件和目录的层级关系。目录项是描述文件的逻辑属性,只存在于内存中,并没有实际对应的磁盘上的描述,更确切的说是存在于内存的目录项缓存,为了提高查找性能而设计。不管是文件夹还是最终的文件,都是属于目录项,所有的目录项在一起构成一颗庞大的目录树。
例如:open一个文件/home/xxx/yyy.txt,那么/、home、xxx、yyy.txt都是一个目录项,VFS在查找的时候,根据一层一层的目录项找到对应的每个目录项的inode,那么沿着目录项进行操作就可以找到最终的文件。
注意:目录也是一种文件(所以也存在对应的inode)。打开目录,实际上就是打开目录文件。
1 2 3 4 5 6 7 8 9 10 11 12 struct dentry { struct uk_hlist_node d_link ; int d_refcnt; char *d_path; struct vnode *d_vnode ; struct mount *d_mount ; struct dentry *d_parent ; struct uk_list_head d_names_link ; struct uk_mutex d_lock ; struct uk_list_head d_child_list ; struct uk_list_head d_child_link ; };
d_link: 同v_link,用于快速查找dentry
d_refcnt: 同v_refcnt, 引用计数
*d_path: 在文件系统里的路径的指针
*d_vnode: 目录项指向的节点,一个有效的dentry结构必定有一个vnode结构,这是因为一个目录项要么代表着一个文件,要么代表着一个目录,而目录实际上也是文件。所以,只要dentry结构是有效的,则其指针d_vnode必定指向一个vnode结构。但是一个vnode却可以对应多个目录项(例如在别的路径下创建的软链接)
*d_mount: 目录项指向的挂载
*d_parent: 目录项的父节点
d_names_link:
d_lock: 同v_lock,是一个互斥锁
d_child_list: 目录项的子
d_child_link:
dentry的函数:
1 2 3 4 5 6 struct dentry *dentry_alloc (struct dentry *parent_dp, struct vnode *vp, const char *path) ;struct dentry *dentry_lookup (struct mount *mp, char *path) ;int dentry_move (struct dentry *dp, struct dentry *parent_dp, char *path) ;void dentry_remove (struct dentry *dp) ;void dref (struct dentry *dp) ;void drele (struct dentry *dp) ;
alloc: 通过父目录项节点、对应的文件节点vnode、路径path创建一个目录项
lookup:通过挂载和路径来找到目录项
move: 移动目录项到指定路径
remove: 删除目录项
ref:
rele: 释放目录项
2.3 mount.h mount主要用于挂载设备,其结构如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 struct mount { struct vfsops *m_op ; int m_flags; int m_count; char m_path[PATH_MAX]; char m_special[PATH_MAX]; struct device *m_dev ; struct dentry *m_root ; struct dentry *m_covered ; void *m_data; struct uk_list_head mnt_list ; fsid_t m_fsid; };
m_op: mount操作的指针
m_flags: 挂载的类型,分为只读文件系统、同步写文件系统、异步写文件系统、不能执行的文件系统、不能设置权限的文件系统 、不能解释特别的文件、与底层文件系统的联合。
m_path: 挂载的路径
m_special: 资源的路径
*m_dev: 挂载的设备
*m_root: 根目录项
*m_covered: 挂载的文件系统的父目录项
*m_data: 挂载的文件系统数据
mnt_list: 挂载的文件系统的链表
m_fsid: 挂载的文件系统的独特的id
挂载操作有以下几个操作:
1 2 3 4 5 6 7 8 struct vfsops { int (*vfs_mount) (struct mount *, const char *, int , const void *); int (*vfs_unmount) (struct mount *, int flags); int (*vfs_sync) (struct mount *); int (*vfs_vget) (struct mount *, struct vnode *); int (*vfs_statfs) (struct mount *, struct statfs *); struct vnops *vfs_vnops ; };
2.4 file.h vfscore_file
1 2 3 4 5 6 7 8 9 10 11 12 struct vfscore_file { int fd; int f_flags; int f_count; off_t f_offset; void *f_data; int f_vfs_flags; struct dentry *f_dentry ; struct uk_mutex f_lock ; struct uk_list_head f_ep ; };
fd: 文件描述符 file descriptor
f_flags: 文件是否是打开的标志
f_count: 文件的引用计数
f_offset: 在文件中的当前位置
*f_data: 文件描述符描述的特定数据
f_vfs_flags: 内部实现的标志
*f_dentry: 文件的目录项
f_lock: 文件的互斥锁
f_ep: 事件队列的列表
2.5 main.c 首先main.c定义了三个内联函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 static inline int libc_error (int err) { errno = err; return -1 ; } static inline int has_error (int error, int bytes) { return error && ( (bytes == 0 ) || (error != EWOULDBLOCK && error != EINTR)); } static inline mode_t apply_umask (mode_t mode) { return mode & ~ukarch_load_n(&global_umask); }
2.5.1 open 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 UK_LLSYSCALL_R_DEFINE(int , open, const char *, pathname, int , flags, mode_t , mode) { trace_vfs_open(pathname, flags, mode); struct task *t = main_task; char path[PATH_MAX]; struct vfscore_file *fp ; int fd, error; int acc; acc = 0 ; switch (flags & O_ACCMODE) { case O_RDONLY: acc = VREAD; break ; case O_WRONLY: acc = VWRITE; break ; case O_RDWR: acc = VREAD | VWRITE; break ; } error = task_conv(t, pathname, acc, path); if (error) goto out_error; error = sys_open(path, flags, mode, &fp); if (error) goto out_error; error = fdalloc(fp, &fd); if (error) goto out_fput; fdrop(fp); trace_vfs_open_ret(fd); return fd; out_fput: fdrop(fp); out_error: trace_vfs_open_err(error); return -error; }
sys_open的代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 int sys_open (char *path, int flags, mode_t mode, struct vfscore_file **fpp) { struct vfscore_file *fp ; struct dentry *dp , *ddp ; struct vnode *vp ; char *filename; int error; DPRINTF(VFSDB_SYSCALL, ("sys_open: path=%s flags=%x mode=%x\n" , path, flags, mode)); flags = vfscore_fflags(flags); if (flags & O_CREAT) { error = namei(path, &dp); if (error == ENOENT) { if ((error = lookup(path, &ddp, &filename)) != 0 ) return error; vn_lock(ddp->d_vnode); if ((error = vn_access(ddp->d_vnode, VWRITE)) != 0 ) { vn_unlock(ddp->d_vnode); drele(ddp); return error; } mode &= ~S_IFMT; mode |= S_IFREG; error = VOP_CREATE(ddp->d_vnode, filename, mode); vn_unlock(ddp->d_vnode); drele(ddp); if (error) return error; if ((error = namei(path, &dp)) != 0 ) return error; vp = dp->d_vnode; flags &= ~O_TRUNC; } else if (error) { return error; } else { if (flags & O_EXCL) { error = EEXIST; goto out_drele; } } vp = dp->d_vnode; flags &= ~O_CREAT; } else { if (flags & O_NOFOLLOW) { error = open_no_follow_chk(path); if (error != 0 ) return error; } error = namei(path, &dp); if (error) return error; vp = dp->d_vnode; if (flags & UK_FWRITE || flags & O_TRUNC) { error = vn_access(vp, VWRITE); if (error) goto out_drele; error = EISDIR; if (vp->v_type == VDIR) goto out_drele; } if (flags & O_DIRECTORY) { if (vp->v_type != VDIR) { error = ENOTDIR; goto out_drele; } } } fp = calloc (sizeof (struct vfscore_file), 1 ); if (!fp) { error = ENOMEM; goto out_drele; } fhold(fp); fp->f_flags = flags; fp->f_dentry = dp; uk_mutex_init(&fp->f_lock); UK_INIT_LIST_HEAD(&fp->f_ep); vn_lock(vp); if (flags & O_TRUNC) { error = EINVAL; if (!(flags & UK_FWRITE) || vp->v_type == VDIR) goto out_fp_free_unlock; error = VOP_TRUNCATE(vp, 0 ); if (error) goto out_fp_free_unlock; } error = VOP_OPEN(vp, fp); if (error) goto out_fp_free_unlock; vn_unlock(vp); *fpp = fp; return 0 ; out_fp_free_unlock: free (fp); vn_unlock(vp); out_drele: if (dp) drele(dp); return error; }
VOP_OPEN的实现代码如下:9pfs是qemu所使用的文件系统Plan 9 Filesystem Protocol
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 static int uk_9pfs_open (struct vfscore_file *file) { struct uk_9pdev *dev = UK_9PFS_MD(file->f_dentry->d_mount)->dev; struct uk_9pfid *openedfid ; struct uk_9pfs_file_data *fd ; int rc; fd = calloc (1 , sizeof (*fd)); if (!fd) return ENOMEM; openedfid = uk_9p_walk(dev, UK_9PFS_VFID(file->f_dentry->d_vnode), NULL ); if (PTRISERR(openedfid)) { rc = PTR2ERR(openedfid); goto out; } rc = uk_9p_open(dev, openedfid, uk_9pfs_open_mode_from_posix_flags(file->f_flags)); if (rc) goto out_err; fd->fid = openedfid; file->f_data = fd; UK_9PFS_ND(file->f_dentry->d_vnode)->nb_open_files++; return 0 ; out_err: uk_9pfid_put(openedfid); out: free (fd); return -rc; }
2.6 一些函数 2.6.1 task.c : task_conv、path_conv 1 2 3 4 5 6 7 8 9 10 11 12 13 14 int task_conv (struct task *t, const char *cpath, int acc __unused, char *full) { int rc; rc = path_conv(t->t_cwd, cpath, full); if (rc != 0 ) { return (rc); } return (0 ); }
path_conv:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 int path_conv (char *wd, const char *cpath, char *full) { char path[PATH_MAX]; char *src, *tgt, *p, *end; size_t len = 0 ; strlcpy(path, cpath, PATH_MAX); path[PATH_MAX - 1 ] = '\0' ; len = strlen (path); if (len >= PATH_MAX) return ENAMETOOLONG; if (strlen (wd) + len >= PATH_MAX) return ENAMETOOLONG; src = path; tgt = full; end = src + len; if (path[0 ] == '/' ) { *tgt++ = *src++; len = 1 ; } else { strlcpy(full, wd, PATH_MAX); len = strlen (wd); tgt += len; if (len > 1 && path[0 ] != '.' ) { *tgt = '/' ; tgt++; len++; } } while (*src) { p = src; while (*p != '/' && *p != '\0' ) p++; *p = '\0' ; if (!strcmp (src, ".." )) { if (len >= 2 ) { len -= 2 ; tgt -= 2 ; while (*tgt != '/' ) { tgt--; len--; } if (len == 0 ) { tgt++; len++; } } } else if (!strcmp (src, "." )) { } else { while (*src != '\0' ) { *tgt++ = *src++; len++; } } if (p == end) break ; if (len > 0 && *(tgt - 1 ) != '/' ) { *tgt++ = '/' ; len++; } src = p + 1 ; } *tgt = '\0' ; return (0 ); }
2.6.2 fd.c: fdalloc 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 int fdalloc (struct vfscore_file *fp, int *newfd) { int fd, ret = 0 ; fhold(fp); fd = vfscore_alloc_fd(); if (fd < 0 ) { ret = fd; goto exit ; } ret = vfscore_install_fd(fd, fp); if (ret) fdrop(fp); else *newfd = fd; exit : return ret; }
vfscore_alloc_fd:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 int vfscore_alloc_fd (void ) { unsigned long flags; int ret; flags = ukplat_lcpu_save_irqf(); ret = uk_find_next_zero_bit(fdtable.bitmap, FDTABLE_MAX_FILES, 0 ); if (ret == FDTABLE_MAX_FILES) { ret = -ENFILE; goto exit ; } uk_bitmap_set(fdtable.bitmap, ret, 1 ); exit : ukplat_lcpu_restore_irqf(flags); return ret; }
2.6.3 lookup.c: namei、lookup lookup:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 int lookup (char *path, struct dentry **dpp, char **name) { char buf[PATH_MAX]; char root[] = "/" ; char *file, *dir; struct dentry *dp ; int error; DPRINTF(VFSDB_VNODE, ("lookup: path=%s\n" , path)); strlcpy(buf, path, sizeof (buf)); file = strrchr (buf, '/' ); if (!buf[0 ]) { return ENOTDIR; } if (file == buf) { dir = root; } else { *file = '\0' ; dir = buf; } if ((error = namei(dir, &dp)) != 0 ) { return error; } if (dp->d_vnode->v_type != VDIR) { drele(dp); return ENOTDIR; } *dpp = dp; if (name) { *name = strrchr (path, '/' ) + 1 ; } return 0 ; }
namei:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 int namei (const char *path, struct dentry **dpp) { char *p; char node[PATH_MAX]; char name[PATH_MAX]; char fp[PATH_MAX]; struct mount *mp ; struct dentry *dp , *ddp ; struct vnode *dvp , *vp ; int error, i; int links_followed; int need_continue; DPRINTF(VFSDB_VNODE, ("namei: path=%s\n" , path)); links_followed = 0 ; strlcpy(fp, path, PATH_MAX); do { need_continue = 0 ; if (vfs_findroot(fp, &mp, &p)) { return ENOTDIR; } int mountpoint_len = p - fp - 1 ; strlcpy(node, "/" , sizeof (node)); strlcat(node, p, sizeof (node)); dp = dentry_lookup(mp, node); if (dp) { *dpp = dp; return 0 ; } ddp = mp->m_root; if (!ddp) { UK_CRASH("VFS: no root" ); } dref(ddp); node[0 ] = '\0' ; while (*p != '\0' ) { while (*p == '/' ) { p++; } if (*p == '\0' ) { break ; } for (i = 0 ; i < PATH_MAX; i++) { if (*p == '\0' || *p == '/' ) { break ; } name[i] = *p++; } name[i] = '\0' ; strlcat(node, "/" , sizeof (node)); strlcat(node, name, sizeof (node)); dvp = ddp->d_vnode; vn_lock(dvp); dp = dentry_lookup(mp, node); if (dp == NULL ) { error = VOP_LOOKUP(dvp, name, &vp); if (error) { vn_unlock(dvp); drele(ddp); return error; } dp = dentry_alloc(ddp, vp, node); vput(vp); if (!dp) { vn_unlock(dvp); drele(ddp); return ENOMEM; } } vn_unlock(dvp); drele(ddp); ddp = dp; if (dp->d_vnode->v_type == VLNK) { error = namei_follow_link(dp, node, name, fp, mountpoint_len); if (error) { drele(dp); return (error); } drele(dp); p = fp; dp = NULL ; ddp = NULL ; vp = NULL ; dvp = NULL ; name[0 ] = 0 ; node[0 ] = 0 ; if (++links_followed >= MAXSYMLINKS) { return (ELOOP); } need_continue = 1 ; break ; } if (*p == '/' && ddp->d_vnode->v_type != VDIR) { drele(ddp); return ENOTDIR; } } } while (need_continue); *dpp = dp; return 0 ; }
2.6.4 mount.c: vfs_findroot 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 int vfs_findroot (const char *path, struct mount **mp, char **root) { struct mount *m = NULL , *tmp; size_t len, max_len = 0 ; if (!path) return -1 ; uk_mutex_lock(&mount_lock); uk_list_for_each_entry(tmp, &mount_list, mnt_list) { len = count_match(path, tmp->m_path); if (len > max_len) { max_len = len; m = tmp; } } uk_mutex_unlock(&mount_lock); if (m == NULL ) return -1 ; *root = (char *)(path + max_len); if (**root == '/' ) (*root)++; *mp = m; return 0 ; }
2.6.5 dentry.c: dentry_lookup、dentry_alloc 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 struct dentry *dentry_lookup (struct mount *mp, char *path) { struct dentry *dp ; uk_mutex_lock(&dentry_hash_lock); uk_hlist_for_each_entry(dp, &dentry_hash_table[dentry_hash(mp, path)], d_link) { if (dp->d_mount == mp && !strncmp (dp->d_path, path, PATH_MAX)) { dp->d_refcnt++; uk_mutex_unlock(&dentry_hash_lock); return dp; } } uk_mutex_unlock(&dentry_hash_lock); return NULL ; }
dentry_alloc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 struct dentry *dentry_alloc (struct dentry *parent_dp, struct vnode *vp, const char *path) { struct mount *mp = vp->v_mount; struct dentry *dp = (struct dentry*)calloc (sizeof (*dp), 1 ); if (!dp) { return NULL ; } dp->d_path = strdup(path); if (!dp->d_path) { free (dp); return NULL ; } vref(vp); dp->d_refcnt = 1 ; dp->d_vnode = vp; dp->d_mount = mp; UK_INIT_LIST_HEAD(&dp->d_child_list); if (parent_dp) { dref(parent_dp); uk_mutex_lock(&parent_dp->d_lock); uk_list_add(&dp->d_child_link, &parent_dp->d_child_list); uk_mutex_unlock(&parent_dp->d_lock); } dp->d_parent = parent_dp; vn_add_name(vp, dp); uk_mutex_lock(&dentry_hash_lock); uk_hlist_add_head(&dp->d_link, &dentry_hash_table[dentry_hash(mp, path)]); uk_mutex_unlock(&dentry_hash_lock); return dp; };
3. unikraft——vfscore 3.1 dentry目录项的结构
3.2 vnode的结构和dentry的关系
3.3 mount挂载的结构
3.4 open函数的流程