文件系统(一)--super.c bitmap.c inode.c 源码分析

本文深入剖析Linux文件系统,详细解读super.c的超级块管理,bitmap.c的数据区位图管理和inode.c的索引节点操作。通过源码解析,理解文件系统的底层运作机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. super.c

  1 /*
  2  *  linux/fs/super.c
  3  *
  4  *  (C) 1991  Linus Torvalds
  5  */
  6
  7 /*
  8  * super.c contains code to handle the super-block tables.
  9  */
 10 #include <linux/config.h>
 11 #include <linux/sched.h>
 12 #include <linux/kernel.h>
 13 #include <asm/system.h>
 14
 15 #include <errno.h>
 16 #include <sys/stat.h>

 18 int sync_dev(int dev);
 19 void wait_for_keypress(void);
 20
 21 /* set_bit uses setb, as gas doesn't recognize setc */
 22 #define set_bit(bitnr,addr) ({ \
 23 register int __res __asm__("ax"); \
 24 __asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
 25 __res; })
bt 功能:按照源操作指定的位号,测试目的操作数,当指令执行时,被测试位的状态被复制到进位标志CF
在asm语句中对硬件寄存器的引用必须用“%%
如果CF为1,setb就会置位后面的寄存器。因此这里就是测试addr开始内存处第bitnr位是1还是0

 27 struct super_block super_block[NR_SUPER];

 28 /* this is initialized in init/main.c */
 29 int ROOT_DEV = 0;
init/main.c:60:#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC)
init/main.c:110:     ROOT_DEV = ORIG_ROOT_DEV;
这里的ORIG_ROOT_DEV是在init/main中通过询问BIOS获得并保存的。

 31 static void lock_super(struct super_block * sb)
 32 {
 33     cli();
 34     while (sb->s_lock)
 35         sleep_on(&(sb->s_wait));
 36     sb->s_lock = 1;
 37     sti();
 38 }
如果其他任务已经锁定了,就等待它释放,然后自己锁定。

 40 static void free_super(struct super_block * sb)
 41 {
 42     cli();
 43     sb->s_lock = 0;
 44     wake_up(&(sb->s_wait));
 45     sti();
 46 }
这里其实是解锁操作,叫unlock更好一些

 48 static void wait_on_super(struct super_block * sb)
 49 {
 50     cli();
 51     while (sb->s_lock)
 52         sleep_on(&(sb->s_wait));
 53     sti();
 54 }

 56 struct super_block * get_super(int dev)
 57 {
 58     struct super_block * s;
 59
 60     if (!dev)
 61         return NULL;
 62     s = 0+super_block;
 63     while (s < NR_SUPER+super_block)
 64         if (s->s_dev == dev) {
 65             wait_on_super(s);
 66             if (s->s_dev == dev)
 67                 return s;
 68             s = 0+super_block;     //重新从头开始搜索
 69         } else
 70             s++;
 71     return NULL;
 72 }
从这里可以看到super_block是保存在super_block数组中的。另外,当找到对应的super_block之后还要等待它被释放(65行),释放之后还要再进行一次判断(66行),因为中间super_block可能又会被其他任务锁定。

 74 void put_super(int dev)     //释放超级块
 75 {
 76     struct super_block * sb;
 77     struct m_inode * inode;
 78     int i;
 79
 80     if (dev == ROOT_DEV) {
 81         printk("root diskette changed: prepare for armageddon\n\r");
 82         return;
         这里的ROOT_DEV指的是根文件系统所在的分区
 83     }
 84     if (!(sb = get_super(dev)))
 85         return;
 86     if (sb->s_imount) {
 87         printk("Mounted disk changed - tssk, tssk\n\r");
 88         return;
 89     }
 90     lock_super(sb);
 91     sb->s_dev = 0;
 92     for(i=0;i<I_MAP_SLOTS;i++)
 93         brelse(sb->s_imap[i]);
 94     for(i=0;i<Z_MAP_SLOTS;i++)
 95         brelse(sb->s_zmap[i]);
 96     free_super(sb);
 97     return;
 98 }



100 static struct super_block * read_super(int dev)
101 {
102     struct super_block * s;
103     struct buffer_head * bh;
104     int i,block;

106     if (!dev)
107         return NULL;
108     check_disk_change(dev);
109     if (s = get_super(dev))
110         return s;
获取到直接返回
111     for (s = 0+super_block; ; s++) {
112         if (s >= NR_SUPER+super_block)
113             return NULL;
114         if (!s->s_dev)
115             break;
116     }
从super_block[]中找到一个s_dev为0的super_block

117     s->s_dev = dev;
118     s->s_isup = NULL;
119     s->s_imount = NULL;
120     s->s_time = 0;
121     s->s_rd_only = 0;
122     s->s_dirt = 0;
初始化它的属性
123     lock_super(s); //锁定

124     if (!(bh = bread(dev,1))) { //读取该设备第一个块号,也就是超级块
125         s->s_dev=0;              //读取失败
126         free_super(s);
127         return NULL;
128     }
到这里说明成功读取了超级块
129     *((struct d_super_block *) s) =
130         *((struct d_super_block *) bh->b_data);
用它来为s赋值
131     brelse(bh);

132     if (s->s_magic != SUPER_MAGIC) {     //检查魔数
133         s->s_dev = 0;
134         free_super(s);
135         return NULL;
136     }

137     for (i=0;i<I_MAP_SLOTS;i++)
138         s->s_imap[i] = NULL;
139     for (i=0;i<Z_MAP_SLOTS;i++)
140         s->s_zmap[i] = NULL;
初始化imap和zmap
141     block=2;
142     for (i=0 ; i < s->s_imap_blocks ; i++)
143         if (s->s_imap[i]=bread(dev,block)) //读取相应的inode bitmap块,来为s_imap赋值
144             block++;
145         else
146             break;
147     for (i=0 ; i < s->s_zmap_blocks ; i++)
148         if (s->s_zmap[i]=bread(dev,block))
149             block++;
150         else
151             break;
读取相应的逻辑块bitmap来为s_zmap赋值

152     if (block != 2+s->s_imap_blocks+s->s_zmap_blocks) {
正常情况下这里应该相等,否则就释放所有的buffer_head
153         for(i=0;i<I_MAP_SLOTS;i++)
154             brelse(s->s_imap[i]);
155         for(i=0;i<Z_MAP_SLOTS;i++)
156             brelse(s->s_zmap[i]);
157         s->s_dev=0;
158         free_super(s);
159         return NULL;
160     }

161     s->s_imap[0]->b_data[0] |= 1;
162     s->s_zmap[0]->b_data[0] |= 1;
s_imap和s_zmap是buffer_head类型的,它的b_data对应着磁盘数据映射。这里把第0个位都置为1.因为第0个inode节点和逻辑块是不能被分配的。
163     free_super(s);     //解锁超级块
164     return s;
165 }
从这里可以看出,super_block数组可以看做系统中super_block的缓存。

167 int sys_umount(char * dev_name)
168 {
169     struct m_inode * inode;
170     struct super_block * sb;
171     int dev;
173     if (!(inode=namei(dev_name)))
174         return -ENOENT;
根据设备名找到对应的inode

175     dev = inode->i_zone[0];
取得设备号(设备文件在其i_zone[0]中存放设备号

176     if (!S_ISBLK(inode->i_mode)) {
177         iput(inode);         //如果不是块设备,放回inode即可
178         return -ENOTBLK;
179     }

180     iput(inode);
是块设备

181     if (dev==ROOT_DEV)
182         return -EBUSY;
如果是根设备,返回-EBUSY

183     if (!(sb=get_super(dev)) || !(sb->s_imount))
184         return -ENOENT;
没有找到超级块或者该文件系统没有被安装过,返回

185     if (!sb->s_imount->i_mount)
186         printk("Mounted inode has i_mount=0\n");
如果超级块所指明的被安装到的inode节点的i_mount标志没有被置位,则打印信息。

187     for (inode=
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值