Commit 7bc9020b authored by David Woodhouse's avatar David Woodhouse Committed by Linus Torvalds

[PATCH] Kernel thread signal handling.

 - add disallow_signal() to complement allow_signal(), rather than
   having different subsystems try to do it by hand.

 - add a version of dequeue_signal() which does the necessary locking on
   its own, again to avoid having modules have to care.

 - let allow_signal() to actually allow signals other than
   SIGKILL. Currently they get either converted to SIGKILL or
   silently dropped, according to whether your kernel thread
   happens to have sa_handler set for the signal in question.

   (Barf alert: we do this by just installing a dummy handler)

 - make jffs2 use the cleaned up infrastructure
parent 6ab5c9ad
......@@ -19,6 +19,7 @@
#include <linux/completion.h>
#include <linux/sched.h>
#include <linux/unistd.h>
#include <linux/suspend.h>
#include "nodelist.h"
......@@ -75,6 +76,9 @@ static int jffs2_garbage_collect_thread(void *_c)
struct jffs2_sb_info *c = _c;
daemonize("jffs2_gcd_mtd%d", c->mtd->index);
allow_signal(SIGKILL);
allow_signal(SIGSTOP);
allow_signal(SIGCONT);
c->gc_task = current;
up(&c->gc_thread_start);
......@@ -82,10 +86,7 @@ static int jffs2_garbage_collect_thread(void *_c)
set_user_nice(current, 10);
for (;;) {
spin_lock_irq(&current_sig_lock);
siginitsetinv (&current->blocked, sigmask(SIGHUP) | sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
recalc_sigpending();
spin_unlock_irq(&current_sig_lock);
allow_signal(SIGHUP);
if (!thread_should_wake(c)) {
set_current_state (TASK_INTERRUPTIBLE);
......@@ -97,6 +98,13 @@ static int jffs2_garbage_collect_thread(void *_c)
schedule();
}
if (current->flags & PF_FREEZE) {
refrigerator(0);
/* refrigerator() should recalc sigpending for us
but doesn't. No matter - allow_signal() will. */
continue;
}
cond_resched();
/* Put_super will send a SIGKILL and then wait on the sem.
......@@ -105,9 +113,7 @@ static int jffs2_garbage_collect_thread(void *_c)
siginfo_t info;
unsigned long signr;
spin_lock_irq(&current_sig_lock);
signr = dequeue_signal(current, &current->blocked, &info);
spin_unlock_irq(&current_sig_lock);
signr = dequeue_signal_lock(current, &current->blocked, &info);
switch(signr) {
case SIGSTOP:
......@@ -132,10 +138,7 @@ static int jffs2_garbage_collect_thread(void *_c)
}
}
/* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
spin_lock_irq(&current_sig_lock);
siginitsetinv (&current->blocked, sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGCONT));
recalc_sigpending();
spin_unlock_irq(&current_sig_lock);
disallow_signal(SIGHUP);
D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): pass\n"));
if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
......
......@@ -576,6 +576,19 @@ extern void proc_caches_init(void);
extern void flush_signals(struct task_struct *);
extern void flush_signal_handlers(struct task_struct *, int force_default);
extern int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info);
static inline int dequeue_signal_lock(struct task_struct *tsk, sigset_t *mask, siginfo_t *info)
{
unsigned long flags;
int ret;
spin_lock_irqsave(&tsk->sighand->siglock, flags);
ret = dequeue_signal(tsk, mask, info);
spin_unlock_irqrestore(&tsk->sighand->siglock, flags);
return ret;
}
extern void block_all_signals(int (*notifier)(void *priv), void *priv,
sigset_t *mask);
extern void unblock_all_signals(void);
......@@ -673,6 +686,7 @@ extern NORET_TYPE void do_group_exit(int);
extern void reparent_to_init(void);
extern void daemonize(const char *, ...);
extern int allow_signal(int);
extern int disallow_signal(int);
extern task_t *child_reaper;
extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *);
......
......@@ -273,6 +273,13 @@ int allow_signal(int sig)
spin_lock_irq(&current->sighand->siglock);
sigdelset(&current->blocked, sig);
if (!current->mm) {
/* Kernel threads handle their own signals.
Let the signal code know it'll be handled, so
that they don't get converted to SIGKILL or
just silently dropped */
current->sighand->action[(sig)-1].sa.sa_handler = (void *)2;
}
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
return 0;
......@@ -280,6 +287,20 @@ int allow_signal(int sig)
EXPORT_SYMBOL(allow_signal);
int disallow_signal(int sig)
{
if (sig < 1 || sig > _NSIG)
return -EINVAL;
spin_lock_irq(&current->sighand->siglock);
sigaddset(&current->blocked, sig);
recalc_sigpending();
spin_unlock_irq(&current->sighand->siglock);
return 0;
}
EXPORT_SYMBOL(disallow_signal);
/*
* Put all the gunge required to become a kernel thread without
* attached user resources in one place where it belongs.
......
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