lkml.org 
[lkml]   [2009]   [Apr]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH] netfilter: use per-cpu spinlock rather than RCU (v3)
    This is an alternative version of ip/ip6/arp tables locking using
    per-cpu locks. This avoids the overhead of synchronize_net() during
    update but still removes the expensive rwlock in earlier versions.

    The idea for this came from an earlier version done by Eric Dumazet.
    Locking is done per-cpu, the fast path locks on the current cpu
    and updates counters. The slow case involves acquiring the locks on
    all cpu's.

    The mutex that was added for 2.6.30 in xt_table is unnecessary since
    there already is a mutex for xt[af].mutex that is held.

    Signed-off-by: Stephen Hemminger <shemminger@vyatta.com>

    ---
    include/linux/netfilter/x_tables.h | 5 -
    net/ipv4/netfilter/arp_tables.c | 112 +++++++++------------------------
    net/ipv4/netfilter/ip_tables.c | 123 +++++++++++--------------------------
    net/ipv6/netfilter/ip6_tables.c | 119 +++++++++++------------------------
    net/netfilter/x_tables.c | 28 --------
    5 files changed, 110 insertions(+), 277 deletions(-)

    --- a/include/linux/netfilter/x_tables.h 2009-04-14 10:13:59.932292529 -0700
    +++ b/include/linux/netfilter/x_tables.h 2009-04-14 10:14:04.121043331 -0700
    @@ -354,9 +354,6 @@ struct xt_table
    /* What hooks you will enter on */
    unsigned int valid_hooks;

    - /* Lock for the curtain */
    - struct mutex lock;
    -
    /* Man behind the curtain... */
    struct xt_table_info *private;

    @@ -434,8 +431,6 @@ extern void xt_proto_fini(struct net *ne

    extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
    extern void xt_free_table_info(struct xt_table_info *info);
    -extern void xt_table_entry_swap_rcu(struct xt_table_info *old,
    - struct xt_table_info *new);

    /*
    * This helper is performance critical and must be inlined
    --- a/net/ipv4/netfilter/ip_tables.c 2009-04-14 10:13:59.923167357 -0700
    +++ b/net/ipv4/netfilter/ip_tables.c 2009-04-14 11:13:51.066830533 -0700
    @@ -297,6 +297,8 @@ static void trace_packet(struct sk_buff
    }
    #endif

    +static DEFINE_PER_CPU(spinlock_t, ip_tables_lock);
    +
    /* Returns one of the generic firewall policies, like NF_ACCEPT. */
    unsigned int
    ipt_do_table(struct sk_buff *skb,
    @@ -339,9 +341,13 @@ ipt_do_table(struct sk_buff *skb,

    IP_NF_ASSERT(table->valid_hooks & (1 << hook));

    - rcu_read_lock_bh();
    - private = rcu_dereference(table->private);
    - table_base = rcu_dereference(private->entries[smp_processor_id()]);
    + /* Not spin_lock_bh() because get_cpu_var
    + * needs to happen after preempt is disabled
    + */
    + local_bh_disable();
    + spin_lock(&__get_cpu_var(ip_tables_lock));
    + private = table->private;
    + table_base = private->entries[smp_processor_id()];

    e = get_entry(table_base, private->hook_entry[hook]);

    @@ -436,8 +442,8 @@ ipt_do_table(struct sk_buff *skb,
    e = (void *)e + e->next_offset;
    }
    } while (!hotdrop);
    -
    - rcu_read_unlock_bh();
    + spin_unlock(&__get_cpu_var(ip_tables_lock));
    + local_bh_enable();

    #ifdef DEBUG_ALLOW_ALL
    return NF_ACCEPT;
    @@ -902,75 +908,25 @@ get_counters(const struct xt_table_info
    curcpu = raw_smp_processor_id();

    i = 0;
    + spin_lock_bh(&per_cpu(ip_tables_lock, curcpu));
    IPT_ENTRY_ITERATE(t->entries[curcpu],
    t->size,
    set_entry_to_counter,
    counters,
    &i);
    + spin_unlock_bh(&per_cpu(ip_tables_lock, curcpu));

    for_each_possible_cpu(cpu) {
    if (cpu == curcpu)
    continue;
    i = 0;
    + spin_lock_bh(&per_cpu(ip_tables_lock, cpu));
    IPT_ENTRY_ITERATE(t->entries[cpu],
    t->size,
    add_entry_to_counter,
    counters,
    &i);
    - }
    -
    -}
    -
    -/* We're lazy, and add to the first CPU; overflow works its fey magic
    - * and everything is OK. */
    -static int
    -add_counter_to_entry(struct ipt_entry *e,
    - const struct xt_counters addme[],
    - unsigned int *i)
    -{
    - ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
    -
    - (*i)++;
    - return 0;
    -}
    -
    -/* Take values from counters and add them back onto the current cpu */
    -static void put_counters(struct xt_table_info *t,
    - const struct xt_counters counters[])
    -{
    - unsigned int i, cpu;
    -
    - local_bh_disable();
    - cpu = smp_processor_id();
    - i = 0;
    - IPT_ENTRY_ITERATE(t->entries[cpu],
    - t->size,
    - add_counter_to_entry,
    - counters,
    - &i);
    - local_bh_enable();
    -}
    -
    -
    -static inline int
    -zero_entry_counter(struct ipt_entry *e, void *arg)
    -{
    - e->counters.bcnt = 0;
    - e->counters.pcnt = 0;
    - return 0;
    -}
    -
    -static void
    -clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
    -{
    - unsigned int cpu;
    - const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
    -
    - memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
    - for_each_possible_cpu(cpu) {
    - memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
    - IPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
    - zero_entry_counter, NULL);
    + spin_unlock_bh(&per_cpu(ip_tables_lock, cpu));
    }
    }

    @@ -979,7 +935,6 @@ static struct xt_counters * alloc_counte
    unsigned int countersize;
    struct xt_counters *counters;
    struct xt_table_info *private = table->private;
    - struct xt_table_info *info;

    /* We need atomic snapshot of counters: rest doesn't change
    (other than comefrom, which userspace doesn't care
    @@ -990,26 +945,10 @@ static struct xt_counters * alloc_counte
    if (counters == NULL)
    goto nomem;

    - info = xt_alloc_table_info(private->size);
    - if (!info)
    - goto free_counters;
    -
    - clone_counters(info, private);
    -
    - mutex_lock(&table->lock);
    - xt_table_entry_swap_rcu(private, info);
    - synchronize_net(); /* Wait until smoke has cleared */
    -
    - get_counters(info, counters);
    - put_counters(private, counters);
    - mutex_unlock(&table->lock);
    -
    - xt_free_table_info(info);
    + get_counters(private, counters);

    return counters;

    - free_counters:
    - vfree(counters);
    nomem:
    return ERR_PTR(-ENOMEM);
    }
    @@ -1377,6 +1316,18 @@ do_replace(struct net *net, void __user
    return ret;
    }

    +/* We're lazy, and add to the first CPU; overflow works its fey magic
    + * and everything is OK. */
    +static int
    +add_counter_to_entry(struct ipt_entry *e,
    + const struct xt_counters addme[],
    + unsigned int *i)
    +{
    + ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
    +
    + (*i)++;
    + return 0;
    +}

    static int
    do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
    @@ -1437,25 +1388,26 @@ do_add_counters(struct net *net, void __
    goto free;
    }

    - mutex_lock(&t->lock);
    private = t->private;
    if (private->number != num_counters) {
    ret = -EINVAL;
    goto unlock_up_free;
    }

    - preempt_disable();
    - i = 0;
    /* Choose the copy that is on our node */
    - loc_cpu_entry = private->entries[raw_smp_processor_id()];
    + local_bh_disable();
    + spin_lock(&__get_cpu_var(ip_tables_lock));
    + loc_cpu_entry = private->entries[smp_processor_id()];
    + i = 0;
    IPT_ENTRY_ITERATE(loc_cpu_entry,
    private->size,
    add_counter_to_entry,
    paddc,
    &i);
    - preempt_enable();
    + spin_unlock(&__get_cpu_var(ip_tables_lock));
    + local_bh_enable();
    +
    unlock_up_free:
    - mutex_unlock(&t->lock);
    xt_table_unlock(t);
    module_put(t->me);
    free:
    @@ -2272,7 +2224,10 @@ static struct pernet_operations ip_table

    static int __init ip_tables_init(void)
    {
    - int ret;
    + int cpu, ret;
    +
    + for_each_possible_cpu(cpu)
    + spin_lock_init(&per_cpu(ip_tables_lock, cpu));

    ret = register_pernet_subsys(&ip_tables_net_ops);
    if (ret < 0)
    --- a/net/netfilter/x_tables.c 2009-04-14 10:13:59.901168540 -0700
    +++ b/net/netfilter/x_tables.c 2009-04-14 10:14:04.123043143 -0700
    @@ -625,20 +625,6 @@ void xt_free_table_info(struct xt_table_
    }
    EXPORT_SYMBOL(xt_free_table_info);

    -void xt_table_entry_swap_rcu(struct xt_table_info *oldinfo,
    - struct xt_table_info *newinfo)
    -{
    - unsigned int cpu;
    -
    - for_each_possible_cpu(cpu) {
    - void *p = oldinfo->entries[cpu];
    - rcu_assign_pointer(oldinfo->entries[cpu], newinfo->entries[cpu]);
    - newinfo->entries[cpu] = p;
    - }
    -
    -}
    -EXPORT_SYMBOL_GPL(xt_table_entry_swap_rcu);
    -
    /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
    struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
    const char *name)
    @@ -682,26 +668,19 @@ xt_replace_table(struct xt_table *table,
    struct xt_table_info *newinfo,
    int *error)
    {
    - struct xt_table_info *oldinfo, *private;
    + struct xt_table_info *private;

    /* Do the substitution. */
    - mutex_lock(&table->lock);
    private = table->private;
    /* Check inside lock: is the old number correct? */
    if (num_counters != private->number) {
    duprintf("num_counters != table->private->number (%u/%u)\n",
    num_counters, private->number);
    - mutex_unlock(&table->lock);
    *error = -EAGAIN;
    return NULL;
    }
    - oldinfo = private;
    - rcu_assign_pointer(table->private, newinfo);
    - newinfo->initial_entries = oldinfo->initial_entries;
    - mutex_unlock(&table->lock);
    -
    - synchronize_net();
    - return oldinfo;
    + newinfo->initial_entries = private->initial_entries;
    + return xchg(&table->private, newinfo);
    }
    EXPORT_SYMBOL_GPL(xt_replace_table);

    @@ -734,7 +713,6 @@ struct xt_table *xt_register_table(struc

    /* Simplifies replace_table code. */
    table->private = bootstrap;
    - mutex_init(&table->lock);

    if (!xt_replace_table(table, 0, newinfo, &ret))
    goto unlock;
    --- a/net/ipv6/netfilter/ip6_tables.c 2009-04-14 10:13:59.909167832 -0700
    +++ b/net/ipv6/netfilter/ip6_tables.c 2009-04-14 11:15:15.405141464 -0700
    @@ -329,6 +329,8 @@ static void trace_packet(struct sk_buff
    }
    #endif

    +static DEFINE_PER_CPU(spinlock_t, ip6_tables_lock);
    +
    /* Returns one of the generic firewall policies, like NF_ACCEPT. */
    unsigned int
    ip6t_do_table(struct sk_buff *skb,
    @@ -365,9 +367,10 @@ ip6t_do_table(struct sk_buff *skb,

    IP_NF_ASSERT(table->valid_hooks & (1 << hook));

    - rcu_read_lock_bh();
    - private = rcu_dereference(table->private);
    - table_base = rcu_dereference(private->entries[smp_processor_id()]);
    + local_bh_disable();
    + spin_lock(&__get_cpu_var(ip6_tables_lock));
    + private = table->private;
    + table_base = private->entries[smp_processor_id()];

    e = get_entry(table_base, private->hook_entry[hook]);

    @@ -466,7 +469,8 @@ ip6t_do_table(struct sk_buff *skb,
    #ifdef CONFIG_NETFILTER_DEBUG
    ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
    #endif
    - rcu_read_unlock_bh();
    + spin_unlock(&__get_cpu_var(ip6_tables_lock));
    + local_bh_enable();

    #ifdef DEBUG_ALLOW_ALL
    return NF_ACCEPT;
    @@ -931,73 +935,25 @@ get_counters(const struct xt_table_info
    curcpu = raw_smp_processor_id();

    i = 0;
    + spin_lock_bh(&per_cpu(ip6_tables_lock, curcpu));
    IP6T_ENTRY_ITERATE(t->entries[curcpu],
    t->size,
    set_entry_to_counter,
    counters,
    &i);
    + spin_unlock_bh(&per_cpu(ip6_tables_lock, curcpu));

    for_each_possible_cpu(cpu) {
    if (cpu == curcpu)
    continue;
    i = 0;
    + spin_lock_bh(&per_cpu(ip6_tables_lock, cpu));
    IP6T_ENTRY_ITERATE(t->entries[cpu],
    t->size,
    add_entry_to_counter,
    counters,
    &i);
    - }
    -}
    -
    -/* We're lazy, and add to the first CPU; overflow works its fey magic
    - * and everything is OK. */
    -static int
    -add_counter_to_entry(struct ip6t_entry *e,
    - const struct xt_counters addme[],
    - unsigned int *i)
    -{
    - ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
    -
    - (*i)++;
    - return 0;
    -}
    -
    -/* Take values from counters and add them back onto the current cpu */
    -static void put_counters(struct xt_table_info *t,
    - const struct xt_counters counters[])
    -{
    - unsigned int i, cpu;
    -
    - local_bh_disable();
    - cpu = smp_processor_id();
    - i = 0;
    - IP6T_ENTRY_ITERATE(t->entries[cpu],
    - t->size,
    - add_counter_to_entry,
    - counters,
    - &i);
    - local_bh_enable();
    -}
    -
    -static inline int
    -zero_entry_counter(struct ip6t_entry *e, void *arg)
    -{
    - e->counters.bcnt = 0;
    - e->counters.pcnt = 0;
    - return 0;
    -}
    -
    -static void
    -clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
    -{
    - unsigned int cpu;
    - const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
    -
    - memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
    - for_each_possible_cpu(cpu) {
    - memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
    - IP6T_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
    - zero_entry_counter, NULL);
    + spin_unlock_bh(&per_cpu(ip6_tables_lock, cpu));
    }
    }

    @@ -1006,7 +962,6 @@ static struct xt_counters *alloc_counter
    unsigned int countersize;
    struct xt_counters *counters;
    struct xt_table_info *private = table->private;
    - struct xt_table_info *info;

    /* We need atomic snapshot of counters: rest doesn't change
    (other than comefrom, which userspace doesn't care
    @@ -1017,26 +972,9 @@ static struct xt_counters *alloc_counter
    if (counters == NULL)
    goto nomem;

    - info = xt_alloc_table_info(private->size);
    - if (!info)
    - goto free_counters;
    -
    - clone_counters(info, private);
    -
    - mutex_lock(&table->lock);
    - xt_table_entry_swap_rcu(private, info);
    - synchronize_net(); /* Wait until smoke has cleared */
    -
    - get_counters(info, counters);
    - put_counters(private, counters);
    - mutex_unlock(&table->lock);
    -
    - xt_free_table_info(info);
    -
    + get_counters(private, counters);
    return counters;

    - free_counters:
    - vfree(counters);
    nomem:
    return ERR_PTR(-ENOMEM);
    }
    @@ -1405,6 +1343,19 @@ do_replace(struct net *net, void __user
    return ret;
    }

    +/* We're lazy, and add to the first CPU; overflow works its fey magic
    + * and everything is OK. */
    +static int
    +add_counter_to_entry(struct ip6t_entry *e,
    + const struct xt_counters addme[],
    + unsigned int *i)
    +{
    + ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
    +
    + (*i)++;
    + return 0;
    +}
    +
    static int
    do_add_counters(struct net *net, void __user *user, unsigned int len,
    int compat)
    @@ -1465,25 +1416,26 @@ do_add_counters(struct net *net, void __
    goto free;
    }

    - mutex_lock(&t->lock);
    private = t->private;
    if (private->number != num_counters) {
    ret = -EINVAL;
    goto unlock_up_free;
    }

    - preempt_disable();
    - i = 0;
    + local_bh_disable();
    /* Choose the copy that is on our node */
    - loc_cpu_entry = private->entries[raw_smp_processor_id()];
    + spin_lock(&__get_cpu_var(ip6_tables_lock));
    + loc_cpu_entry = private->entries[smp_processor_id()];
    + i = 0;
    IP6T_ENTRY_ITERATE(loc_cpu_entry,
    private->size,
    add_counter_to_entry,
    paddc,
    &i);
    - preempt_enable();
    + spin_unlock(&__get_cpu_var(ip6_tables_lock));
    + local_bh_enable();
    +
    unlock_up_free:
    - mutex_unlock(&t->lock);
    xt_table_unlock(t);
    module_put(t->me);
    free:
    @@ -2298,7 +2250,10 @@ static struct pernet_operations ip6_tabl

    static int __init ip6_tables_init(void)
    {
    - int ret;
    + int cpu, ret;
    +
    + for_each_possible_cpu(cpu)
    + spin_lock_init(&per_cpu(ip6_tables_lock, cpu));

    ret = register_pernet_subsys(&ip6_tables_net_ops);
    if (ret < 0)
    --- a/net/ipv4/netfilter/arp_tables.c 2009-04-14 10:13:59.915167635 -0700
    +++ b/net/ipv4/netfilter/arp_tables.c 2009-04-14 14:12:30.169955949 -0700
    @@ -231,6 +231,8 @@ static inline struct arpt_entry *get_ent
    return (struct arpt_entry *)(base + offset);
    }

    +static DEFINE_PER_CPU(spinlock_t, arp_tables_lock);
    +
    unsigned int arpt_do_table(struct sk_buff *skb,
    unsigned int hook,
    const struct net_device *in,
    @@ -253,9 +255,10 @@ unsigned int arpt_do_table(struct sk_buf
    indev = in ? in->name : nulldevname;
    outdev = out ? out->name : nulldevname;

    - rcu_read_lock_bh();
    - private = rcu_dereference(table->private);
    - table_base = rcu_dereference(private->entries[smp_processor_id()]);
    + local_bh_disable();
    + spin_lock(&__get_cpu_var(arp_tables_lock));
    + private = table->private;
    + table_base = private->entries[smp_processor_id()];

    e = get_entry(table_base, private->hook_entry[hook]);
    back = get_entry(table_base, private->underflow[hook]);
    @@ -328,8 +331,8 @@ unsigned int arpt_do_table(struct sk_buf
    e = (void *)e + e->next_offset;
    }
    } while (!hotdrop);
    -
    - rcu_read_unlock_bh();
    + spin_unlock(&__get_cpu_var(arp_tables_lock));
    + local_bh_enable();

    if (hotdrop)
    return NF_DROP;
    @@ -716,74 +719,25 @@ static void get_counters(const struct xt
    curcpu = raw_smp_processor_id();

    i = 0;
    + spin_lock_bh(&per_cpu(arp_tables_lock, curcpu));
    ARPT_ENTRY_ITERATE(t->entries[curcpu],
    t->size,
    set_entry_to_counter,
    counters,
    &i);
    + spin_unlock_bh(&per_cpu(arp_tables_lock, curcpu));

    for_each_possible_cpu(cpu) {
    if (cpu == curcpu)
    continue;
    i = 0;
    + spin_lock_bh(&per_cpu(arp_tables_lock, cpu));
    ARPT_ENTRY_ITERATE(t->entries[cpu],
    t->size,
    add_entry_to_counter,
    counters,
    &i);
    - }
    -}
    -
    -
    -/* We're lazy, and add to the first CPU; overflow works its fey magic
    - * and everything is OK. */
    -static int
    -add_counter_to_entry(struct arpt_entry *e,
    - const struct xt_counters addme[],
    - unsigned int *i)
    -{
    - ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
    -
    - (*i)++;
    - return 0;
    -}
    -
    -/* Take values from counters and add them back onto the current cpu */
    -static void put_counters(struct xt_table_info *t,
    - const struct xt_counters counters[])
    -{
    - unsigned int i, cpu;
    -
    - local_bh_disable();
    - cpu = smp_processor_id();
    - i = 0;
    - ARPT_ENTRY_ITERATE(t->entries[cpu],
    - t->size,
    - add_counter_to_entry,
    - counters,
    - &i);
    - local_bh_enable();
    -}
    -
    -static inline int
    -zero_entry_counter(struct arpt_entry *e, void *arg)
    -{
    - e->counters.bcnt = 0;
    - e->counters.pcnt = 0;
    - return 0;
    -}
    -
    -static void
    -clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
    -{
    - unsigned int cpu;
    - const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
    -
    - memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
    - for_each_possible_cpu(cpu) {
    - memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
    - ARPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
    - zero_entry_counter, NULL);
    + spin_unlock_bh(&per_cpu(arp_tables_lock, cpu));
    }
    }

    @@ -792,7 +746,6 @@ static struct xt_counters *alloc_counter
    unsigned int countersize;
    struct xt_counters *counters;
    struct xt_table_info *private = table->private;
    - struct xt_table_info *info;

    /* We need atomic snapshot of counters: rest doesn't change
    * (other than comefrom, which userspace doesn't care
    @@ -804,26 +757,10 @@ static struct xt_counters *alloc_counter
    if (counters == NULL)
    goto nomem;

    - info = xt_alloc_table_info(private->size);
    - if (!info)
    - goto free_counters;
    -
    - clone_counters(info, private);
    -
    - mutex_lock(&table->lock);
    - xt_table_entry_swap_rcu(private, info);
    - synchronize_net(); /* Wait until smoke has cleared */
    -
    - get_counters(info, counters);
    - put_counters(private, counters);
    - mutex_unlock(&table->lock);
    -
    - xt_free_table_info(info);
    + get_counters(private, counters);

    return counters;

    - free_counters:
    - vfree(counters);
    nomem:
    return ERR_PTR(-ENOMEM);
    }
    @@ -1165,6 +1102,19 @@ static int do_replace(struct net *net, v
    return ret;
    }

    +/* We're lazy, and add to the first CPU; overflow works its fey magic
    + * and everything is OK. */
    +static int
    +add_counter_to_entry(struct arpt_entry *e,
    + const struct xt_counters addme[],
    + unsigned int *i)
    +{
    + ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
    +
    + (*i)++;
    + return 0;
    +}
    +
    static int do_add_counters(struct net *net, void __user *user, unsigned int len,
    int compat)
    {
    @@ -1224,25 +1174,25 @@ static int do_add_counters(struct net *n
    goto free;
    }

    - mutex_lock(&t->lock);
    private = t->private;
    if (private->number != num_counters) {
    ret = -EINVAL;
    goto unlock_up_free;
    }

    - preempt_disable();
    - i = 0;
    /* Choose the copy that is on our node */
    + local_bh_disable();
    + spin_lock(&__get_cpu_var(arp_tables_lock));
    loc_cpu_entry = private->entries[smp_processor_id()];
    + i = 0;
    ARPT_ENTRY_ITERATE(loc_cpu_entry,
    private->size,
    add_counter_to_entry,
    paddc,
    &i);
    - preempt_enable();
    + spin_unlock(&__get_cpu_var(arp_tables_lock));
    + local_bh_enable();
    unlock_up_free:
    - mutex_unlock(&t->lock);

    xt_table_unlock(t);
    module_put(t->me);
    @@ -1923,7 +1873,10 @@ static struct pernet_operations arp_tabl

    static int __init arp_tables_init(void)
    {
    - int ret;
    + int cpu, ret;
    +
    + for_each_possible_cpu(cpu)
    + spin_lock_init(&per_cpu(arp_tables_lock, cpu));

    ret = register_pernet_subsys(&arp_tables_net_ops);
    if (ret < 0)

    \
     
     \ /
      Last update: 2009-04-14 23:17    [W:0.088 / U:29.420 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site