Chinaunix

标题: nf_conntrack_set_hashsize [打印本页]

作者: zhanglin496    时间: 2016-08-31 11:15
标题: nf_conntrack_set_hashsize
本帖最后由 zhanglin496 于 2016-08-31 11:20 编辑

int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp)
{
        int i, bucket, vmalloced, old_vmalloced;
        unsigned int hashsize, old_size;
        struct hlist_nulls_head *hash, *old_hash;
        struct nf_conntrack_tuple_hash *h;
        struct nf_conn *ct;

        if (current->nsproxy->net_ns != &init_net)
                return -EOPNOTSUPP;

        /* On boot, we can set this without any fancy locking. */
        if (!nf_conntrack_htable_size)
                return param_set_uint(val, kp);

        hashsize = simple_strtoul(val, NULL, 0);
        if (!hashsize)
                return -EINVAL;

        hash = nf_ct_alloc_hashtable(&hashsize, &vmalloced, 1);
        if (!hash)
                return -ENOMEM;

        /* Lookups in the old hash might happen in parallel, which means we
         * might get false negatives during connection lookup. New connections
         * created because of a false negative won't make it into the hash
         * though since that required taking the lock.
         */
        spin_lock_bh(&nf_conntrack_lock);
        for (i = 0; i < init_net.ct.htable_size; i++) {
                while (!hlist_nulls_empty(&init_net.ct.hash)) {
                        h = hlist_nulls_entry(init_net.ct.hash.first,
                                        struct nf_conntrack_tuple_hash, hnnode);
                        ct = nf_ct_tuplehash_to_ctrack(h);
                        hlist_nulls_del_rcu(&h->hnnode);
                        bucket = __hash_conntrack(&h->tuple, nf_ct_zone(ct),
                                                  hashsize,
                                                  nf_conntrack_hash_rnd);
                        hlist_nulls_add_head_rcu(&h->hnnode, &hash[bucket]);
                }
        }
        old_size = init_net.ct.htable_size;
        old_vmalloced = init_net.ct.hash_vmalloc;
        old_hash = init_net.ct.hash;

        init_net.ct.htable_size = nf_conntrack_htable_size = hashsize;
        init_net.ct.hash_vmalloc = vmalloced;
        init_net.ct.hash = hash;
        spin_unlock_bh(&nf_conntrack_lock);

        nf_ct_free_hashtable(old_hash, old_vmalloced, old_size);
        return 0;
}
EXPORT_SYMBOL_GPL(nf_conntrack_set_hashsize);

module_param_call(hashsize, nf_conntrack_set_hashsize, param_get_uint,
                  &nf_conntrack_htable_size, 0600);

1、conntrack hash桶可以通过用户命令重新分配,我有个疑问,在老的hash表释放时,如何保证没有其他的路径在引用老的hash表,我看代码迁移完成后直接调用nf_ct_free_hashtable就把老的hash表给释放了,为什么没有调用rcu来同步呢?
2、CPU A调用nf_ct_free_hashtable释放老的hash表时,CPU B正在引用老的hash表,感觉会出问题啊?
3、感觉应该在调用nf_ct_free_hashtable时插入synchronize_rcu, 但实际上没有,why?

作者: zhanglin496    时间: 2016-08-31 11:27
哈哈,好像是内核的BUG,在4.7.4 中修复了,我看了下4.0.5中也应该有这个问题
         synchronize_net();
         nf_ct_free_hashtable(old_hash, old_size);
         return 0;
作者: zhanglin496    时间: 2016-08-31 14:01
查看提交记录,在2016-05-05修复,同时patch也fix了另外一个bug,比如使用了新的hash表,却使用的旧的hash size,
我要是早点发现,说不定能给内核提交个patch,
http://git.kernel.org/cgit/linux ... 4e2c673121028449e35
作者: nswcfd    时间: 2016-08-31 14:15
的确有点震惊,赞楼上




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2