minor kthread/signals cleanups and fix
Subsystems (6)
cover minor kthread/signals cleanups and fix
On top of signals-kill-block_all_signals-and-unblock_all_signals.patch
Simple but untested, hopefully maintainers can ack or nack 1/3 at least.
Oleg.
drivers/block/nbd.c | 9 ++------- drivers/usb/gadget/function/f_mass_storage.c | 4 +--- fs/jffs2/background.c | 7 ++----- include/linux/sched.h | 21 ++++++++++++++++----- 4 files changed, 21 insertions(+), 20 deletions(-)
PATCH 1/3 signal: turn dequeue_signal_lock() into kernel_dequeue_signal()
1. Rename dequeue_signal_lock() to kernel_dequeue_signal(). This matches another "for kthreads only" kernel_sigaction() helper.
2. Remove the "tsk" and "mask" arguments, they are always current and current->blocked. And it is simply wrong if tsk != current.
3. We could also remove the 3rd "siginfo_t *info" arg but it looks potentially useful. However we can simplify the callers if we change kernel_dequeue_signal() to accept info => NULL.
4. Remove _irqsave, it is never called from atomic context.
--- drivers/block/nbd.c | 9 ++------- drivers/usb/gadget/function/f_mass_storage.c | 4 +--- fs/jffs2/background.c | 3 +-- include/linux/sched.h | 11 ++++++----- 4 files changed, 10 insertions(+), 17 deletions(-)
drivers/block/nbd.c +2 -7
@@ -432,9 +432,7 @@ static int nbd_thread_recv(struct nbd_device *nbd) nbd->task_recv =NULL ;if (signal_pending (current)) { -siginfo_t info; - - ret =dequeue_signal_lock (current, ¤t->blocked, &info); + ret =kernel_dequeue_signal (NULL );dev_warn (nbd_to_dev (nbd),"pid %d, %s, got signal %d\n" ,task_pid_nr (current), current->comm, ret);mutex_lock (&nbd->tx_lock);
@@ -545,11 +543,8 @@ static int nbd_thread_send(void *data) !list_empty(&nbd->waiting_queue));if (signal_pending (current)) { -siginfo_t info; -int ret; +int ret =kernel_dequeue_signal (NULL ); - ret =dequeue_signal_lock (current, ¤t->blocked, - &info);dev_warn (nbd_to_dev (nbd),"pid %d, %s, got signal %d\n" ,task_pid_nr (current), current->comm, ret);mutex_lock (&nbd->tx_lock);
drivers/usb/gadget/function/f_mass_storage.c +1 -3
@@ -2347,7 +2347,6 @@ static void fsg_disable(struct usb_function *f)static void handle_exception (struct fsg_common *common) { -siginfo_t info;int i;struct fsg_buffhd *bh;enum fsg_state old_state;
@@ -2359,8 +2358,7 @@ static void handle_exception(struct fsg_common *common)* into a high-priority EXIT exception. */ for (;;) { -int sig = -dequeue_signal_lock (current, ¤t->blocked, &info); +int sig =kernel_dequeue_signal (NULL );if (!sig)break ;if (sig !=SIGUSR1 ) {
fs/jffs2/background.c +1 -2
@@ -121,13 +121,12 @@ static int jffs2_garbage_collect_thread(void *_c)/* Put_super will send a SIGKILL and then wait on the sem. */ while (signal_pending (current) ||freezing (current)) { -siginfo_t info;unsigned long signr;if (try_to_freeze ()) goto again; - signr =dequeue_signal_lock (current, ¤t->blocked, &info); + signr =kernel_dequeue_signal (NULL );switch (signr) {case SIGSTOP :
include/linux/sched.h +6 -5
@@ -2464,14 +2464,15 @@ extern void ignore_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) +static inline int kernel_dequeue_signal (siginfo_t *info) { -unsigned long flags; +struct task_struct *tsk = current; +siginfo_t __info;int ret; -spin_lock_irqsave (&tsk->sighand->siglock, flags); - ret =dequeue_signal (tsk, mask, info); -spin_unlock_irqrestore (&tsk->sighand->siglock, flags); +spin_lock_irq (&tsk->sighand->siglock); + ret =dequeue_signal (tsk, &tsk->blocked, info ?: &__info); +spin_unlock_irq (&tsk->sighand->siglock);return ret; }
Signature · 1 line
2.4.3
Re: [PATCH 1/3] signal: turn dequeue_signal_lock() into kernel_dequeue_signal()
Quoted 6 lines · Oleg Nesterov
1. Rename
dequeue_signal_lock()tokernel_dequeue_signal(). This matches another "for kthreads only"kernel_sigaction()helper.2. Remove the "tsk" and "mask" arguments, they are always current and
current->blocked. And it is simply wrong if tsk != current.
Quoted 7 lines
3. We could also remove the 3rd "
siginfo_t*info" arg but it looks potentially useful. However we can simplify the callers if we changekernel_dequeue_signal()to accept info => NULL.4. Remove
_irqsave, it is never called from atomic context.Signed-off-by Oleg Nesterov <[email protected]>
FWIW, looks good to me.
Thanks.
Signature · 1 line
tejun
PATCH 1/1 signal-turn-dequeue_signal_lock-into-kernel_dequeue_signal-fix
In reply to Oleg NesterovAndrew,
As Markus reports (thanks!)
signal-turn-dequeue_signal_lock-into-kernel_dequeue_signal.patch
conflicts with the recent change in Linus' tree,
Quoted 7 lines
I just realised that this patch will conflict with a fixup patch for nbd that will be included in rc7.
dcc909d90ccd(nbd: Add locking for tasks)I think there is basically one new instance of
dequeue_signal_lock()that needs to be replaced withkernel_dequeue_signal().
Unless I missed something, this new dequeue_signal_lock() should simply die, but lets fix the conflict first.
drivers/block/nbd.c +2 -4
@@ -592,10 +592,8 @@ static int nbd_thread_send(void *data)spin_unlock_irqrestore (&nbd->tasks_lock, flags);/* Clear maybe pending signals */ -if (signal_pending (current)) { -siginfo_t info; -dequeue_signal_lock (current, ¤t->blocked, &info); - } +if (signal_pending (current)) +kernel_dequeue_signal (NULL );return 0 ; }
PATCH 2/3 signal: introduce kernel_signal_stop() to fix jffs2_garbage_collect_thread()
In reply to Oleg Nesterovjffs2_garbage_collect_thread() can race with SIGCONT and sleep in TASK_STOPPED state after it was already sent. Add the new helper, kernel_signal_stop(), which does this correctly.
--- fs/jffs2/background.c | 3 +-- include/linux/sched.h | 10 ++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-)
fs/jffs2/background.c +1 -2
@@ -132,8 +132,7 @@ static int jffs2_garbage_collect_thread(void *_c)case SIGSTOP :jffs2_dbg (1 ,"%s(): SIGSTOP received\n" , __func__); -set_current_state (TASK_STOPPED ); -schedule (); +kernel_signal_stop ();break ;case SIGKILL :
include/linux/sched.h +10 -0
@@ -2477,6 +2477,16 @@ static inline int kernel_dequeue_signal(siginfo_t *info)return ret; } +static inline void kernel_signal_stop (void ) +{ +spin_lock_irq (¤t->sighand->siglock); +if (current->jobctl &JOBCTL_STOP_DEQUEUED ) +__set_current_state (TASK_STOPPED ); +spin_unlock_irq (¤t->sighand->siglock); + +schedule (); +} +extern void release_task (struct task_struct * p);extern int send_sig_info (int ,struct siginfo *,struct task_struct *);extern int force_sigsegv (int ,struct task_struct *);
Signature · 1 line
2.4.3
Re: [PATCH 2/3] signal: introduce kernel_signal_stop() to fix jffs2_garbage_collect_thread()
Quoted 5 lines · Oleg Nesterov
jffs2_garbage_collect_thread()can race with SIGCONT and sleep inTASK_STOPPEDstate after it was already sent. Add the new helper,kernel_signal_stop(), which does this correctly.Signed-off-by Oleg Nesterov <[email protected]>
Thanks.
Signature · 1 line
tejun
PATCH 3/3 signal: remove jffs2_garbage_collect_thread()->allow_signal(SIGCONT)
In reply to Oleg Nesterovjffs2_garbage_collect_thread() does allow_signal(SIGCONT) for no reason, SIGCONT will wake a stopped task up even if it is ignored.
--- fs/jffs2/background.c | 1 - 1 file changed, 1 deletion(-)
fs/jffs2/background.c +0 -1
@@ -80,7 +80,6 @@ static int jffs2_garbage_collect_thread(void *_c)siginitset (&hupmask,sigmask (SIGHUP ));allow_signal (SIGKILL );allow_signal (SIGSTOP ); -allow_signal (SIGCONT );allow_signal (SIGHUP ); c->gc_task = current;
Signature · 1 line
2.4.3
Re: [PATCH 3/3] signal: remove jffs2_garbage_collect_thread()->allow_signal(SIGCONT)
Quoted 4 lines · Oleg Nesterov
jffs2_garbage_collect_thread()doesallow_signal(SIGCONT)for no reason, SIGCONT will wake a stopped task up even if it is ignored.Signed-off-by Oleg Nesterov <[email protected]>
Thanks.
Signature · 1 line
tejun