Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4251398
  • 博文数量: 82
  • 博客积分: 671
  • 博客等级: 上尉
  • 技术积分: 24576
  • 用 户 组: 普通用户
  • 注册时间: 2010-12-18 16:08
个人简介

www.kernel.org

文章分类

全部博文(82)

文章存档

2016年(1)

2015年(3)

2014年(12)

2013年(14)

2012年(52)

分类: 服务器与存储

2013-01-15 23:46:39

     今天我们来认识一下superblock,inode,block,group,group descriptor,block bitmap,inode table这些家伙。为什么在上一篇博文开篇没详细介绍这些概念呢,因为任何关于文件系统的文章还是书籍一开始都是先说概念、说理论,让人一直有种雾里看花的感觉。纸上得来终觉浅,事必躬亲才印象深,所以我们以一块实际硬盘为例(当然是虚拟出来的,呵呵)来向大家展示了一下文件系统在存储介质上的布局情况,先让大家对其有个比较直观的认识,然后再逐一对它们进行解释和说明,印象会更深刻些。咱不否认理论的重要性,秉承着“理论指导实践,以实践加深对理论的认识”的宗旨来一步一步入文件系统的乐园。



superblock

     这个东西确实很重要,前面我们已经见识过。为此,文件系统还特意精挑细选的找了N多后备Group,在这些Group中都存有superblock的副本,你就知道它有多重要了。说白了,superblock 的作用就是记录文件系统的类型、block大小、block总数、inode大小、inode总数、group的总数等等。

group descriptors

     千万不要以为这就是一个组描述符,看到descriptor后面加了个s就知道这是N多描述符的集合。确实,这是文件系统中所有group的描述符所构成的一个数组,它的结构定义在include/linux/ext2_fs.h中:

/*

 * Structure of a blocks group descriptor

 */

struct ext2_group_desc

{

         __le32      bg_block_bitmap;             /* groupblock bitmap所在的第一个block */

         __le32      bg_inode_bitmap;            /* groupinode bitmap 所在的第一个block */

         __le32      bg_inode_table;                /* groupinodes table 所在的第一个block */

         __le16      bg_free_blocks_count;    /* group中空闲的block总数 */

         __le16      bg_free_inodes_count;   /* group中空闲的inode总数*/

         __le16      bg_used_dirs_count;       /* 目录数 */

         __le16      bg_pad;

         __le32      bg_reserved[3];

};

     下面的程序可以帮助了解一下/dev/hdd1中所有groupdescriptor的详情:

[root@localhost cu]# cat grp_dsp.c

#include

#include

#include

#include

#include

#include

#include

 

#define B_LEN 32  //一个struct ext2_group_desc{}占固定32字节

 

int main(int argc,char** argv){

    char buf[B_LEN] = {0};

    int i=0,fd = -1;

    struct ext2_group_desc gd;

    memset(&gd,0,B_LEN);

 

    if(-1 == (fd=open(argv[1],O_RDONLY,0777))){

        printf("open file error!\n");

        return 1;

    }

 

    while(i<64){    //因为我已经知道了/dev/hdd1中只有64group

        if(-1 == read(fd,buf,B_LEN)){

            printf("read error!\n");

            close(fd);

            return 1;

        }

        memcpy((char*)&gd,buf,B_LEN);

        printf("========== Group %d: ==========\n",i);

        printf("Blocks bitmap block %ld \n",gd.bg_block_bitmap);

        printf("Inodes bitmap block %ld \n",gd.bg_inode_bitmap);

        printf("Inodes table block %ld \n",gd.bg_inode_table);

        printf("Free blocks count %d \n",gd.bg_free_blocks_count);

        printf("Free inodes count %d \n",gd.bg_free_inodes_count);

        printf("Directories count %d \n",gd.bg_used_dirs_count);

 

        memset(buf,0,B_LEN);

        i++;

    }

 

    close(fd);

    return 0;

}

     运行结果和dumpe2fs /dev/hdd1的输出对比如下:

     其中,文件gp0decp是由命令“dd if=/dev/hdd1 of=./gp0decp bs=4096 skip=1 count=1”生成。每个group descriptor里记录了该group中的inode table的起始block号,因为inode table有可能会占用连续的多个block;空闲的blockinode数等等。



block bitmap:

     在文件系统中每个对象都有一个对应的inode节点(这句话有些不太准确,因为符号链接和它的目标文件共用一个inode),里存储了一个对象(文件或目录)的信息有权限、所占字节数、创建时间、修改时间、链接数、属主ID、组ID,如果是文件的话还会包含文件内容占用的block总数以及block号。inode是从1编号,这一点不同于block,需要格外注意。另外,/dev/hdd1是新挂载的硬盘,格式化成ext2后并没有任何数据,只有一个lost+found目录。接下来我们用命令“dd if=/dev/hdd1 of=./gp0 bs=4096 count=32768”将Group0里的所有数据提取出来。

     前面已经了解了Group0的一些基本信息如下:

Group 0: (Blocks 0-32767)

  Primary superblock at 0, Group descriptors at 1-1

  Reserved GDT blocks at 2-512

  Block bitmap at 513 (+513), Inode bitmap at 514 (+514)

  Inode table at 515-1026 (+515)

  31739 free blocks, 16374 free inodes, 1 directories       #包含一个目录

  Free blocks: 1028-1031, 1033-32767                          #一共有31739个空闲block

  Free inodes: 11-16384                                                 #一共有16374个空闲inode

     一个block bitmap占用一个block大小,而block bitmap中每个bit表示一个对应block的占用情况,0表示对应的block为空,为1表示相应的block中存有数据。在/dev/hdd1中,一个group里最多只能包含8×4096=32768个block,这一点我们已经清楚了。接下来我们来看一下Group0的block bitmap,如下:

     发现block bitmap的前128字节和第129字节的低4位都为1,说明发现Group0中前128×8+4=1028block,即block0~block1027都已被使用了。第129字节的高4位为0,表示block1028~block1031四个block是空闲的;第130字节的最低位是1,说明block1032被占用了;从block1033~block32767的block bitmap都是0,所以这些block都是空闲的,和上表输出的结果一致。

 

inode bitmap:

     和block bitmap类似,每个比特表示相应的inode是否被使用。Group0inode bitmap如下:



      /dev/hdd1inode总数为1048576,要被均分到64Group里,所以每个Group中都包含了16384inode。要表示每个Group16384inodeinode bitmap总共需要使用2048(16384/8)字节。inode bitmap本身就占据了一个block,所以它只用到了该block中的前2048个字节,剩下的2048字节都被填充成1,如上图所示。

     我们可以看到Group0中的inode bitmap前两个字节分别是ff03,说明Group0里的前11inode已经被使用了。其中前10inodeext2预留起来,第11inode就是lost+found目录,如下:




inode table:

     那么每个Group中的所有inode到底存放在哪里呢?答案就是inode table。它是每个Group中所有inode的聚合地。

因为一个inode128字节,所以每个Group里的所有inode共占16384×128=2097152字节,总共消耗了512blockGroupgroup descriptor里记录了inode table的所占block的起始号,所以就可以唯一确定每个Groupinode table所在的block的起始号和结束号了。inode的结构如下:



     这里我们主要关注的其中的数据block指针部分。前12block指针直接指向了存有数据的block号;第13block指针所指向的block中存储的并不是数据而是由其他block号,这些block号所对应的block里存储的才是真正的数据,即所谓的两级block指针;第14block为三级block指针;第15block为四级block指针。最后效果图如下:



     一个block4096字节,每个块指针4字节,所以一个block里最多可以容纳4096/4=1024block指针,我们可以计算出一个inode最大能表示的单个文件的最大容量如下:

直接block指针(字节)
两级block指针(字节)
三级block指针(字节)
四级block指针(字节)
单个文件的最大容量(字节)
12×409
4096/4×4096
40962/4×4096
40963/4×4096
4TB

     所以,我们可以得出不同block大小,对单个文件最大容量的影响。假设block大小为X字节,则:



     如下表所示

block大小(字节)
单个文件容量(字节)
1024
17247240192字节(16GB)
2048 275415826432字节(256GB)
4096 4402345672704字节(4TB)
     最后来一张全家福:


       完。

阅读(9511) | 评论(5) | 转发(13) |
给主人留下些什么吧!~~

jingzhe_2015-04-29 08:55:29

大神,Linux文件系统存储分为inode和block两块,通过inode查找数据块block读出文件。有没有办法通过发送命令的方式获取分区上所有的inode信息或者已经使用的block块?就像windows下通过发送FSCTL_GET_VOLUME_BITMAP来获取簇的占用信息一样的

wjlkoorey2582013-01-17 22:25:08

shangbaogen:这样的文章必须顶,文章图文并茂,通俗易懂,相当好,你和Bean_lee兄让我学到了很多东西,感谢~

和大家分享学习过程,本身也是一件快乐的事儿。希望你也感同身受,呵呵

回复 | 举报

shangbaogen2013-01-17 09:56:35

这样的文章必须顶,文章图文并茂,通俗易懂,相当好,你和Bean_lee兄让我学到了很多东西,感谢~

wjlkoorey2582013-01-16 22:17:42

Bean_lee:文章真好,图是怎么画的啊

兄弟过奖了。viso画的,目前只能达到这种水平,哈哈~~~

回复 | 举报

Bean_lee2013-01-16 13:37:06

文章真好,图是怎么画的啊