• 20201318李兴昕第11章学习笔记


    第11章:EXT2文件系统

    知识点总结:

    本章讨论EXT2文件系统。本章将引导读者实现一个完全与Linux兼容的完整EXT2文件系统。前提是,只要读者充分理解了一个文件系统,那么就可以轻松改编其他任何文件系统。

    本章首先描述了EXT2文件系统在Linux中的历史地位以及EXT3/EXT4文件系统的当前状况;

    用编程示例展示了各种EXT2数据结构以及如何遍历EXT2文件系统树;介绍了如何实现支持Linux内核中所有文件操作的EXT2文件系统;

    展示了如何通过虚拟磁盘的mount_root来构建基本文件系统;

    将文件系统的实现划分为3个级别,级别1扩展了基本文件系统,以实现文件系统树,级别2实现了文件内容的读/写操作,级别3实现了文件系统的挂载/装載和文件保护;

    描述了各个级别文件系统函数的算法,并通过编程示例演示了它 们的实现过程;

    将所有级别融合到一个编程项目中;最后,将所有编程示例和练习整合到一 个完全有效的文件系统中。
    其中让我最有收获的几个部分如下:

    • EXT2文件系统数据结构
    • 邮差算法
    • 教材编程实例
    • 超级块
    • 索引节点
    • 块组描述符

    超级块重要字段:

    __u32 s_inodes_count://文件系统中节点总数
    __u32 s_blocks_count://文件系统中块总数
    __u32 s_r_blocks_count//为超级用户保留的块数
    __u32 s_free_blocks_count//文件系统中空闲块总数
    __u32 s_mtime://文件系统的挂接时间
    __u32 s_wtime://最后一次对该超级块进行写操作的时间
    __u32 s_magic://魔数签名,用于确定文件系统版本的标志
    __u32 s_inodes_per_group:表示每个组块的inode数目,查找文件inode所在块的位置很重要
    __u32 s_mnt_count://文件系统挂接计数
    __u32 s_max_mnt_count://文件系统最大挂接计数
    __u32 s_state://文件系统的状态
    

    util.c重要函数介绍:

    get_block/put_block:我们假设某个块设备,例如真实磁盘或虚拟磁盘,只能以块大小为单位读写。对于真实磁盘,这是因为受到硬件的限制。对于虚拟磁盘,我们假设也是以块大小为单位读/写,这样就可以在需要时将代码移植到真实磁盘上。在虚拟磁盘上,我们先以读|写模式打开它,并使用文件描述符作为设备号。
    
    iget(dev,ino):该函数返回一个指针,指向包含INODE(dev, ino)的内存 minodeo返回的minode是唯一的,即内存中只存在一个INODE副本。在实际文件系统中, 返回的minode被锁定为独占使用,直到它被释放或解锁。
    
    input(INODE *mip):该函数会释放一个mip指向的用完的minode0每 个minode都有一个refCount,表示使用minode. iput()的用户数量为refCount减1。如 果refCount 非零,则表示minode仍有其他用户,那么调用者只是返回。如果调用者是 minode的最后一个用户(refCount = 0 ),那么如果INODE被修改(dirty),它将被写回磁盘。
    
    getino():getino()函数可实现文件系统树遍历算法。它会返回指定路径名的INODE编号(ino)。首先,我们假设在1级文件系统的实现中,文件系统属于单个根设备, 不存在挂载设备和挂载点交叉。因此,getino()函数本质上返回的是路径名的(dev, ino)。
    

    文件系统项目的扩展:

    简单的EXT2文件系统使用IKB块大小,只有一个磁盘块组。它可以轻松进行以下扩展。

    • 多个组:组描述符的大小为32字节”对于1KB大小的块,一个块可能包含 1024/32 = 32组描述符。32个组的文件系统大小可以扩展为32*8 = 256MB.
    • 4KB大小的块:对于4KB大小的块和一个组,文件系统大小应为48 = 32MB。对于一个组描述符块,文件系统可能有128个组,可将文件系统大小扩展到12832 = 4GB。 对于2个组描述符块,文件系统大小为8GB等。大多数扩展都很简单,适合用于编程项目。

    • 管道文件:管道可实现为普通文件,这些文件遵循管道的读/写协议。此方案的优点是:它统一了管道和文件索引节点,并允许可被不相关进程使用的命名管道。为支持快速读/写操作,管道内容应在内存中,比如在RAMdisk中。必要时,读者可将命名管道实现为FIFO文件.

    • I/O缓冲:在编程项目中,每个磁盘块都是直接读写的。这会产生过多的物理磁盘I/O操作。为提髙效率,实际文件系统通常使用一系列I/O缓冲区作为磁盘块的缓存内存。

    实践:显示超级块

    代码:

    /*********** superblock.c program ************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/io.h>
    #include <ext2fs/ext2_fs.h>
    // Cypedef u8, ul6, u32 SUPER for convenience typedef typedef typedef
    typedef unsigned char u8;
    typedef unsigned short ul6;
    typedef unsigned int u32;
    typedef struct ext2_super_block SUPER;
    SUPER *sp;
    char buf[1024];
    int fd, blksize, inodesize;
    int print(char *s, u32 x)
    {
        printf("%-30s = %8d\n", s, x);
    }
    int super(char *device)
    {
        fd = open(device, O_RDONLY);
        if (fd < 0) 
        {
            printf("open %s failed\n", device); 
            exit(1);
        }
        lseek(fd, (long)1024*1, 0);	// block 1 or offset 1024
        read(fd, buf, 1024);
        sp = (SUPER *)buf;	// as a super block structure
        // check for EXT2 FS magic number
        printf("%-30s = %8x ", "s_magic", sp->s_magic);
        if (sp->s_magic != 0xEF53)
        {
            printf("NOT an EXT2 FS\n"); exit(2);
        }
        printf("EXT2 FS OK\n"); 
        print("s_inodes_count",  sp->s_inodes_count);
        print("s_blocks _count", sp->s_blocks_count); 
        print("s_r_blocks_count", sp->s_r_blocks_count);
        print("s_free_inodes_count", sp->s_free_inodes_count);
        print("s_free_blocks_count", sp->s_free_blocks_count);
        print("s_first_data_blcok", sp->s_first_data_block); 
        print("s_log_block_s i z e", sp->s_log_block_size);
        print("s_blocks_per_group", sp->s_blocks_per_group); 
        print("s_inodes_per_group", sp-> s_inodes_per_group); 
        print("s_mnt_count", sp->s_mnt_count);
        print("s_max_mnt_count", sp-> s_max_mnt_count);
        printf("%-30s = %8x\n", "s_magic", sp->s_magic); 
        printf ("s_mtime = %s\n", ctime ((const time_t *)&sp->s_mtime)); 
        printf ("s_wtime = %s", ctime ((const time_t *)&sp->s_wtime)); 
        blksize = 1024 * (1 << sp->s_log_block_size);
        printf("block size = %d\n", blksize);
        printf("inode size = %d\n", sp->s_inode_size);
    }
    char *device = "mydisk";	// 这里vdisk要改为自己创建磁盘的名字
    int main(int argc, char *argv[])
    {
        if (argc>1)
            device = argv[1];
        super(device);
    }
    

    运行发现少了头文件ext2fs.h
    image
    下载头文件包sudo apt-get install libext2fs-dev
    image
    再次运行成功
    image

    实践:显示位图

    代码:

    /*** imap program **************/
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/io.h>
    #include <ext2fs/ext2_fs.h>
    typedef unsigned char u8;
    typedef struct ext2_super_block SUPER;
    typedef struct ext2_group_desc GD;
    #define BLKSIZE 1024
    
    SUPER *sp;
    GD *gp;
    char buf[BLKSIZE]; 
    int fd;
    // get_block() reads a disk block into a buf[]?
    int get_block(int fd, int blk, char *buf)
    {
        lseek(fd, (long)blk*BLKSIZE, SEEK_SET); 
        return read(fd, buf, BLKSIZE);
    }
    
    int imap(char *device)
    {
        int i, ninodes, blksize, imapblk;
        fd = open(device, O_RDONLY);
        if (fd < 0) 
        {
            printf("open %s failed\n", device);
            exit(1);
        }
        get_block(fd, 1, buf);	// get superblock
        sp = (SUPER *)buf;
        // check magic number to ensure itz s an EXT2 FS ninodes = sp->s_inodes_count	//
        ninodes = sp->s_inodes_count;
        printf("ninodes = %d\n", ninodes);
        get_block(fd, 2, buf);	
        gp = (GD *)buf;
        imapblk = gp->bg_inode_bitmap;	
        printf("imapblk = %d\n", imapblk);
        get_block(fd, imapblk, buf);	
        for ( i = 0; i <= ninodes/8; i++)
        {
            printf("%02x ", (u8)buf[i]);
        }
        printf("\n");
    }
    char *dev = "mydisk";
    int main(int argc, char*argv[])
    {
        if(argc>1) dev = argv[1];
        imap(dev);
    }
    

    截图:
    image

  • 相关阅读:
    在Ubuntu 20.04.2 LTS上,启动samba服务
    怎么将ppt中插入的文件单独保存出来
    两款造包工具,科来和xcap
    intel 网卡 && realtek网卡 抓vlan 设定
    Spring注解和一些类
    ReentrantLock源码阅读
    UG12.0安装
    SQL SERVER 分页代码
    SQL SERVER 处理小数位数函数FU_DecimalDigits
    SQL SERVER 表和列添加备注
  • 原文地址:https://www.cnblogs.com/shady545/p/16744213.html
Copyright © 2020-2023  润新知