--------------------------------------------------------
制作文件系统
--------------------------------------------------------
所谓系统,就是有规则、有规律、有效率的管理,操作系统也是,文件系统都是,其实最简单的文件系统你可以整块磁盘存储一个文件,也不会有人说它不是文件系统,所以我们的职责是设计一个有效率、有规则地组织管理文件的系统!
关于几点
- 我们的文件大小都是 2048 个扇区
- 最大可以支持 4096 个文件,这个意义是:磁盘分区小于 4G 的时候,支持的文件数目将减少,磁盘分区大于 4G 的时候,也不会超过会有 4096 个文件!
- 我们的分区大小为 40257 个扇区——40257 / 2048 == 19 ,所以我们的磁盘能存储 19 个 1M 大小的文件!
- 如果文件存在了,那么文件对应的 2048 位 smap 位都要置 1 (表示占用)!
·mkfs 函数
PRIVATE void mkfs()
{
MESSAGE driver_msg;
int i, j;
int bits_per_sect = SECTOR_SIZE * 8; /* 8 bits per byte */
// 获得根分区的起始 LBA,Size
struct part_info geo;
driver_msg.type = DEV_IOCTL;
driver_msg.DEVICE = MINOR(ROOT_DEV);
driver_msg.REQUEST = DIOCTL_GET_GEO;
driver_msg.BUF = &geo;
driver_msg.PROC_NR = TASK_FS;
assert(dd_map[MAJOR(ROOT_DEV)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(ROOT_DEV)].driver_nr, &driver_msg);
printl("dev size: 0x%x sectors\n", geo.size);
/************************/
/* super block */
/************************/
struct super_block sb;
sb.magic = MAGIC_V1; /* magic number 0x111 */
sb.nr_inodes = bits_per_sect; /* 允许有多少个 inode ( 4096 )*/
sb.nr_inode_sects = sb.nr_inodes * INODE_SIZE / SECTOR_SIZE; /* inode_array 占用的扇区数( 256个扇区 ) */
sb.nr_sects = geo.size; /* 跟设备分区一共有多少个扇区( 40257 个扇区 )*/
sb.nr_imap_sects = 1; /* imap 占用的扇区数 ( 1 个扇区)*/
sb.nr_smap_sects = sb.nr_sects / bits_per_sect + 1; /* smap 占用的扇区数(80m.img 算完是 9 + 1 = 10 个扇区) */
sb.n_1st_sect = 1 + /* 1 + 1 + 1 + 10 + 256 == 269 */
1 +
sb.nr_imap_sects +
sb.nr_smap_sects +
sb.nr_inode_sects;
sb.root_inode = ROOT_INODE; /* 根目录文件的 i 节点号 */
sb.inode_size = INODE_SIZE; /* sizeof(struct inode) */
struct inode x; /* offset in [inode] */
sb.inode_isize_off = (int)&x.i_size - (int)&x;
sb.inode_start_off = (int)&x.i_start_sect - (int)&x;
sb.dir_ent_size = DIR_ENTRY_SIZE;
struct dir_entry de; /* offset in [dir_ent] */
sb.dir_ent_inode_off = (int)&de.inode_nr - (int)&de;
sb.dir_ent_fname_off = (int)&de.name - (int)&de;
// 写文件系统其实就这三句
// 起始扇区:1 号扇区
// 写入数量:1 个扇区
memset(fsbuf, 0x90, SECTOR_SIZE);
memcpy(fsbuf, &sb, SUPER_BLOCK_SIZE);
WR_SECT(ROOT_DEV, 1); /* write the super block */
printl("RootDevBaseAddr(Byte): [0x%x]\n"
"-----------------------\n"
"SuperBlockAddr(Byte): [0x%x]\n"
"imapAddr(Byte): [0x%x]\n"
"smapAddr(Byte): [0x%x]\n"
"inodeAddr(Byte): [0x%x]\n"
"1st_sectorAdrr(Byte): [0x%x]\n"
"-----------------------\n",
geo.base * 512,
(geo.base + 1) * 512,
(geo.base + 1 + 1) * 512,
(geo.base + 1 + 1 + sb.nr_imap_sects) * 512,
(geo.base + 1 + 1 + sb.nr_imap_sects + sb.nr_smap_sects) * 512,
(geo.base + sb.n_1st_sect) * 512);
/************************/
/* inode map */
/************************/
// 起始扇区:2 号扇区
// 写入数量:1 个扇区
memset(fsbuf, 0, SECTOR_SIZE);
for (i = 0; i < (NR_CONSOLES + 2); i++)
fsbuf[0] |= 1 << i;
assert(fsbuf[0] == 0x1F); /* 0001 1111 */
WR_SECT(ROOT_DEV, 2);
/************************/
/* secter map */
/************************/
// 起始扇区:3 号扇区
// 写入数量:1 个扇区
memset(fsbuf, 0, SECTOR_SIZE);
int nr_sects = NR_DEFAULT_FILE_SECTS + 1;
for (i = 0; i < nr_sects / 8 /* 256 */; i++) /* 根目录文件占用的 2048 个扇区置 dirty */
fsbuf[i] = 0xFF;
for (j = 0; j < nr_sects % 8; j++) /* 保留位置 dirty */
fsbuf[i] |= (1 << j);
// 根目录文件占用的 smap 位图加起来 256 字节,在一个扇区范围内,所以写入一个扇区就行了!
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects);
// smap 第一个扇区的位图赋值完了,其余(还有 9 个)扇区的都清零!
// 起始扇区:4 号扇区
// 写入数量:9 个扇区(循环写入)
memset(fsbuf, 0, SECTOR_SIZE);
for (i = 1; i < sb.nr_smap_sects; i++)
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + i);
/************************/
/* inodes */
/************************/
/* inode of `/' */
memset(fsbuf, 0, SECTOR_SIZE);
struct inode *pi = (struct inode *)fsbuf;
pi->i_mode = I_DIRECTORY;
pi->i_size = DIR_ENTRY_SIZE * 4; /* 根目录文件包含 4 个 dir entry */
pi->i_start_sect = sb.n_1st_sect; /* 根目录文件的数据从“数据起始扇区”开始算起 */
pi->i_nr_sects = NR_DEFAULT_FILE_SECTS;
/* inode of `/dev_tty0~2' */
for (i = 0; i < NR_CONSOLES; i++)
{
pi = (struct inode *)(fsbuf + (INODE_SIZE * (i + 1)));
pi->i_mode = I_CHAR_SPECIAL;
pi->i_size = 0; /* 无意义 */
pi->i_nr_sects = 0; /* 无意义 */
pi->i_start_sect = MAKE_DEV(DEV_CHAR_TTY, i); /* i_start_sect 保存的是设备的设备号 */
/* tty 的主设备号是 4 ,次设备号就是 0,1,2 */
}
// 32 * 4 < 512 ,所以只写入一个扇区
// 起始扇区:13 号扇区
// 写入数量:1 个扇区
WR_SECT(ROOT_DEV, 2 + sb.nr_imap_sects + sb.nr_smap_sects);
/************************/
/* `/' */
/************************/
// 为根目录文件赋值数据(填充 4 个 dir entry)!
// 这里过后,起始目录(所谓“目录包含文件”)就建立起来了,因为通过目录文件可以找到具体文件了!
memset(fsbuf, 0, SECTOR_SIZE);
struct dir_entry *pde = (struct dir_entry *)fsbuf;
pde->inode_nr = 1; /* 重要:这里算的是 imap 中的序号 */
strcpy(pde->name, ".");
/* dir entries of `/dev_tty0~2' */
for (i = 0; i < NR_CONSOLES; i++)
{
pde++;
pde->inode_nr = i + 2; /* dev_tty0's inode_nr is 2 */
sprintf(pde->name, "dev_tty%d", i);
}
// 四个 dir entry 加起来不会超过 512 字节,所以写一个扇区
// 起始扇区:n_1st_sect
// 写入数量:1 个扇区
WR_SECT(ROOT_DEV, sb.n_1st_sect);
}
·rw_sector 函数
PUBLIC int rw_sector(int io_type, int dev, u64 pos, int bytes, int proc_nr,
void *buf)
{
MESSAGE driver_msg;
driver_msg.type = io_type;
driver_msg.DEVICE = MINOR(dev);
driver_msg.POSITION = pos;
driver_msg.BUF = buf;
driver_msg.CNT = bytes;
driver_msg.PROC_NR = proc_nr;
assert(dd_map[MAJOR(dev)].driver_nr != INVALID_DRIVER);
send_recv(BOTH, dd_map[MAJOR(dev)].driver_nr, &driver_msg);
return 0;
}
mkfs 的过程中通篇每次只写一个扇区(多扇区也就 smap 的时候用到了,但用了循环写入一个扇区),起始位置都是扇区号(严格按照 512 字节对齐),编码也是严格按照事先分析的布局来的!
运行:
OK,我们打印出了几个关键的地址,但是文件系统已经存在于硬盘上了!