【Linux内核】---- 03 安装文件系统



3.1 从硬盘上获取hello.txt 文件的 i 节点

在文件系统中,每个文件都对应一个唯一的 i 节点。

目录文件和普通文件是有区别的,它们存储的内容不一样。目录文件存储着若干个目录项,每个目录项由两部分组成:
一个是文件名,表明该项目所对应的文件名,它可以是对应着普通文件,也可以对应着目录。
另一个是 i 节点号,表明该目录项所对应的文件在 i 节点表中的项号,通过这个i节点表中找到所对应的文件的 i 节点。

整个解析过程如下
根目录文件 i 节点 ----> 找到根目录文件 ----> mnt目录文件 i 节点 ----> 对应硬盘上超级块
----> 磁盘根目录文件 i 节点----> 找到硬盘根目录文件 ----> user目录文件 i 节点 —> 找到user 目录文件
----> hello.txt文件 i 节点 —> 找到hello.c 文件。
在这里插入图片描述


3.1.1 准备查找枝梢 i 节点 ---- user目录文件的 i 节点

hello.txt 的目录为 /mnt/user/hello.txt
通过路径解析出 i 节点,这是由open_namei函数完成的,所以sys_open 函数接下来要调用open_namei

// fs/open.c
int sys_open(const char * filename, int flag, int mode){
	if( (i = open_namei(filename, flag, mode, &inode) ) < 0 )
	...
}

进入 open_namei 函数后,调用 dir_namei 函数,通过解析路径名得到枝梢 i 节点,对于 “/mnt/user/hello.txt” 这个路径名而言,枝梢i 节点就是 user这个目录文件的 i 节点,执行代码如下:

// fs/namei.c
int open_namei(const char * pathname, int flag , int mode, struct m_inode ** res_inode){
	if(!(dir = dir_namei(pathname, &namelen, &basename )))
		...
}

进入 dir_namei 函数 后,调用 get_dir 函数,同时将路径名也传递下去,开始实质性的 i 节点解析工作。

// fs/namei.c
static struct m_inode * dir_namei(const char * pathname, int * namelen, const char ** name)
{
	if(!(idr = get_dir(pathname)))
		...
}

3.1.2 确定查找操作起点

进入 get_dir 函数后,开始对路径名进行分析,

// fs/namei.c
static struct m_inode * get_dir(const char * pathname ){
	if((c = get_fs_byte(pathname)) == '/' ){
		inode = current->root;
		pathname++;
	}
}

3.1.3 获得名为mnt的目录项

  1. 先解析出 mnt 这个字符串的长度。
// 代码路径: fs/namei.c
static struct m_inode * get_dir(const char * pathname){
	for(namelen = 0; (c = get_fs_byte(pathname++)) && (c!='/'); namelen++)
}
  1. 再以mnt这个名字为参照,在根目录文件中找到名字为mnt的目录项,
// 代码路径: fs/namei.c
static struct m_inode * get_dir(const char * pathname){
	if(!(bh=find_entry(&inode, thisname, namelen, &de)))
}

thisname 标识了mnt字符串的起始位置,namelen标识了该字符串的长度,这样就能锁写mnt这个 字符串。
进入find_entry函数后,开始将根目录文件读取出来,从中找到 名字为mnt的目录项,读取并分析的过程 是这样的:
先确定这个目录文件的大小,因为确定了大小就可以确定目录文件包含多少条目录项,方法是通过根 i 节点中表示根目录文件大小的 i_size 字段除以每个目录占用的字节数。

// fs/namei.c
static struct buffer_head * find_entry(struct m_inode ** dir, const char * name, int namelen, struct dir_entry ** res_dir){
	entries = (*dir)->i_size / (sizeof( struct dir_entry) );
}
  1. 从目录文件的第一个数据块开始读取数据,将数据块读入到 缓冲块,并调用match(namelen, name, de) 函数分析这些数据中有没有mnt的目录项。
// fs/namei.c
static struct buffer_head * find_entry(struct m_inode ** dir , const char *name, int namelen, struct dir_entry ** res_dir){
	if(! (bh = bread((*dir)->i_dev, block)) )
	de = (struct dir_entry *)bh->b_data;

	while(i < entries){
		if((char *)de >= BLOCK_SIZE + bh->b_data){
			breles(bh);
			bh = NULL;
			if(! (block = bmap(*dir, i/DIR_ENTRIES_PER_BLOCK)) || !(bh = bread((*dir)->i_dev, block))){
				i +=  DIR_ENTRIES_PER_BLOCK;
				continue;
			}
			de = (struct dir_entry *) bh->b_data;
		}
		if(match(namelen, name, de)){
			*res_dir = de;
			return bh;
		}
		de++;
		i++;
	}
}

  1. 最终找到 mnt 这个目录项,值得注意的是,根目录文件在虚拟盘上,所以此时调用bread 函数从设备上读取数据并不会产生中断,之后,find_entry 函数就返回了,

发布了329 篇原创文章 · 获赞 66 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/Ciellee/article/details/104837103
今日推荐