inode_hashtable哈希表及f2fs查找inode过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/jasonLee_lijiaqi/article/details/82970221

文件系统中的位于内存中所有inode存放在一个名为inode_hashtable的全局哈希表中(如果inode还在磁盘,尚未读到内存中,则不会加入到全局哈希表中)。另一方面,所有的inode还存放在超级块中的s_inode链表中。

inode_hashtable哈希表加快了对索引节点对象的搜索。

前提是必须知道索引节点号和文件所在文件系统对应的超级块对象。

inode_table位于fs/inode.c中:

static unsigned int i_hash_mask __read_mostly;
static unsigned int i_hash_shift __read_mostly;
static struct hlist_head *inode_hashtable __read_mostly;  //哈希表定义
static __cacheline_aligned_in_smp DEFINE_SPINLOCK(inode_hash_lock);

/*
 * Empty aops. Can be used for the cases where the user does not
 * define any of the address_space operations.
 */
const struct address_space_operations empty_aops = {
};
EXPORT_SYMBOL(empty_aops);

————————————————————————————————————————————————————————
下面以f2fs文件系统查找inode为例:
f2fs_iget依据索引节点号ino,查找对应的inode;

/* 
	依据节点号ino,获得对应的inode;
	若没有,则创建一个新的inode,读取磁盘上的inode所在的block,生成f2f2_inode对象去初始化这个新inode
*/
struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
{
	struct f2fs_sb_info *sbi = F2FS_SB(sb);
	struct inode *inode;
	int ret = 0;

	//依据索引节点号ino,获得对应的inode;若没有,则创建一个新的inode
	inode = iget_locked(sb, ino);
	if (!inode)
		return ERR_PTR(-ENOMEM);

	/* 该inode不是新inode,直接返回该inode */
	if (!(inode->i_state & I_NEW)) {
		trace_f2fs_iget(inode);
		return inode;
	}

	/* 如果索引节点号是NODE节点或者META节点,调到make_now */
	if (ino == F2FS_NODE_INO(sbi) || ino == F2FS_META_INO(sbi))
		goto make_now;

	/* 索引节点是DATA节点:依据inode的节点号,将inode对应的block读到页缓存,此时磁盘上的f2fs_node节点就位于页缓存中。
		使用f2fs_node 对inode初始化 */
	ret = do_read_inode(inode);
	if (ret)
		goto bad_inode;
make_now:

	/* 依据ino对应的节点类型或者文件类型,赋予inode不同的操作方法 */
	if (ino == F2FS_NODE_INO(sbi)) {   //ino是NODE节点
		inode->i_mapping->a_ops = &f2fs_node_aops;
		mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
	} else if (ino == F2FS_META_INO(sbi)) {  //ino是META节点
		inode->i_mapping->a_ops = &f2fs_meta_aops;
		mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
	} else if (S_ISREG(inode->i_mode)) {    //inode代表普通文件
		inode->i_op = &f2fs_file_inode_operations;
		inode->i_fop = &f2fs_file_operations;
		inode->i_mapping->a_ops = &f2fs_dblock_aops;
	} else if (S_ISDIR(inode->i_mode)) {   //inode代表目录文件
		inode->i_op = &f2fs_dir_inode_operations;
		inode->i_fop = &f2fs_dir_operations;
		inode->i_mapping->a_ops = &f2fs_dblock_aops;
		mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO);
	} else if (S_ISLNK(inode->i_mode)) {   //inode代表符号链接
		if (f2fs_encrypted_inode(inode))
			inode->i_op = &f2fs_encrypted_symlink_inode_operations;
		else
			inode->i_op = &f2fs_symlink_inode_operations;
		inode_nohighmem(inode);
		inode->i_mapping->a_ops = &f2fs_dblock_aops;
	} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
			S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {  //inode代表字符设备、块设备、管道或者套接字文件
		inode->i_op = &f2fs_special_inode_operations;
		init_special_inode(inode, inode->i_mode, inode->i_rdev);
	} else {
		ret = -EIO;
		goto bad_inode;
	}
	unlock_new_inode(inode);
	trace_f2fs_iget(inode);
	return inode;

bad_inode:
	iget_failed(inode);
	trace_f2fs_iget_exit(inode, ret);
	return ERR_PTR(ret);
}

其中iget_locked负责查找对应的inode;
具体实现:inode_hashtable中查找对应的inode;如果查找不到,则申请一个新的inode插入到inode_hashtable中。
哈希表的具体操作参考:http://blog.51cto.com/cizyzhang/1381084
参数: 索引节点号ino;超级块对象sb;

/**
	依据ino节点号,得到对应的inode;如果没有,则创建新的inode,并将该inode节点号置为ino
 * iget_locked - obtain an inode from a mounted file system
 * @sb:		super block of file system
 * @ino:	inode number to get
 *
 * Search for the inode specified by @ino in the inode cache and if present
 * return it with an increased reference count. This is for file systems
 * where the inode number is sufficient for unique identification of an inode.
 *
 * If the inode is not in cache, allocate a new inode and return it locked,
 * hashed, and with the I_NEW flag set.  The file system gets to fill it in
 * before unlocking it via unlock_new_inode().
 */
struct inode *iget_locked(struct super_block *sb, unsigned long ino)
{
	struct hlist_head *head = inode_hashtable + hash(sb, ino);
	struct inode *inode;

	spin_lock(&inode_hash_lock);
	/* 在inode_hashtable哈希表中快速查找inode */
	inode = find_inode_fast(sb, head, ino);
	spin_unlock(&inode_hash_lock);

	/* 找到该inode就返回该inode */
	if (inode) {
		wait_on_inode(inode);
		return inode;
	}

	/* 未找到,申请新的inode 
	f2fs特定的alloc_inode方法:f2fs_alloc_inode
	*/
	inode = alloc_inode(sb);
	if (inode) {
		struct inode *old;

		spin_lock(&inode_hash_lock);
		/* We released the lock, so.. 
		再次尝试查找节点号为ino的inode(很大概率还是找不到)
		*/
		old = find_inode_fast(sb, head, ino);
		//仍然找不到,则将申请到的新inode的节点号设置为ino,并把该inode插入到inode->i_sb_list链表中
		if (!old) {
			inode->i_ino = ino;  //将申请到的新inode的节点号设置为ino
			spin_lock(&inode->i_lock);
			inode->i_state = I_NEW;
			hlist_add_head(&inode->i_hash, head);  //将inode插入到全局的inode_hashtable中
			spin_unlock(&inode->i_lock);
			inode_sb_list_add(inode);   //把该inode插入到inode->i_sb_list链表中
			spin_unlock(&inode_hash_lock);

			/* Return the locked inode with I_NEW set, the
			 * caller is responsible for filling in the contents
			 */
			return inode;
		}

		/*
			有个进程此时创建了相同的inode,使用这个inode代替我们刚才申请的inode
		 * Uhhuh, somebody else created the same inode under
		 * us. Use the old inode instead of the one we just
		 * allocated.
		 */
		spin_unlock(&inode_hash_lock);
		destroy_inode(inode);
		inode = old;
		wait_on_inode(inode);
	}
	return inode;
}
EXPORT_SYMBOL(iget_locked);

猜你喜欢

转载自blog.csdn.net/jasonLee_lijiaqi/article/details/82970221