当前位置: 首页 > Linux

01-OCFS2文件系统磁盘布局分析

时间:2023-04-06 22:11:56 Linux

文件系统本质上是在磁盘上存储文件。因此,了解文件系统的整体磁盘布局对于理解一个文件系统非常重要。文件系统的所有功能都围绕着磁盘。布局及其管理,让我们看一下OCFS2集群文件系统的整体磁盘布局。1.格式格式:mkfs.ocfs2-b4K-C1M-N32-Jsize=128M-L"xxx"-Tvmstore--fs-features=indexed-dirs,refcount--cluster-stack=o2cb--cluster-name=ocfs2fs.img格式参数说明:-b,--block-sizeblock-size文件系统执行IO的最小单位,本例取block4KB=4096=2^10-C,--cluster-sizecluster-size是文件数据分配空间的最小单位。本例中,cluster1MB=2^20-N,--node-slotsnumber-of-node-slots节点槽指向一系列系统文件,每个槽专供一个节点使用。插槽数表示该卷可以同时挂载多少个节点。-J,--journal-optionsoptionsOCFS2使用预写日志WAL(Write-AheadLog),使用JBD2,用户可配置,根据文件系统类型和卷大小决定,默认值:datafilestype64MB,vmstoretype128MB,mailtype256MB-L,--labelvolume-label标记卷以便于管理。-Tfilesystem-typeValidtypesaremail,datafilesandvmstore.mail:用作邮件服务器存储,将大量的元数据变成大量的小文件,使用更大的日志日志更有好处。datafiles:建议少分配大文件,需要较少的元数据更改,因此使用较大的日志日志无益。vmstore:顾名思义,稀疏分配大文件的虚拟机镜像--fs-features=[no]sparse...指定启用或禁用某些特性,如:稀疏文件、非写入范围、backupsuperblock--fs-feature-level=feature-level有效值为max-compat、default和max-features。默认支持稀疏文件、非写入范围、内联数据。查看根目录和系统目录通过debugfs.ocfs2可以看到系统文件。在此示例中,指定-N32进行格式化。因此,一些带有槽号的系统文件,如:local_allock:0000~0031,只显示下面截图的一部分。其余省略,不影响分析。通过格式化的参数,可以得到以下基本的数据信息,可以方便的进行计算。1block4KB=4096=2^101cluster1MB=2^201cluster=256blocks=2^8二、SuperBlockSuperBlock对于一个文件系统来说是最重要的,它描述了一个文件系统的基本数据信息,包含许多重要的关键信息。挂载文件系统后,首先要读取SuperBlock。格式化后可以看到SuperBlock的信息如下:其中,格式化命令行中有一个关键的数据参数,如:BlockSizeBits:12,ClusterSizeBits:20等,而SuperBlockBlkno必须预先指定,从这个SuperBlockBlkno计算出以下关键信息,比如:首先ClusterGroupBlknum:256,然后计算RootBlknum:513,SystemDirBlknum:514。>#defineOCFS2_SUPER_BLOCK_BLKNO2SuperBlock上的数据结构磁盘如下:格式化最重要的是指定磁盘的划分和布局。因此,需要先划分ClusterGroups。3、下面分析OCFS2磁盘的整体布局:OCFS2磁盘的整体布局主要描述如何实现对整个磁盘的管理。OCFS2将磁盘分成若干个ClusterGroup进行管理,称为簇组(ClusterGroup),在Ext4文件系统中中文称为块组(BlockGroup),用途相同。如下图所示:每个ClusterGroup由若干个Cluster组成,包括Descriptor+BitMap和描述ClusterGroup的DataClusters。第一个ClusterGroup比较特殊,因为它包含OCFS2元数据信息,包括SuperBlock、系统文件夹和系统文件。ClusterGroup中磁盘空间的管理是通过一个Block来体现ClusterGroup的信息,Block的剩余空间使用一个位图BitMap来管理整个ClusterGroup。位图BitMap中的每个Bit对应ClusterGroup中的一个簇。如果BitMap中第i个cluster对应的Bit为1,表示该cluster已经分配,??0表示没有使用。OCFS2使用BitMap确认可以使用哪些集群(本例中为1cluster=1MB)。系统文件global_bitmap用于描述ClusterGroups的信息。系统文件为global_bitmap(global_bitmap全局位图,用于实现集群组的全局管理,访问时需要分布式锁保护。)系统文件的磁盘数据结构为structocfs2_dinode,如图下图:structocfs2_dinode.id2.ocfs2_chain_list.ocfs2_chain_rec用于描述ClusterGroup信息,如下图:chain_list为ClusterGroupsList,磁盘数据结构记录了整个磁盘被划分为若干个Cluster团体。每个ClusterGroupChain用ocfs2_chain_rec描述,ocfs2_chain_rec.c_blkno是描述每个ClusterGroup的Block块位图(BitMap),磁盘数据结构为structocfs2_group_desc,用1个Block表示,如下:从0x00到0x40=64B,1Block4096B-64B=剩余的4032B*8bits=32256bits,因此,一个ocfs2_group_desc可以代表32256个簇,所以每个簇组的簇数,即:1个簇组包含32256个簇=32256MB=31.5GB。一个Disk或Volume可用的集群组总数=totalclusters/每个集群组包含的集群数,最后一个集群组包含剩余的集群数。在此示例中,80GVolume=81920个集群,(81920个集群+32256个集群-1)/32256个集群=3个集群组。下图为本例中全局位图global_bitmap中记录的ClusterGroups信息:一共有3个clustergroups,GroupChain:0,1,2blkno256/blkno8257536/blkno16515072图中,每个blkno是一个structocfs2_group_desc,用来表示这个clustergroup的位图信息。Clustergroupdescriptor:FirstClusterGroupBlknum:256在ocfs2_group_desc格式信息中也有显示,那么blkno256是怎么来的呢?blkno8257536和blkno16515072是怎么来的?接下来一步步分析。首先格式化首先确定global_bitmap的结构,着重划分clustergroup,确定每个clustergroup的descriptorblock。根据superblockblkno2计算出first_cluster_group_blkno=blkno256,剩下的clustergroupN为每个clustergroup的第一个block。第一个clustergroup不是第一个block,因为blkno0和1是reserved表示ocfsversion2,而blkno2用来表示SuperBlock,所以global_bitmapchain0中下标1的第一个cluster选择block256。关键代码截取如下:s->global_bm=initialize_bitmap(s,s->volume_size_in_clusters,//初始化全局global_bitmaps->cluster_size_bits,//20bits"globalbitmap",tmprec);/*到下一个对齐的簇*/s->first_cluster_group=(OCFS2_SUPER_BLOCK_BLKNO+1);//块3s->first_cluster_group+=((1<first_cluster_group>>=c_to_b_bits;//258>>8=1s->first_cluster_group_blkno=(uint64_t)s->first_cluster_group<global_cpg<<(s->cluster_size_bits-s->blocksize_bits);//确定链1的组描述符blkno32256<<8=blkno8257536cpg=s->global_cpg;blkno+=(uint64_t)s->global_cpg<<(s->cluster_size_bits-s->blocksize_bits);//确定下一条链的组描述符blkno16515072=blkno8257536+32256<<8=blkno8257536*2chain++;//等等因为集群rGroup0比较特殊,因为这里记录了SuperBlock和系统文件。这时需要指出ClusterGroup0的位图global_bitmap中占用了哪些位?之前分析过1bit=1cluster=1MB=256blocksSupberBlockblkno2在global_bitmap的第0簇,所以global_bitmap的第0位设置为1,FirstClusterGroupBlkno256在global_bitmap的第1簇,所以global_bitmapBit1设置为1。系统文件inode接下来分析根目录root_dir(513),系统目录system_dir(514),以及各个系统文件的inode号是如何分配的。首先确定系统文件从哪里开始申请inode。首先要做的是初始化global_inode_alloc系统文件,如下图:首先从global_bitmap申请total系统文件使用的Block总数。在此示例中,需要203。通过下面的代码需要2位,num_bits=(bytes+bitmap->unit-1)>>bitmap->unit_bits;//(needbytes+1MB-1)>>20=needclusterbits:(831488+1,048,576-1)/1,048,576=1.79=2bits,所以从global_bitmap中申请2个可用的bits,groupchain0中的bits可以满足,并且因为第0和第1bits的cluster已经被superblock2和group所在的cluster替换了descriptorblkno256都被设置了位,所以得到的是第2和第3位簇,即:从2MB位置开始,这个是blkno512。截取的部分关键代码如下:/**Nowallocatetheglobalinodeallocgroup*/tmprec=&(record[GLOBAL_INODE_ALLOC_SYSTEM_INODE][0]);need=blocks_needed(s);//计算目录和系统目录及系统文件的总和NumberofBlocksrequired:203alloc_bytes_from_bitmap(s,need<blocksize_bits,//从global_bitmap<<12=申请这些Block数needbytess->global_bm,//现在0,1/group1ofgroup0ofglobal_bitmap0of0/group2被占用&(crap_rec.extent_off),//输出参数:从offset偏移2MB,即:blkno512&(crap_rec.extent_len));//输出参数:长度为2MB大小即可Systeminodes->system_group=initialize_alloc_group(s,"systeminodegroup",tmprec,crap_rec.extent_off>>s->blocksize_bits,//offset偏移量2MB,即:blkno5120,crap_rec.extent_len>>s->cluster_size_bits,//2MB>>20=2,1cluster=256bits,2clusters=512bitss->cluster_size/s->blo尺寸);//256,1bit=1blockinsystem_group接下来利用这个2cluster=512bits生成系统文件inode的子分配器global_inode_alloc,用于为系统文件分配inode,磁盘数据结构也复用了ocfs2_group_chain_list,bitmap还是用bitmap,这个bitmap位图用blkno512描述,每个groupchain包含2个簇,256bits代表一个簇,所以1bit代表一个blocksizeblkno512是第0位,然后apply得到的系统文件inode都是基于关于blkno512位偏移,例如:根目录(root_dir)申请系统文件,第1位为blkno512+1=blkno513,SubAllocBit:1。已申请第i位的系统文件为:blkno512+i=blkno(512+i),SubAllocBit:i,i>0.截取的部分关键代码如下申请根目录和每个剩余的系统文件索引节点:staticuint64_talloc_inode(States,uint16_tsuballoc_bit){uint64_tret;uint16_t数;alloc_from_group(s,1,s->system_group,&ret,&num);//从system_group申请1位,从blkno512开始,共256位,第0位已经被gb_blkno512占用,所以申请第一位这里,即:blkno513.*suballoc_bit=(int)(ret-s->system_group->gd->bg_blkno);//blkno513-blkno512=1suballoc_bit/*我有没有提到我讨厌这段代码?*/return(ret<blocksize_bits);//返回blkno513的字节}root_dir_rec.fe_off=alloc_inode(s,&root_dir_rec.suballoc_bit);root_dir->record=&root_dir_rec;add_entry_to_directory(s,root_dir,".",root_dir_rec.fe_off,OCFS2_FT_DIR);//所以根目录inodeblkno513add_entry_to_directory(s,root_dir,"..",root_dir_rec.fe_off,OCFS2_FT_(i=0;iinitial_slots;for(j=0;j