内核hlist分析

一. 参考网址

  1. Linux 内核 hlist 详解

  2. Linux内核中的数据结构与算法(三)哈希链表

二. 源码

  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);
    }
}

 

posted @ 2024-05-22 15:19  shanyu20  阅读(16)  评论(0编辑  收藏  举报