内核hlist分析
一. 参考网址
二. 源码
1. 哈希表操作函数:include/linux/list.h
2. 哈希表结构体定义:include/linux/types.h
3. 两个重要结构体定义:
//hash桶的头结点 struct hlist_head { struct hlist_node *first;//指向每一个hash桶的第一个结点的指针 }; //hash桶的普通结点 struct hlist_node { struct hlist_node *next;//指向下一个结点的指针 struct hlist_node **pprev;//指向上一个结点的next指针的地址 };
三. 疑问
1. hlist_add_head函数
1.1 源码
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) { struct hlist_node *first = h->first; n->next = first; if (first) first->pprev = &n->next; //为什么不用first->pprev=&n? h->first = n; n->pprev = &h->first; }
解答:将 first->pprev = &n->next;
作为指针赋值的方式,确保了代码的灵活性和健壮性。无论 struct hlist_node
结构体内部成员的顺序如何排列,都可以正确地获取到 next
成员的地址,这使得代码更加健壮和易于维护。因此,这种方式在实际编程中是一种良好的做法,可以减少因为结构体成员顺序变化而导致的错误
四. linux内核代码运用示例
参考内核代码: fs/fat/inode.c(fat文件系统管理)
1. 初始化哈希表
static void fat_hash_init(struct super_block *sb) { struct msdos_sb_info *sbi = MSDOS_SB(sb); int i; spin_lock_init(&sbi->inode_hash_lock); for (i = 0; i < FAT_HASH_SIZE; i++) INIT_HLIST_HEAD(&sbi->inode_hashtable[i]); //初始化其firs指针为空 }
2. 增加哈希表节点
void fat_attach(struct inode *inode, loff_t i_pos) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); if (inode->i_ino != MSDOS_ROOT_INO) { struct hlist_head *head = sbi->inode_hashtable + fat_hash(i_pos); spin_lock(&sbi->inode_hash_lock); MSDOS_I(inode)->i_pos = i_pos; hlist_add_head(&MSDOS_I(inode)->i_fat_hash, head); //增加节点 spin_unlock(&sbi->inode_hash_lock); } /* If NFS support is enabled, cache the mapping of start cluster * to directory inode. This is used during reconnection of * dentries to the filesystem root. */ if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { struct hlist_head *d_head = sbi->dir_hashtable; d_head += fat_dir_hash(MSDOS_I(inode)->i_logstart); spin_lock(&sbi->dir_hash_lock); hlist_add_head(&MSDOS_I(inode)->i_dir_hash, d_head); //增加节点 spin_unlock(&sbi->dir_hash_lock); } }
3. 删除哈希表节点
void fat_detach(struct inode *inode) { struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); spin_lock(&sbi->inode_hash_lock); MSDOS_I(inode)->i_pos = 0; hlist_del_init(&MSDOS_I(inode)->i_fat_hash); //删除节点 spin_unlock(&sbi->inode_hash_lock); if (S_ISDIR(inode->i_mode) && sbi->options.nfs) { spin_lock(&sbi->dir_hash_lock); hlist_del_init(&MSDOS_I(inode)->i_dir_hash); //删除节点 spin_unlock(&sbi->dir_hash_lock); } }