inode和逻辑块,目录的结构,挂载的实现 源码级分析linux内核的文件系统的结构

文章详细描述了在文件系统中如何使用位图进行逻辑块和i节点的管理,包括创建、释放、查找和更新。new_block和free_block分别用于分配和释放逻辑块,new_inode和free_inode则对应i节点的分配和回收。此外,还涉及到了超级块的使用、挂载过程以及文件长度截断(truncate)的功能。
摘要由CSDN通过智能技术生成

在这里插入图片描述

bitmap.c 位图相关

封装了set_bit clear_bit find_first_zero clear_block等操作位图的宏

对应i节点位图和逻辑块位图有对应的四个函数 free_inode, new_inode,free_block, new_block

new_block 创建逻辑块

通过super_block找到逻辑块位图,给逻辑块位图的第一个空闲位(find_first_zero) 置1 (set_bit),获得逻辑块号后,通过getblk(dev,j)来申请一个缓冲块指向设备中的逻辑块,清空缓冲块,从而让对应的设备上的逻辑块清空。bh->b_dirt = 1出现了两次,一次是修改逻辑块位图要落盘,一次是new逻辑块要落盘。

free_block 释放逻辑块

通过super_block找到逻辑块位图,给逻辑块位图的对应的占用位置0 (clear_bit),同时使得hash_table中的该块对应的缓冲块(如果有的话)失效bh->b_uptodate=0

  • 有了缓冲区的存在创建和释放逻辑块的速度非常快,不涉及到同步IO,后面会在某个时刻将buffer同步到设备上的逻辑块。创建和释放也只是操作位图

new_inode 创建i节点

通过super_block找到i节点位图,给i节点位图的第一个空闲位(find_first_zero) 置1 (set_bit),获得i节点号后,通过get_empty_inode取得inode_table中空闲i节点,设置i_count,i_dev,i_num,即说明dev设备的num号i节点被使用(count)。i_dirt,b_dirt都置1,修改的i节点位图要落盘,新的i节点要落盘

free_inode 释放i节点

通过super_block找到i节点位图,给i节点位图的对应的占用位置0 (clear_bit),同时使得inode_table中的该i节点失效memset(inode,0,sizeof(*inode))

inode.c i节点相关

read_inode 读i节点 static

从设备上读取含有指定i节点信息的i节点(d_inode)盘块,然后复制到指定的i节点(m_inode)结构中。

write_inode 写i节点 static

把参数指定的i节点(m_inode)写入缓冲区相应的缓冲块(d_inode)中,bh->b_dirt=1,待缓冲区刷新时会写入盘中。i节点内容已经与缓冲区中的一致,因此修改标志置零inode->i_dirt=0

iget 取一个i节点

首先在位于高速缓冲区中的i节点表中搜寻,若找到指定节点号的i节点则在经过一些判断处理后返回该i节点指针。否则read_inode从设备dev上读取指定i节点号的i节点信息放入i节点表中,并返回该i节点指针。

iput 放回一个i节点

该函数主要用于把i节点引用计数值递减1,并且若是管道i节点,则唤醒等待的进程。若是块设备文件i节点则刷新设备。并且若i节点的链接计数为0,则释放该i节点占用的所有磁盘逻辑块,并释放该i节点。

get_empty_inode

从i节点表(inode table)中获取一个空闲i节点项,寻找引用计数count为0的i节点,并将其写盘后清零,返回其指针。引用计数被置1。

bmap/create_block (f, x) = y

文件数据块映射到盘块的处理操作。(block位图处理函数,bmap: block map) 对于文件f中的第x个数据块,对应的是磁盘上的逻辑块y,返回y,后续根据(dev, y)去访问文件。create_block即为文件f(也可能是目录)的第x个数据块分配一个逻辑块y
在这里插入图片描述

namei.c 目录/软硬链接

add_entry/find_entry static

在这里插入图片描述

添加/查找dir目录下的name目录项,通过res_dir返回目录项,以及目录项所在缓冲区的buffer_head,因为之后肯定涉及到目录项的修改,buffer_head->dirt =1

在文件系统的角度看待软硬连接
在文件系统中,软链接(符号链接)和硬链接是基于文件的i节点来实现的,但它们的工作原理和行为有显著差异。通过理解i节点(inode)和逻辑块(data block)的概念,可以更好地把握软链接和硬链接的特性和区别。
硬链接
定义:硬链接是一个指向文件系统中某个i节点的直接链接。当为一个文件创建硬链接时,实际上是在创建一个新的目录项,该目录项指向与原文件相同的i节点。
i节点使用:硬链接不会创建新的i节点,而是增加了现有i节点的链接计数(link count)。这意味着原始文件和硬链接共享相同的i节点及其数据块。
逻辑块:因为硬链接与原始文件共享相同的i节点,它们也共享相同的数据块。无论通过原始文件还是任何硬链接修改文件内容,变更都会反映在所有链接中。
删除和持久性:只要i节点的链接计数不为零,文件数据就保持在磁盘上。即使删除了原始文件的目录条目,只要还存在至少一个硬链接,文件内容就不会被删除。

软链接(符号链接)
定义:软链接是一个特殊类型的文件,它包含了另一个文件的路径名的文本记录。软链接有自己的i节点和数据块。
i节点使用:软链接创建一个全新的i节点,其数据块存储的是目标文件或目录的路径名。
逻辑块:软链接的数据块不直接链接到目标文件的数据块,而是保存目标的路径。因此,软链接是对目标路径的间接引用。
删除和持久性:软链接与其目标的生命周期是独立的。即使删除了目标文件,软链接依然存在(尽管变成了“悬空”的链接,因为它指向一个不存在的路径)。

总结
硬链接:像是文件的另一个真实的访问入口,与原始文件无差别地共享同一个i节点和数据块。
软链接:相当于是对另一个文件的快捷方式或者引用,有自己的i节点和数据块,但仅存储了目标文件的路径信息。
这种设计允许文件系统灵活地处理文件引用和共享,同时也提供了对不同使用场景的支持。硬链接常用于文件的不透明处理,比如备份和不需要路径信息的数据共享,而软链接则适合创建跨文件系统的链接,以及需要明确表示文件来源的场景。

static struct buffer_head * add_entry(struct m_inode * dir,
	const char * name, int namelen, struct dir_entry ** res_dir)
static struct buffer_head * find_entry(struct m_inode ** dir,
	const char * name, int namelen, struct dir_entry ** res_dir)

get_dir static

// 搜寻指定路径名的目录(或文件名)的i节点。
// 参数:pathname-路径名。
// 返回:目录或文件的i节点指针。失败时返回NULL。
// usr/src/linux  : src						  linux不是最顶层目录,因为后面没有/
// usr/src/linux/ : linux
// usr/src/linux/1.txt : linux                可知道最顶层目录是  [xxx]/的形式
static struct m_inode * get_dir(const char * pathname)

dir_namei static

/*
 *	dir_namei函数返回指定目录名的i节点指针,以及在最顶层目录的名称。
 */
// 参数:pathname-目录路径名:namelen-路径名长度:name-返回的最顶层目录名。
// 返回:指定目录名最顶层目录的i节点指针 | 最顶层目录名称及长度。      
// pathname: /home/zyx/video  则 namelen:5 name:video          
// 出错时返回NULL。注意!! 这里"最顶层目录"是指路径名中最靠近末端的目录。
// usr/src/linux  : 		返回src			name:linux		len:5					  
// usr/src/linux/ :			返回linux		name:""			len:0
// usr/src/linux/1.txt : 	返回linux       name:1.txt   	len:4
static struct m_inode * dir_namei(const char * pathname,
	int * namelen, const char ** name)

namei

// 取指定路径名的i节点 
// pathname:路径名
// 返回对应的i节点
// 即:
// usr/src/ 				src节点				dir_namei后返回src
// usr/src/linux			src下搜linux目录	iget后返回linux
// usr/src/linux/1.txt: 	linux下搜1.txt文件	iget后返回1.txt
struct m_inode * namei(const char * pathname)

*open_namei

根据路径名返回对应的i节点。

// namei
// 参数filename是文件名,flag是打开文件标志,它可取值:O_RDONLY(只读)、O_WRONLY
// (只写)或O_RDWR(读写),以及O_CREAT(创建)、O_EXCL(被创建文件必须不存在)、
// O_APPEND(在文件尾添加数据)等其他一些标志的组合。如果本调用创建了一个新文件,则
// mode就用于指定文件的许可属性。这些属性有S_IRWXU(文件宿主具有读、写和执行权限)、
// S_IRUSR(用户具有读文件权限)、S_IRWXG(组成员具有读、写和执行权限)等等。对于新
// 创建的文件,这些属性只应用于将来对文件的访问,创建了只读文件的打开调用也将返回一
// 个可读写的文件句柄。参见相关文件sys/stat.h、fcntl.h。
// 返回:成功返回0,否则返回出错码:res_inode 返回对应文件路径名的i节点指针。
int open_namei(const char * pathname, int flag, int mode,
	struct m_inode ** res_inode)

目录相关的系统调用 mkdir rmdir link unlink

super.c 挂载是怎么实现的

get_super

取指定设备的超级块,在超级块表(数组)中搜索指定设备dev的超级块结构信息。若找到则返回超级块的指针,否则返回空指针。

read_super

读取超级块信息,如果内存中的超级块数组没有该块,bh = bread(dev,1)直接读超级块到超级块数组中

*((struct d_super_block *) s) = *((struct d_super_block *) bh->b_data);检查i节点位图和逻辑块位图中的block数量 和 2+s->s_imap_blocks+s->s_zmap_blocks记录块数进行对比。

mount 挂载

mount相关的函数有三个,分别是 sys_umount sys_mount mount_root。把一个 mount -o ro /dev/hda1 /mnt 挂载会影响super_block的s_imount字段,以及挂在对应i节点的i_mount字段,后续在iget取节点时,如果是个挂在节点,就会返回对应的挂载的设备和i节点号

if (inode->i_mount)
    dev = super_block[i].s_dev;
	nr = ROOT_INO;

在这里插入图片描述

truncate.c

free_ind static

释放一次间接块

free_dind static

释放二次间接块

truncate

将节点对应的文件长度截为0,并释放占用的设备空间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值