X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=net%2Fipv4%2Fnetfilter%2Fipt_hashlimit.c;h=6e4d8e0e65d5d84993d6cb4e804ecca02c80ba24;hb=6a77f38946aaee1cd85eeec6cf4229b204c15071;hp=04c95d874886802a6f7e35191dea14ede6f537fd;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/net/ipv4/netfilter/ipt_hashlimit.c b/net/ipv4/netfilter/ipt_hashlimit.c index 04c95d874..6e4d8e0e6 100644 --- a/net/ipv4/netfilter/ipt_hashlimit.c +++ b/net/ipv4/netfilter/ipt_hashlimit.c @@ -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;