Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -768,7 +768,6 @@ static int de_thread(struct task_struct *tsk)
		/*
		 * 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 @@ static int de_thread(struct task_struct *tsk)
		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));
+0 −8
Original line number Diff line number Diff line
@@ -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
+11 −10
Original line number Diff line number Diff line
@@ -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);
+1 −1
Original line number Diff line number Diff line
@@ -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)