Skip to contentSkip to conversation

minor kthread/signals cleanups and fix

PATCH In review Oleg Nesterov 2 participants 8 messages Oct 3, 2015 – Oct 25, 2015

Subsystems (6)
lore
Share & tools
lore
#0 lore raw

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(-)
#1 lore raw

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
index 293495a..214de17 100644
@@ -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, &current->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, &current->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
index a6eb537..9d1e3b3 100644
@@ -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, &current->blocked, &info);
+		int sig = kernel_dequeue_signal(NULL);
 		if (!sig)
 			break;
 		if (sig != SIGUSR1) {
fs/jffs2/background.c +1 -2
index bb9cebc..f3145fd 100644
@@ -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, &current->blocked, &info);
+			signr = kernel_dequeue_signal(NULL);
 
 			switch(signr) {
 			case SIGSTOP:
include/linux/sched.h +6 -5
index 8c3fa80..e714539 100644
@@ -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
Reviewed-by on v1 1/3
#2 lore raw

Re: [PATCH 1/3] signal: turn dequeue_signal_lock() into kernel_dequeue_signal()

Quoted 6 lines · Oleg Nesterov

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.

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 change kernel_dequeue_signal() to accept info => NULL.

4. Remove _irqsave, it is never called from atomic context.

FWIW, looks good to me.

Thanks.

Signature · 1 line
tejun
#3 lore raw

PATCH 1/1 signal-turn-dequeue_signal_lock-into-kernel_dequeue_signal-fix

In reply to Oleg Nesterov

Andrew,

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 with kernel_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, &current->blocked, &info);
-	}
+	if (signal_pending(current))
+		kernel_dequeue_signal(NULL);
 
 	return 0;
 }
#4 lore raw

PATCH 2/3 signal: introduce kernel_signal_stop() to fix jffs2_garbage_collect_thread()

In reply to Oleg Nesterov

jffs2_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
index f3145fd..53cc735 100644
@@ -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
index e714539..56e688c 100644
@@ -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(&current->sighand->siglock);
+	if (current->jobctl & JOBCTL_STOP_DEQUEUED)
+		__set_current_state(TASK_STOPPED);
+	spin_unlock_irq(&current->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
Reviewed-by on v1 2/3
#5 lore raw

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 in TASK_STOPPED state after it was already sent. Add the new helper, kernel_signal_stop(), which does this correctly.

Thanks.

Signature · 1 line
tejun
#6 lore raw

PATCH 3/3 signal: remove jffs2_garbage_collect_thread()->allow_signal(SIGCONT)

In reply to Oleg Nesterov

jffs2_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
index 53cc735..e5c1783 100644
@@ -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
Reviewed-by on v1 3/3
#7 lore raw

Re: [PATCH 3/3] signal: remove jffs2_garbage_collect_thread()->allow_signal(SIGCONT)

Quoted 4 lines · Oleg Nesterov

jffs2_garbage_collect_thread() does allow_signal(SIGCONT) for no reason, SIGCONT will wake a stopped task up even if it is ignored.

Thanks.

Signature · 1 line
tejun