本篇比较短小精悍,只针对书上的第14.2.3挂载分区这一小节,在前面我们已经通过fdisk将硬盘划分为了主分区与主扩展分区(主扩展分区又被划分成子扩展分区与逻辑分区),最终我们把主分区以及逻辑分区的信息读入到了ide.c中的partition_list队列中。本节要做的就是将分区的超级块sb,block位图以及inode位图读入到对应的partition的对应属性中,这就称之为分区的挂载,实际上就是将硬盘上分区的相关内容读入到内存的partition数据结构中。
再复习一下分区在硬盘中的结构,以及partition数据结构:
/* 分区结构 */
struct partition {
uint32_t start_lba;
uint32_t sec_cnt;
struct disk* my_disk;
struct list_elem part_tag;
char name[8];
struct super_block* sb;
struct bitmap block_bitmap;
struct bitmap inode_bitmap;
struct list open_inodes;
};
/* 位图结构 */
struct bitmap {
uint32_t btmp_bytes_len;
uint8_t *bits;
};
/* 超级块结构 */
struct super_block {
uint32_t magic; //标识文件系统类型
uint32_t sec_cnt; //本分区总扇区数
uint32_t inode_cnt; //本分区中inode数量
uint32_t part_lba_base; //本分区起始lba地址
uint32_t block_bitmap_lba; //块位图起始扇区lba地址
uint32_t block_bitmap_sects; //块位图占用的扇区数量
uint32_t inode_bitmap_lba; //i节点位图起始扇区地址
uint32_t inode_bitmap_sects; //i节点位图占用扇区数量
uint32_t inode_table_lba; //i节点数组起始扇区地址
uint32_t inode_table_sects; //i节点数组占用扇区数量
uint32_t data_start_lba; //空闲块起始lba地址
uint32_t root_inode_no; //根目录所在i节点号
uint32_t dir_entry_size; //目录项大小
uint8_t pad[460]; //加上460字节,凑够512字节1扇区大小
}__attribute__((packed));
有了以上的铺垫,我们就可以正式敲代码了,代码的内容其实就是从硬盘中读出对应的数据结构填充到partition的sb属性、block_bitmap属性以及inode_bitmap属性中并将open_inodes队列进行初始化,代码如下(fs.c中):
static bool mount_partition(struct list_elem* pelem, int arg) {
char* part_name = (char*) arg;
struct partition* part = elem2entry(struct partition, part_tag, pelem);
if(!strcmp(part->name, part_name)) {
cur_part = part;
/* 从硬盘中读取超级块到partition的sb字段中 */
part->sb = (struct super_block*) sys_malloc(SECTOR_SIZE);
if(part->sb == NULL) {
PANIC("alloc memory failed!");
}
ide_read(part->my_disk, part->start_lba + 1, part->sb, 1);
/* 从硬盘中读取block位图到partition的block_bitmap字段中 */
part->block_bitmap.bits = (uint8_t*) sys_malloc(part->sb->block_bitmap_sects * SECTOR_SIZE);
if(part->block_bitmap.bits == NULL) {
PANIC("alloc memory failed!");
}
part->block_bitmap.btmp_bytes_len = part->sb->block_bitmap_sects * SECTOR_SIZE;
ide_read(part->my_disk, part->sb->block_bitmap_lba, part->block_bitmap.bits, part->sb->block_bitmap_sects);
/* 从硬盘中读取inode位图到partition的inode_bitmap字段中 */
part->inode_bitmap.bits = (uint8_t*) sys_malloc(part->sb->inode_bitmap_sects * SECTOR_SIZE);
if(part->inode_bitmap.bits == NULL) {
PANIC("alloc memory failed!");
}
part->inode_bitmap.btmp_bytes_len = part->sb->inode_bitmap_sects * SECTOR_SIZE;
ide_read(part->my_disk, part->sb->inode_bitmap_lba, part->inode_bitmap.bits, part->sb->inode_bitmap_sects);
/* 初始化该分区的open_inodes队列 */
list_init(&cur_part->open_inodes);
printk("mount %s done!\n", part->name);
return true;
}
return false;
}
我们还要在filesys_init函数中调用mount_partition函数,mount_partition函数作为链表的回调函数进行调用。
void filesys_init() {
uint8_t channel_no = 0, dev_no = 0, part_idx = 0;
struct super_block* sb_buf = (struct super_block*) sys_malloc(SECTOR_SIZE);
if(sb_buf == NULL) {
PANIC("alloc memory failed!");
}
printk("searching filesystem......\n");
while(channel_no < channel_cnt) {
dev_no = 0;
while(dev_no < 2) {
if (dev_no == 0) {
dev_no++;
continue;
}
struct disk* hd = &channels[channel_no].devices[dev_no];
struct partition* part = hd->prim_parts;
while (part_idx < 12) {
if(part_idx == 4) {
part = hd->logic_parts;
}
if(part->sec_cnt != 0) {
memset(sb_buf, 0, SECTOR_SIZE);
ide_read(hd, part->start_lba + 1, sb_buf, 1);
if(sb_buf->magic == 0x19970814) {
printk("%s has filesystem\n", part->name);
} else {
printk("formatting %s's partition %s......\n", hd->name, part->name);
partition_format(hd, part);
}
}
part_idx++;
part++;
}
dev_no++;
}
channel_no++;
}
sys_free(sb_buf);
/* 这两行代码进行了sdb1分区的挂载 */
char default_part[8] = "sdb1";
list_traversal(&partition_list, mount_partition, (int)default_part);
}
到此,本篇结束,这篇是最近写文件系统最轻松的一篇了,文件系统这部分是真的长,要吐了。