EXT4文件系统之ext4_fill_super()

EXT4文件系统之ext4_fill_super()

一.概述

    在磁盘挂载的时候文件系统需要从磁盘中读取超级块来填充内存中的结构,EXT4文件系统超级块的填充是由函数ext4_fill_super()来完成的。在EXT4文件系统中,磁盘上的超级块结构是与结构体structext4_super_block的定义是一致的,大小是1K,即1024个字节。顺便提下,EXT3文件系统超级块在磁盘上的大小也是1024个字节,EXT4扩展了EXT3的定义,EXT3只是占了1024个字节,有些字节没有定义,在EXT4中重新定义了,总的大小没有改变。

二.具体流程

在挂载文件系统的时候,读取磁盘上ext4_super_block结构的值,填充内存中ext4_sb_info的结构。

2.1读取超级块

sb_block= get_sb_block(&data);

 //计算超级块所在的块,data数值来自于参数,当data为空值,则sb_block=1; data中可以指定超级块的块号,即定义”sb=3”,超级块在块3.

……

blocksize= sb_min_blocksize(sb, EXT4_MIN_BLOCK_SIZE);

//初步计算块大小,最小为EXT4_MIN_BLOCK_SIZE,即1K

    ……

if(blocksize != EXT4_MIN_BLOCK_SIZE)

{//块大小不一致,需要重新计算

   logical_sb_block= sb_block * EXT4_MIN_BLOCK_SIZE;

   offset= do_div(logical_sb_block, blocksize);

}else 

{

   logical_sb_block= sb_block;     //块大小一致,直接读取 

}

    ……

if(!(bh = sb_bread(sb, logical_sb_block)))//从磁盘中读取logical_sb_block块

es= (struct ext4_super_block *) (bh->b_data + offset); //超级块数据

sbi->s_es= es;    //超级块

/

logical_sb_block= sb_block * EXT4_MIN_BLOCK_SIZE;

offset= do_div(logical_sb_block, blocksize);

 

# define do_div(n,base) ({                                 \

       uint32_t__base = (base);                           \

       uint32_t__rem;                                         \

       __rem= ((uint64_t)(n)) % __base;                     \

       (n)= ((uint64_t)(n)) / __base;                           \

       __rem;                                              \

 })

 

即 

logic_sb_block = (sb_block * EXT4_MIN_BLOCK_SIZE)/ blocksize;

offset= (sb_block * EXT4_MIN_BLOCK_SIZE) % blocksize;

如果块大小为1K,那logic_sb_block即为1,offset=0;超级块所在位置为块1;

如果块大小为4K,那logic_sb_block即为0,offset=1024;超姐块所在位置为块0,但是偏移为1024,两者比较,其实在磁盘的同一个位置上,与整个块组开头偏移1024个字节。

当超级块内容读取出来后,里面会有个参数指定磁盘上的块大小,如果块大小的值与本次读的时候的块不一致,会根据新的块大小来重新读一遍,但本质不变,超级块即1K大小的磁盘块数据。

2.2读取块组描述符

blocks_count= (ext4_blocks_count(es) -le32_to_cpu(es->s_first_data_block) +EXT4_BLOCKS_PER_GROUP(sb) - 1);

do_div(blocks_count,EXT4_BLOCKS_PER_GROUP(sb));//do_div上文已提到

块的总数/每个块组中的块数=块组个数,即blocks_count。

 

sbi->s_groups_count= blocks_count;

db_count= (sbi->s_groups_count + EXT4_DESC_PER_BLOCK(sb) - 1) /EXT4_DESC_PER_BLOCK(sb);

块组个数/一个块中包含的块组描述符的个数=块描述符需要的块的个数,即有多少个块来表示这些块组描述符

 

 structbuffer_head **s_group_desc;

 sbi->s_group_desc= ext4_kvmalloc(db_count *sizeof(struct buffer_head *),GFP_KERNEL);

分配块描述符的内存;

 

for (i = 0; i < db_count; i++)

 {//循坏块的个数

block= descriptor_loc(sb, logical_sb_block, i);//块组描述符所在的块

sbi->s_group_desc[i]= sb_bread(sb, block);  //读取块组描述符

}

 

static ext4_fsblk_t descriptor_loc(structsuper_block *sb,ext4_fsblk_t logical_sb_block, int nr)

{

       structext4_sb_info *sbi = EXT4_SB(sb);

       ext4_group_tbg, first_meta_bg;

       inthas_super = 0;

       first_meta_bg= le32_to_cpu(sbi->s_es->s_first_meta_bg);

       if(!EXT4_HAS_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_META_BG) ||nr <first_meta_bg)

              returnlogical_sb_block + nr + 1;  //flex_bg模式,块组描述符在超级块的后面,从0到db_count,保存了磁盘上所有的块组描述符。

//下面是meta_bg的模式

       bg= sbi->s_desc_per_block * nr; //一个meta_bg中块组的个数*第nr个meta_bg块组 ,一个meta_bg中块组的个数=一个块的大小/块组描述符的大小

       if(ext4_bg_has_super(sb, bg))//根据是否有sparse_super的参数来确认是否有超级块

              has_super= 1;

       return(has_super + ext4_group_first_block_no(sb, bg));//根据sparse_super判断块组中是否有超级块。0,3,5,7的幂

}

 

static inline ext4_fsblk_t

ext4_group_first_block_no(structsuper_block *sb, ext4_group_t group_no)

{

     return group_no * (ext4_fsblk_t)EXT4_BLOCKS_PER_GROUP(sb) +le32_to_cpu(EXT4_SB(sb)->s_es->s_first_data_block);

//上文中一个meta_bg中块组的个数*nr*一个块组中的块数,nr即为循环偏移

}

2.3读取根节点

#define EXT4_ROOT_INO          2    /* Root inode */

root = ext4_iget(sb, EXT4_ROOT_INO);

根节点即为整个文件系统的入口,得到根目录或者根目录下的文件或者目录。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Linux内核的ext4文件系统是一种高性能、可靠性高的文件系统,其代码在内核源码树的/fs/ext4目录下。 代码文件主要包括以下几个部分: 1. ext4.h:定义了ext4文件系统的数据结构和相关常量。 2. super.c:实现了ext4文件系统超级块的读取和写入。 3. inode.c:实现了ext4文件系统inode节点的读取和写入。 4. namei.c:实现了ext4文件系统文件名的查找和创建。 5. dir.c:实现了ext4文件系统目录的读写操作。 6. file.c:实现了ext4文件系统文件的读写操作。 7. extents.c:实现了ext4文件系统extents分配和管理。 8. inode_table.c:实现了ext4文件系统inode表的管理。 9. resize.c:实现了ext4文件系统的动态扩容和缩容。 10. journal.c:实现了ext4文件系统的日志功能。 下面以super.c文件为例,对其代码进行逐行注释介绍。 ```c /* * linux/fs/ext4/super.c * * Copyright (C) 1995-2006 Theodore Ts'o. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */ ``` 代码开头是版权和许可证声明。 ```c #include <linux/module.h> #include <linux/fs.h> #include <linux/seq_file.h> #include <linux/parser.h> #include <linux/random.h> #include <linux/string.h> #include <linux/slab.h> #include <linux/time.h> #include <linux/uaccess.h> #include <linux/crc32c.h> #include <linux/buffer_head.h> #include <linux/init.h> #include <linux/magic.h> #include <linux/blkdev.h> #include <linux/backing-dev.h> #include <linux/kdev_t.h> #include <linux/sched.h> #include <linux/quotaops.h> #include <linux/pagemap.h> #include <linux/compat.h> #include <linux/falloc.h> #include <linux/atomic.h> #include <linux/fiemap.h> #include <linux/fscrypt.h> #include "ext4.h" #include "xattr.h" #include "acl.h" #include "ext4_jbd2.h" #include "mballoc.h" #include "extents.h" #include "ext4_extents.h" #include "ext4_inode.h" #include "ext4_raw.h" #include "htree.h" ``` 接下来是一些头文件的引用,包括了一些常用的内核函数和结构体定义。 ```c static void ext4_put_super(struct super_block *sb); static int ext4_sync_fs(struct super_block *sb, int wait); static int ext4_freeze(struct super_block *sb); static int ext4_unfreeze(struct super_block *sb); static int ext4_statfs(struct dentry *dentry, struct kstatfs *buf); static int ext4_remount(struct super_block *sb, int *flags, char *data); static int ext4_show_options(struct seq_file *seq, struct dentry *root); static int ext4_commit_super(struct super_block *sb, int sync); static int ext4_write_super(struct super_block *sb); ``` 这部分是函数的声明。 ```c static int ext4_fill_super(struct super_block *sb, void *data, int silent); ``` 这是ext4文件系统的核心函数,用于读取超级块和初始化文件系统。 ```c static struct dentry *ext4_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data); ``` 这是文件系统挂载函数,用于将ext4文件系统挂载到指定设备上。 ```c static struct file_system_type ext4_fs_type = { .owner = THIS_MODULE, .name = "ext4", .mount = ext4_mount, .kill_sb = kill_block_super, .fs_flags = FS_REQUIRES_DEV, }; MODULE_ALIAS_FS("ext4"); MODULE_ALIAS("fs-ext4"); ``` 这部分定义了一个file_system_type结构体,用于注册ext4文件系统类型。其中mount指向ext4_mount函数,kill_sb指向kill_block_super函数。 ```c static int __init init_ext4_fs(void) { int err = init_ext4_fs_once(); if (err) return err; err = register_filesystem(&ext4_fs_type); if (err) goto out1; err = ext4_register_li_request(); if (err) goto out2; return 0; out2: unregister_filesystem(&ext4_fs_type); out1: destroy_ext4_fs(); return err; } module_init(init_ext4_fs); static void __exit exit_ext4_fs(void) { ext4_unregister_li_request(); unregister_filesystem(&ext4_fs_type); destroy_ext4_fs(); } module_exit(exit_ext4_fs); ``` 这部分是初始化和销毁ext4文件系统的函数。 以上就是ext4文件系统的主要代码,对其进行注释可以更好地理解它的实现原理和具体实现方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值