[PATCH] convert sighand_cache to use SLAB_DESTROY_BY_RCU
authorOleg Nesterov <oleg@tv-sign.ru>
Wed, 29 Mar 2006 00:11:12 +0000 (16:11 -0800)
committerLinus Torvalds <torvalds@g5.osdl.org>
Wed, 29 Mar 2006 02:36:42 +0000 (18:36 -0800)
This patch borrows a clever Hugh's 'struct anon_vma' trick.

Without tasklist_lock held we can't trust task->sighand until we locked it
and re-checked that it is still the same.

But this means we don't need to defer 'kmem_cache_free(sighand)'.  We can
return the memory to slab immediately, all we need is to be sure that
sighand->siglock can't dissapear inside rcu protected section.

To do so we need to initialize ->siglock inside ctor function,
SLAB_DESTROY_BY_RCU does the rest.

Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
fs/exec.c
include/linux/sched.h
kernel/fork.c
kernel/signal.c

index 9046ad2b061411ef8bbbab4cff13592ca84fbc74..950ebd43cdc35dd2503214db36289dddb5f26250 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -768,7 +768,6 @@ no_thread_group:
                /*
                 * Move our state over to newsighand and switch it in.
                 */
-               spin_lock_init(&newsighand->siglock);
                atomic_set(&newsighand->count, 1);
                memcpy(newsighand->action, oldsighand->action,
                       sizeof(newsighand->action));
@@ -785,7 +784,7 @@ no_thread_group:
                write_unlock_irq(&tasklist_lock);
 
                if (atomic_dec_and_test(&oldsighand->count))
-                       sighand_free(oldsighand);
+                       kmem_cache_free(sighand_cachep, oldsighand);
        }
 
        BUG_ON(!thread_group_leader(current));
index ddc0df7f8bf5cdf8130a40899ce19d02ef76c26a..bbcfc873bd98414f1d61cb38d550838c20535361 100644 (file)
@@ -355,16 +355,8 @@ struct sighand_struct {
        atomic_t                count;
        struct k_sigaction      action[_NSIG];
        spinlock_t              siglock;
-       struct rcu_head         rcu;
 };
 
-extern void sighand_free_cb(struct rcu_head *rhp);
-
-static inline void sighand_free(struct sighand_struct *sp)
-{
-       call_rcu(&sp->rcu, sighand_free_cb);
-}
-
 /*
  * NOTE! "signal_struct" does not have it's own
  * locking, because a shared signal_struct always
index 0c32e28cdc5f1e0748b500a16b19b5b693f427f9..33ffb5bf0dbc6092ed1ad5bae1c5b46289026efd 100644 (file)
@@ -786,14 +786,6 @@ int unshare_files(void)
 
 EXPORT_SYMBOL(unshare_files);
 
-void sighand_free_cb(struct rcu_head *rhp)
-{
-       struct sighand_struct *sp;
-
-       sp = container_of(rhp, struct sighand_struct, rcu);
-       kmem_cache_free(sighand_cachep, sp);
-}
-
 static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk)
 {
        struct sighand_struct *sig;
@@ -806,7 +798,6 @@ static inline int copy_sighand(unsigned long clone_flags, struct task_struct * t
        rcu_assign_pointer(tsk->sighand, sig);
        if (!sig)
                return -ENOMEM;
-       spin_lock_init(&sig->siglock);
        atomic_set(&sig->count, 1);
        memcpy(sig->action, current->sighand->action, sizeof(sig->action));
        return 0;
@@ -1356,11 +1347,21 @@ long do_fork(unsigned long clone_flags,
 #define ARCH_MIN_MMSTRUCT_ALIGN 0
 #endif
 
+static void sighand_ctor(void *data, kmem_cache_t *cachep, unsigned long flags)
+{
+       struct sighand_struct *sighand = data;
+
+       if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+                                       SLAB_CTOR_CONSTRUCTOR)
+               spin_lock_init(&sighand->siglock);
+}
+
 void __init proc_caches_init(void)
 {
        sighand_cachep = kmem_cache_create("sighand_cache",
                        sizeof(struct sighand_struct), 0,
-                       SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
+                       SLAB_HWCACHE_ALIGN|SLAB_PANIC|SLAB_DESTROY_BY_RCU,
+                       sighand_ctor, NULL);
        signal_cachep = kmem_cache_create("signal_cache",
                        sizeof(struct signal_struct), 0,
                        SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
index dc8f91bf9f8970d00eeb73d9a4c49082fe7b8d91..b0b1ca9daa336cfd6b015d57182f06ae93e50e04 100644 (file)
@@ -330,7 +330,7 @@ void __exit_sighand(struct task_struct *tsk)
        /* Ok, we're done with the signal handlers */
        tsk->sighand = NULL;
        if (atomic_dec_and_test(&sighand->count))
-               sighand_free(sighand);
+               kmem_cache_free(sighand_cachep, sighand);
 }
 
 void exit_sighand(struct task_struct *tsk)