Patch from Stephen Hemminger Replace brlock in netfilter code with RCU. 25-akpm/net/core/netfilter.c | 51 ++++++++++++++++++++++++++----------------- 1 files changed, 31 insertions(+), 20 deletions(-) diff -puN net/core/netfilter.c~brlock-5 net/core/netfilter.c --- 25/net/core/netfilter.c~brlock-5 Tue Mar 11 16:59:47 2003 +++ 25-akpm/net/core/netfilter.c Tue Mar 11 16:59:47 2003 @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -46,6 +45,7 @@ static DECLARE_MUTEX(nf_sockopt_mutex); struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]; static LIST_HEAD(nf_sockopts); +static spinlock_t nf_lock = SPIN_LOCK_UNLOCKED; /* * A queue handler may be registered for each protocol. Each is protected by @@ -56,28 +56,31 @@ static struct nf_queue_handler_t { nf_queue_outfn_t outfn; void *data; } queue_handler[NPROTO]; +static spinlock_t queue_lock = SPIN_LOCK_UNLOCKED; int nf_register_hook(struct nf_hook_ops *reg) { struct list_head *i; - br_write_lock_bh(BR_NETPROTO_LOCK); + spin_lock_bh(&nf_lock); for (i = nf_hooks[reg->pf][reg->hooknum].next; i != &nf_hooks[reg->pf][reg->hooknum]; i = i->next) { if (reg->priority < ((struct nf_hook_ops *)i)->priority) break; } - list_add(®->list, i->prev); - br_write_unlock_bh(BR_NETPROTO_LOCK); + list_add_rcu(®->list, i->prev); + spin_unlock_bh(&nf_lock); return 0; } void nf_unregister_hook(struct nf_hook_ops *reg) { - br_write_lock_bh(BR_NETPROTO_LOCK); + spin_lock_bh(&nf_lock); list_del(®->list); - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_unlock_bh(&nf_lock); + + synchronize_kernel(); } /* Do exclusive ranges overlap? */ @@ -344,7 +347,9 @@ static unsigned int nf_iterate(struct li int (*okfn)(struct sk_buff *), int hook_thresh) { - for (*i = (*i)->next; *i != head; *i = (*i)->next) { + + for (*i = (*i)->next; *i != head; *i = (*i)->next, + ({ read_barrier_depends(); 0;})) { struct nf_hook_ops *elem = (struct nf_hook_ops *)*i; if (hook_thresh > elem->priority) @@ -381,15 +386,16 @@ int nf_register_queue_handler(int pf, nf { int ret; - br_write_lock_bh(BR_NETPROTO_LOCK); + spin_lock_bh(&queue_lock); if (queue_handler[pf].outfn) ret = -EBUSY; else { - queue_handler[pf].outfn = outfn; queue_handler[pf].data = data; + wmb(); + queue_handler[pf].outfn = outfn; ret = 0; } - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_unlock_bh(&queue_lock); return ret; } @@ -397,10 +403,14 @@ int nf_register_queue_handler(int pf, nf /* The caller must flush their queue before this */ int nf_unregister_queue_handler(int pf) { - br_write_lock_bh(BR_NETPROTO_LOCK); + spin_lock_bh(&queue_lock); queue_handler[pf].outfn = NULL; + wmb(); queue_handler[pf].data = NULL; - br_write_unlock_bh(BR_NETPROTO_LOCK); + spin_unlock_bh(&queue_lock); + + synchronize_kernel(); + return 0; } @@ -422,9 +432,10 @@ static void nf_queue(struct sk_buff *skb struct net_device *physoutdev = NULL; #endif + rcu_read_lock(); if (!queue_handler[pf].outfn) { kfree_skb(skb); - return; + goto out; } info = kmalloc(sizeof(*info), GFP_ATOMIC); @@ -433,7 +444,7 @@ static void nf_queue(struct sk_buff *skb printk(KERN_ERR "OOM queueing packet %p\n", skb); kfree_skb(skb); - return; + goto out; } *info = (struct nf_info) { @@ -463,8 +474,9 @@ static void nf_queue(struct sk_buff *skb #endif kfree(info); kfree_skb(skb); - return; } + out: + rcu_read_unlock(); } int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb, @@ -491,7 +503,7 @@ int nf_hook_slow(int pf, unsigned int ho } /* We may already have this, but read-locks nest anyway */ - br_read_lock_bh(BR_NETPROTO_LOCK); + rcu_read_lock(); #ifdef CONFIG_NETFILTER_DEBUG if (skb->nf_debug & (1 << hook)) { @@ -520,7 +532,7 @@ int nf_hook_slow(int pf, unsigned int ho break; } - br_read_unlock_bh(BR_NETPROTO_LOCK); + rcu_read_unlock(); return ret; } @@ -530,8 +542,7 @@ void nf_reinject(struct sk_buff *skb, st struct list_head *elem = &info->elem->list; struct list_head *i; - /* We don't have BR_NETPROTO_LOCK here */ - br_read_lock_bh(BR_NETPROTO_LOCK); + rcu_read_lock(); for (i = nf_hooks[info->pf][info->hook].next; i != elem; i = i->next) { if (i == &nf_hooks[info->pf][info->hook]) { /* The module which sent it to userspace is gone. */ @@ -569,7 +580,7 @@ void nf_reinject(struct sk_buff *skb, st kfree_skb(skb); break; } - br_read_unlock_bh(BR_NETPROTO_LOCK); + rcu_read_unlock(); /* Release those devices we held, or Alexey will kill me. */ if (info->indev) dev_put(info->indev); _