Commit aa1757f9 authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Linus Torvalds

[PATCH] convert sighand_cache to use SLAB_DESTROY_BY_RCU

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: default avatarOleg Nesterov <oleg@tv-sign.ru>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 1f09f974
...@@ -768,7 +768,6 @@ static int de_thread(struct task_struct *tsk) ...@@ -768,7 +768,6 @@ static int de_thread(struct task_struct *tsk)
/* /*
* Move our state over to newsighand and switch it in. * Move our state over to newsighand and switch it in.
*/ */
spin_lock_init(&newsighand->siglock);
atomic_set(&newsighand->count, 1); atomic_set(&newsighand->count, 1);
memcpy(newsighand->action, oldsighand->action, memcpy(newsighand->action, oldsighand->action,
sizeof(newsighand->action)); sizeof(newsighand->action));
...@@ -785,7 +784,7 @@ static int de_thread(struct task_struct *tsk) ...@@ -785,7 +784,7 @@ static int de_thread(struct task_struct *tsk)
write_unlock_irq(&tasklist_lock); write_unlock_irq(&tasklist_lock);
if (atomic_dec_and_test(&oldsighand->count)) if (atomic_dec_and_test(&oldsighand->count))
sighand_free(oldsighand); kmem_cache_free(sighand_cachep, oldsighand);
} }
BUG_ON(!thread_group_leader(current)); BUG_ON(!thread_group_leader(current));
......
...@@ -355,16 +355,8 @@ struct sighand_struct { ...@@ -355,16 +355,8 @@ struct sighand_struct {
atomic_t count; atomic_t count;
struct k_sigaction action[_NSIG]; struct k_sigaction action[_NSIG];
spinlock_t siglock; 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 * NOTE! "signal_struct" does not have it's own
* locking, because a shared signal_struct always * locking, because a shared signal_struct always
......
...@@ -786,14 +786,6 @@ int unshare_files(void) ...@@ -786,14 +786,6 @@ int unshare_files(void)
EXPORT_SYMBOL(unshare_files); 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) static inline int copy_sighand(unsigned long clone_flags, struct task_struct * tsk)
{ {
struct sighand_struct *sig; struct sighand_struct *sig;
...@@ -806,7 +798,6 @@ static inline int copy_sighand(unsigned long clone_flags, struct task_struct * t ...@@ -806,7 +798,6 @@ static inline int copy_sighand(unsigned long clone_flags, struct task_struct * t
rcu_assign_pointer(tsk->sighand, sig); rcu_assign_pointer(tsk->sighand, sig);
if (!sig) if (!sig)
return -ENOMEM; return -ENOMEM;
spin_lock_init(&sig->siglock);
atomic_set(&sig->count, 1); atomic_set(&sig->count, 1);
memcpy(sig->action, current->sighand->action, sizeof(sig->action)); memcpy(sig->action, current->sighand->action, sizeof(sig->action));
return 0; return 0;
...@@ -1356,11 +1347,21 @@ long do_fork(unsigned long clone_flags, ...@@ -1356,11 +1347,21 @@ long do_fork(unsigned long clone_flags,
#define ARCH_MIN_MMSTRUCT_ALIGN 0 #define ARCH_MIN_MMSTRUCT_ALIGN 0
#endif #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) void __init proc_caches_init(void)
{ {
sighand_cachep = kmem_cache_create("sighand_cache", sighand_cachep = kmem_cache_create("sighand_cache",
sizeof(struct sighand_struct), 0, 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", signal_cachep = kmem_cache_create("signal_cache",
sizeof(struct signal_struct), 0, sizeof(struct signal_struct), 0,
SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL);
......
...@@ -330,7 +330,7 @@ void __exit_sighand(struct task_struct *tsk) ...@@ -330,7 +330,7 @@ void __exit_sighand(struct task_struct *tsk)
/* Ok, we're done with the signal handlers */ /* Ok, we're done with the signal handlers */
tsk->sighand = NULL; tsk->sighand = NULL;
if (atomic_dec_and_test(&sighand->count)) if (atomic_dec_and_test(&sighand->count))
sighand_free(sighand); kmem_cache_free(sighand_cachep, sighand);
} }
void exit_sighand(struct task_struct *tsk) void exit_sighand(struct task_struct *tsk)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment