深度剖析 Linux cp 命令的秘密( 三 )


一个文件的对应一个 inode,这个文件需要按照 Block 切分存储在磁盘上,存储的位置则由 inode 记录起来,通过 inode 则能找到 block,也就获取到用户数据 。
现在有一个新的小问题,inode 区和 block 区都是在初始化就构造好的 。存储一个文件的时候,需要取一个空闲的 inode,然后把数据切分成 4k 大小存储到空闲的 block 上,对吧?
划重点:空闲的inode,空闲的 block 。 这个很关键,已经存储了数据的地方不能再让写,不然会把别人的数据覆盖掉 。
那么,怎么区分空闲和已经在用的 inode ,block 呢?
答案是 :inode 区和 block 区分别需要另一张表,用来表示 inode 是否在用,block 是否在用,这个表的名字我们叫做 bitmap 表 。bitmap 是一个 bit 数组,用 0 表示空闲,1 表示在用,如下:

深度剖析 Linux cp 命令的秘密

文章插图
 
bitmap 什么时候用呢?自然是写的时候,也就是分配 inode 或者 block 的时候,因为只有分配的时候,你才需要找空闲的空间 。
上图我为了突出本质思想,类似于超级块,块描述符都省略了,这个感兴趣可以自己扩展,这里只突出主干哈 。
小结一下:
  1. bitmap 本质是个 bit 数组,占用空间极其少,用 0 来表示空闲,1 表示在用 。使用时机是在创建文件,或者写数据的时候;
  2. inode 则对应一个文件,里面存储的是元数据,主要是数据 block 的位置信息;
  3. block 里面存储的是用户数据,用户数据按照 block 大小(4k)切分,离散的分布在磁盘上 。读的时候只有依赖于 inode 里面记录的位置才能恢复出完整的文件;
  4. inode 和 block 的总个数在文件系统格式化的时候就确定了,所以文件数和文件大小都是有上限的;
 
一个文件真实的模样 
上面是抽象的样子,现在我们看一个真实的 inode -> block 的样子 。一个文件除了数据需要存储之外,一些元信心也需要存储,例如文件类型,权限,文件大小,创建/修改/访问时间等,这些信息存在 inode 中,每个文件唯一对应一个inode。
看一下 inode 的数据结构(就以 linxu ext2 为例,该结构定义在 linux/fs/ext2/ext2.h 头文件中 ):
struct ext2_inode {    __le16  i_mode;     /* File mode */    __le16  i_uid;      /* Low 16 bits of Owner Uid */    __le32  i_size;     /* Size in bytes */    __le32  i_atime;    /* Access time */    __le32  i_ctime;    /* Creation time */    __le32  i_mtime;    /* Modification time */    __le32  i_dtime;    /* Deletion Time */    __le16  i_gid;      /* Low 16 bits of Group Id */    __le16  i_links_count;  /* Links count */    __le32  i_blocks;   /* Blocks count */    __le32  i_flags;    /* File flags */    __le32  i_block[EXT2_N_BLOCKS];/* Pointers to blocks */    __le32  i_file_acl; /* File ACL */    __le32  i_dir_acl;  /* Directory ACL */    __le32  i_faddr;    /* Fragment address */};重点:
  • 上面的结构 mode,uid,size,time 等信息就是我们常说的文件类型,大小,创建修改等时间元数据;
  • 注意到 i_block[EXT2_N_BLOCKS] 这个字段,这个字段将会带你找到数据, 因为里面存储的就是 block 所在的位置,也就是 block 的编号;
再来,理解下什么叫做 block 的位置(编号) 。
深度剖析 Linux cp 命令的秘密

文章插图
 
位置就是编号,记录位置就是记录编号,编号就是索引 。
我们看到有一个数组:i_block[EXT2_N_BLOCKS],这个数组是存储 block 位置的数组 。其中 EXT2_N_BLOCKS 是一个宏定义,值为 15。也就是说,i_block 是一个 15 个元素的数组,每个元素是 4 字节(32 bit)大小 。


推荐阅读