X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fbridge%2Fbr_fdb.c;h=324489dda89a5ce9e367e91d5cc3f80118084c9d;hb=1341115471cc16954510b0e67295468f5a32b088;hp=940699997793db57f2cefdabe041cee8a94dfa88;hpb=a91482bdcc2e0f6035702e46f1b99043a0893346;p=linux-2.6.git diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index 940699997..324489dda 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c @@ -73,9 +73,9 @@ static __inline__ int br_mac_hash(const unsigned char *mac) static __inline__ void fdb_delete(struct net_bridge_fdb_entry *f) { - hlist_del_rcu(&f->hlist); + hlist_del(&f->hlist); if (!f->is_static) - list_del(&f->u.age_list); + list_del(&f->age_list); br_fdb_put(f); } @@ -85,7 +85,7 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) struct net_bridge *br = p->br; int i; - spin_lock_bh(&br->hash_lock); + write_lock_bh(&br->hash_lock); /* Search all chains since old address/hash is unknown */ for (i = 0; i < BR_HASH_SIZE; i++) { @@ -117,7 +117,7 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr) fdb_insert(br, p, newaddr, 1); - spin_unlock_bh(&br->hash_lock); + write_unlock_bh(&br->hash_lock); } void br_fdb_cleanup(unsigned long _data) @@ -126,15 +126,13 @@ void br_fdb_cleanup(unsigned long _data) struct list_head *l, *n; unsigned long delay; - spin_lock_bh(&br->hash_lock); + write_lock_bh(&br->hash_lock); delay = hold_time(br); list_for_each_safe(l, n, &br->age_list) { - struct net_bridge_fdb_entry *f; - unsigned long expires; - - f = list_entry(l, struct net_bridge_fdb_entry, u.age_list); - expires = f->ageing_timer + delay; + struct net_bridge_fdb_entry *f + = list_entry(l, struct net_bridge_fdb_entry, age_list); + unsigned long expires = f->ageing_timer + delay; if (time_before_eq(expires, jiffies)) { WARN_ON(f->is_static); @@ -146,14 +144,14 @@ void br_fdb_cleanup(unsigned long _data) break; } } - spin_unlock_bh(&br->hash_lock); + write_unlock_bh(&br->hash_lock); } void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p) { int i; - spin_lock_bh(&br->hash_lock); + write_lock_bh(&br->hash_lock); for (i = 0; i < BR_HASH_SIZE; i++) { struct hlist_node *h, *g; @@ -184,53 +182,37 @@ void br_fdb_delete_by_port(struct net_bridge *br, struct net_bridge_port *p) skip_delete: ; } } - spin_unlock_bh(&br->hash_lock); + write_unlock_bh(&br->hash_lock); } -/* No locking or refcounting, assumes caller has no preempt (rcu_read_lock) */ -struct net_bridge_fdb_entry *__br_fdb_get(struct net_bridge *br, - const unsigned char *addr) +struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, unsigned char *addr) { struct hlist_node *h; - struct net_bridge_fdb_entry *fdb; - hlist_for_each_entry_rcu(fdb, h, &br->hash[br_mac_hash(addr)], hlist) { + read_lock_bh(&br->hash_lock); + + hlist_for_each(h, &br->hash[br_mac_hash(addr)]) { + struct net_bridge_fdb_entry *fdb + = hlist_entry(h, struct net_bridge_fdb_entry, hlist); + if (!memcmp(fdb->addr.addr, addr, ETH_ALEN)) { - if (unlikely(has_expired(br, fdb))) - break; + if (has_expired(br, fdb)) + goto ret_null; + + atomic_inc(&fdb->use_count); + read_unlock_bh(&br->hash_lock); return fdb; } } - + ret_null: + read_unlock_bh(&br->hash_lock); return NULL; } -/* Interface used by ATM hook that keeps a ref count */ -struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br, - unsigned char *addr) -{ - struct net_bridge_fdb_entry *fdb; - - rcu_read_lock(); - fdb = __br_fdb_get(br, addr); - if (fdb) - atomic_inc(&fdb->use_count); - rcu_read_unlock(); - return fdb; -} - -static void fdb_rcu_free(struct rcu_head *head) -{ - struct net_bridge_fdb_entry *ent - = container_of(head, struct net_bridge_fdb_entry, u.rcu); - kmem_cache_free(br_fdb_cache, ent); -} - -/* Set entry up for deletion with RCU */ void br_fdb_put(struct net_bridge_fdb_entry *ent) { if (atomic_dec_and_test(&ent->use_count)) - call_rcu(&ent->u.rcu, fdb_rcu_free); + kmem_cache_free(br_fdb_cache, ent); } /* @@ -247,9 +229,9 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf, memset(buf, 0, maxnum*sizeof(struct __fdb_entry)); - rcu_read_lock(); + read_lock_bh(&br->hash_lock); for (i = 0; i < BR_HASH_SIZE; i++) { - hlist_for_each_entry_rcu(f, h, &br->hash[i], hlist) { + hlist_for_each_entry(f, h, &br->hash[i], hlist) { if (num >= maxnum) goto out; @@ -273,7 +255,7 @@ int br_fdb_fillbuf(struct net_bridge *br, void *buf, } out: - rcu_read_unlock(); + read_unlock_bh(&br->hash_lock); return num; } @@ -316,7 +298,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, return 0; /* move to end of age list */ - list_del(&fdb->u.age_list); + list_del(&fdb->age_list); goto update; } } @@ -327,7 +309,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, memcpy(fdb->addr.addr, addr, ETH_ALEN); atomic_set(&fdb->use_count, 1); - hlist_add_head_rcu(&fdb->hlist, &br->hash[hash]); + hlist_add_head(&fdb->hlist, &br->hash[hash]); if (!timer_pending(&br->gc_timer)) { br->gc_timer.expires = jiffies + hold_time(br); @@ -340,7 +322,7 @@ static int fdb_insert(struct net_bridge *br, struct net_bridge_port *source, fdb->is_static = is_local; fdb->ageing_timer = jiffies; if (!is_local) - list_add_tail(&fdb->u.age_list, &br->age_list); + list_add_tail(&fdb->age_list, &br->age_list); return 0; } @@ -350,8 +332,8 @@ int br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source, { int ret; - spin_lock_bh(&br->hash_lock); + write_lock_bh(&br->hash_lock); ret = fdb_insert(br, source, addr, is_local); - spin_unlock_bh(&br->hash_lock); + write_unlock_bh(&br->hash_lock); return ret; }