EXT4 之 Dentry 和 Inode对象

综述

文件系统在内存中是通过dentry和inode来表现的,换句话说:文件系统本身是一个虚拟的概念,但是我们可以通过它在内存中的表现形式dentry和inode来进行研究。Inodes是底层的对象的表现形式(也是目录的表现形式),dentry是一个由d_name、指向一个inode的d_node、一个指向父dentry的d_parent组成。

Dentry 和Inode

加入我们有如下的结构:

/
|
foo
|   \
bar  bar2

在上面所示的结构中,可以提取到如下信息:

  • 有4个inode,分别是foo,bar,bar2,/
  • 有3个denry, 分别是bar–>foobar2–>foofoo–>/

对于上述的关系,做一个简单的说明。对于一个d_namebar的dentry来说,该dentry拥有一个指向底层文件名为bar的指针d_inode、一个指向父dentry的指针d_parent。对于root dentry来说,d_parent指向自己。

Dentry 和Inode之间的映射关系

这里需要注意的是。从dentry 到 inode之间的映射关系是由d_inode指针来维护的,一个inode可以对应多个dentry,多个dentry可以对应一个inode。dentry到inode是多对一的关系。在同一文件系统中,一个文件可以被多个dentry所引用(我们通常称之为:硬链接);这种映射关系有这样的特性:除非当当前文件的所有dentry引用被删除,否则当前file是不会被删除的。

文件和目录的操作者是进程,当然了其实质是操作相应的数据结构。在进程操作的数据结构中包含了指向dentry的指针。其所代表的文件在进程打开期间同样也是无法删除的,除非文件不再被任何dentry所引用。

Inode 和superblock的关系

另外,Inode也同superblock之间保存有密切的联系。在inode的结构体中有一个指向superblock的指针i_sb。superblock是一个描述了当前文件系统状态的结构体,通常是存储在物理设备上。

不同文件系统之间的关系

但是从进程(或则叫用户角度)来看:该进程不可能同时只和同一个文件系统发生关系,相应的会同各种不同的文件系统有关联;不同的文件系统之间也存在着种种关联,这就需要一个结构来对这种关系加以规范,这种结构就是由vfsmount struct所代表的mountpoint结构。
除了需要同父子vfsmounts关联之外,每一个vfsmount都包含有如下信息:

  • mnt_root:一个指向vfsmount root dentry的指针
  • mnt_mountpoint: 一个指向当前vfsmount所被挂载点的dentry指针

vfsmount和底层文件系统之间的关系同样也是多对一的关系。可以将同一个文件系统mount到不同的地方,这样的一个显著结果是:被挂在在不同地方的文件系统拥有同样的dentries、inodes和superblock

举例说明

不同的进程隶属不同的命名空间。当某一进程使用clone并配合CLONE_NEWNS标识创建一个新的task时,文件系统会赋予该进程一分其父dentry的vfsmount关系树。命名空间的root是由task->namespace->root指针来指明的(尽管task->fs->root task->fs->rootmnt看起来更像实际的起始位置,但是在拥有chroot的情况下,他们二者还是有很大不同的)。
当我们看到了一个绝对路径"/foo/bar",

  1. 遍历task->fs->rootmnt 所指向的vfsmount以及task->fs->root所指向的dentry
  2. 开始查找一个名为foo的并且保存有d_parent的dentry
  3. 检查当前dentry是否有相应的mount信息;如果在当前的dentry上存储有mont信息,那么首先查看下到底mount在什么地方,并使用当前的vfsmount替换dentry上原有的vfsmount,替换其root指向的dentry
  4. 对于bar重复step 2 的操作,并产生新的vfsmount和dentry

step 3比较晦涩,这稍作介绍。在step 2 中所找到的dentry 实际上是可能被多方引用到多个命名空间中的;对于引用该dentry的每一方来说,可能就是不同文件系统的挂载点(或者啥都米有)。所有即便是我们知道了dentry上的所有信息,依然无法确定该dentry是否有被mount到啥地方,因此我们推出了vfsmount。因此通常的做法是去查找当前保存在dentry hash table中的vfsmount,所查找到的vfsmount结果向我们展示了当前dentry所mount了什么dentry

我们也可以在已经挂在了文件系统的dentry上重新挂载一个新的文件系统,此时会将前一次挂载的文件系统隐藏。所有当我们在Dentry中发现了被挂在的vfsmount时,需要重复的去搜索新的vfsmount以及判定当前dentry的root dentry是否又被挂载的什么位置;一直重复这个动作直到发现一个没有任何挂载的root dentry为止。这个流程,我们可以通过研读kernel/fs/namei.c:follow_mount()来明确。

在上述的每一个阶段中,所遍历到的dentry并不是我们所需要的信息,相反我们所需要的信息是成对的dentry和vfsmount。所以在struct nameidata结构体中保存了指向dentry和vfsmount的指针,可以用来进行回溯。

struct nameidata {
    struct path path;
    struct qstr last;
    struct path root;
    struct inode    *inode; /* path.dentry.d_inode */
    unsigned int    flags;
    unsigned    seq, m_seq;
    int     last_type;
    unsigned    depth;
    char *saved_names[MAX_NESTED_LINKS + 1];
};
struct path {
    struct vfsmount *mnt;
    struct dentry *dentry;
};

题外话

fs_struct 和struct namespace

对于定义在include/linux/sched.h中的task_struct,其中抱恨了struct fs_structstruct namespace结构。

struct fs_struct {
    atomic_t count;
    rwlock_t lock;
    int umask;
    struct dentry * root, * pwd, * altroot;
    struct vfsmount * rootmnt, * pwdmnt, * altrootmnt;
};

struct namespace {
    atomic_t                count;
    struct vfsmount *       root;
    struct list_head        list;
    struct rw_semaphore     sem;
};

sys_chroot()函数调用set_fs_root时,仅仅支护改变fs->rootfs->rootmnt,但是并不会改变当前实际工作的目录(使用pwd命令所打印出的信息)。尽管我们执行了chroot指令,但是的状态其实是继承在执行该指令之前状态(打开了那些文件、任务啊等等)

struct vfsmount

详细可查阅代码:include/linux/mount.h:

struct vfsmount
{
    struct list_head mnt_hash;
    struct vfsmount *mnt_parent;    /* fs we are mounted on */
    struct dentry *mnt_mountpoint;  /* dentry of mountpoint */
    struct dentry *mnt_root;        /* root of the mounted tree */
    struct super_block *mnt_sb;     /* pointer to superblock */
    struct list_head mnt_mounts;    /* list of children, anchored here */
    struct list_head mnt_child;     /* and going through their mnt_child */
    atomic_t mnt_count;
    int mnt_flags;
    char *mnt_devname;              /* Name of device e.g. /dev/dsk/hda1 */
    struct list_head mnt_list;
};

原文参见:
http://www.fieldses.org/~bfields/kernel/vfs.txt

猜你喜欢

转载自blog.csdn.net/cpwolaichile/article/details/74377579