- 论坛徽章:
- 0
|
本帖最后由 独孤九贱 于 2012-12-19 11:12 编辑
5、查找
查找是rculist_null最为重要的应用,可以说所有的准备都是为它而来,
____nf_conntrack_find完成hash表的查找工作,它返回要查找的节点,
该函数的结构为标准的hlist_nulls的查找,但是这个函数没有RCU锁的保护,
作者将其一分为二,锁放在上层了调用函数了:
- /*
- * Warning :
- * - Caller must take a reference on returned object
- * and recheck nf_ct_tuple_equal(tuple, &h->tuple)
- * OR
- * - Caller must lock nf_conntrack_lock before calling this function
- */
- static struct nf_conntrack_tuple_hash *
- ____nf_conntrack_find(struct net *net, u16 zone,
- const struct nf_conntrack_tuple *tuple, u32 hash)
- {
- struct nf_conntrack_tuple_hash *h;
- struct hlist_nulls_node *n;
- unsigned int bucket = hash_bucket(hash, net);
- /* Disable BHs the entire time since we normally need to disable them
- * at least once for the stats anyway.
- */
- local_bh_disable();
- begin:
- hlist_nulls_for_each_entry_rcu(h, n, &net->ct.hash[bucket], hnnode) {
- if (nf_ct_tuple_equal(tuple, &h->tuple) &&
- nf_ct_zone(nf_ct_tuplehash_to_ctrack(h)) == zone) {
- NF_CT_STAT_INC(net, found);
- local_bh_enable();
- return h;
- }
- NF_CT_STAT_INC(net, searched);
- }
- /*
- * if the nulls value we got at the end of this lookup is
- * not the expected one, we must restart lookup.
- * We probably met an item that was moved to another chain.
- */
- if (get_nulls_value(n) != bucket) {
- NF_CT_STAT_INC(net, search_restart);
- goto begin;
- }
- local_bh_enable();
- return NULL;
- }
复制代码 上层调用函数使用RCU锁保护,来调用该查找函数,并且如果查找命中,增加引用计数器:
- /* Find a connection corresponding to a tuple. */
- static struct nf_conntrack_tuple_hash *
- __nf_conntrack_find_get(struct net *net, u16 zone,
- const struct nf_conntrack_tuple *tuple, u32 hash)
- {
- struct nf_conntrack_tuple_hash *h;
- struct nf_conn *ct;
- rcu_read_lock();
- begin:
- h = ____nf_conntrack_find(net, zone, tuple, hash);
- if (h) {
- ct = nf_ct_tuplehash_to_ctrack(h);
- if (unlikely(nf_ct_is_dying(ct) ||
- !atomic_inc_not_zero(&ct->ct_general.use)))
- h = NULL;
- else {
- if (unlikely(!nf_ct_tuple_equal(tuple, &h->tuple) ||
- nf_ct_zone(ct) != zone)) {
- nf_ct_put(ct);
- goto begin;
- }
- }
- }
- rcu_read_unlock();
- return h;
- }
复制代码 这同样与rculist_nulls.txt中描述是完全相同的,只是实现的时候切割开了:- 1) lookup algo
- head = &table[slot];
- rcu_read_lock(); begin: hlist_nulls_for_each_entry_rcu(obj, node, head, member) { if (obj->key == key) { if (!try_get_ref(obj)) // might fail for free objects goto begin; if (obj->key != key) { // not the object we expected put_ref(obj);
- goto begin; } goto out; } /*
- * if the nulls value we got at the end of this lookup is
- * not the expected one, we must restart lookup.
- * We probably met an item that was moved to another chain.
- */
- if (get_nulls_value(node) != slot) goto begin; obj = NULL;
- out: rcu_read_unlock();
复制代码 6、更新
当查找到的节点需要对其成员进行操作时,需要加节点锁,如下所示:- static int tcp_packet(struct nf_conn *ct,
- const struct sk_buff *skb,
- unsigned int dataoff,
- enum ip_conntrack_info ctinfo,
- u_int8_t pf,
- unsigned int hooknum)
- {
- spin_lock_bh(&ct->lock);
-
- //对ct成员的若干操作
- ……
-
- spin_unlock_bh(&ct->lock);
- }
复制代码 这里,最重要的理解查找操作不需要更多的自旋锁保护,只需rcu_read_lock即可。这涉及到RCU锁的原理与实现,本文侧重于rculist_null的使用接口介绍与分析,不再RCU相关东东了。
未完,待续……
|
|