从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

相关推荐
阿阳微客4 小时前
Steam 搬砖项目深度拆解:从抵触到真香的转型之路
前端·笔记·学习·游戏
Chef_Chen9 小时前
从0开始学习R语言--Day18--分类变量关联性检验
学习
键盘敲没电9 小时前
【IOS】GCD学习
学习·ios·objective-c·xcode
海的诗篇_10 小时前
前端开发面试题总结-JavaScript篇(一)
开发语言·前端·javascript·学习·面试
AgilityBaby10 小时前
UE5 2D角色PaperZD插件动画状态机学习笔记
笔记·学习·ue5
AgilityBaby10 小时前
UE5 创建2D角色帧动画学习笔记
笔记·学习·ue5
HAPPY酷11 小时前
Kafka 和Redis 在系统架构中的位置
redis·kafka·系统架构
武昌库里写JAVA12 小时前
iview Switch Tabs TabPane 使用提示Maximum call stack size exceeded堆栈溢出
java·开发语言·spring boot·学习·课程设计
一弓虽13 小时前
git 学习
git·学习
Moonnnn.15 小时前
【单片机期末】串行口循环缓冲区发送
笔记·单片机·嵌入式硬件·学习