patch-2.4.22 linux-2.4.22/net/ipv4/fib_hash.c
Next file: linux-2.4.22/net/ipv4/fib_semantics.c
Previous file: linux-2.4.22/net/ipv4/fib_frontend.c
Back to the patch index
Back to the overall index
- Lines: 125
- Date:
2003-08-25 04:44:44.000000000 -0700
- Orig file:
linux-2.4.21/net/ipv4/fib_hash.c
- Orig date:
2001-12-21 09:42:05.000000000 -0800
diff -urN linux-2.4.21/net/ipv4/fib_hash.c linux-2.4.22/net/ipv4/fib_hash.c
@@ -89,7 +89,7 @@
int fz_nent; /* Number of entries */
int fz_divisor; /* Hash divisor */
- u32 fz_hashmask; /* (1<<fz_divisor) - 1 */
+ u32 fz_hashmask; /* (fz_divisor - 1) */
#define FZ_HASHMASK(fz) ((fz)->fz_hashmask)
int fz_order; /* Zone order */
@@ -149,9 +149,19 @@
static rwlock_t fib_hash_lock = RW_LOCK_UNLOCKED;
-#define FZ_MAX_DIVISOR 1024
+#define FZ_MAX_DIVISOR ((PAGE_SIZE<<MAX_ORDER) / sizeof(struct fib_node *))
-#ifdef CONFIG_IP_ROUTE_LARGE_TABLES
+static struct fib_node **fz_hash_alloc(int divisor)
+{
+ unsigned long size = divisor * sizeof(struct fib_node *);
+
+ if (divisor <= 1024) {
+ return kmalloc(size, GFP_KERNEL);
+ } else {
+ return (struct fib_node **)
+ __get_free_pages(GFP_KERNEL, get_order(size));
+ }
+}
/* The fib hash lock must be held when this is called. */
static __inline__ void fn_rebuild_zone(struct fn_zone *fz,
@@ -174,6 +184,15 @@
}
}
+static void fz_hash_free(struct fib_node **hash, int divisor)
+{
+ if (divisor <= 1024)
+ kfree(hash);
+ else
+ free_pages((unsigned long) hash,
+ get_order(divisor * sizeof(struct fib_node *)));
+}
+
static void fn_rehash_zone(struct fn_zone *fz)
{
struct fib_node **ht, **old_ht;
@@ -185,24 +204,30 @@
switch (old_divisor) {
case 16:
new_divisor = 256;
- new_hashmask = 0xFF;
break;
case 256:
new_divisor = 1024;
- new_hashmask = 0x3FF;
break;
default:
- printk(KERN_CRIT "route.c: bad divisor %d!\n", old_divisor);
- return;
+ if ((old_divisor << 1) > FZ_MAX_DIVISOR) {
+ printk(KERN_CRIT "route.c: bad divisor %d!\n", old_divisor);
+ return;
+ }
+ new_divisor = (old_divisor << 1);
+ break;
}
+
+ new_hashmask = (new_divisor - 1);
+
#if RT_CACHE_DEBUG >= 2
printk("fn_rehash_zone: hash for zone %d grows from %d\n", fz->fz_order, old_divisor);
#endif
- ht = kmalloc(new_divisor*sizeof(struct fib_node*), GFP_KERNEL);
+ ht = fz_hash_alloc(new_divisor);
if (ht) {
memset(ht, 0, new_divisor*sizeof(struct fib_node*));
+
write_lock_bh(&fib_hash_lock);
old_ht = fz->fz_hash;
fz->fz_hash = ht;
@@ -210,10 +235,10 @@
fz->fz_divisor = new_divisor;
fn_rebuild_zone(fz, old_ht, old_divisor);
write_unlock_bh(&fib_hash_lock);
- kfree(old_ht);
+
+ fz_hash_free(old_ht, old_divisor);
}
}
-#endif /* CONFIG_IP_ROUTE_LARGE_TABLES */
static void fn_free_node(struct fib_node * f)
{
@@ -233,12 +258,11 @@
memset(fz, 0, sizeof(struct fn_zone));
if (z) {
fz->fz_divisor = 16;
- fz->fz_hashmask = 0xF;
} else {
fz->fz_divisor = 1;
- fz->fz_hashmask = 0;
}
- fz->fz_hash = kmalloc(fz->fz_divisor*sizeof(struct fib_node*), GFP_KERNEL);
+ fz->fz_hashmask = (fz->fz_divisor - 1);
+ fz->fz_hash = fz_hash_alloc(fz->fz_divisor);
if (!fz->fz_hash) {
kfree(fz);
return NULL;
@@ -467,12 +491,10 @@
if ((fi = fib_create_info(r, rta, n, &err)) == NULL)
return err;
-#ifdef CONFIG_IP_ROUTE_LARGE_TABLES
- if (fz->fz_nent > (fz->fz_divisor<<2) &&
+ if (fz->fz_nent > (fz->fz_divisor<<1) &&
fz->fz_divisor < FZ_MAX_DIVISOR &&
(z==32 || (1<<z) > fz->fz_divisor))
fn_rehash_zone(fz);
-#endif
fp = fz_chain_p(key, fz);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)