📄 super.c
字号:
block++; else break; for (i = 0; i < s->s_zmap_blocks; i++) if (s->s_zmap[i] = bread (dev, block)) block++; else break;// 如果读出的位图逻辑块数不等于位图应该占有的逻辑块数,说明文件系统位图信息有问题,超级块// 初始化失败。因此只能释放前面申请的所有资源,返回空指针并退出。 if (block != 2 + s->s_imap_blocks + s->s_zmap_blocks) {// 释放i 节点位图和逻辑块位图占用的高速缓冲区。 for (i = 0; i < I_MAP_SLOTS; i++) brelse (s->s_imap[i]); for (i = 0; i < Z_MAP_SLOTS; i++) brelse (s->s_zmap[i]);//释放上面选定的超级块数组中的项,并解锁该超级块项,返回空指针退出。 s->s_dev = 0; free_super (s); return NULL; }// 否则一切成功。对于申请空闲i 节点的函数来讲,如果设备上所有的i 节点已经全被使用,则查找// 函数会返回0 值。因此0 号i 节点是不能用的,所以这里将位图中的最低位设置为1,以防止文件// 系统分配0 号i 节点。同样的道理,也将逻辑块位图的最低位设置为1。 s->s_imap[0]->b_data[0] |= 1; s->s_zmap[0]->b_data[0] |= 1;// 解锁该超级块,并返回超级块指针。 free_super (s); return s;}//// 卸载文件系统的系统调用函数。// 参数dev_name 是设备文件名。intsys_umount (char *dev_name){ struct m_inode *inode; struct super_block *sb; int dev;// 首先根据设备文件名找到对应的i 节点,并取其中的设备号。 if (!(inode = namei (dev_name))) return -ENOENT; dev = inode->i_zone[0];// 如果不是块设备文件,则释放刚申请的i 节点dev_i,返回出错码。 if (!S_ISBLK (inode->i_mode)) { iput (inode); return -ENOTBLK; }// 释放设备文件名的i 节点。 iput (inode);// 如果设备是根文件系统,则不能被卸载,返回出错号。 if (dev == ROOT_DEV) return -EBUSY;// 如果取设备的超级块失败,或者该设备文件系统没有安装过,则返回出错码。 if (!(sb = get_super (dev)) || !(sb->s_imount)) return -ENOENT;// 如果超级块所指明的被安装到的i 节点没有置位其安装标志,则显示警告信息。 if (!sb->s_imount->i_mount) printk ("Mounted inode has i_mount=0\n");// 查找i 节点表,看是否有进程在使用该设备上的文件,如果有则返回忙出错码。 for (inode = inode_table + 0; inode < inode_table + NR_INODE; inode++) if (inode->i_dev == dev && inode->i_count) return -EBUSY;// 复位被安装到的i 节点的安装标志,释放该i 节点。 sb->s_imount->i_mount = 0; iput (sb->s_imount);// 置超级块中被安装i 节点字段为空,并释放设备文件系统的根i 节点,置超级块中被安装系统// 根i 节点指针为空。 sb->s_imount = NULL; iput (sb->s_isup); sb->s_isup = NULL;// 释放该设备的超级块以及位图占用的缓冲块,并对该设备执行高速缓冲与设备上数据的同步操作。 put_super (dev); sync_dev (dev); return 0;}//// 安装文件系统调用函数。// 参数dev_name 是设备文件名,dir_name 是安装到的目录名,rw_flag 被安装文件的读写标志。// 将被加载的地方必须是一个目录名,并且对应的i 节点没有被其它程序占用。intsys_mount (char *dev_name, char *dir_name, int rw_flag){ struct m_inode *dev_i, *dir_i; struct super_block *sb; int dev;// 首先根据设备文件名找到对应的i 节点,并取其中的设备号。// 对于块特殊设备文件,设备号在i 节点的i_zone[0]中。 if (!(dev_i = namei (dev_name))) return -ENOENT; dev = dev_i->i_zone[0];// 如果不是块设备文件,则释放刚取得的i 节点dev_i,返回出错码。 if (!S_ISBLK (dev_i->i_mode)) { iput (dev_i); return -EPERM; }// 释放该设备文件的i 节点dev_i。 iput (dev_i);// 根据给定的目录文件名找到对应的i 节点dir_i。 if (!(dir_i = namei (dir_name))) return -ENOENT;// 如果该i 节点的引用计数不为1(仅在这里引用),或者该i 节点的节点号是根文件系统的节点// 号1,则释放该i 节点,返回出错码。 if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO) { iput (dir_i); return -EBUSY; }// 如果该节点不是一个目录文件节点,则也释放该i 节点,返回出错码。 if (!S_ISDIR (dir_i->i_mode)) { iput (dir_i); return -EPERM; }// 读取将安装文件系统的超级块,如果失败则也释放该i 节点,返回出错码。 if (!(sb = read_super (dev))) { iput (dir_i); return -EBUSY; }// 如果将要被安装的文件系统已经安装在其它地方,则释放该i 节点,返回出错码。 if (sb->s_imount) { iput (dir_i); return -EBUSY; }// 如果将要安装到的i 节点已经安装了文件系统(安装标志已经置位),则释放该i 节点,返回出错码。 if (dir_i->i_mount) { iput (dir_i); return -EPERM; }// 被安装文件系统超级块的“被安装到i 节点”字段指向安装到的目录名的i 节点。 sb->s_imount = dir_i;// 设置安装位置i 节点的安装标志和节点已修改标志。/* 注意!这里没有iput(dir_i) */ dir_i->i_mount = 1; /* 这将在umount 内操作 */ dir_i->i_dirt = 1; /* NOTE! we don't iput(dir_i) */ return 0; /* we do that in umount */}//// 安装根文件系统。// 该函数是在系统开机初始化设置时(sys_setup())调用的。( kernel/blk_drv/hd.c, 157 )voidmount_root (void){ int i, free; struct super_block *p; struct m_inode *mi;// 如果磁盘i 节点结构不是32 个字节,则出错,死机。该判断是用于防止修改源代码时的不一致性。 if (32 != sizeof (struct d_inode)) panic ("bad i-node size");// 初始化文件表数组(共64 项,也即系统同时只能打开64 个文件),将所有文件结构中的引用计数// 设置为0。[??为什么放在这里初始化?] for (i = 0; i < NR_FILE; i++) file_table[i].f_count = 0;// 如果根文件系统所在设备是软盘的话,就提示“插入根文件系统盘,并按回车键”,并等待按键。 if (MAJOR (ROOT_DEV) == 2) { printk ("Insert root floppy and press ENTER"); wait_for_keypress (); }// 初始化超级块数组(共8 项)。 for (p = &super_block[0]; p < &super_block[NR_SUPER]; p++) { p->s_dev = 0; p->s_lock = 0; p->s_wait = NULL; }// 如果读根设备上超级块失败,则显示信息,并死机。 if (!(p = read_super (ROOT_DEV))) panic ("Unable to mount root");//从设备上读取文件系统的根i 节点(1),如果失败则显示出错信息,死机。 if (!(mi = iget (ROOT_DEV, ROOT_INO))) panic ("Unable to read root i-node");// 该i 节点引用次数递增3 次。因为下面266-268 行上也引用了该i 节点。 mi->i_count += 3; /* NOTE! it is logically used 4 times, not 1 *//* 注意!从逻辑上讲,它已被引用了4 次,而不是1 次 */// 置该超级块的被安装文件系统i 节点和被安装到的i 节点为该i 节点。 p->s_isup = p->s_imount = mi;// 设置当前进程的当前工作目录和根目录i 节点。此时当前进程是1 号进程。 current->pwd = mi; current->root = mi;// 统计该设备上空闲块数。首先令i 等于超级块中表明的设备逻辑块总数。 free = 0; i = p->s_nzones;// 然后根据逻辑块位图中相应比特位的占用情况统计出空闲块数。这里宏函数set_bit()只是在测试// 比特位,而非设置比特位。"i&8191"用于取得i 节点号在当前块中的偏移值。"i>>13"是将i 除以// 8192,也即除一个磁盘块包含的比特位数。 while (--i >= 0) if (!set_bit (i & 8191, p->s_zmap[i >> 13]->b_data)) free++;// 显示设备上空闲逻辑块数/逻辑块总数。 printk ("%d/%d free blocks\n\r", free, p->s_nzones);// 统计设备上空闲i 节点数。首先令i 等于超级块中表明的设备上i 节点总数+1。加1 是将0 节点// 也统计进去。 free = 0; i = p->s_ninodes + 1;// 然后根据i 节点位图中相应比特位的占用情况计算出空闲i 节点数。 while (--i >= 0) if (!set_bit (i & 8191, p->s_imap[i >> 13]->b_data)) free++;// 显示设备上可用的空闲i 节点数/i 节点总数。 printk ("%d/%d free inodes\n\r", free, p->s_ninodes);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -