版权声明:本文为博主原创文章,未经博主允许不得转载。 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);