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);
}
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++) {
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)
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);
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;
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);
}
/*
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;
}
out:
- rcu_read_unlock();
+ read_unlock_bh(&br->hash_lock);
return num;
}
return 0;
/* move to end of age list */
- list_del(&fdb->u.age_list);
+ list_del(&fdb->age_list);
goto update;
}
}
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);
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;
}
{
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;
}