patch-2.3.4 linux/net/ipv4/fib_hash.c
Next file: linux/net/ipv4/fib_rules.c
Previous file: linux/net/ipv4/devinet.c
Back to the patch index
Back to the overall index
- Lines: 280
- Date:
Wed May 26 18:14:37 1999
- Orig file:
v2.3.3/linux/net/ipv4/fib_hash.c
- Orig date:
Thu Mar 25 09:23:34 1999
diff -u --recursive --new-file v2.3.3/linux/net/ipv4/fib_hash.c linux/net/ipv4/fib_hash.c
@@ -5,7 +5,7 @@
*
* IPv4 FIB: lookup engine and maintenance routines.
*
- * Version: $Id: fib_hash.c,v 1.8 1999/03/25 10:04:17 davem Exp $
+ * Version: $Id: fib_hash.c,v 1.9 1999/05/27 00:38:05 davem Exp $
*
* Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
*
@@ -145,13 +145,16 @@
return a.datum <= b.datum;
}
+static rwlock_t fib_hash_lock = RW_LOCK_UNLOCKED;
+
#define FZ_MAX_DIVISOR 1024
#ifdef CONFIG_IP_ROUTE_LARGE_TABLES
+/* The fib hash lock must be held when this is called. */
static __inline__ void fn_rebuild_zone(struct fn_zone *fz,
- struct fib_node **old_ht,
- int old_divisor)
+ struct fib_node **old_ht,
+ int old_divisor)
{
int i;
struct fib_node *f, **fp, *next;
@@ -198,13 +201,13 @@
if (ht) {
memset(ht, 0, new_divisor*sizeof(struct fib_node*));
- start_bh_atomic();
+ write_lock_bh(&fib_hash_lock);
old_ht = fz->fz_hash;
fz->fz_hash = ht;
fz->fz_hashmask = new_hashmask;
fz->fz_divisor = new_divisor;
fn_rebuild_zone(fz, old_ht, old_divisor);
- end_bh_atomic();
+ write_unlock_bh(&fib_hash_lock);
kfree(old_ht);
}
}
@@ -243,6 +246,7 @@
fz->fz_mask = inet_make_mask(z);
/* Find the first not empty zone with more specific mask */
+ write_lock_bh(&fib_hash_lock);
for (i=z+1; i<=32; i++)
if (table->fn_zones[i])
break;
@@ -255,6 +259,7 @@
table->fn_zones[i]->fz_next = fz;
}
table->fn_zones[z] = fz;
+ write_unlock_bh(&fib_hash_lock);
return fz;
}
@@ -265,6 +270,7 @@
struct fn_zone *fz;
struct fn_hash *t = (struct fn_hash*)tb->tb_data;
+ read_lock_bh(&fib_hash_lock);
for (fz = t->fn_zone_list; fz; fz = fz->fz_next) {
struct fib_node *f;
fn_key_t k = fz_key(key->dst, fz);
@@ -293,13 +299,16 @@
res->scope = f->fn_scope;
res->prefixlen = fz->fz_order;
res->prefix = &fz_prefix(f->fn_key, fz);
- return 0;
+ goto out;
}
if (err < 0)
- return err;
+ goto out;
}
}
- return 1;
+ err = 1;
+out:
+ read_unlock_bh(&fib_hash_lock);
+ return err;
}
static int fn_hash_last_dflt=-1;
@@ -344,6 +353,7 @@
last_resort = NULL;
order = -1;
+ read_lock_bh(&fib_hash_lock);
for (f = fz->fz_hash[0]; f; f = f->fn_next) {
struct fib_info *next_fi = FIB_INFO(f);
@@ -364,7 +374,7 @@
} else if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
res->fi = fi;
fn_hash_last_dflt = order;
- return;
+ goto out;
}
fi = next_fi;
order++;
@@ -372,18 +382,20 @@
if (order<=0 || fi==NULL) {
fn_hash_last_dflt = -1;
- return;
+ goto out;
}
if (!fib_detect_death(fi, order, &last_resort, &last_idx)) {
res->fi = fi;
fn_hash_last_dflt = order;
- return;
+ goto out;
}
if (last_idx >= 0)
res->fi = last_resort;
fn_hash_last_dflt = last_idx;
+out:
+ read_unlock_bh(&fib_hash_lock);
}
#define FIB_SCAN(f, fp) \
@@ -457,6 +469,8 @@
fp = fz_chain_p(key, fz);
+ write_lock_bh(&fib_hash_lock);
+
/*
* Scan list to find the first route with the same destination
*/
@@ -567,7 +581,7 @@
f = *del_fp;
/* Unlink replaced node */
*del_fp = f->fn_next;
- synchronize_bh();
+ write_unlock_bh(&fib_hash_lock);
if (!(f->fn_state&FN_S_ZOMBIE))
rtmsg_fib(RTM_DELROUTE, f, z, tb->tb_id, n, req);
@@ -576,12 +590,14 @@
fn_free_node(f);
fz->fz_nent--;
} else {
+ write_unlock_bh(&fib_hash_lock);
rt_cache_flush(-1);
}
rtmsg_fib(RTM_NEWROUTE, new_f, z, tb->tb_id, n, req);
return 0;
out:
+ write_unlock_bh(&fib_hash_lock);
fib_release_info(fi);
return err;
}
@@ -619,11 +635,15 @@
fp = fz_chain_p(key, fz);
+ write_lock_bh(&fib_hash_lock);
+
FIB_SCAN(f, fp) {
if (fn_key_eq(f->fn_key, key))
break;
- if (fn_key_leq(key, f->fn_key))
+ if (fn_key_leq(key, f->fn_key)) {
+ write_unlock_bh(&fib_hash_lock);
return -ESRCH;
+ }
}
#ifdef CONFIG_IP_ROUTE_TOS
FIB_SCAN_KEY(f, fp, key) {
@@ -637,9 +657,10 @@
FIB_SCAN_TOS(f, fp, key, tos) {
struct fib_info * fi = FIB_INFO(f);
- if (f->fn_state&FN_S_ZOMBIE)
+ if (f->fn_state&FN_S_ZOMBIE) {
+ write_unlock_bh(&fib_hash_lock);
return -ESRCH;
-
+ }
matched++;
if (del_fp == NULL &&
@@ -656,13 +677,14 @@
if (matched != 1) {
*del_fp = f->fn_next;
- synchronize_bh();
+ write_unlock_bh(&fib_hash_lock);
if (f->fn_state&FN_S_ACCESSED)
rt_cache_flush(-1);
fn_free_node(f);
fz->fz_nent--;
} else {
+ write_unlock_bh(&fib_hash_lock);
f->fn_state |= FN_S_ZOMBIE;
if (f->fn_state&FN_S_ACCESSED) {
f->fn_state &= ~FN_S_ACCESSED;
@@ -674,6 +696,7 @@
return 0;
}
+ write_unlock_bh(&fib_hash_lock);
return -ESRCH;
}
@@ -688,7 +711,6 @@
if (fi && ((f->fn_state&FN_S_ZOMBIE) || (fi->fib_flags&RTNH_F_DEAD))) {
*fp = f->fn_next;
- synchronize_bh();
fn_free_node(f);
found++;
@@ -706,6 +728,7 @@
int found = 0;
fib_hash_zombies = 0;
+ write_lock_bh(&fib_hash_lock);
for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {
int i;
int tmp = 0;
@@ -714,6 +737,7 @@
fz->fz_nent -= tmp;
found += tmp;
}
+ write_unlock_bh(&fib_hash_lock);
return found;
}
@@ -727,6 +751,7 @@
int pos = 0;
int n = 0;
+ read_lock_bh(&fib_hash_lock);
for (fz=table->fn_zone_list; fz; fz = fz->fz_next) {
int i;
struct fib_node *f;
@@ -752,10 +777,12 @@
FZ_MASK(fz), buffer);
buffer += 128;
if (++n >= count)
- return n;
+ goto out;
}
}
}
+out:
+ read_unlock_bh(&fib_hash_lock);
return n;
}
#endif
@@ -818,15 +845,18 @@
struct fn_hash *table = (struct fn_hash*)tb->tb_data;
s_m = cb->args[1];
+ read_lock_bh(&fib_hash_lock);
for (fz = table->fn_zone_list, m=0; fz; fz = fz->fz_next, m++) {
if (m < s_m) continue;
if (m > s_m)
memset(&cb->args[2], 0, sizeof(cb->args) - 2*sizeof(cb->args[0]));
if (fn_hash_dump_zone(skb, cb, tb, fz) < 0) {
cb->args[1] = m;
+ read_unlock_bh(&fib_hash_lock);
return -1;
}
}
+ read_unlock_bh(&fib_hash_lock);
cb->args[1] = m;
return skb->len;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)