netfilter: nfnetlink_log: RCU conversion, part 2
authorEric Dumazet <eric.dumazet@gmail.com>
Mon, 14 Jun 2010 14:15:23 +0000 (16:15 +0200)
committerPatrick McHardy <kaber@trash.net>
Mon, 14 Jun 2010 14:15:23 +0000 (16:15 +0200)
- must use atomic_inc_not_zero() in instance_lookup_get()

- must use hlist_add_head_rcu() instead of hlist_add_head()

- must use hlist_del_rcu() instead of hlist_del()

- Introduce NFULNL_COPY_DISABLED to stop lockless reader from using an
instance, before we do final instance_put() on it.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Patrick McHardy <kaber@trash.net>
include/linux/netfilter/nfnetlink_log.h
net/netfilter/nfnetlink_log.c

index d3bab7a..1d0b84a 100644 (file)
@@ -89,6 +89,7 @@ enum nfulnl_attr_config {
 #define NFULNL_COPY_NONE       0x00
 #define NFULNL_COPY_META       0x01
 #define NFULNL_COPY_PACKET     0x02
+#define NFULNL_COPY_DISABLED   0x03
 
 #define NFULNL_CFG_F_SEQ       0x0001
 #define NFULNL_CFG_F_SEQ_GLOBAL        0x0002
index 8ec23ec..fb86a51 100644 (file)
@@ -109,8 +109,8 @@ instance_lookup_get(u_int16_t group_num)
 
        rcu_read_lock_bh();
        inst = __instance_lookup(group_num);
-       if (inst)
-               instance_get(inst);
+       if (inst && !atomic_inc_not_zero(&inst->use))
+               inst = NULL;
        rcu_read_unlock_bh();
 
        return inst;
@@ -171,7 +171,7 @@ instance_create(u_int16_t group_num, int pid)
        inst->copy_mode         = NFULNL_COPY_PACKET;
        inst->copy_range        = NFULNL_COPY_RANGE_MAX;
 
-       hlist_add_head(&inst->hlist,
+       hlist_add_head_rcu(&inst->hlist,
                       &instance_table[instance_hashfn(group_num)]);
 
        spin_unlock_bh(&instances_lock);
@@ -185,18 +185,23 @@ out_unlock:
 
 static void __nfulnl_flush(struct nfulnl_instance *inst);
 
+/* called with BH disabled */
 static void
 __instance_destroy(struct nfulnl_instance *inst)
 {
        /* first pull it out of the global list */
-       hlist_del(&inst->hlist);
+       hlist_del_rcu(&inst->hlist);
 
        /* then flush all pending packets from skb */
 
-       spin_lock_bh(&inst->lock);
+       spin_lock(&inst->lock);
+
+       /* lockless readers wont be able to use us */
+       inst->copy_mode = NFULNL_COPY_DISABLED;
+
        if (inst->skb)
                __nfulnl_flush(inst);
-       spin_unlock_bh(&inst->lock);
+       spin_unlock(&inst->lock);
 
        /* and finally put the refcount */
        instance_put(inst);
@@ -624,6 +629,7 @@ nfulnl_log_packet(u_int8_t pf,
                size += nla_total_size(data_len);
                break;
 
+       case NFULNL_COPY_DISABLED:
        default:
                goto unlock_and_release;
        }