精华内容
下载资源
问答
  • Linux文件系统之inode、dentry

    千次阅读 2017-04-06 15:20:59
    linux文件系统中重要的两个数据结构: inode、dentry

    inode和dentry在VFS和实体的文件系统(ext2、ext3等)中都是比较重要的概念。首先看一下虚拟文件系统的标准定义:虚拟文件系统英语:Virtual file system,缩写为VFS),又称虚拟文件切换系统(virtual filesystem switch),是操作系统的文件系统虚拟层,在其下是实体的文件系统。虚拟文件系统的主要功用,在于让上层的软件,能够用单一的方式,来跟底层不同的文件系统沟通。在操作系统与之下的各种文件系统之间,虚拟文件系统提供了标准的操作接口,让操作系统能够很快的支持新的文件系统。

    VFS在Linux系统中的结构为:


    在教科书上面,一般是这样描述inode的:inode是内核文件对象的元数据。inode中不包括文件的数据和文件名字信息。inode中只包含数据块的位置信息,数据结构相对稳定,其中没有数据和文件名等变长数据,可以固定其大小,进而可以实现将整个文件系统中的inode按照一定的组织方式来集中存储在硬盘起始的一个,文件系统加载时,可以方便查找即可。

    inode仅仅只是保存了文件对象的属性信息,包括:权限、属组、数据块的位置、时间戳等信息。但是并没有包含文件名,文件在文件系统的目录树中所处的位置信息。那么内核又是怎么管理文件系统的目录树呢?

    目录项在内核中起到了连接不同的文件对象inode的作用,进而起到了维护文件系统目录树的作用。dentry是一个纯粹的内存结构,由文件系统在提供文件访问的过程中在内存中直接建立。dentry中包含了文件名,文件的inode号等信息。

    对于POSIX标准定义了文件系统的inode。VFS接口即是符合POSX标准的,实体文件系统只要能对接上VFS,即可符合POSIX标准。因此,一般而言我们研究VFS文件系统即可了解大部分文件系统的结构。而在VFS中,定义了规范化的inode结构和dentry。

    在读取一个文件时,总是从根目录开始读取,每一个目录或者文件,在VFS中,都是一个文件对象,每一个文件对象都有唯一的一个inode与之对应。根目录的inode号为0,在superblock里,可以很快根据inode号索引到具体的inode,因此读取到的第一个inode就是根目录的。读取到了该目录后,内核对象会为该文件对象建立一个dentry,并将其缓存起来,方便下一次读取时直接从内存中取。而目录本身也是一个文件,目录文件的内容即是该目录下的文件的名字与inode号,目录文件的内容就像一张表,记录的文件名与其inode no.之间的映射关系。根据路径即可找到当前需要读取的下一级文件的名字和inode,同时继续为该文件建立dentry,dentry结构是一种含有指向父节点和子节点指针的双向结构,多个这样的双向结构构成一个内存里面的树状结构,也就是文件系统的目录结构在内存中的缓存了。有了这个缓存,我们在访问文件系统时,通常都非常快捷。

    有了inode和dentry,也就非常容易理解文件的连接了。我们知道软连接,是一个特殊的文件,该文件通过内容指向目标文件。因此软连接有自己的inode,有自己的内容。其内容记录的是目标文件的inode号和自身的名字。软连接是一种特殊的文件。而硬链接则不一样,硬链接是文件的别名,硬链接不是一个完整的文件对象,硬链接只是将自己的名字写在上级目录的内容(文件名与inode no.的映射表)中。而其inode号即是目标文件的inode。这样硬连接与目标文件一起共用一个inode,使用引用计数来管理硬连接。

    展开全文
  • Linux文件系统基础之inode和dentry

    千次阅读 2016-08-10 09:41:28
    Linux文件系统基础之inode和dentry inode(节点)和dentry(目录项)在VFS和实体的文件系统(ext2、ext3等)中都是比较重要的概念。首先看一下虚拟文件系统的标准定义:虚拟文件系统(英语:virtual file system,缩写为...

    Linux文件系统基础之inode和dentry

    inode(节点)和dentry(目录项)在VFS和实体的文件系统(ext2、ext3等)中都是比较重要的概念。首先看一下虚拟文件系统的标准定义:虚拟文件系统(英语:virtual file system,缩写为VFS),又称虚拟文件切换系统(virtual filesystem switch),是操作系统的文件系统虚拟层,在其下是实体的文件系统。虚拟文件系统的主要功用在于让上层的软件,能够用单一的方式,来跟底层不同的文件系统沟通。在操作系统与之下的各种文件系统之间,虚拟文件系统提供了标准的操作接口,让操作系统能够很快的支持新的文件系统。

    VFS在Linux系统中的结构为:

    在教科书上面,一般是这样描述inode的:inode是内核文件对象的元数据。inode中不包括文件的数据和文件名字信息。inode中只包含数据块的位置信息,数据结构相对稳定,其中没有数据和文件名等变长数据,可以固定其大小,进而可以实现将整个文件系统中的inode按照一定的组织方式来集中存储在硬盘起始的一个,文件系统加载时,可以方便查找即可。

    inode仅仅只是保存了文件对象的属性信息,包括:权限、属组、数据块的位置、时间戳等信息。但是并没有包含文件名,文件在文件系统的目录树中所处的位置信息。那么内核又是怎么管理文件系统的目录树呢?

    dentry在内核中起到了连接不同的文件对象inode的作用,进而起到了维护文件系统目录树的作用。dentry是一个纯粹的内存结构,由文件系统在提供文件访问的过程中在内存中直接建立。dentry中包含了文件名,文件的inode号等信息。

    对于POSIX标准定义了文件系统的inode。VFS接口即是符合POSIX标准的,实体文件系统只要能对接上VFS,即可符合POSIX标准。因此,一般而言我们研究VFS文件系统即可了解大部分文件系统的结构。而在VFS中,定义了规范化的inode结构和dentry。

    在读取一个文件时,总是从根目录开始读取,每一个目录或者文件,在VFS中,都是一个文件对象,每一个文件对象都有唯一的一个inode与之对应。根目录的inode号为2,在superblock里,可以很快根据inode号索引到具体的inode,因此读取到的第一个inode就是根目录的。读取到了该目录后,内核对象会为该文件对象建立一个dentry,并将其缓存起来,方便下一次读取时直接从内存中取。而目录本身也是一个文件,目录文件的内容即是该目录下的文件的名字与inode号,目录文件的内容就像一张表,记录的文件名与其inode no.之间的映射关系。根据路径即可找到当前需要读取的下一级文件的名字和inode,同时继续为该文件建立dentry,dentry结构是一种含有指向父节点和子节点指针的双向结构,多个这样的双向结构构成一个内存里面的树状结构,也就是文件系统的目录结构在内存中的缓存了。有了这个缓存,我们在访问文件系统时,通常都非常快捷。

    有了inode和dentry,也就非常容易理解文件的连接了。我们知道软连接,是一个特殊的文件,该文件通过内容指向目标文件。因此软连接有自己的inode,有自己的内容。其内容记录的是目标文件的inode号和自身的名字。软连接是一种特殊的文件。而硬链接则不一样,硬链接是文件的别名,硬链接不是一个完整的文件对象,硬链接只是将自己的名字写在上级目录的内容(文件名与inode no.的映射表)中。而其inode号即是目标文件的inode。这样硬连接与目标文件一起共用一个inode,使用引用计数来管理硬连接。

    展开全文
  • 我们知道,linux文件系统,inode和dentry是有对应关系的,dentry是文件名或者目录的一个管理结构,2.6内核中: struct dentry { atomic_t d_count; unsigned int d_flags; spinlock_t d_lock; int d_...

    我们知道,linux文件系统,inode和dentry是有对应关系的,dentry是文件名或者目录的一个管理结构,2.6内核中:

    struct dentry {
        atomic_t d_count;
        unsigned int d_flags;
        spinlock_t d_lock;
        int d_mounted;
        struct inode *d_inode;
        struct hlist_node d_hash;
        struct dentry *d_parent;
        struct qstr d_name;
        struct list_head d_lru;
        union {
            struct list_head d_child;
            struct rcu_head d_rcu;
        } d_u;
        struct list_head d_subdirs;
        struct list_head d_alias;
        unsigned long d_time;
        const struct dentry_operations *d_op;
        struct super_block *d_sb;
        void *d_fsdata;
        unsigned char d_iname[32];
    }
    SIZE: 192

    3.10的内核中如下:

    struct dentry {
        unsigned int d_flags;
        seqcount_t d_seq;
        struct hlist_bl_node d_hash;
        struct dentry *d_parent;
        struct qstr d_name;
        struct inode *d_inode;
        unsigned char d_iname[32];
        struct lockref d_lockref;
        const struct dentry_operations *d_op;
        struct super_block *d_sb;
        unsigned long d_time;
        void *d_fsdata;
        struct list_head d_lru;
        union {
            struct list_head d_child;
            struct callback_head d_rcu;
        } d_u;
        struct list_head d_subdirs;
        struct hlist_node d_alias;
    }

    对比两个结构,其实主要成员变化不大,比如d_parent,d_name,d_iname,下面以2.6为例来描述proc文件系统的父子关系,而父子关系中,主要就是由d_parent,d_u中的

    d_child,d_subdirs这三个成员来维护的。

    给定一个dentry:

    crash> struct dentry 0xffff8818014b1540
    struct dentry {
      d_count = {
        counter = 1
      },
      d_flags = 0,
      d_lock = {
        raw_lock = {
          slock = 196611
        }
      },
      d_mounted = 0,
      d_inode = 0xffff88100a8117f8,-----------指向这个dentry对应的inode
      d_hash = {
        next = 0x0,
        pprev = 0xffffc90000b13890
      },
      d_parent = 0xffff8818118002c0,----------指向父节点,也是一个dentry
      d_name = {
        hash = 3255717505,
        len = 8,
        name = 0xffff8818014b15e0 "slabinfo"------------------------文件名
      },
      d_lru = {
        next = 0xffff8818014b1580,
        prev = 0xffff8818014b1580
      },
      d_u = {
        d_child = {
          next = 0xffff880c117eb710,
          prev = 0xffff881811800320
        },
        d_rcu = {
          next = 0xffff880c117eb710,
          func = 0xffff881811800320
        }
      },
      d_subdirs = {
        next = 0xffff8818014b15a0,
        prev = 0xffff8818014b15a0
      },
      d_alias = {
        next = 0xffff88100a811828,
        prev = 0xffff88100a811828
      },
      d_time = 0,
      d_op = 0xffffffff81622b00 <proc_file_inode_operations+160>,
      d_sb = 0xffff880c1188cc00,
      d_fsdata = 0x0,
      d_iname = "slabinfo\000_offset\000ndler.py\000m\000\000\000\000"
    可以看出:当前节点的文件名是slabinfo, 0xffff8818118002c0就是这个slabinfo的父节点,
    crash> dentry 0xffff8818118002c0
    struct dentry {
      d_count = {
        counter = 725
      },
      d_flags = 16,
      d_lock = {
        raw_lock = {
          slock = 797912975
        }
      },
      d_mounted = 0,
      d_inode = 0xffff880c11402cf8,
      d_hash = {
        next = 0x0,
        pprev = 0x0
      },
      d_parent = 0xffff8818118002c0,--------------对应的parent是自身,也就是当前是顶级节点。
      d_name = {
        hash = 0,
        len = 1,
        name = 0xffff881811800360 "/"--------------当前节点名字,已经是根目录名字了
      },
      d_lru = {
        next = 0xffff881811800300,
        prev = 0xffff881811800300
      },
      d_u = {
        d_child = {
          next = 0xffff881811800310,-------d_u到dentry的偏移是0x50,也就是d_u的本身地址是310,然后这个地址的prev和next是自己本身,说明是根节点
          prev = 0xffff881811800310
        },
        d_rcu = {
          next = 0xffff881811800310,
          func = 0xffff881811800310
        }
      },
      d_subdirs = {--------------------------这个链表中,存放的就是子节点的d_u的地址
        next = 0xffff8818014b1590,
        prev = 0xffff880c0dd74590
      },
      d_alias = {
        next = 0xffff880c11402d28,
        prev = 0xffff880c11402d28
      },
      d_time = 0,
      d_op = 0x0,
      d_sb = 0xffff880c1188cc00,
      d_fsdata = 0x0,
      d_iname = "/\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
    }

    虽然我们知道slabinfo的目录是/proc/slabinfo,那为什么slabinfo的父目录就已经是“/”,而不是proc呢?因为进入/proc,则意味着切换了文件系统,/proc是挂载点。

    我们来看他父目录的子目录/文件的目录项链表,也就是d_suddir 成员。我们知道,dentry可以通过d_parent来寻找自己的父dentry,比较有意思的是,dentry的d_u,会形成一条双向循环链表,按道理,双向循环链表是没有头的,但由于他们的父dentry的d_suddir 也嵌入在这个列表中,所有就可以从父dentry的d_suddirs 的地址来作为list的头来遍历:

    crash> struct -xo dentry.d_subdirs ffff8818118002c0
    struct dentry {
      [ffff881811800320] struct list_head d_subdirs;
    }
    crash> list ffff881811800320
    ffff881811800320
    ffff8818014b1590-----------------------这个就是slabinfo这个文件的d_u的地址
    ffff880c117eb710
    ffff8804ee7510d0
    ffff880c0df82f50
    ffff880db397a850
    ffff88180c6359d0
    ffff880c0de13110
    ffff880a28539910
    ffff880c0dc589d0
    ffff880bfeee9e50
    ffff8805cbccde90
    ffff880bfed53410
    ffff8812ac422650
    ffff8810794cecd0
    ffff881811812c10
    ffff8812ac661190
    ffff88181180cf10
    ffff881801543c10
    ffff880797d60550
    ffff88100aa00890
    ffff88100aa004d0
    ffff88180140da90
    ffff880a28569590
    ffff880c11648b90
    ffff880430752d90
    ffff8804305dddd0
    ffff8804b1f3ef50
    ffff88126055f310
    ffff88126055fcd0
    ffff88126055f6d0
    ffff881801561610
    ffff881052e7fe90
    ffff88126055f550
    ffff880c1167ead0
    ffff880c0a046850
    ffff880c0dfd5710
    ffff880c0dd40310
    ffff880c0dd40610
    ffff8804b1f2c550
    ffff8810ead120d0
    ffff880ffc7633d0
    ffff8808af56ef10
    ffff880bfed2d550
    ffff880a284baf50
    ffff880c0ddccf50

    在这个list出来的地址中,都是dentry的d_u成员的地址,也就是都可以获取到对应的dentry,我们找到slabinfo这个文件的d_u的地址为:

    crash> struct -xo dentry.d_u 0xffff8818014b1540
    struct dentry {
             union {
      [ffff8818014b1590] } d_u;
    }

    也就是说,dentry可以通过d_parent成员直接找到父节点的dentry的地址,而父节点的dentry,可以通过遍历d_subdirs 找到所有子文件或者子目录的地址,这个地址偏移之后,就可以获取到

    对应的dentry,也就是父子关系形成。当然,并不是所有的子文件或者子目录都能遍历到,因为如果没人打开,则不会有dentry,毕竟内存有限。

    有个地方需要注意,该文件系统的最高根目录,那么它的child按道理要嵌入到它父dentry的d_subdirs 形成链表,但由于他的父dentry就是本身,所以它的child指针还是指向自己,也就是:

    crash> struct -xo dentry.d_u ffff8818118002c0
    struct dentry {
             union {
      [ffff881811800310] } d_u;
    }
    crash>
    crash>
    crash> struct -x dentry.d_u.d_child ffff8818118002c0
      d_u.d_child = {
        next = 0xffff881811800310,
        prev = 0xffff881811800310
      },

     内核中同样用两个成员来表示分级关系的还有:task_struct 中的children,sibling成员,父进程的child成员和子进程的sibling成员传成一个双向循环链表。我们自己设计到层级的结构的时候,可以参照这种设计方法。

     

    注:用一个3.10的例子描述下:经常需要用到的一个结构是name,比如我需要知道某个inode对应的文件名,由于一个inode可以对应多个文件名,所以在inode结构中并没有文件名的直接对应,这个文件名是放在dentry中的,

    crash> struct dentry.d_parent,d_name,d_iname ffff885221936780
      d_parent = 0xffff88579984b140----------------对应的父dentry
      d_name = {
        {
          {
            hash = 1776607972,
            len = 7
          },
          hash_len = 31841379044
        },
        name = 0xffff8852219367b8 "vmlinux"
      }
      d_iname = "vmlinux\000nity_list\000.wants\000\064\000\000\000\000\000"
    crash> struct dentry.d_parent,d_name,d_iname 0xffff88579984b140------查看其父dentry的文件名
      d_parent = 0xffff88579984ac00
      d_name = {
        {
          {
            hash = 4190344536,
            len = 26
          },
          hash_len = 115859494232
        },
        name = 0xffff88579984b178 "3.10.0-693.21.1.el7.x86_64"
      }
      d_iname = "3.10.0-693.21.1.el7.x86_64\000\000\000\000\000"

    通过获取d_name结构中的name,可以获取文件名,依次往上遍历d_parent,就可以获取整个路径名。

    一个比较特殊的是根目录,这个根目录是指挂载的根目录,它的d_parent是自身,而且其名字是"/" 

    所以要获取完整的路径,可以在内核模块中参照如下的写法:

    void get_inode_filename(struct dentry *dentry, char *filename)
    {
            struct dentry *temp;
            const char *item[128];
            int i = 0;
    
            temp = dentry;
            strcpy(filename, "");
            do
            {
                    item[i++] = temp->d_name.name;
                    if (temp == temp->d_parent || !temp->d_parent)
                            break;
                    temp = temp->d_parent;
            }while (1);
    
        while ( i > 0 )
        {
                    strcat(filename, item[i - 1]);
                    i --;
                    if ( i > 0 && strcmp(item[i], "/") )
                    strcat(filename, "/");
            }
    }

    很明显的,如上的方法有一种硬伤,就是它遍历到的根目录,就是这个文件归属的挂载点,而我们知道,一个文件的多级目录,可能属于多个挂载点,那怎么获取进一步的全路径呢?

     我们来看下面的例子:

    crash> files 317933
    PID: 317933  TASK: ffff8853a6c10fd0  CPU: 3   COMMAND: "ZMSSdu"
    ROOT: /    CWD: /tmp
     FD       FILE            DENTRY           INODE       TYPE PATH
      0 ffff882536c4c000 ffff88268e6bc480 ffff8827d88d73a0 CHR  /dev/pts/32
      1 ffff8853d5859500 ffff8828b700a240 ffff8857bf568850 CHR  /dev/null
      2 ffff8853d5859500 ffff8828b700a240 ffff8857bf568850 CHR  /dev/null
      3 ffff8816b12a8100 ffff8834653c26c0 ffff88518d4ef9c0 REG  /var/log/zmsscmd/ZMSSdu.log
      4 ffff88268f550200 ffff8811cadccd80 ffff880505b992f0 REG  /mnt/ZMSS/ZMSSDu.log--------------------作为例子的文件
      5 ffff8829a0cff000 ffff882759336fc0 ffff8817d73f9ae8 REG  /mnt/ZMSS/ZMSSMultiPath_Du.log
      6 ffff8829a0cfc800 ffff884e79e68780 ffff885412896da8 REG  /ZMSS/etc/ZMSSDu/etc/SemLock.sys
      7 ffff8829a0cfe900 ffff8852e44d1b00 ffff884962453130 REG  /var/log/ZMSS/backtrace/ZMSSDu.log
      9 ffff885353dd8c00 ffff8823a3c61740 ffff88135486ad28 REG  /ZMSS/etc/ZMSSRRIProcessd/etc/du_info
     10 ffff885353ddae00 ffff8823a3c600c0 ffff88135486b130 REG  /ZMSS/etc/ZMSSRRIProcessd/etc/df_info
     11 ffff885353dda800 ffff8823a3c60900 ffff88135486b538 REG  /ZMSS/etc/ZMSSRRIProcessd/etc/iostat_info

    根据打印,可以知道文件名为/mnt/ZMSS/ZMSSDu.log,那么假设根据给出的inode:ffff880505b992f0 ,怎么获取到它的全路径呢?

    crash> inode.i_dentry ffff880505b992f0
        i_dentry = {
          first = 0xffff8811cadcce30
        }
    crash> struct -xo dentry.d_alias
    struct dentry {
      [0xb0] struct hlist_node d_alias;
    }
    
    crash> px 0xffff8811cadcce30-0xb0
    $1 = 0xffff8811cadccd80-----------------这个就是inode对应的其中一个dentry的地址,和直接列出来的 0xffff8811cadccd80 是对得上的。

    crash> dentry.d_inode ffff8811cadccd80--------可以再验证一下:
    d_inode = 0xffff880505b992f0

     
     

    开始往parent遍历啦:

    crash> dentry.d_name,d_iname,d_parent ffff8811cadccd80
      d_name = {
        {
          {
            hash = 3146792703,
            len = 10
          },
          hash_len = 46096465663
        },
        name = 0xffff8811cadccdb8 "ZMSSDu.log"
      }
      d_iname = "ZMSSDu.log\000e\000ion.confrr3FQB\000\000\000\000"
      d_parent = 0xffff8857b90d3ec0

    遍历到的最后一层文件名是:ZMSSDu.log,然后根据d_parent 来遍历:

    crash> dentry.d_name,d_iname,d_parent 0xffff8857b90d3ec0
      d_name = {
        {
          {
            hash = 0,
            len = 1
          },
          hash_len = 4294967296
        },
        name = 0xffff8857b90d3ef8 "/"
      }
      d_iname = "/\000lockevents:clockevent61\000\000\000\000\000\000"------------这里面后面都是乱码,前面的/是对的,说明到了该挂载点的根目录
      d_parent = 0xffff8857b90d3ec0----------d_parent 就是本身,说明到了挂载点的根目录

    往下就不能遍历了,这个时候,我们需要回到inode去,找到他的挂载路径:

    crash> inode.i_sb ffff880505b992f0
      i_sb = 0xffff8857a1faa800
    crash> super_block.s_mounts 0xffff8857a1faa800
      s_mounts = {
        next = 0xffff8857aefbc070,
        prev = 0xffff8857aefbc370
      }
    
    crash> struct -xo mount
    struct mount {
        [0x0] struct hlist_node mnt_hash;
       [0x10] struct mount *mnt_parent;
       [0x18] struct dentry *mnt_mountpoint;------------挂载点,其实就是一个dentry,又可以遍历啦
    
    crash> struct mount 0xffff8857aefbc000
    struct mount {
      mnt_hash = {
        next = 0x0,
        pprev = 0xffffc900305fc858
      },
      mnt_parent = 0xffff88587fe82b80,
      mnt_mountpoint = 0xffff8800354d8c00,--------对应挂载点的dentry
    
    crash> dentry.d_iname,d_parent 0xffff8800354d8c00------------继续遍历
      d_iname = "ZMSS\000\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314"
      d_parent = 0xffff8800354d8cc0

    我们找到了它的挂载点,文件名是ZMSS,绝对路径需要进一步往上遍历:

    crash> dentry.d_name,d_iname,d_parent 0xffff8800354d8cc0
      d_name = {
        {
          {
            hash = 7630445,
            len = 3
          },
          hash_len = 12892532333
        },
        name = 0xffff8800354d8cf8 "mnt"
      }
      d_iname = "mnt\000\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314\314"
      d_parent = 0xffff8857b08de9c0------------------------------继续遍历
    crash> dentry.d_name,d_iname,d_parent 0xffff8857b08de9c0
      d_name = {
        {
          {
            hash = 0,
            len = 1
          },
          hash_len = 4294967296
        },
        name = 0xffff8857b08de9f8 "/"
      }
      d_iname = "/\000h13\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
      d_parent = 0xffff8857b08de9c0---------------d_parent和自身相等,说明又遇到了挂载的根目录了

    至此,我们反向遍历完了/mnt/zxdfs/ZMSSDu.log,我们也没法确定我们找到的/就是最终的系统的根目录,所以还需要再确定一下:

    crash> dentry.d_sb 0xffff8857b08de9c0
      d_sb = 0xffff8857b8cfd800
    crash> super_block.s_mounts 0xffff8857b8cfd800
      s_mounts = {
        next = 0xffff88587fe82bf0,
        prev = 0xffff8857bb960f70
      }
    
    crash> struct mount 0xffff8857bb960f00
    struct mount {
      mnt_hash = {
        next = 0x0,
        pprev = 0xffffc900301bf318
      },
      mnt_parent = 0xffff8857bb960480,
    
    crash> struct mount.mnt_devname,mnt_parent 0xffff8857bb960480
      mnt_devname = 0xffff8857bed630c0 "rootfs"
      mnt_parent = 0xffff8857bb960480

    发现mnt_parent指向自己,说明肯定是根节点了。可以看出整个遍历过程很长很无趣。

    如果对文件系统熟悉的人来说,内核中提供了一个函数来实现类似的过程,就是d_path:

    char *d_path(const struct path *path, char *buf, int buflen)
    {
        char *res = buf + buflen;
        struct path root;
        int error;
    
        /*
         * We have various synthetic filesystems that never get mounted.  On
         * these filesystems dentries are never used for lookup purposes, and
         * thus don't need to be hashed.  They also don't need a name until a
         * user wants to identify the object in /proc/pid/fd/.  The little hack
         * below allows us to generate a name for these objects on demand:
         *
         * Some pseudo inodes are mountable.  When they are mounted
         * path->dentry == path->mnt->mnt_root.  In that case don't call d_dname
         * and instead have d_path return the mounted path.
         */
        if (path->dentry->d_op && path->dentry->d_op->d_dname &&
            (!IS_ROOT(path->dentry) || path->dentry != path->mnt->mnt_root))
            return path->dentry->d_op->d_dname(path->dentry, buf, buflen);
    
        rcu_read_lock();
        get_fs_root_rcu(current->fs, &root);
        error = path_with_deleted(path, &root, &res, &buflen);
        rcu_read_unlock();
    
        if (error < 0)
            res = ERR_PTR(error);
        return res;
    }

    给定一个dentry,给定对应的mnt,就能唯一确定一个路径。

     

    转载于:https://www.cnblogs.com/10087622blog/p/9525652.html

    展开全文
  • Linux文件系统中的superblock、inode、dentry、file


    首先,Superblock, Inode, Dentry 和 File 都属于元数据(Metadata),根据维基百科中的解释,所谓元数据,就是描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件纪录等功能。Linux/Unix 文件系统的元数据以多级结构保存。

    Superblock 是文件系统最基本的元数据,它定义了文件系统的类似、大小、状态,和其他元数据结构的信息(元数据的元数据)。Superblock 对于文件系统来说是非常关键的,因此对于每个文件系统它都冗余存储了多份。Superblock对于文件系统来说是一个非常“高等级”的元数据结构。例如,如果 /var 分区的 Superblock 损坏了,那么 /var 分区将无法挂载。在这时候,一般会执行 fsck 来自动选择一份 Superblock 备份来替换损坏的 Superblock,并尝试修复文件系统。主 Superblock 存储在分区的 block 0 或者 block 1 中,而 Superblock 的备份则分散存储在文件系统的多组 block 中。当需要手工恢复时,我们可以使用 dumpe2fs /dev/sda1 | grep -i superblock 来查看 sda1 分区的 superblock 备份有哪一份是可用的。我们假设 dumpe2fs 输出了这样一行:Backup superblock at 163840, Group descriptors at 163841-163841 ,通过这条信息,我们就可以尝试使用这个 superblock 备份:/sbin/fsck.ext3 -163840 -1024 /dev/sda1。请注意,这里我们假设 block 的大小为 1024 字节。

    Inode 中包含了一个文件的元数据。为清晰起见,Linux/Unix 系统中的所有对象均为文件:实际的文件、目录、设备等等。请注意,在 Inode 所包含的元数据中,并没有文件名。一个 Inode 包含的基本信息有:所有权(用户,组),访问模式(读、写、执行权限)和文件类型。

    Dentry 是将 Inode 和 文件联系在一起的”粘合剂”,它将 Inode number 和文件名联系起来。Dentry 也在目录缓存中扮演了一定的角色,它缓存最常使用的文件以便于更快速的访问。Dentry 还保存了目录及其子对象的关系,用于文件系统的遍历。

    File 即文件,其实只是一些逻辑上相关的数据,相对而言没什么好说的。

    展开全文
  • 文件系统dentry

    2021-03-26 20:15:15
    注:本文分析基于linux-4.18.0-193.14.2.el8_2内核版本,即CentOS 8.2 3 dentry 3.1 dentry主要成员变量 3.2 添加dentry到cache 3.3 从cache中删除dentry(回收dentrycache) 4 file 4.1 file主要成员变量 4.2 创建...
  • Linux文件系统,VFS,super_block,超级块,inode... 一: 什么是文件系统,详见:http://zh.wikipedia.org/zh/%E6%96%87%E4%BB%B6%E7%B3%BB%E7%BB%9F 其实一句话就是管理这块文件的机制(组织方式,数据结构之类...)...
  • Linux 文件系统的 Superblock, Inode, Dentry 和 File 分类: linux基础知识 2014-06-30 16:13 133人阅读 评论(0) 收藏 举报 目录(?)[+] 参考文档:...
  • 这个数据结构就是dentrydentry是一个纯粹的内存结构,由文件系统在提供文件访问的过程中在内存中直接建立 其中对于文件夹 d_subdirs 存放了其子文件,与给定目录下的所 有文件和子目录相关联的dentry实例,都归入...
  • 一:文件系统 1. 什么是文件系统? 操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统。 通常文件系统是用于存储和组织文件的一种机制,便于对文件进行方便...2. Linux文件系统 Linux将文件系
  • 最近在看linux内核mount文件系统的相关内容,由此产生了一些疑惑,即在mount一个文件系统后,原有的目录项与被挂载的文件系统的根目录之间是如何联系的,vfs进行路径搜索的时候,是怎么知道该目录项被挂载了一个新的...
  • 转载自 ... linux VFS中dentry结构解析  2011-10-08 10:10:50| 分类: ARM学习|举报|字号 订阅 linux VFS中dentry结构解析http://hi.baidu.com/mn
  • linux VFS 虚拟文件系统 简介 super_block inode dentry file.pdf
  • Linux文件系统详解

    万次阅读 多人点赞 2019-05-29 16:07:53
    从操作系统的角度详解Linux文件系统层次、文件系统分类、文件系统的存储结构、不同存储介质的区别(RAM、ROM、Flash)、存储节点inode。本文参考: http://blog.chinaunix.net/uid-8698570-id-1763151.html ...
  • Linux 内核编程之文件系统(二) 几个关系: (1)inode索引节点表示文件的信息——每个文件都有一个inode。 (2)dentry目录项表示文件名与inode的对应关系。 (3)一个inode可能对应不止一个dentry结构。 ...
  • 因为有文件,所以有管理文件的系统=>因为有很多种文件系统,所以有虚拟文件系统对它们进行封装,让上层的程序只需要调用简单的接口。 文件系统是存储和组织信息的机制,它的目的是管理各种存储设备,所谓的管理是指...
  • 文章目录Linux虚拟文件系统一、文件系统框架二、挂载文件系统三、打开文件 一、文件系统框架 文件系统需要许多层的组件一起协作,具体怎么协作,下面来看一看 在应用层,进程操作文件可以通过 open、read、write ...
  • 对于具体的文件系统,因为在vfs层下,所以必须有inode和dentry才能用,但从前两篇中我们只看到了sysfs中的sysfs_dirent搭建起来的目录树,通过sysfs_dirent与kobject的紧密关系,也可看到kobject的层次关系。...
  • 4.1.1什么是Linux设备文件系统 首先我们不看定义,定义总是太抽象很难理解,我们先看现象。当我们往开发板上移植了一个新的文件系统之后(假如各种设备驱动也移植好了),启动开发板,我们用串口工具进入开发板,...
  • 1.Linux 中允许众多不同的文件系统共存,如 ext2, ext3, vfat 等。通过使用同一套文件 I/O 系统 调用即可对 Linux 中的任意文件进行操作而无需考虑其所在的具体文件系统格式;更进一步,对文件的 操作可以跨文件系统...
  • Linux 文件系统剖析

    2015-12-04 20:36:20
    Linux 文件系统剖析页首 http://www.ibm.com/developerworks/cn/linux/l-linux-filesystem/Linux 文件系统剖析基本的文件系统体系结构 什么是文件系统 文件系统体系结构 高层体系结构 主要结构 虚拟文件系统层 超级...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,631
精华内容 5,052
关键字:

linux文件系统dentry

linux 订阅