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
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,并释放占用的设备空间