尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Linux内核-文件系统-位图操作
inode节点概念文件与磁盘的映射原文链接Linux内核-文件系统-位图操作 – kidwjb的小站文件系统概念不管读取什么磁盘上的资源都是先getblk获取该资源对应的设备和块号的高速缓冲区然后在bread确认有效数据的高速缓冲区最后再进行区域内存的拷贝一个设备的文件系统框架所有块的大小都是固定的,称为盘块或磁盘块扇区块设备上一个长度为512B的数据块在不同的文件系统中扇区和盘块的对应关系不同两个扇区对应一个盘块--1024B四个扇区对应一个盘块--2048Bi节点位图块中的一个比特对应一个i节点如果是两个扇区一个盘块那么i节点就是1024*8 8191个i节点,因为i节点位图的第0位不用逻辑块位图中一个比特对应一个逻辑块超级块结构体在超级块结构体中有// 内存中磁盘超级块结构 struct super_block { unsigned short s_ninodes; // 节点数 unsigned short s_nzones; // 逻辑块数 unsigned short s_imap_blocks; // i 节点位图所占用的数据块数 unsigned short s_zmap_blocks; // 逻辑块位图所占用的数据块数 unsigned short s_firstdatazone; // 第一个数据逻辑块号,相对于引导块而言 unsigned short s_log_zone_size; // log(数据块数/逻辑块) unsigned long s_max_size; // 文件最大长度 unsigned short s_magic; /* These are only in memory */ struct buffer_head * s_imap[8]; // i 节点位图缓冲块指针数组(占用 8 块可表示 64M) struct buffer_head * s_zmap[8]; // 逻辑块位图缓冲块指针数组 unsigned short s_dev; // 超级块所在的设备号 struct m_inode * s_isup; // 被安装的文件系统根目录的 i 节点。(isup-super i) struct m_inode * s_imount; // 被安装到的 i 节点 unsigned long s_time; // 修改时间 struct task_struct * s_wait; // 等待该超级块的进程 unsigned char s_lock; // 被锁定标志 unsigned char s_rd_only; // 只读标志 unsigned char s_dirt; // 已修改标志脏标志 };其中的struct buffer_head * s_imap[8]; // i 节点位图缓冲块指针数组(占用 8 块可表示 64M) struct buffer_head * s_zmap[8]; // 逻辑块位图缓冲块指针数组指的是指向i节点位图和指向逻辑块位图的buffer_head指针数组,在这里每个数组都有八项说明在当前linux0.1内核中一个文件系统支持8个i节点位图和8个逻辑块位图那么对应逻辑块的最大大小8个缓冲区头* 1024一个逻辑块位图1024字节 * 8一个字节8个bit* 10241个bit对应一个块 64Mi节点同理位图操作源码bitmap.c释放逻辑块free_block//// 释放设备 dev 上数据区中的逻辑块 block。 // 复位指定逻辑块 block 的逻辑块位图比特位 void free_block(int dev, int block)释放逻辑块总共分为两个操作释放掉指定的逻辑块struct super_block * sb; struct buffer_head * bh; if (!(sb get_super(dev))) //get super block panic(trying to free block on nonexistent device); if (block sb-s_firstdatazone || block sb-s_nzones) // 若逻辑块号小于首个逻辑块号或者大于设备上总逻辑块数 panic(trying to free block not in datazone); bh get_hash_table(dev,block); // 在hash表中找到该数据块 if (bh) { if (bh-b_count ! 1) { printk(trying to free block (%04x:%d), count%d\n, dev,block,bh-b_count); return; } bh-b_dirt0; // 复位脏已修改标志位 bh-b_uptodate0; // 复位更新标志 brelse(bh); // 释放缓冲块 }在最开始调用get_super函数获取得到这个设备对应的超级块,然后检查传入的逻辑块号是否是合理的接着就使用get_hash_table在哈希表中获取得到对应设备异或逻辑块号的高速缓冲区块如果得到了逻辑块查看是否只有当前进程使用这个逻辑块如果不是的话说明还有进程正在使用还不能释放如果只有当前进程使用那么就将b_dirt和b_uptodate复位并且释放缓冲块注意这里为什么没有调用getblk获取对应的高速缓冲区块应该是本来getblk就会进行复位操作这样子就多此一举的复位指定逻辑块对应的逻辑块位图中的比特位block - sb-s_firstdatazone - 1 ; // 计算 block 在数据区开始算起的逻辑块号从 1 开始计数。然后对逻辑块(区段)位图进行操作复位对应的比特位 if (clear_bit(block8191,sb-s_zmap[block/8192]-b_data)) { printk(block (%04x:%d) ,dev,blocksb-s_firstdatazone-1); panic(free_block: bit already cleared); } // 置相应逻辑块位图所在缓冲区已修改标志。 sb-s_zmap[block/8192]-b_dirt 1;block - sb-s_firstdatazone - 1 ;这里是算出block相对于逻辑块开始的块号s_firstdatazone的数值因为逻辑块号是相对于引导块而言的clear_bit(block8191,sb-s_zmap[block/8192]-b_data)这里使用了一个嵌入式汇编宏clear_bit(nr,addr)//// 复位指定地址开始的第 nr 位偏移处的比特位。返回原比特位的反码1 或 0。 // 输入%0 - eax返回值)%1 - eax(0)%2 - nr位偏移值%3 - (addr)addr 的内容。 #define clear_bit(nr,addr)参数第一项block8191,这里是让与操作得到的结果只能是[0,8191]参数第二项sb-s_zmap[block/8192]-b_data这里block/8192是每8192个block作为数组的一项二者结合起来看是因为struct buffer_head * s_zmap[8];逻辑块位图一共有八个对于每一个单独的逻辑块位图他们的bit位置是相同的所以找到了对于s_zmap指针数组,他指向的b_data就是一块逻辑块位图,然后第一项得到要复位这块逻辑块位图的第几位最后记得将这个逻辑块位图对应高速缓冲区头中的b_dirt置1,表明这个高速缓冲区已经被修改了申请逻辑块new_block////向设备 dev 申请一个逻辑块磁盘块区段。返回逻辑块号。 // 置位指定逻辑块 block 的逻辑块位图比特位。 int new_block(int dev)该函数用于向指定的设备申请一个逻辑块主要分为三个操作获取逻辑块位图空闲比特位struct buffer_head * bh; struct super_block * sb; int i,j; if (!(sb get_super(dev))) panic(trying to get new block from nonexistant device); j 8192; for (i0 ; i8 ; i) if (bhsb-s_zmap[i]) if ((jfind_first_zero(bh-b_data))8192) break; if (i8 || !bh || j8192) return 0;首先也是先从根据设备号获取得到指定的超级块因为超级块存储着逻辑块位图和i节点位图信息然后就是通过一个for循环去寻找逻辑块位图中第一个有空闲的比特位for (i0 ; i8 ; i)是因为s_zmap数组**一共八项,**每一项管理一块逻辑块位图然后让bhsb-s_zmap[i]在每一块位图上试jfind_first_zero(bh-b_data))8192表示如果找到了第一个为0的比特位并且没有超过这个位图块的大小那么就是找到了最后进行一个简单的判断查看找到的比特是否在合理的位置置位逻辑块位图if (set_bit(j,bh-b_data)) panic(new_block: bit already set); bh-b_dirt 1; j i*8192 sb-s_firstdatazone-1; if (j sb-s_nzones) return 0;经过上面for循环找到了比特位和对应的逻辑块位图的高速缓冲区那么就通过set_bit宏去设置这个比特位//// 置位指定地址开始的第 nr 个位偏移处的比特位(nr 可以大于 32)。返回原比特位0 或 1。 // 输入%0 - eax返回值)%1 - eax(0)%2 - nr位偏移值%3 - (addr)addr 的内容。 #define set_bit(nr,addr)置位后说明高速缓冲区有数据更新将b_dirt置1j i*8192 sb-s_firstdatazone-1是计算出该比特位在整个设备内存中的位置,j表示他指向的逻辑块号如果超过了最大的逻辑块号就报错获取逻辑块号对应的高速缓冲区块if (!(bhgetblk(dev,j))) //key panic(new_block: cannot get block); if (bh-b_count ! 1) panic(new block: count is ! 1); clear_block(bh-b_data); bh-b_uptodate 1; bh-b_dirt 1; brelse(bh); return j;最后是获取设备号和该逻辑块号对应的高速缓冲区块getblk拿到这个对应的高速缓冲区块之后会去判断是否b_count为1它不是为了处理正常情况而是为了捕捉文件系统逻辑上的严重错误Bug。在正确的内核逻辑下getblk返回的b_count必须等于 1。new_block的作用是分配一个全新的、空闲的磁盘块。它的查找依据是逻辑块位图s_zmap。在调用getblk之前函数已经通过find_first_zero在位图中找到了一个明确标记为“空闲0”的比特位并立即调用set_bit将其置为“占用1”。关键推论既然这个磁盘块号j在位图中是“空闲”的那就意味着当前文件系统中没有任何一个文件inode指向这个块号。因此理论上绝对不可能有任何进程正在通过文件系统路径访问这个块。既然没有进程通过文件系统访问它那么当getblk去哈希表里查找(dev, j)时可能出现的只有两种情况情况哈希表中是否存在b_count原本是多少getblk后的b_count结果情况 A缓存残留存在之前用过释放后还在缓存里0无人使用但数据残留0 →1正常情况 B全新分配不存在无从空闲链表拿新块置为1正常在这两种正常场景下getblk返回时b_count都是1。然后调用clear_block宏将这块高速缓冲区数据清空// 将指定地址(addr)处的一块内存清零。嵌入汇编程序宏。 256B // 输入eax 0ecx 数据块大小 BLOCK_SIZE/4edi addr。 #define clear_block(addr)清空后表明这块高速缓冲区数据更新了把b_uptodate和b_dirt都置1。然后释放掉这块内存的占用brelse释放指定i节点free_inode//// 释放指定的 i 节点。 // 复位对应 i 节点位图比特位 void free_inode(struct m_inode * inode) { struct super_block * sb; struct buffer_head * bh; if (!inode) return; if (!inode-i_dev) { memset(inode,0,sizeof(*inode)); return; } if (inode-i_count1) { printk(trying to free inode with count%d\n,inode-i_count); panic(free_inode); } if (inode-i_nlinks) panic(trying to free inode with links); if (!(sb get_super(inode-i_dev))) panic(trying to free inode on nonexistent device); if (inode-i_num 1 || inode-i_num sb-s_ninodes) panic(trying to free inode 0 or nonexistant inode); if (!(bhsb-s_imap[inode-i_num13])) panic(nonexistent imap in superblock); if (clear_bit(inode-i_num8191,bh-b_data)) printk(free_inode: bit already cleared.\n\r); bh-b_dirt 1; memset(inode,0,sizeof(*inode)); }这里的流程和前面释放指定逻辑块的流程和思路都是一样的先把i节点对应的i节点位图中的bit置0,然后情况i节点位图中的信息创建inode//// 为设备 dev 建立一个新 i 节点。返回该新 i 节点的指针。 // 在内存 i 节点表中获取一个空闲 i 节点表项并从 i 节点位图中找一个空闲 i 节点。 struct m_inode * new_inode(int dev) { struct m_inode * inode; struct super_block * sb; struct buffer_head * bh; int i,j; if (!(inodeget_empty_inode())) //key return NULL; if (!(sb get_super(dev))) panic(new_inode with unknown device); j 8192; for (i0 ; i8 ; i) if (bhsb-s_imap[i]) if ((jfind_first_zero(bh-b_data))8192) break; if (!bh || j 8192 || ji*8192 sb-s_ninodes) { iput(inode); return NULL; } if (set_bit(j,bh-b_data)) panic(new_inode: bit already set); bh-b_dirt 1; inode-i_count1; inode-i_nlinks1; inode-i_devdev; inode-i_uidcurrent-euid; inode-i_gidcurrent-egid; inode-i_dirt1; inode-i_num j i*8192; inode-i_mtime inode-i_atime inode-i_ctime CURRENT_TIME; return inode; }通过super_block找到对应的inode信息i节点位图逻辑块位图通过inode操作函数找到对应的inode的分配内存设置inode位图中对应的位1返回设置好的inode
RELATED

相关推荐

Android面试相关

Android面试相关

https://www.diycode.cc/wiki/androidinterview https://github.com/linsir6/AndroidNote https://www.jianshu.com/p/c70989bd5f29 https://blog.csdn.net/ClAndEllen/article/details/79257663 https://interview.raoyunsoft.com/category/Android

📅 2026/9/9 18:42:13
华为MetaERP Oracle EBS‑PA / Fusion Project Costing 项目模块全核算场景、数据流、会计分录汇总核心差异前置说明OracleEBS R12‑PA:使用 A

华为MetaERP Oracle EBS‑PA / Fusion Project Costing 项目模块全核算场景、数据流、会计分录汇总核心差异前置说明OracleEBS R12‑PA:使用 A

Oracle EBS‑PA / Fusion Project Costing 项目模块全核算场景、数据流、会计分录汇总核心差异前置说明OracleEBS R12‑PA:使用 AutoAccounting 自动会计生成默认科目,交给 SLA 生成子分类账分录;Fusion Project:无 AutoAccountin…

📅 2026/9/7 2:21:27
大模型时代的数据库范式转移:从SQL到自然语言交互的技术演进

大模型时代的数据库范式转移:从SQL到自然语言交互的技术演进

大模型时代的数据库范式转移:从SQL到自然语言交互的技术演进 大模型正在重新定义人与数据库的交互方式。从SQL到自然语言的范式转移,不仅仅是"换一种查询方式",而是改变了数据访问的门槛和方式。本文从技术演进、质量评估和场景边…

📅 2026/9/16 15:57:50
MORE NEWS

更多资讯

📰

Apache Pulsar 集群 bookiesanity 失败?用 TaoToken 接 Codex 对照 bookkeeper.conf 查

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

如何快速上手pytorch-tutorial:autograd计算图与梯度下降3步实战

如何快速上手pytorch-tutorial:autograd计算图与梯度下降3步实战 【免费下载链接】pytorch-tutorial PyTorch Tutorial for Deep Learning Researchers 项目地址: https://gitcode.com/gh_mirrors/py/pytorch-tutorial pytorch-tutorial 是一个面向深度学习研…

📰

半导体全制程深度解析:从硅片到芯片的完整工艺链

简介:半导体全制程是集成电路制造的核心环节,这份DOC资料面向半导体行业分析人士、工艺工程师及相关专业学生,系统梳理从晶圆处理到晶柱成长、切片后处理的完整流程。内容覆盖清洗、氧化、CVD沉积、微影、蚀刻、离子注入、光阻去除等晶圆处理…

📰

RapidOCR Docker 部署避坑指南:9003 端口上稳定跑通 OCR 服务的完整路径

RapidOCR Docker 部署避坑指南:9003 端口上稳定跑通 OCR 服务的完整路径 【免费下载链接】RapidOCR 📄 Awesome OCR multiple programing languages toolkits based on ONNX Runtime, OpenVINO, MNN, PaddlePaddle, TensorRT and PyTorch. 项目地址: h…

📰

CarSim车型等级与动力学模型选型匹配指南

1. 车型等级与动力学模型的匹配逻辑1.1 为什么车型等级决定了模型选型很多刚接触CarSim的朋友,打开软件第一件事就是找“最全”的模型,恨不得把所有自由度都勾上,觉得参数越多仿真越准。我刚开始也这么干过,结果一台A级两厢车配了…

📰

输电线路金具检测专用YOLO数据集(10000张工业级图像)

简介:本资源是面向电力AI视觉检测初学者与工程实践者的YOLO输电线路金具检测专项数据集,专为解决真实巡检场景下小目标、多类别、复杂背景的金具识别难题而构建。数据集包含10000张高质量实地采集图像,配套VOC(XML)、C…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬