Linux文件系统基本概念记录

真是一个无情的搬运工

前言

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

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

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文件系统基本概念记录)