美文网首页CP-日常随笔
Linux文件系统基本概念记录

Linux文件系统基本概念记录

作者: CPinging | 来源:发表于2020-02-01 17:00 被阅读0次

    真是一个无情的搬运工

    前言

    本文同样更新在私人公众号上,在此推广一下欢迎大家关注:

    公众号会定期更新一些计算机系统的底层知识,争取以最细节、最简洁的方式帮助读者理解系统的一些知识。

    image.png

    inode

    文件储存在硬盘上,硬盘的最小存储单位叫做"扇区"(Sector)。每个扇区储存512字节(相当于0.5KB)。

    操作系统读取硬盘的时候,不会一个个扇区地读取,这样效率太低,而是一次性连续读取多个扇区,即一次性读取一个"块"(block)。这种由多个扇区组成的"块",是文件存取的最小单位。"块"的大小,最常见的是4KB,即连续八个 sector组成一个 block。

    • inode内容

    inode包含文件的元信息,具体来说有以下内容:

    * 文件的字节数

    * 文件拥有者的User ID

    * 文件的Group ID

    * 文件的读、写、执行权限

    * 文件的时间戳,共有三个:ctime指inode上一次变动的时间,mtime指文件内容上一次变动的时间,atime指文件上一次打开的时间。

    * 链接数,即有多少文件名指向这个inode

    * 文件数据block的位置

    • inode大小

    inode也会消耗硬盘空间,所以硬盘格式化的时候,操作系统自动将硬盘分成两个区域。一个是数据区,存放文件数据;另一个是inode区(inode table),存放inode所包含的信息。

    每个inode节点的大小,一般是128字节或256字节。inode节点的总数,在格式化时就给定,一般是每1KB或每2KB就设置一个inode。假定在一块1GB的硬盘中,每个inode节点的大小为128字节,每1KB就设置一个inode,那么inode table的大小就会达到128MB,占整块硬盘的12.8%。

    读取文件的过程

    • 首先,系统找到这个文件名对应的inode号码;
    • 其次,通过inode号码,获取inode信息;
    • 最后,根据inode信息,找到文件数据所在的block,读出数据。

    硬链接

    一般情况下,文件名和inode号码是"一一对应"关系,每个inode号码对应一个文件名。但是,Unix/Linux系统允许,多个文件名指向同一个inode号码。

    这意味着,可以用不同的文件名访问同样的内容;对文件内容进行修改,会影响到所有文件名;但是,删除一个文件名,不影响另一个文件名的访问。这种情况就被称为"硬链接"(hard link)。

    ln命令可以创建硬链接: ln 源文件 目标文件

    软链接

    文件A和文件B的inode号码虽然不一样,但是文件A的内容是文件B的路径。读取文件A时,系统会自动将访问者导向文件B。因此,无论打开哪一个文件,最终读取的都是文件B。这时,文件A就称为文件B的"软链接"(soft link)或者"符号链接(symbolic link)。

    这意味着,文件A依赖于文件B而存在,如果删除了文件B,打开文件A就会报错:"No such file or directory"。这是软链接与硬链接最大的不同:文件A指向文件B的文件名,而不是文件B的inode号码,文件B的inode"链接数"不会因此发生变化。

    一个数据块大小4KB,则一个位图块可以表示410248个数据块的使用情况,所以一个块组中可存储数据的大小是128MB(4 * 1024 * 8 * 4KB)

    EXT-x文件系统中数据块映射

    Ext2/Ext3中数据块映射方式:


    image.png image.png

    于是inode
    1024+ 1024^2 +1024^3+12=1,074,791,436

    Extent学习记录

    Ext4中用extent树代替了逻辑块映射。使用extents,用一个struct ext4_extent结构就可以映射多个数据块,减少元数据块的使用。

    extent结构是12个字节,所以你可以在每个inode中最多试用5个extent。然后,前12个字节是extent区(40到51字节),被一个extent头结构占用,所以一个inode中实际上可以包含4个extent。

    每个extent结构中只有16个bit用来保存块号,实际上,最高位被保存了下来(最高位用来表示这个externt是“保存?预分?”还是已经初始化, 部分用于EXT4的预分配功能)。这意味着,一个extent最大只能包含2的15次方个块,当一个block为4k大小的时候,即128MB。

    128MB看起来足够大了,但是当你的文件大于0.5G的时候,这个文件就需要大于4个extent来保存整个block的索引。或者,当你的文件很小,但是由很多不连续的片段组成。这些情况下,就需要用大于4个extent来组织文件。

    Extent并没有非常详细的了解,后期有需要补充

    Ext4中目录项

    Ext4文件系统中,一个目录差不多是一个平面文件,映射任意长度的字符串到文件系统中的一个inode。文件系统中存在多个目录项引用同一个inode——硬链接,这也是硬链接不能链接其他文件系统中的文件的原因。

    在目录中并没有存储文件的数据信息,而只是存储了一个类似C语言指针的东东,这个东东就是文件的inode id。而目录中的子目录数据和文件数据仍然是平铺在磁盘上的。这样,在目录中通过这个指针就可以轻易的找到文件的数据,而且目录的数据和文件的数据组织也变得非常简单。

    image.png

    目录本质上也是一个文件,只不过其中存储的数据是关于子目录和文件的名称信息

    那么这个大数组中的元素是什么呢?就是图6所示的这个结构体。从该结构体可以看出,每一项内容包括inode的id、该结构体的大小、文件(子目录)名大小和文件名等信息。在检索目录内容的时候,其实就是根据文件名获得inode的id,然后在根据该id从inode表中获得inode(文件)的详细信息。

    image.png

    目录查询加速

    在Ext4文件系统中这个索引是通过一个成为哈希树(多叉树)的方式实现的,其中Key为文件名的哈希值,而Value则是具体的数据位置(磁盘块位置)。由于Key是有序的,因此查找非常方便,也就是可以通过文件名快速的找到ext4_dir_entry_2,然后可以找到inode信息。

    image.png image.png

    超级块

    在Linux操作系统的文件系统中,超级块相当于文件系统的地图。在超级块中保存着文件系统的属性信息、磁盘布局和资源使用情况等信息。文件系统通过超级块了解磁盘的布局,查找已用和可用资源等。超级块又相当于入口,文件系统的操作通常从超级块开始

    struct super_block {  
    746         struct list_head        s_list;         /* Keep this first */  
    747         kdev_t                  s_dev;  
    748         unsigned long           s_blocksize;  
    749         unsigned char           s_blocksize_bits;  
    750         unsigned char           s_dirt;  
    751         unsigned long long      s_maxbytes;     /* Max file size */  
    752         struct file_system_type *s_type;  
    753         struct super_operations *s_op;  
    754         struct dquot_operations *dq_op;  
    755         struct quotactl_ops     *s_qcop;  
    756         unsigned long           s_flags;  
    757         unsigned long           s_magic;  
    758         struct dentry           *s_root;  
    759         struct rw_semaphore     s_umount;  
    760         struct semaphore        s_lock;  
    761         int                     s_count;  
    762         atomic_t                s_active;  
    763   
    764         struct list_head        s_dirty;        /* dirty inodes */  
    765         struct list_head        s_locked_inodes;/* inodes being synced */  
    766         struct list_head        s_files;  
    767   
    768         struct block_device     *s_bdev;  
    769         struct list_head        s_instances;  
    770         struct quota_info       s_dquot;        /* Diskquota specific options */  
    771   
    772         union {  
    773                 struct minix_sb_info    minix_sb;  
    774                 struct ext2_sb_info     ext2_sb;  
    775                 struct ext3_sb_info     ext3_sb;  
    776                 struct hpfs_sb_info     hpfs_sb;  
    777                 struct ntfs_sb_info     ntfs_sb;  
    778                 struct msdos_sb_info    msdos_sb;  
    779                 struct isofs_sb_info    isofs_sb;  
    780                 struct nfs_sb_info      nfs_sb;  
    781                 struct sysv_sb_info     sysv_sb;  
    782                 struct affs_sb_info     affs_sb;  
    783                 struct ufs_sb_info      ufs_sb;  
    784                 struct efs_sb_info      efs_sb;  
    785                 struct shmem_sb_info    shmem_sb;  
    786                 struct romfs_sb_info    romfs_sb;  
    787                 struct smb_sb_info      smbfs_sb;  
    788                 struct hfs_sb_info      hfs_sb;  
    789                 struct adfs_sb_info     adfs_sb;  
    790                 struct qnx4_sb_info     qnx4_sb;  
    791                 struct reiserfs_sb_info reiserfs_sb;  
    792                 struct bfs_sb_info      bfs_sb;  
    793                 struct udf_sb_info      udf_sb;  
    794                 struct ncp_sb_info      ncpfs_sb;  
    795                 struct usbdev_sb_info   usbdevfs_sb;  
    796                 struct jffs2_sb_info    jffs2_sb;  
    797                 struct cramfs_sb_info   cramfs_sb;  
    798                 void                    *generic_sbp;  
    799         } u;  
    800         /* 
    801          * The next field is for VFS *only*. No filesystems have any business 
    802          * even looking at it. You had been warned. 
    803          */  
    804         struct semaphore s_vfs_rename_sem;      /* Kludge */  
    805   
    806         /* The next field is used by knfsd when converting a (inode number based) 
    807          * file handle into a dentry. As it builds a path in the dcache tree from 
    808          * the bottom up, there may for a time be a subpath of dentrys which is not 
    809          * connected to the main tree.  This semaphore ensure that there is only ever 
    810          * one such free path per filesystem.  Note that unconnected files (or other 
    811          * non-directories) are allowed, but not unconnected diretories. 
    812          */  
    813         struct semaphore s_nfsd_free_path_sem;  
    814 }
    

    s_list:指向超级块链表的指针,这个struct list_head是很熟悉的结构了,里面其实就是用于连接关系的prev和next字段。

    内核中的结构处理都是有讲究的(内核协议栈中也说过),内核单独使用一个简单的结构体将所有的super_block都链接起来,但是这个结构不是super_block本身,因为本身数据结构太大,效率不高,所有仅仅使用

    struct

    {

    list_head prev;

    list_head next;

    }

    这样的结构来将super_block中的s_list链接起来,那么遍历到s_list之后,直接读取super_block这么长的一个内存块,就可以将这个

    super_block直接读进来!这样就很快捷方便!这也是为什么s_list必须放在第一个字段的原因。

    s_dev:包含该具体文件系统的块设备标识符。例如,对于 /dev/hda1,其设备标识符为 0x301

    s_blocksize:文件系统中数据块大小,以字节单位

    s_blocksize_bits:上面的size大小占用位数,例如512字节就是9 bits

    s_dirt:脏位,标识是否超级块被修改

    s_maxbytes:允许的最大的文件大小(字节数)

    struct file_system_type *s_type:文件系统类型(也就是当前这个文件系统属于哪个类型?ext2还是fat32)

    要区分“文件系统”和“文件系统类型”不一样!一个文件系统类型下可以包括很多文件系统即很多的super_block,后面会说!

    struct super_operations *s_op:指向某个特定的具体文件系统的用于超级块操作的函数集合

    struct dquot_operations *dq_op:指向某个特定的具体文件系统用于限额操作的函数集合

    struct quotactl_ops *s_qcop:用于配置磁盘限额的的方法,处理来自用户空间的请求
    s_flags:安装标识

    s_magic:区别于其他文件系统的标识

    s_root:指向该具体文件系统安装目录的目录项

    s_umount:对超级块读写时进行同步

    s_lock:锁标志位,若置该位,则其它进程不能对该超级块操作

    s_count:对超级块的使用计数

    s_active:引用计数

    s_dirty:已修改的索引节点inode形成的链表,一个文件系统中有很多的inode,有些inode节点的内容会被修改,那么会先被记录,然后写回磁盘。

    s_locked_inodes:要进行同步的索引节点形成的链表

    s_files:所有的已经打开文件的链表,这个file和实实在在的进程相关的

    s_bdev:指向文件系统被安装的块设备

    u:u 联合体域包括属于具体文件系统的超级块信息

    s_instances:具体的意义后来会说的!(同一类型的文件系统通过这个子墩将所有的super_block连接起来)

    s_dquot:磁盘限额相关选项

    文件系统中的各个数据结构源码:
    https://www.cnblogs.com/linux-xin/p/8126999.html

    参考链接

    http://www.ruanyifeng.com/blog/2011/12/inode.html

    https://www.cnblogs.com/alantu2018/p/8461272.html

    相关文章

      网友评论

        本文标题:Linux文件系统基本概念记录

        本文链接:https://www.haomeiwen.com/subject/wtlgthtx.html