Linux内核笔记七 inode节点

1、inode节点的概念

文件与磁盘的映射结构

Linux内核笔记七 inode节点_第1张图片

高速缓冲区是用户与磁盘的映射结构

2、inode节点的学习目的

了解文件与磁盘是如何构建关系
深刻理解文件系统的工作方法
Linux中对文件的操作有更深的认识与方法
软件工程中的分区域管理系统 --向上设计模型 (模块化)

3、理解一些文件系统的概念

i节点位图中的一个bit对应一个节点 1024*8=8191个i节点 因为i节点位图的0位是不用的
逻辑块位图中的一个bit对应一个逻辑块

所有的块大小都固定,盘块 磁盘块
扇区:是一个长度为512B的数据块
在不同的文件系统中 扇区和盘块对应关系是不同的
2个扇区 对应一个盘块 1024B MINIX
4个扇区 对应一个盘块 2048B

引导块没什么用但必须有

一个设备最大的文件系统为多少M?
1024 * 8 * 1k = 8M
8M * 8 = 64M

超级块的结构体

struct super_block {
	unsigned short s_ninodes;        //inode节点个数
	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;  //暂时不管
	unsigned long s_max_size;        //最大文件长度
	unsigned short s_magic;          //幻数
/* These are only in memory */
	struct buffer_head * s_imap[8];  //i节点位图在高速缓冲区块指针数组
	struct buffer_head * s_zmap[8];  //逻辑块位图在高速缓冲区块指针数组
	unsigned short s_dev;            //设备号
	struct m_inode * s_isup;         //根目录的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;
};

不管读取什么磁盘上的资源,都是先getblk(获取该资源对应的设备和块号的高速缓冲区)
然后bread的流程(确认有效数据的高速缓冲区)
最后进行区域内存的拷贝(从bh的b_date数据区域拷贝到要用的数据的内存中)

bitmap.c
操作逻辑块位图、i节点位图(销毁、创建、查找)

然后来看一看

#define clear_block(addr) \
__asm__("cld\n\t" \
	"rep\n\t" \
	"stosl" \
	::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")

嵌入式汇编宏
是非常非常高效的代码
清空给定地址的一块内存区域(块1024B)

#define set_bit(nr,addr) ({\
register int res __asm__("ax"); \
__asm__ __volatile__("btsl %2,%3\n\tsetb %%al": \
"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
res;})

将指定地址的第nr个bit位置一

#define clear_bit(nr,addr) ({\
register int res __asm__("ax"); \
__asm__ __volatile__("btrl %2,%3\n\tsetnb %%al": \
"=a" (res):"0" (0),"r" (nr),"m" (*(addr))); \
res;})

清空指定地址的第nr个bit位

#define find_first_zero(addr) ({ \
int __res; \
__asm__("cld\n" \
	"1:\tlodsl\n\t" \
	"notl %%eax\n\t" \
	"bsfl %%eax,%%edx\n\t" \
	"je 2f\n\t" \
	"addl %%edx,%%ecx\n\t" \
	"jmp 3f\n" \
	"2:\taddl $32,%%ecx\n\t" \
	"cmpl $8192,%%ecx\n\t" \
	"jl 1b\n" \
	"3:" \
	:"=c" (__res):"c" (0),"S" (addr):"ax","dx","si"); \
__res;})

着地第一个为0的地址并且返回地址的偏移量
找空闲的i节点或者逻辑块,然后返回偏移量

接下来四个函数 释放、申请逻辑块位图、inode节点位图

void free_block(int dev, int block)    //释放逻辑块位图
{                                      //设备号、块号都得知道
	struct super_block * sb;
	struct buffer_head * bh;

	if (!(sb = get_super(dev)))         //get_super
		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);
	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_dirt=0;
		bh->b_uptodate=0;
		brelse(bh);
	}
	//计算当前块是第几个数据块
	block -= sb->s_firstdatazone - 1 ;
	if (clear_bit(block&8191,sb->s_zmap[block/8192]->b_data)) {
		printk("block (%04x:%d) ",dev,block+sb->s_firstdatazone-1);
		panic("free_block: bit already cleared");
	}
	sb->s_zmap[block/8192]->b_dirt = 1;
	//对应的该块所在的逻辑块位图块的高速缓冲区
	//逻辑块位图对应的块
}

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;
	
	//在该设备的所有逻辑块位图中找到第一个为0的逻辑块位图空位
	for (i=0 ; i<8 ; i++)
		if (bh=sb->s_zmap[i])     
			if ((j=find_first_zero(bh->b_data))<8192)
				break;
	if (i>=8 || !bh || j>=8192)
		return 0;
	if (set_bit(j,bh->b_data))      //bh是找到的有空位的逻辑块对应的高速缓冲区的地址  然后data就是对应的数据的地址
		panic("new_block: bit already set");
	bh->b_dirt = 1;       //修改更新标志置为1

	//己算当前分配的逻辑块是第几个逻辑块
	j += i*8192 + sb->s_firstdatazone-1;
	if (j >= sb->s_nzones)
		return 0;
	if (!(bh=getblk(dev,j)))
		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;
}

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_count>1) {
		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 (!(bh=sb->s_imap[inode->i_num>>13]))
		panic("nonexistent imap in superblock");
	if (clear_bit(inode->i_num&8191,bh->b_data))
		printk("free_inode: bit already cleared.\n\r");
	bh->b_dirt = 1;
	memset(inode,0,sizeof(*inode));
}

struct m_inode * new_inode(int dev)
{
	struct m_inode * inode;
	struct super_block * sb;
	struct buffer_head * bh;
	int i,j;

	if (!(inode=get_empty_inode()))
		return NULL;
	if (!(sb = get_super(dev)))
		panic("new_inode with unknown device");
	j = 8192;
	for (i=0 ; i<8 ; i++)
		if (bh=sb->s_imap[i])
			if ((j=find_first_zero(bh->b_data))<8192)
				break;
	if (!bh || j >= 8192 || j+i*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_count=1;
	inode->i_nlinks=1;
	inode->i_dev=dev;
	inode->i_uid=current->euid;
	inode->i_gid=current->egid;
	inode->i_dirt=1;
	inode->i_num = j + i*8192;
	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
	return inode;
}

free_block 释放块
get_super 通过设备号找出超级块,获得里面的信息
判断块号是不是在范围内
然后读取块信息,就把高速缓冲区拿出来
没用就释放掉逻辑块对应高速缓冲区
计算当前块号,然后区清空逻辑块位图上面对应的bit
逻辑块位图对应的块设为1

new_block 新建一个块的函数
获得了一个超级块
for循环的8指的是我们的逻辑块位图
找到第一个为0的位的位数
然后修改数据 修改标志啥的
然后得到block块号
然后我们需要给这个块申请高速缓冲区 getblk
清空这个block
然后给这个高速缓冲区设置各种标志

free_inode 释放指定i节点
把i节点对应的i节点位图中的bit置0
清空i节点位图信息

new_inode 创建一个新的i节点,返回该i节点的指针
get_empty_inode

通过super_block找到对应的inode信息
通过inode的操作函数找到对应的inode分配内存区
设置inode位图中对应的位为1
返回设置好的inode结构体

给整个的inode节点的管理设置了一个数组

struct m_inode inode_table[NR_INODE]={{0,},};

操作系统中我们有一个超级块数组
mount 把需要挂载的设备文件系统的super_block读到高速缓冲区中并且放到超级块数组中

inode.c主要包括处理inode节点的函数
iget获得inode节点
iput释放inode节点
bmap对文件进行磁盘映射

wait_on_inode

static inline void wait_on_inode(struct m_inode * inode)
{
	cli();
	while (inode->i_lock)
		sleep_on(&inode->i_wait);
	sti();
}

因为多线程,这些资源都是可以被共享的,就会有同步的问题,就会有解锁非解锁的问题。

lock_inode unlock_inode

static inline void lock_inode(struct m_inode * inode)
{
	cli();
	while (inode->i_lock)
		sleep_on(&inode->i_wait);
	inode->i_lock=1;
	sti();
}
//如果锁了就睡眠等待,等待就是等待醒来,等待解锁
//没锁就锁了

static inline void unlock_inode(struct m_inode * inode)
{
	inode->i_lock=0;
	wake_up(&inode->i_wait);
}

释放所有的i节点 invalidate_inodes

void invalidate_inodes(int dev)
{
	int i;
	struct m_inode * inode;

	inode = 0+inode_table;
	for(i=0 ; i<NR_INODE ; i++,inode++) {
		wait_on_inode(inode);
		if (inode->i_dev == dev) {
			if (inode->i_count)
				printk("inode in use on removed disk\n\r");
			inode->i_dev = inode->i_dirt = 0;
		}
	}
}

同步i节点

void sync_inodes(void)
{
	int i;
	struct m_inode * inode;

	inode = 0+inode_table;
	for(i=0 ; i<NR_INODE ; i++,inode++) {
		wait_on_inode(inode);
		if (inode->i_dirt && !inode->i_pipe)
			write_inode(inode);
	}
}

inode->i_pipe
证明文件是一个pipe管道
pipe文件会

write_inode

static void write_inode(struct m_inode * inode)
{
	struct super_block * sb;
	struct buffer_head * bh;
	int block;

	lock_inode(inode);                                      //锁定
	if (!inode->i_dirt || !inode->i_dev) {
		unlock_inode(inode);
		return;
	}
	if (!(sb=get_super(inode->i_dev)))
		panic("trying to write inode without device");

	//计算当前inode节点的逻辑块号
	block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
		(inode->i_num-1)/INODES_PER_BLOCK;
	if (!(bh=bread(inode->i_dev,block)))
		panic("unable to read i-node block");
	((struct d_inode *)bh->b_data)
		[(inode->i_num-1)%INODES_PER_BLOCK] =
			*(struct d_inode *)inode;    //一段诡异的赋值方式
	bh->b_dirt=1;
	inode->i_dirt=0;
	brelse(bh);
	unlock_inode(inode);
}

从磁盘周哥读写数据信息 inode等的流程
1、找到指定的dev
2、通过dev找到设备的super block
2、通过sb中的信息己算要读的块号
4、掉哦用bread将其读取或写入到高速缓冲区
5、读:将高速缓冲物的b_data读到你要读的内存地址 释放高速缓冲区
写:将要写入的数据写入高速缓冲区的b_data,并设置dirt修改标志位 等待系统的sys_syn进行写盘 释放高速缓冲区

struct m_inode * get_empty_inode(void)
{
	struct m_inode * inode;
	static struct m_inode * last_inode = inode_table;
	int i;

	do {
		inode = NULL;
		for (i = NR_INODE; i ; i--) {
			if (++last_inode >= inode_table + NR_INODE)
				last_inode = inode_table;
			if (!last_inode->i_count) {
				inode = last_inode;
				if (!inode->i_dirt && !inode->i_lock)
					break;
			}
		}
		if (!inode) {
			for (i=0 ; i<NR_INODE ; i++)
				printk("%04x: %6d\t",inode_table[i].i_dev,
					inode_table[i].i_num);
			panic("No free inodes in mem");
		}
		wait_on_inode(inode);
		while (inode->i_dirt) {
			write_inode(inode);
			wait_on_inode(inode);
		}
	} while (inode->i_count);
	memset(inode,0,sizeof(*inode));
	inode->i_count = 1;
	return inode;
}

Linux内核笔记七 inode节点_第2张图片
inode节点有一部分写回磁盘,有一部分就在内存中就行了。

read_inode

static void read_inode(struct m_inode * inode)  //参数是一块内存
{
	struct super_block * sb;
	struct buffer_head * bh;
	int block;

	lock_inode(inode);
	if (!(sb=get_super(inode->i_dev)))                //还是要拿到超级块才能怎么怎么滴
		panic("trying to read inode without dev");
	block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
		(inode->i_num-1)/INODES_PER_BLOCK;
	if (!(bh=bread(inode->i_dev,block)))
		panic("unable to read i-node block");
	*(struct d_inode *)inode =
		((struct d_inode *)bh->b_data)
			[(inode->i_num-1)%INODES_PER_BLOCK];
	brelse(bh);
	unlock_inode(inode);
}

read inode读出来的inode节点信息是不包含内存信息的。

bmap函数 块映射

static int _bmap(struct m_inode * inode,int block,int create)
{
	struct buffer_head * bh;
	int i;

	if (block<0)
		panic("_bmap: block<0");
	if (block >= 7+512+512*512)
		panic("_bmap: block>big");
	if (block<7) {
		if (create && !inode->i_zone[block])
			if (inode->i_zone[block]=new_block(inode->i_dev)) {
				inode->i_ctime=CURRENT_TIME;
				inode->i_dirt=1;
			}
		return inode->i_zone[block];
	}
	//文件占用的号大于7,就要用到一次简介块号
	block -= 7;
	if (block<512) {
		if (create && !inode->i_zone[7])
			if (inode->i_zone[7]=new_block(inode->i_dev)) {
				inode->i_dirt=1;
				inode->i_ctime=CURRENT_TIME;
			}
		if (!inode->i_zone[7])
			return 0;
		if (!(bh = bread(inode->i_dev,inode->i_zone[7])))
			return 0;
		i = ((unsigned short *) (bh->b_data))[block];
		if (create && !i)
			if (i=new_block(inode->i_dev)) {
				((unsigned short *) (bh->b_data))[block]=i;
				bh->b_dirt=1;
			}
		brelse(bh);
		return i;
	}
	block -= 512;
	if (create && !inode->i_zone[8])
		if (inode->i_zone[8]=new_block(inode->i_dev)) {
			inode->i_dirt=1;
			inode->i_ctime=CURRENT_TIME;
		}
	if (!inode->i_zone[8])
		return 0;
	if (!(bh=bread(inode->i_dev,inode->i_zone[8])))
		return 0;
	i = ((unsigned short *)bh->b_data)[block>>9];
	if (create && !i)
		if (i=new_block(inode->i_dev)) {
			((unsigned short *) (bh->b_data))[block>>9]=i;
			bh->b_dirt=1;
		}
	brelse(bh);
	if (!i)
		return 0;
	if (!(bh=bread(inode->i_dev,i)))
		return 0;
	i = ((unsigned short *)bh->b_data)[block&511];
	if (create && !i)
		if (i=new_block(inode->i_dev)) {
			((unsigned short *) (bh->b_data))[block&511]=i;
			bh->b_dirt=1;
		}
	brelse(bh);
	return i;
}

首先看一下这个函数是干嘛的
进行inode节点的磁盘块映射的

在对m_inode结构体的i_zone[9],磁盘映射变量进行赋值。
如果已有磁盘信息进行赋值即可
如果没有磁盘信息则分配新的逻辑块,然后进行赋值

Linux内核笔记七 inode节点_第3张图片所以一个文件最大多大也就很明白了

iput 释放一个inode节点
iget 获得一个inode节点

get_pipe_inode

struct m_inode * get_pipe_inode(void)
{
	struct m_inode * inode;

	if (!(inode = get_empty_inode()))
		return NULL;
	//为当前inode节点分配一个内存页做为pipe
	if (!(inode->i_size=get_free_page())) {
		inode->i_count = 0;
		return NULL;
	}
	//又读又写  count就是操作数
	inode->i_count = 2;	/* sum of readers/writers */
	PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
	inode->i_pipe = 1;
	return inode;
}

icount++就是这个文件在用,我们文件关闭不了问题就在这里 count不为0.

super.c

1、对设备的超级块进行操作(获取 读取 释放)
get_super put_super read_super
2、因为超级块是设备的映射(代码中的类),超级块的操作关系到设备的文件系统的操作

文件系统的加载、卸载 mount umoint
sys_mount sys_umount

3、根文件系统的加载(/) 调用了一个mount_root函数 就在super.c里面

set_bit(bitnr,addr) ({ \
register int __res __asm__("ax"); \
__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \
__res; })

struct super_block super_block[NR_SUPER];
所有超级块的数组

static void lock_super(struct super_block * sb)
{
	cli();
	while (sb->s_lock)
		sleep_on(&(sb->s_wait));
	sb->s_lock = 1;
	sti();
}

static void free_super(struct super_block * sb)
{
	cli();
	sb->s_lock = 0;
	wake_up(&(sb->s_wait));
	sti();
}

static void wait_on_super(struct super_block * sb)
{
	cli();
	while (sb->s_lock)
		sleep_on(&(sb->s_wait));
	sti();
}

多线程

get_super 获取指定dev的超级块
从全局的已挂载的所有文件系统设备中找到对应设备的超级块

struct super_block * get_super(int dev)
{
	struct super_block * s;

	if (!dev)
		return NULL;
	s = 0+super_block;
	while (s < NR_SUPER+super_block)
		if (s->s_dev == dev) {
			wait_on_super(s);
			if (s->s_dev == dev)
				return s;
			s = 0+super_block;
		} else
			s++;
	return NULL;
}

put_super
1、锁定块并清控设备号
2、清空其i节点位图和逻辑块位图所占用的高速缓冲区
3、解锁该块,并唤醒等待该资源(系统super_bolck数组的空槽)的进程队列

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(i=0;i<I_MAP_SLOTS;i++)
		brelse(sb->s_imap[i]);
	for(i=0;i<Z_MAP_SLOTS;i++)
		brelse(sb->s_zmap[i]);
	free_super(sb);
	return;
}

read_super
跟设备去做交互
读取指定设备的文件系统

static struct super_block * read_super(int dev)
{
	struct super_block * s;
	struct buffer_head * bh;
	int i,block;

	if (!dev)
		return NULL;
	check_disk_change(dev);
	if (s = get_super(dev))
		return s;
	//找对应的super_block数组中的空槽
	for (s = 0+super_block ;; s++) {
		if (s >= NR_SUPER+super_block)
			return NULL;
		if (!s->s_dev)
			break;
	}
	//设置超级块在内存中的一些动态配置项
	//超级块有一些东西只在内存中出现 有些事在物理设备中被写死的
	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))) {
		s->s_dev=0;
		free_super(s);
		return NULL;
	}
	//设置超级块中固有的超级块配置参数
	*((struct d_super_block *) s) =
		*((struct d_super_block *) bh->b_data);
	brelse(bh);
	//检测文件系统的ID号,如果不支持该文件系统则释放并返回
	if (s->s_magic != SUPER_MAGIC) {
		s->s_dev = 0;
		free_super(s);
		return NULL;
	}
	for (i=0;i<I_MAP_SLOTS;i++)
		s->s_imap[i] = NULL;
	for (i=0;i<Z_MAP_SLOTS;i++)
		s->s_zmap[i] = NULL;
	block=2;                 //根据取出的超级块信息分配该设备文件设备的i节点位图
	for (i=0 ; i < s->s_imap_blocks ; i++)
		if (s->s_imap[i]=bread(dev,block))
			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) {
		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;
	}
	s->s_imap[0]->b_data[0] |= 1;
	s->s_zmap[0]->b_data[0] |= 1;
	//不让用第0个i节点跟逻辑块
	free_super(s);
	return s;
}

卸载指定设备的文件系统

int sys_umount(char * dev_name)
{
	struct m_inode * inode;
	struct super_block * sb;
	int dev;

	if (!(inode=namei(dev_name)))
		return -ENOENT;
	dev = inode->i_zone[0];
	if (!S_ISBLK(inode->i_mode)) {
		iput(inode);
		return -ENOTBLK;
	}
	iput(inode);
	if (dev==ROOT_DEV)
		return -EBUSY;
	if (!(sb=get_super(dev)) || !(sb->s_imount))
		return -ENOENT;
	//s_imount  该文件系统的挂接节点   super_block中
	//i_mount  挂接标志 是否有文件系统在该节点挂接   m_inode中
	//如果没有被挂接或者读取失败返回错误
	if (!sb->s_imount->i_mount)
		printk("Mounted inode has i_mount=0\n");
	//如果该文件系统的挂接节点的挂接标志位空,返回错误
	for (inode=inode_table+0 ; inode<inode_table+NR_INODE ; inode++)
		if (inode->i_dev==dev && inode->i_count)
				return -EBUSY;
	//检索系统的i节点表,如果有进程正在使用该设备上的文件,则返回错误
	//就是umount的时候报错就是仅为有东西在使用它
	sb->s_imount->i_mount=0;
	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

void mount_root(void)
{
	int i,free;
	struct super_block * p;
	struct m_inode * mi;

	if (32 != sizeof (struct d_inode))
		panic("bad i-node size");
	//文件表数组的初始化
	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();
	}
	//验证根文件系统是否在软盘上
	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");
	if (!(mi=iget(ROOT_DEV,ROOT_INO)))
		panic("Unable to read root i-node");
	//给根文件系统的inode节点引用数加3  因为被三个地方用到了
	mi->i_count += 3 ;	/* NOTE! it is logically used 4 times, not 1 */
	p->s_isup = p->s_imount = mi;
	current->pwd = mi;
	current->root = mi;
	free=0;
	i=p->s_nzones;
	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);
	free=0;
	i=p->s_ninodes+1;
	while (-- i >= 0)
		if (!set_bit(i&8191,p->s_imap[i>>13]->b_data))
			free++;
	printk("%d/%d free inodes\n\r",free,p->s_ninodes);
}

sys_set_up调用的根文件的挂载 这是个0号系统调用

你可能感兴趣的:(CTF,linux)