目录
挂载分区可能是一些朋友不理解的------实际上挂载就是将我们的文件系统封装好了的设备(硬盘啊,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_partition
是 list_traversal
的回调函数,其功能是在分区链表中找到与传入的分区名匹配的分区,并将其指针赋值给全局变量 cur_part
,用于记录当前操作的分区。
在 mount_partition
函数中,首先将传入的参数 arg
还原为字符指针 part_name
,然后通过宏 elem2entry
将 pelem
还原为分区结构体 part
。接着,通过 strcmp
比对 part->name
和 part_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);
上电看现象

