Linux内核-文件系统-超级块操作
文件系统的超级块操作主要是在super.c这个源文件中这个文件的作用主要有对设备的超级块进行操作获取读取释放因为超级块是设备文件系统的映射所以超级块的操作关系到设备文件系统的操作包含文件系统的加载卸载挂载等根文件系统的加载get_super//// 取指定设备的超级块。返回该超级块结构指针 struct super_block * get_super(int dev) { struct super_block * s; if (!dev) return NULL; s 0super_block; // s 指向超级块数组开始处。搜索整个超级块数组寻找指定设备的超级块 while (s NR_SUPERsuper_block) // 如果当前搜索项是指定设备的超级块则首先等待该超级块解锁若已经被其它进程上锁的话。 // 在等待期间该超级块有可能被其它设备使用因此此时需再判断一次是否是指定设备的超级块 // 如果是则返回该超级块的指针。否则就重新对超级块数组再搜索一遍因此 s 重又指向超级块数组 // 开始处 if (s-s_dev dev) { wait_on_super(s); if (s-s_dev dev) return s; s 0super_block; } else s; return NULL; }这个函数和前面几次文章的函数都差不多获取指定设备的超级块put_super//// 释放指定设备的超级块 void put_super(int dev) { struct super_block * sb; struct m_inode * inode; int i; if (dev ROOT_DEV) { printk(root diskette changed: prepare for armageddon\n\r); return; } if (!(sb get_super(dev))) return; if (sb-s_imount) { printk(Mounted disk changed - tssk, tssk\n\r); return; } lock_super(sb); sb-s_dev 0; for(i0;iI_MAP_SLOTS;i) brelse(sb-s_imap[i]); for(i0;iZ_MAP_SLOTS;i) brelse(sb-s_zmap[i]); free_super(sb); return; }put_super用于释放掉指定的超级块在这里需要注意如果设备是根目录那不能被释放以及s_imount如果被挂载到了某个inode也是不能被释放的对于释放操作主要是将s_dev置0让系统不能找到这个超级块然后将inode位图和逻辑块位图清空读取超级块到内存read_super//// 从设备上读取超级块到内存中。 // 如果该设备的超级块已经在高速缓冲中并且有效则直接返回该超级块的指针 static struct super_block * read_super(int dev)查看软驱是否有更改check_disk_change(dev);check_disk_change(dev);这行代码的核心作用是检测指定设备主要是软盘上的介质是否被更换过。如果被更换了就使内核中该设备相关的所有旧缓存数据失效以确保接下来读取到的是新插入介质上的正确超级块。由于这段代码出自 Linux 0.11 内核那个时代主要依赖软盘作为移动存储设备且系统不支持热插拔通知机制所以这个函数是保证数据一致性的关键“防御性”检查。他的底层机制大致如下void check_disk_change(int dev) { int i; if (MAJOR(dev) ! 2) // 只对软盘设备主设备号 2进行检查 return; if (!floppy_change(dev)) // 调用软盘驱动检测磁盘是否真的被抽换过 return; // 如果检测到介质已更换立即执行清理操作 // 1. 从超级块数组中清除该设备的旧超级块 for (i 0; i NR_SUPER; i) if (super_block[i].s_dev dev) put_super(dev); // 2. 使内存中该设备的所有 i 节点inode失效 invalidate_inodes(dev); // 3. 使高速缓冲区buffer cache中该设备的所有数据块失效 invalidate_buffers(dev); }如果在高速缓冲直接拿取if (s get_super(dev)) // 如果该设备的超级块已经在高速缓冲中则直接返回 return s; for (s 0super_block ;; s) { // 否则首先在超级块数组中找出一个空项(也即其 s_dev0 的项)。如果数组已经占满则返回空指针 if (s NR_SUPERsuper_block) return NULL; if (!s-s_dev) // 当前dev为空 break; }如果get_super能够拿到那就说明已经在高速缓冲中了直接返回如果没有的话就需要在超级块数组中找到一个空闲的项存放这个设备的超级块设置动态配置项// 找到超级块空项后就将该超级块用于指定设备对该超级块进行部分初始化 //这里设置的都是一些超级块内存中的一些动态配置项 s-s_dev dev; s-s_isup NULL; s-s_imount NULL; s-s_time 0; s-s_rd_only 0; s-s_dirt 0; lock_super(s);在得到一个空闲的超级块数组项后就去初始化一些超级块存储在内存中的动态配置项读取超级块固定配置项到高速缓冲区if (!(bh bread(dev,1))) { // 从设备上读取超级块信息到 bh 指向的缓冲区中 s-s_dev0; free_super(s); return NULL; } // 将设备上读取的超级块信息复制到内存超级块结构中。并释放存放读取信息的高速缓冲块 *((struct d_super_block *) s) *((struct d_super_block *) bh-b_data); brelse(bh);超级块结构体有一部分是存储在磁盘上的固定配置项包含了节点数逻辑块数位图占据逻辑块数等等使用bread读取这部分内容到高速缓冲区这里的1表示的就是超级块的逻辑块号如果成功拿取到超级块的固定配置项就赋值拷贝到内存s这里也是直接结构体赋值是不规范的最后释放掉使用的这块高速缓冲区根据固定配置项设置位图信息//s_magic是文件系统ID号如果不支持则释放掉这个超级块 if (s-s_magic ! SUPER_MAGIC) { // 说明设备上不是正确的文件系统 s-s_dev 0; free_super(s); return NULL; } // 下面开始读取设备上 i 节点位图和逻辑块位图数据 for (i0;iI_MAP_SLOTS;i) // 初始化 s-s_imap[i] NULL; for (i0;iZ_MAP_SLOTS;i) s-s_zmap[i] NULL; block2; //指向i节点位图 //根据得到的超级块信息分配该设备的i节点位图 for (i0 ; i s-s_imap_blocks ; i) // 读取 if (s-s_imap[i]bread(dev,block)) // 表示inode block; else break; //根据得到的超级块信息分配该设备的逻辑块位图 for (i0 ; i s-s_zmap_blocks ; i) if (s-s_zmap[i]bread(dev,block)) // 表示逻辑块 block; else break; //出错处理还原一切 if (block ! 2s-s_imap_blockss-s_zmap_blocks) { for(i0;iI_MAP_SLOTS;i) brelse(s-s_imap[i]); for(i0;iZ_MAP_SLOTS;i) brelse(s-s_zmap[i]); s-s_dev0; free_super(s); return NULL; }最上面是去判断是不是支持的文件系统不是的话就直接返回NULL然后接下来将设备上的每块i节点位图和逻辑块位图置空等待接下来的分配让block2; //指向i节点位图然后从第一块i节点位图到最后一块逻辑块位图依次分配高速缓冲块如果block ! 2s-s_imap_blockss-s_zmap_blocks就代表出现问题直接将一切还原将位图第一位置1// 一切成功。对于申请空闲 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;位图的第一个bit位是固定不使用的所以强制让他们一直被占用挂载文件系统sys_mount/** * brief 安装文件系统 * * param dev_name 设备文件名 * param dir_name 安装到的目录名 * param rw_flag 被安装文件的读写标志 * return int 0-成功other-错误号 */ int sys_mount(char * dev_name, char * dir_name, int rw_flag)这个函数是mount的系统调用将dev_name的设备挂载到dir_name目录上获取设备和目录i节点struct m_inode * dev_i, * dir_i; struct super_block * sb; int dev; if (!(dev_inamei(dev_name))) // 首先根据设备文件名找到对应的 i 节点并取其中的设备号 return -ENOENT; dev dev_i-i_zone[0]; // 通过i节点获取设备号 if (!S_ISBLK(dev_i-i_mode)) { iput(dev_i); return -EPERM; } iput(dev_i); // 释放刚申请的 i 节点 dev_i if (!(dir_inamei(dir_name))) return -ENOENT; if (dir_i-i_count ! 1 || dir_i-i_num ROOT_INO) { iput(dir_i); return -EBUSY; } if (!S_ISDIR(dir_i-i_mode)) { iput(dir_i); return -EPERM; }1.首先是通过namei函数根据设备文件名和目录名去获取得到设备和目录对应的inode在获取得到设备inode后要去判断它是不是一个块设备S_ISBLK并且去获取得到设备号,块设备inode中的i_zone第一个直接块号存储的设备号dev dev_i-i_zone[0];在完成判断之后就可以释放掉设备的inode节点了,所以才会看到不管是不是块设备都有iput(dev_i);2.然后也会去查看当前要被挂载的文件目录是否没有被其他占用dir_i-i_count并且不是根目录ROOT_INO,以及是否是目录S_ISDIR获取设备超级块if (!(sbread_super(dev))) { // 通过设备号读取设备的超级块 iput(dir_i); return -EBUSY; } if (sb-s_imount) { iput(dir_i); return -EBUSY; } if (dir_i-i_mount) { iput(dir_i); return -EPERM; }这里根据设备号去获取得到设备超级块因为超级块存储着设备文件系统的相关信息通过s_imount i_mount去查看设备和目录是否已经被挂载,如果已经被挂载就退出设置挂载信息sb-s_imountdir_i; // 被安装设备挂载到目录设备节点 dir_i-i_mount1; // 已挂载已修改 dir_i-i_dirt1; /* NOTE! we dont iput(dir_i) */ return 0; /* we do that in umount 在umount 中释放 */在最后将设备的挂载节点指向目录节点,然后将它们各自的挂载标志位置1卸载文件系统sys_umount卸载文件系统sys_umount这里跟上面的挂载操作的思路类似这里是遍历寻找然后间朝状态位最后置位对应信息位,在此不赘述/** * brief 卸载文件系统调用函数 * * param dev_name 设备文件名 * return int 0-成功other-错误号 */ int sys_umount(char * dev_name) { struct m_inode * inode; struct super_block * sb; int dev; if (!(inodenamei(dev_name))) return -ENOENT; dev inode-i_zone[0]; if (!S_ISBLK(inode-i_mode)) { iput(inode); return -ENOTBLK; } iput(inode); if (devROOT_DEV) return -EBUSY; if (!(sbget_super(dev)) || !(sb-s_imount)) return -ENOENT; if (!sb-s_imount-i_mount) printk(Mounted inode has i_mount0\n); for (inodeinode_table0 ; inodeinode_tableNR_INODE ; inode) if (inode-i_devdev inode-i_count) return -EBUSY; sb-s_imount-i_mount0; iput(sb-s_imount); sb-s_imount NULL; iput(sb-s_isup); sb-s_isup NULL; put_super(dev); sync_dev(dev); return 0; }挂载根文件系统mount_root// 加载根文件系统 统开机初始化设置时(sys_setup())调用的 void mount_root(void)根文件系统挂载是在开机时的sys_setup调用的sys_setup函数内部主要是获取BIOS信息硬盘信息加载主存最后就是调用mount_root挂载初始化文件表和超级块数组int i,free; struct super_block * p; struct m_inode * mi; if (32 ! sizeof (struct d_inode)) panic(bad i-node size); for(i0;iNR_FILE;i) // 初始化文件表数组共 64 项也即系统同时只能打开 64 个文件将所有文件结构中的引用计数设置为0 file_table[i].f_count0; if (MAJOR(ROOT_DEV) 2) { // 如果根文件系统所在设备是软盘的话就提示“插入根文件系统盘并按回车键”并等待按键 printk(Insert root floppy and press ENTER); wait_for_keypress(); } for(p super_block[0] ; p super_block[NR_SUPER] ; p) { // 初始化超级块数组共 8 项 p-s_dev 0; p-s_lock 0; p-s_wait NULL; }在函数开始首先判断d_inode大小是否是32,如果不是就报错然后去初始化文件表数组将每一项的文件描述符都清零// 文件表数组 系统同时只能打开64个文件 struct file file_table[NR_FILE];并且对于软盘设备需要用户敲击键盘启动最后就是初始化超级块数组设置s_dev,s_lock,s_wait为0获取根设备超级块和inodeif (!(pread_super(ROOT_DEV))) // 读根设备上超级块 panic(Unable to mount root); if (!(miiget(ROOT_DEV,ROOT_INO))) //从设备上读取文件系统的根 i 节点 panic(Unable to read root i-node); mi-i_count 3 ; /* NOTE! it is logically used 4 times, not 1 */ p-s_isup p-s_imount mi; // 设置i节点挂载 current-pwd mi; // 设置当前工作目录和根目录i节点 current-root mi;接下来就是获取设备的超级块和inode这里的i_count3后实际数值是4,那么是哪4个指针在使用它呢mount_root()的后续代码中这个mi根目录 inode被赋值给了以下位置p-s_isup p-s_imount mi; // ① 超级块的 s_isup② 超级块的 s_imount current-pwd mi; // ③ 当前进程的工作目录 current-root mi; // ④ 当前进程的根目录s_isup文件系统超级块中指向“根目录”的指针用于路径解析的起点。s_imount超级块中指向“被挂载的 inode”的指针虽然根文件系统挂载在自身但这个指针必须有效。current-pwd当前进程的当前工作目录。current-root当前进程的根目录用于chroot环境根文件系统下就是根目录本身。iget(ROOT_DEV, ROOT_INO)在返回 inode 指针时会将该 inode 的i_count设置为1表示“有人正在使用这个 inode 结构体”。统计设备空闲块数和节点数// 统计该设备上空闲块数。 // 首先令 i 等于超级块中的设备逻辑块总数 // 然后根据位图统计出空闲总块 // 接着统计设备上空闲i节点数 free0; ip-s_nzones; while (-- i 0) if (!set_bit(i8191,p-s_zmap[i13]-b_data)) free; printk(%d/%d free blocks\n\r,free,p-s_nzones); free0; ip-s_ninodes1; while (-- i 0) if (!set_bit(i8191,p-s_imap[i13]-b_data)) free; printk(%d/%d free inodes\n\r,free,p-s_ninodes);

相关新闻

局部莫兰指数(LISA)原理、计算与可视化:空间热点探测全解析

局部莫兰指数(LISA)原理、计算与可视化:空间热点探测全解析

1. 项目概述:从全局到局部,洞察空间异质性的关键一步在空间数据分析领域,我们常常需要回答一个核心问题:某个区域的现象,是否与其周边区域存在某种关联?全局莫兰指数(Global Moran‘s I&#xf…

2026/8/2 3:35:47 阅读更多 →
2026年8月更新:ChatGPT、Codex、Pro、Plus背后的Policy as Code——为什么Agent规则不能只写在提示词里?

2026年8月更新:ChatGPT、Codex、Pro、Plus背后的Policy as Code——为什么Agent规则不能只写在提示词里?

过去,团队管理开发规范,主要依靠代码审查、文档和人的经验。进入Agent开发阶段后,规则直接影响执行:Agent能否安装依赖、访问网络、修改目录、继续重试和完成验证,都会决定自动化是安全交付,还是快速扩散错…

2026/8/2 3:35:47 阅读更多 →
CentOS 7.9 上搭建 Valheim 专用服务器:从零部署到稳定运维

CentOS 7.9 上搭建 Valheim 专用服务器:从零部署到稳定运维

1. 从零开始的英灵神殿服务器:为什么选择自己搭建?如果你最近被朋友安利了《英灵神殿》(Valheim),或者已经沉迷于这个维京风格的生存建造游戏,那你大概率会遇到一个共同的烦恼:联机。游戏自带的…

2026/8/2 3:35:47 阅读更多 →

最新新闻

别再用ChatGPT粘贴复制了!真正能进生产环境的AI表格提取系统,必须满足这6个SLO硬指标

别再用ChatGPT粘贴复制了!真正能进生产环境的AI表格提取系统,必须满足这6个SLO硬指标

更多请点击: https://kaifayun.com 第一章:AI表格数据提取的核心挑战与生产级定义 在真实工业场景中,AI驱动的表格数据提取远非OCR规则匹配的简单叠加。其核心挑战根植于文档异构性、语义歧义性与系统可靠性三重张力:扫描质量参差…

2026/8/2 23:28:21 阅读更多 →
AI创造力断层警报:2024全球测评显示青少年发散思维下降37%,这份思维免疫方案仅开放首批500份

AI创造力断层警报:2024全球测评显示青少年发散思维下降37%,这份思维免疫方案仅开放首批500份

更多请点击: https://kaifayun.com 第一章:AI创造力断层警报:2024全球测评揭示的思维危机本质 2024年,由MIT、DeepMind与联合国教科文组织联合发布的《全球AI创造力基准报告》首次量化揭示了一种隐性但系统性的“创造力断层”——…

2026/8/2 23:28:21 阅读更多 →
如何快速实现《鸣潮》全自动化游戏体验:面向技术爱好者的完整指南

如何快速实现《鸣潮》全自动化游戏体验:面向技术爱好者的完整指南

如何快速实现《鸣潮》全自动化游戏体验:面向技术爱好者的完整指南 【免费下载链接】ok-wuthering-waves 鸣潮 后台自动战斗 自动刷声骸 一键日常 Automation for Wuthering Waves 项目地址: https://gitcode.com/GitHub_Trending/ok/ok-wuthering-waves 你是…

2026/8/2 23:28:21 阅读更多 →
洛雪音乐音源:打破平台壁垒,打造你的专属音乐图书馆

洛雪音乐音源:打破平台壁垒,打造你的专属音乐图书馆

洛雪音乐音源:打破平台壁垒,打造你的专属音乐图书馆 【免费下载链接】lxmusic- lxmusic(洛雪音乐)全网最新最全音源 项目地址: https://gitcode.com/gh_mirrors/lx/lxmusic- 你是否曾为了一首歌在不同音乐平台间来回切换?是否厌倦了为…

2026/8/2 23:28:21 阅读更多 →
TV-Multiplatform高级技巧:历史记录同步、播放速度调节与快捷键使用

TV-Multiplatform高级技巧:历史记录同步、播放速度调节与快捷键使用

TV-Multiplatform高级技巧:历史记录同步、播放速度调节与快捷键使用 【免费下载链接】TV-Multiplatform 基于fonmi/TV项目的, 简单桌面版本实现。 项目地址: https://gitcode.com/gh_mirrors/tv/TV-Multiplatform TV-Multiplatform是一款基于fonm…

2026/8/2 23:28:21 阅读更多 →
企业AI落地开发:从技术选型到价值交付的实践路径

企业AI落地开发:从技术选型到价值交付的实践路径

在过去的两年时间里, 国内企业级AI应用开发市场历经了一场关键转折, 也就是从概念验证转变到规模化落地。依照中国信息通信研究院在2025年发布的《人工智能发展报告》来看, 截止到2025年年底的时候, 我国提供企业级AI应用开发服务的公司数量已然超过了4800家, 其中专注于垂直行…

2026/8/2 23:27:20 阅读更多 →

日新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/2 0:00:38 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/2 0:00:38 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/2 0:00:38 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/2 6:34:16 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/2 2:47:48 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/2 0:23:22 阅读更多 →