vserver 1.9.5.x5
[linux-2.6.git] / net / ipv4 / netfilter / ipt_hashlimit.c
index 04c95d8..6e4d8e0 100644 (file)
@@ -97,7 +97,8 @@ struct ipt_hashlimit_htable {
        struct list_head hash[0];       /* hashtable itself */
 };
 
-DECLARE_RWLOCK(hashlimit_lock);                /* protects htables list */
+static DECLARE_RWLOCK(hashlimit_lock); /* protects htables list */
+static DECLARE_MUTEX(hlimit_mutex);    /* additional checkentry protection */
 static LIST_HEAD(hashlimit_htables);
 static kmem_cache_t *hashlimit_cachep;
 
@@ -531,10 +532,19 @@ hashlimit_checkentry(const char *tablename,
        if (!r->cfg.expire)
                return 0;
 
+       /* This is the best we've got: We cannot release and re-grab lock,
+        * since checkentry() is called before ip_tables.c grabs ipt_mutex.  
+        * We also cannot grab the hashtable spinlock, since htable_create will 
+        * call vmalloc, and that can sleep.  And we cannot just re-search
+        * the list of htable's in htable_create(), since then we would
+        * create duplicate proc files. -HW */
+       down(&hlimit_mutex);
        r->hinfo = htable_find_get(r->name);
        if (!r->hinfo && (htable_create(r) != 0)) {
+               up(&hlimit_mutex);
                return 0;
        }
+       up(&hlimit_mutex);
 
        /* Ugly hack: For SMP, we only want to use one set */
        r->u.master = r;
@@ -570,7 +580,7 @@ static void *dl_seq_start(struct seq_file *s, loff_t *pos)
        if (*pos >= htable->cfg.size)
                return NULL;
 
-       bucket = kmalloc(sizeof(unsigned int), GFP_KERNEL);
+       bucket = kmalloc(sizeof(unsigned int), GFP_ATOMIC);
        if (!bucket)
                return ERR_PTR(-ENOMEM);
 
@@ -668,11 +678,9 @@ static int init_or_fini(int fini)
                goto cleanup_nothing;
        }
 
-       /* FIXME: do we really want HWCACHE_ALIGN since our objects are
-        * quite small ? */
        hashlimit_cachep = kmem_cache_create("ipt_hashlimit",
                                            sizeof(struct dsthash_ent), 0,
-                                           SLAB_HWCACHE_ALIGN, NULL, NULL);
+                                           0, NULL, NULL);
        if (!hashlimit_cachep) {
                printk(KERN_ERR "Unable to create ipt_hashlimit slab cache\n");
                ret = -ENOMEM;