当前位置: 首页 > 工具软件 > simplefs > 使用案例 >

SimpleFs文件系统初步四(Inode的创建过程)

朱高超
2023-12-01

我们在文件系统下面创建一个文件或者目录,毫无疑问,文件系统必须先去检查这个文件或者文件夹是否存在吧,随后如果文件系统检查到文件或者文件夹不存在才会为你新建,否则返回出错。

1.文件或者文件夹的检查过程
struct dentry *simplefs_lookup(struct inode *parent_inode,
			       struct dentry *child_dentry, unsigned int flags)
{
	//从根节点的Inode获取在Mount的时候读取到的磁盘中Sb的信息
	struct simplefs_inode *parent = SIMPLEFS_INODE(parent_inode);
	struct super_block *sb = parent_inode->i_sb;
	struct buffer_head *bh;
	struct simplefs_dir_record *record;
	int i;
	//因为根节点中会包含Data Block的索引,通过这个索引获取根节点这个dentry中存放的内容
	/*      根节点(Dentry)的内容如下:
	 *      文件名:  "vanakkam"     
	 *      Inode号:  2
	 */
	bh = sb_bread(sb, parent->data_block_number);
	BUG_ON(!bh);

	//指向父目录Inode中内容头部
	record = (struct simplefs_dir_record *)bh->b_data;
	//先确定该目录下面有多少个Inode(这里是包含文件和目录的)
	for (i = 0; i < parent->dir_children_count; i++) {
		//如果遍历了整个目录后,都无法找到这个文件或者文件夹,那么直接返回NULL,让VFS为其新
		//建一个Inode,child_dentry->d_name.name是希望创建的目标文件或者文件夹  
		if (!strcmp(record->filename, child_dentry->d_name.name)) {
			/* FIXME: There is a corner case where if an allocated inode,
			 * is not written to the inode store, but the inodes_count is
			 * incremented. Then if the random string on the disk matches
			 * with the filename that we are comparing above, then we
			 * will use an invalid uninitialized inode */
			/*
			 * 进入这个分支是一种比较极端的情况,意味着分配的Inode并没有被写入存储区,但是InodesCount确递增了
			 * 同时磁盘上的Inode的随机字符串和我们比较的字符串匹配上了,那么我们直接使用这个非法的未初始化的
			 * Inode即可
			 */
			struct inode *inode;
			struct simplefs_inode *sfs_inode;

			//使用这个未被写入存储区的Inode号,查询到具体的Inode信息结构
			sfs_inode = simplefs_get_inode(sb, record->inode_no);
			//使用SuperBlock分配一个空闲的Inode
			inode = new_inode(sb);
			//设置Inode号
			inode->i_ino = record->inode_no;
			//设置这个Inode归属于哪个父节点(Inode)下,同时设置其模式(例如:表明其是目录还是文件)
			inode_init_owner(inode, parent_inode, sfs_inode->mode);
			//该Inode指向的超级块指针需要设置
			inode->i_sb = sb;
			//设置该Inode的节点操作指针(因为有可能这个节点它是一个目录,那就需要支持mkdir,touch等操作)
			inode->i_op = &simplefs_inode_ops;

			//针对目录和常规文件的操作指针
			if (S_ISDIR(inode->i_mode))
				inode->i_fop = &simplefs_dir_operations;
			else if (S_ISREG(inode->i_mode))
				inode->i_fop = &simplefs_file_operations;
			else
				printk(KERN_ERR
				       "Unknown inode type. Neither a directory nor a file");

			/* FIXME: We should store these times to disk and retrieve them */
			//设置Inode的创建时间
			inode->i_atime = inode->i_mtime = inode->i_ctime =
			    CURRENT_TIME;

			//如前所述,i_private指针指向的是Inode具体信息(文件大小,属性,数据块的位置)
			inode->i_private = sfs_inode;

			//将该Inode加入到当前目录(Dentry)下
			d_add(child_dentry, inode);
			//由于我们使用的是之前分配的inode号(未写入存储区),因此并不需要再重新创建了,直接
			//返回NULL即可
			return NULL;
		}
		record++;
	}

	printk(KERN_ERR
	       "No inode found for the filename [%s]\n",
	       child_dentry->d_name.name);

	return NULL;
}

2.文件的创建过程

当我们文件系统检查完,该文件不存在时,就会通过vfs创建一个文件

static struct inode_operations simplefs_inode_ops = {
	.create = simplefs_create,
	.lookup = simplefs_lookup,
	.mkdir = simplefs_mkdir,
};

如上对于一个目录的Inode我们之前为其设置了simplefs_inode_ops的结构,其中有个成员就是create指针。如下

simplefs_create

        ->simplefs_create_fs_object

下面就是Inode的创建过程

static int simplefs_create_fs_object(struct inode *dir, struct dentry *dentry,
				     umode_t mode)
{
	struct inode *inode;
	struct simplefs_inode *sfs_inode;
	struct super_block *sb;
	struct simplefs_inode *parent_dir_inode;
	struct buffer_head *bh;
	struct simplefs_dir_record *dir_contents_datablock;
	uint64_t count;
	int ret;

	if (mutex_lock_interruptible(&simplefs_directory_children_update_lock)) {
		sfs_trace("Failed to acquire mutex lock\n");
		return -EINTR;
	}
	//通过这个父Inode获取到这个文件系统的SuperBlock
	sb = dir->i_sb;
	
	//我们首先思考,我们如果想要创建一个Inode是不是应该看下该文件系统的Inode位置是否		
	//还有空余来允许我们创建呢,因此,我们先要得到当前文件系统已经使用的Inode总数。
	ret = simplefs_sb_get_objects_count(sb, &count);
	if (ret < 0) {
		mutex_unlock(&simplefs_directory_children_update_lock);
		return ret;
	}

	//先判断Inode总数是否超了,如果是,则返回用户,没有空间创建了
	if (unlikely(count >= SIMPLEFS_MAX_FILESYSTEM_OBJECTS_SUPPORTED)) {
		/* The above condition can be just == insted of the >= */
		printk(KERN_ERR
		       "Maximum number of objects supported by simplefs is already reached");
		mutex_unlock(&simplefs_directory_children_update_lock);
		return -ENOSPC;
	}

	//该文件系统只支持目录和普通文件的创建,否则返回出错
	if (!S_ISDIR(mode) && !S_ISREG(mode)) {
		printk(KERN_ERR
		       "Creation request but for neither a file nor a directory");
		mutex_unlock(&simplefs_directory_children_update_lock);
		return -EINVAL;
	}
	
	//通过SuperBlock创建一个空的Inode  
	inode = new_inode(sb);
	if (!inode) {
		mutex_unlock(&simplefs_directory_children_update_lock);
		return -ENOMEM;
	}
	//设置这个Inode指向的SuperBlock   
	inode->i_sb = sb;
	//设置这个Inode的操作指针
	inode->i_op = &simplefs_inode_ops;
	//设置这个Inode的创建时间
	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
	//设置Inode的Inode号
	inode->i_ino = (count + SIMPLEFS_START_INO - SIMPLEFS_RESERVED_INODES + 1);
	//创建特定文件系统的Inode结构
	sfs_inode = kmem_cache_alloc(sfs_inode_cachep, GFP_KERNEL);
	//对该节点的Inode号赋值
	sfs_inode->inode_no = inode->i_ino;
	//将内核标准节点的私有指针指向当前特定文件系统的Inode结构
	inode->i_private = sfs_inode;
	//设置文件系统的属性
	sfs_inode->mode = mode;

	//对文件目录以及普通文件分别做设置,需要注意的是,如果创建的是一个目录,那么毫无疑问,当前目录下
	//的Inode个数肯定还是为0的
	if (S_ISDIR(mode)) {
		printk(KERN_INFO "New directory creation request\n");
		sfs_inode->dir_children_count = 0;
		inode->i_fop = &simplefs_dir_operations;
	} else if (S_ISREG(mode)) {
		printk(KERN_INFO "New file creation request\n");
		sfs_inode->file_size = 0;
		//针对普通文件设置读写操作
		inode->i_fop = &simplefs_file_operations;
	}

	/* First get a free block and update the free map,
	 * Then add inode to the inode store and update the sb inodes_count,
	 * Then update the parent directory's inode with the new child.
	 *
	 * The above ordering helps us to maintain fs consistency
	 * even in most crashes
	 */
	//从超级块中获取空闲的数据块
	ret = simplefs_sb_get_a_freeblock(sb, &sfs_inode->data_block_number);
	if (ret < 0) {
		printk(KERN_ERR "simplefs could not get a freeblock");
		mutex_unlock(&simplefs_directory_children_update_lock);
		return ret;
	}
	//新建一个Inode需要更新Inode的数据区,并同步
	simplefs_inode_add(sb, sfs_inode);

	/*除了更新Inode的数据区,我们还需要做一件事:在父目录(Inode)下面,添加该Inode的信息*/
	//既然要添加信息,必须首先取得当前父目录的结构信息,通过内核的标准Inode获取特定文件系统的Inode
	//信息
	parent_dir_inode = SIMPLEFS_INODE(dir);
	//通过simplefs_inode中的成员从而获取到数据信息
	bh = sb_bread(sb, parent_dir_inode->data_block_number);
	BUG_ON(!bh);
	//需要知道的是目录Inode中存放的内容结构都是固定的,因此做下强制转换
	dir_contents_datablock = (struct simplefs_dir_record *)bh->b_data;

	/* Navigate to the last record in the directory contents */
	/*让DIR的内容指针指向空闲区域*/
	dir_contents_datablock += parent_dir_inode->dir_children_count;
	/*让DIR的内容inode_no以及文件名称更新到父目录中*/
	dir_contents_datablock->inode_no = sfs_inode->inode_no;
	strcpy(dir_contents_datablock->filename, dentry->d_name.name);

	/*将父目录指向的数据块设置为dirty,并将其回写到磁盘,之后释放*/
	mark_buffer_dirty(bh);
	sync_dirty_buffer(bh);
	brelse(bh);

	if (mutex_lock_interruptible(&simplefs_inodes_mgmt_lock)) {
		mutex_unlock(&simplefs_directory_children_update_lock);
		sfs_trace("Failed to acquire mutex lock\n");
		return -EINTR;
	}
	//将父目录中的dir_children_count也自增
	parent_dir_inode->dir_children_count++;
	//同理我们更改了Inode数据区,这个数据区自然也要同步下了
	ret = simplefs_inode_save(sb, parent_dir_inode);
	if (ret) {
		mutex_unlock(&simplefs_inodes_mgmt_lock);
		mutex_unlock(&simplefs_directory_children_update_lock);

		/* TODO: Remove the newly created inode from the disk and in-memory inode store
		 * and also update the superblock, freemaps etc. to reflect the same.
		 * Basically, Undo all actions done during this create call */
		return ret;
	}

	mutex_unlock(&simplefs_inodes_mgmt_lock);
	mutex_unlock(&simplefs_directory_children_update_lock);
	//将当前Inode和其父目录关联
	inode_init_owner(inode, dir, mode);
	//将当前文件加入到denrty下面
	d_add(dentry, inode);

	return 0;
}
 类似资料: