冬天OS(二十七):写入文件系统

--------------------------------------------------------

制作文件系统

--------------------------------------------------------

所谓系统,就是有规则、有规律、有效率的管理,操作系统也是,文件系统都是,其实最简单的文件系统你可以整块磁盘存储一个文件,也不会有人说它不是文件系统,所以我们的职责是设计一个有效率、有规则地组织管理文件的系统!

 

关于几点

  1. 我们的文件大小都是 2048 个扇区
  2. 最大可以支持 4096 个文件,这个意义是:磁盘分区小于 4G 的时候,支持的文件数目将减少,磁盘分区大于 4G 的时候,也不会超过会有 4096 个文件!
  3. 我们的分区大小为 40257 个扇区——40257 / 2048 == 19 ,所以我们的磁盘能存储 19 个 1M 大小的文件
  4. 如果文件存在了,那么文件对应的 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,我们打印出了几个关键的地址,但是文件系统已经存在于硬盘上了!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

柔弱胜刚强.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值