Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net
[linux-2.6-microblaze.git] / net / netfilter / x_tables.c
index af22dbe..acce622 100644 (file)
@@ -1349,6 +1349,14 @@ struct xt_counters *xt_counters_alloc(unsigned int counters)
 }
 EXPORT_SYMBOL(xt_counters_alloc);
 
+struct xt_table_info
+*xt_table_get_private_protected(const struct xt_table *table)
+{
+       return rcu_dereference_protected(table->private,
+                                        mutex_is_locked(&xt[table->af].mutex));
+}
+EXPORT_SYMBOL(xt_table_get_private_protected);
+
 struct xt_table_info *
 xt_replace_table(struct xt_table *table,
              unsigned int num_counters,
@@ -1356,7 +1364,6 @@ xt_replace_table(struct xt_table *table,
              int *error)
 {
        struct xt_table_info *private;
-       unsigned int cpu;
        int ret;
 
        ret = xt_jumpstack_alloc(newinfo);
@@ -1366,47 +1373,20 @@ xt_replace_table(struct xt_table *table,
        }
 
        /* Do the substitution. */
-       local_bh_disable();
-       private = table->private;
+       private = xt_table_get_private_protected(table);
 
        /* Check inside lock: is the old number correct? */
        if (num_counters != private->number) {
                pr_debug("num_counters != table->private->number (%u/%u)\n",
                         num_counters, private->number);
-               local_bh_enable();
                *error = -EAGAIN;
                return NULL;
        }
 
        newinfo->initial_entries = private->initial_entries;
-       /*
-        * Ensure contents of newinfo are visible before assigning to
-        * private.
-        */
-       smp_wmb();
-       table->private = newinfo;
-
-       /* make sure all cpus see new ->private value */
-       smp_wmb();
 
-       /*
-        * Even though table entries have now been swapped, other CPU's
-        * may still be using the old entries...
-        */
-       local_bh_enable();
-
-       /* ... so wait for even xt_recseq on all cpus */
-       for_each_possible_cpu(cpu) {
-               seqcount_t *s = &per_cpu(xt_recseq, cpu);
-               u32 seq = raw_read_seqcount(s);
-
-               if (seq & 1) {
-                       do {
-                               cond_resched();
-                               cpu_relax();
-                       } while (seq == raw_read_seqcount(s));
-               }
-       }
+       rcu_assign_pointer(table->private, newinfo);
+       synchronize_rcu();
 
        audit_log_nfcfg(table->name, table->af, private->number,
                        !private->number ? AUDIT_XT_OP_REGISTER :
@@ -1442,12 +1422,12 @@ struct xt_table *xt_register_table(struct net *net,
        }
 
        /* Simplifies replace_table code. */
-       table->private = bootstrap;
+       rcu_assign_pointer(table->private, bootstrap);
 
        if (!xt_replace_table(table, 0, newinfo, &ret))
                goto unlock;
 
-       private = table->private;
+       private = xt_table_get_private_protected(table);
        pr_debug("table->private->number = %u\n", private->number);
 
        /* save number of initial entries */
@@ -1470,7 +1450,8 @@ void *xt_unregister_table(struct xt_table *table)
        struct xt_table_info *private;
 
        mutex_lock(&xt[table->af].mutex);
-       private = table->private;
+       private = xt_table_get_private_protected(table);
+       RCU_INIT_POINTER(table->private, NULL);
        list_del(&table->list);
        mutex_unlock(&xt[table->af].mutex);
        audit_log_nfcfg(table->name, table->af, private->number,