从0开始的操作系统手搓教程33:挂载我们的文件系统

目录

代码实现

添加到初始化上

上电看现象


挂载分区可能是一些朋友不理解的------实际上挂载就是将我们的文件系统封装好了的设备(硬盘啊,SD卡啊,U盘啊等等),挂到我们的默认分区路径下。这样我们就能访问到了(嘿!想象你是一个蚂蚁,别人把葡萄挂到了树枝上,然后你就可以爬着访问到了)

文件系统的挂载和卸载在Linux中是非常重要的功能,它允许用户将一个分区的文件系统与另一个分区的目录树连接起来。通常情况下,Linux会将根分区作为默认分区,并通过mount命令将其他分区挂载到默认分区的某个目录上。在这个过程里,分区的根目录是固定存在的,其他分区尽管有自己的根目录,但它们的根目录并不直接与整个系统的文件结构挂钩。通过mount命令,其他分区可以在需要时被挂载到指定的目录下,而默认分区的根目录则作为所有分区的父目录,挂载后形成一个统一的路径树结构。

对于挂载操作系统到裸盘的情况,并没有现成的分区和文件系统。这时,为了实现文件操作,首先必须在裸盘上创建文件系统,至少要实现基本的文件写入功能。然后,操作系统可以通过文件系统进行安装。例如,在Windows或Linux系统安装过程中,首先会选择目标分区,格式化并安装操作系统到文件系统中。对于学习操作系统实现的场景,虽然也可以模仿这一过程,但为了简化操作,一开始可以避免复杂的分区挂载过程。

实现分区挂载的本质是通过读取硬盘上的元信息并将其加载到内存中,这样,所有硬盘资源的使用情况都能通过内存中的元信息进行管理。当执行写操作时,内存中的数据需要及时同步到硬盘,确保数据的一致性和持久性

代码实现

cpp 复制代码
/* Finds the partition named 'part_name' in the partition list and assigns its 
 * pointer to 'cur_part' */
static bool mount_partition(list_elem *pelem, int arg) {
    // Convert the argument to a partition name string
    char *part_name = (char *)arg;
    
    // Retrieve the DiskPartition structure from the list element
    DiskPartition *part = elem2entry(DiskPartition, part_tag, pelem);
​
    // If the partition name matches, mount this partition
    if (!k_strcmp(part->name, part_name)) {
        cur_part = part; // Set the current partition to the found partition
        Disk *hd = cur_part->my_disk; // Get the disk that contains this partition
​
        // Allocate a buffer to temporarily store the superblock read from disk
        SuperBlock *sb_buf = (SuperBlock *)sys_malloc(SECTOR_SIZE);
​
        // Allocate memory for the superblock of the current partition
        cur_part->sb = (SuperBlock *)sys_malloc(sizeof(SuperBlock));
        if (!cur_part->sb) {
            KERNEL_PANIC_SPIN("alloc memory failed!"); // Kernel panic if allocation fails
        }
​
        // Read the superblock from disk into the buffer
        k_memset(sb_buf, 0, SECTOR_SIZE);
        ide_read(hd, cur_part->start_lba + 1, sb_buf, 1);
​
        // Copy the superblock information from the buffer to the partition's superblock
        k_memcpy(cur_part->sb, sb_buf, sizeof(SuperBlock));
​
        /********** Load the block bitmap from disk into memory **********/
        // Allocate memory for the block bitmap
        cur_part->block_bitmap.bits = (uint8_t *)sys_malloc(sb_buf->block_bitmap_sects * SECTOR_SIZE);
        if (!(cur_part->block_bitmap.bits)) {
            KERNEL_PANIC_SPIN("alloc memory failed!"); // Kernel panic if allocation fails
        }
        // Set the length of the block bitmap in bytes
        cur_part->block_bitmap.btmp_bytes_len = sb_buf->block_bitmap_sects * SECTOR_SIZE;
        
        // Read the block bitmap from disk into memory
        ide_read(hd, sb_buf->block_bitmap_lba, cur_part->block_bitmap.bits, sb_buf->block_bitmap_sects);
        /****************************************************************/
​
        /********** Load the inode bitmap from disk into memory **********/
        // Allocate memory for the inode bitmap
        cur_part->inode_bitmap.bits = (uint8_t *)sys_malloc(sb_buf->inode_bitmap_sects * SECTOR_SIZE);
        if (!(cur_part->inode_bitmap.bits)) {
            KERNEL_PANIC_SPIN("alloc memory failed!"); // Kernel panic if allocation fails
        }
        // Set the length of the inode bitmap in bytes
        cur_part->inode_bitmap.btmp_bytes_len = sb_buf->inode_bitmap_sects * SECTOR_SIZE;
        
        // Read the inode bitmap from disk into memory
        ide_read(hd, sb_buf->inode_bitmap_lba, cur_part->inode_bitmap.bits, sb_buf->inode_bitmap_sects);
        /****************************************************************/
​
        // Initialize the list of open inodes in this partition
        list_init(&cur_part->open_inodes);
        
        verbose_printk("disk mount %s done!\n", part->name); // Print a message indicating successful mounting
​
        // Return true to stop further traversal, as the partition has been found and mounted
        return true;
    }
    return false; // Continue traversing the list if the partition was not found
}
复制代码

mount_filesystem函数就是完成了文件系统中挂载默认分区并加载其元信息的过程。默认分区的名称为 default_part,其值为 sdb1,表示默认操作的分区是 sdb1。分区挂载通过 list_traversal 函数完成,该函数遍历分区列表 partition_list,并对每个分区调用回调函数 mount_partition,传入的参数是 default_part 的地址转换为整型后的值。mount_partitionlist_traversal 的回调函数,其功能是在分区链表中找到与传入的分区名匹配的分区,并将其指针赋值给全局变量 cur_part,用于记录当前操作的分区。

mount_partition 函数中,首先将传入的参数 arg 还原为字符指针 part_name,然后通过宏 elem2entrypelem 还原为分区结构体 part。接着,通过 strcmp 比对 part->namepart_name,如果匹配则找到目标分区,并将其指针赋值给 cur_part。随后,获取该分区所在的硬盘 hd,作为后续硬盘操作的参数。

接下来,系统为超级块申请内存缓冲区 sb_buf,并从硬盘中读取超级块信息到 sb_buf,然后将有用的超级块信息复制到 cur_part->sb 中,忽略填充部分以节省内存。之后,为块位图申请内存,并根据超级块中的 block_bitmap_sects 初始化块位图的大小,最后将硬盘上的块位图读入内存。类似地,系统还会加载 inode 位图到内存中。整个过程确保了分区的元信息被正确加载,并为后续的文件系统操作做好准备。

添加到初始化上

cpp 复制代码
...
    /* Determine the default partition for operations */
    char default_part[8] = "sdb1";
    /* Mount the partition */
    list_traversal(&partition_list, mount_partition, (int)default_part);

上电看现象

下一篇

从0开始的操作系统手搓教程34:说说文件描述符与常见的操作和文件基本操作-CSDN博客文章浏览阅读614次,点赞4次,收藏13次。我们还需要打开根目录并初始化文件表// filesystem_init函数下追加:*/return ret;函数将本地文件描述符转换为全局文件表索引。首先,它获取当前任务的文件描述符表,然后根据传入的本地文件描述符返回对应的全局文件描述符索引。sys_close函数用于关闭文件。首先,它检查文件描述符是否大于2(标准输入、输出和错误文件描述符不处理)。然后,调用将本地文件描述符转换为全局文件描述符,并尝试关闭文件。如果成功,更新任务的文件描述符表并返回0;否则,返回-1。https://blog.csdn.net/charlie114514191/article/details/146143441

相关推荐
一只乔哇噻7 分钟前
java后端工程师进修ing(研一版 || day41)
java·开发语言·学习·算法
知识分享小能手21 分钟前
React学习教程,从入门到精通,React 使用属性(Props)创建组件语法知识点与案例详解(15)
前端·javascript·vue.js·学习·react.js·前端框架·vue
知识分享小能手7 小时前
React学习教程,从入门到精通, React 属性(Props)语法知识点与案例详解(14)
前端·javascript·vue.js·学习·react.js·vue·react
茯苓gao9 小时前
STM32G4 速度环开环,电流环闭环 IF模式建模
笔记·stm32·单片机·嵌入式硬件·学习
是誰萆微了承諾9 小时前
【golang学习笔记 gin 】1.2 redis 的使用
笔记·学习·golang
DKPT10 小时前
Java内存区域与内存溢出
java·开发语言·jvm·笔记·学习
aaaweiaaaaaa10 小时前
HTML和CSS学习
前端·css·学习·html
看海天一色听风起雨落11 小时前
Python学习之装饰器
开发语言·python·学习
speop12 小时前
llm的一点学习笔记
笔记·学习
非凡ghost12 小时前
FxSound:提升音频体验,让音乐更动听
前端·学习·音视频·生活·软件需求