* [RFC PATCH 03/18] kthread: Add kthread_stop_current()
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: linux-nfs, Borislav Petkov, Jiri Kosina, Richard Weinberger,
Trond Myklebust, linux-kernel, Steven Rostedt, Michal Hocko,
Chris Mason, Petr Mladek, linux-mtd, linux-api, Linus Torvalds,
live-patching, Thomas Gleixner, Paul E. McKenney, David Woodhouse,
Anna Schumaker
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
For example, jffs2_gcd_mtd kthread can be stopped by SIGKILL.
The signal is handled inside the main function.
We would like to convert such kthreads to the iterant API
and use proper signal handlers.
The new functions will allow to pass the information
between the signal handler and the main kthread functions.
kthread_stop_current() allows to quit the kthread correctly.
It means to leave the main cycle on a safe point and call
clean up actions via post() function.
Signed-off-by: Petr Mladek <pmladek@suse.cz>
---
include/linux/kthread.h | 1 +
kernel/kthread.c | 13 +++++++++++++
2 files changed, 14 insertions(+)
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 06fe9ad192dd..100c1e006729 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -86,6 +86,7 @@ kthread_iterant_create_on_cpu(struct kthread_iterant *kti,
})
void kthread_bind(struct task_struct *k, unsigned int cpu);
+void kthread_stop_current(void);
int kthread_stop(struct task_struct *k);
bool kthread_should_stop(void);
bool kthread_should_park(void);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 4b2698bcc622..688bb4cfd807 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -70,6 +70,19 @@ static struct kthread *to_live_kthread(struct task_struct *k)
}
/**
+ * kthread_stop_current - make the current kthread to terminate a safe way
+ *
+ * This function sets KTHREAD_SHOULD_STOP flags. It makes kthread to break
+ * the main loop and do some clean up actions before the main kthread
+ * function finishes. It is the standard behavior for SIGTERM signal.
+ */
+void kthread_stop_current(void)
+{
+ set_bit(KTHREAD_SHOULD_STOP, &to_kthread(current)->flags);
+}
+EXPORT_SYMBOL(kthread_stop_current);
+
+/**
* kthread_should_stop - should this kthread return now?
*
* When someone calls kthread_stop() on your kthread, it will be woken
--
1.8.5.6
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related
* [RFC PATCH 04/18] signal: Rename kernel_sigaction() to kthread_sigaction() and clean it up
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: linux-nfs, Borislav Petkov, Jiri Kosina, Richard Weinberger,
Trond Myklebust, linux-kernel, Steven Rostedt, Michal Hocko,
Chris Mason, Petr Mladek, linux-mtd, linux-api, Linus Torvalds,
live-patching, Thomas Gleixner, Paul E. McKenney, David Woodhouse,
Anna Schumaker
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
This patch defines __kthread_sighandler_t so that we do not need to force
a cast from __sighandler_t when passing an address from kernel space.
At the same time, it defines constants for the ignore, default, and
error sigactions that could be used within the kernel space. The __force
is a bit ugly but it is needed because of the ordering of includes.
Finally, the patch renames kernel_sigaction() to kthread_sigaction().
We are going to add proper signal handling to kthreads and this will
help to distinguish the related functions from the user-space
orientated ones. Note that we will just improve the existing
basic support for signals in kthreads.
The patch does not have any runtime effects. It is just a cleanup.
Note that it does not break the compilation with sparse. It warns
when a wrong part or the union is used in a wrong context.
Signed-off-by: Petr Mladek <pmladek@suse.cz>
---
include/linux/signal.h | 23 ++++++++++++++++++-----
kernel/kmod.c | 2 +-
kernel/signal.c | 8 ++++----
3 files changed, 23 insertions(+), 10 deletions(-)
diff --git a/include/linux/signal.h b/include/linux/signal.h
index ab1e0392b5ac..06e54762c281 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -241,13 +241,26 @@ extern void __set_current_blocked(const sigset_t *);
extern int show_unhandled_signals;
extern int sigsuspend(sigset_t *);
+typedef __signalfn_t *__kthread_sighandler_t;
+
+/* use the default signal handler for the kthread */
+#define KTHREAD_SIG_DFL ((__force __kthread_sighandler_t)SIG_DFL)
+/* ignore the signal in the kthread */
+#define KTHREAD_SIG_IGN ((__force __kthread_sighandler_t)SIG_IGN)
+
struct sigaction {
#ifndef __ARCH_HAS_IRIX_SIGACTION
- __sighandler_t sa_handler;
+ union {
+ __sighandler_t sa_handler;
+ __kthread_sighandler_t kthread_sa_handler;
+ };
unsigned long sa_flags;
#else
unsigned int sa_flags;
- __sighandler_t sa_handler;
+ union {
+ __sighandler_t sa_handler;
+ __kthread_sighandler_t kthread_sa_handler;
+ };
#endif
#ifdef __ARCH_HAS_SA_RESTORER
__sigrestore_t sa_restorer;
@@ -280,7 +293,7 @@ struct ksignal {
extern int get_signal(struct ksignal *ksig);
extern void signal_setup_done(int failed, struct ksignal *ksig, int stepping);
extern void exit_signals(struct task_struct *tsk);
-extern void kernel_sigaction(int, __sighandler_t);
+extern void kthread_sigaction(int, __kthread_sighandler_t);
static inline void allow_signal(int sig)
{
@@ -289,12 +302,12 @@ static inline void allow_signal(int sig)
* know it'll be handled, so that they don't get converted to
* SIGKILL or just silently dropped.
*/
- kernel_sigaction(sig, (__force __sighandler_t)2);
+ kthread_sigaction(sig, (__kthread_sighandler_t)2);
}
static inline void disallow_signal(int sig)
{
- kernel_sigaction(sig, SIG_IGN);
+ kthread_sigaction(sig, KTHREAD_SIG_IGN);
}
extern struct kmem_cache *sighand_cachep;
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 2777f40a9c7b..d45966319bcc 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -273,7 +273,7 @@ static int wait_for_helper(void *data)
pid_t pid;
/* If SIGCLD is ignored sys_wait4 won't populate the status. */
- kernel_sigaction(SIGCHLD, SIG_DFL);
+ kthread_sigaction(SIGCHLD, KTHREAD_SIG_DFL);
pid = kernel_thread(____call_usermodehelper, sub_info, SIGCHLD);
if (pid < 0) {
sub_info->retval = pid;
diff --git a/kernel/signal.c b/kernel/signal.c
index d51c5ddd855c..ca6bdb411449 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -3077,11 +3077,11 @@ COMPAT_SYSCALL_DEFINE4(rt_tgsigqueueinfo,
/*
* For kthreads only, must not be used if cloned with CLONE_SIGHAND
*/
-void kernel_sigaction(int sig, __sighandler_t action)
+void kthread_sigaction(int sig, __kthread_sighandler_t action)
{
spin_lock_irq(¤t->sighand->siglock);
- current->sighand->action[sig - 1].sa.sa_handler = action;
- if (action == SIG_IGN) {
+ current->sighand->action[sig - 1].sa.kthread_sa_handler = action;
+ if (action == KTHREAD_SIG_IGN) {
sigset_t mask;
sigemptyset(&mask);
@@ -3093,7 +3093,7 @@ void kernel_sigaction(int sig, __sighandler_t action)
}
spin_unlock_irq(¤t->sighand->siglock);
}
-EXPORT_SYMBOL(kernel_sigaction);
+EXPORT_SYMBOL(kthread_sigaction);
int do_sigaction(int sig, struct k_sigaction *act, struct k_sigaction *oact)
{
--
1.8.5.6
______________________________________________________
Linux MTD discussion mailing list
http://lists.infradead.org/mailman/listinfo/linux-mtd/
^ permalink raw reply related
* [RFC PATCH 05/18] freezer/scheduler: Add freezable_cond_resched()
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Trond Myklebust,
Anna Schumaker, linux-nfs-u79uwXL29TY76Z2rM5mHXA, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko,
live-patching-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek-AlSwsSmVLrQ@public.gmane.org>
It makes sense to call cond_resched() in freezable kthreads.
But there is the chicken&egg problem whether to call try_to_freeze()
before or after the schedule.
This patch adds freezable_cond_resched(). It uses the same trick as
freezable_schedule(). It tells the freezer that it might ignore
the sleeping process.
Note that it might be used only on locations where the freezing
is safe. It means that no lock is taken and we are ready to sleep
for a very long time.
Signed-off-by: Petr Mladek <pmladek-AlSwsSmVLrQ@public.gmane.org>
---
include/linux/freezer.h | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index 6b7fd9cf5ea2..1446f210dfc6 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -172,6 +172,14 @@ static inline void freezable_schedule(void)
freezer_count();
}
+/* Like cond_resched(), but should not block the freezer. */
+static inline void freezable_cond_resched(void)
+{
+ freezer_do_not_count();
+ cond_resched();
+ freezer_count();
+}
+
/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
static inline void freezable_schedule_unsafe(void)
{
--
1.8.5.6
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [RFC PATCH 06/18] signal/kthread: Initial implementation of kthread signal handling
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Trond Myklebust,
Anna Schumaker, linux-nfs-u79uwXL29TY76Z2rM5mHXA, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko,
live-patching-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek-AlSwsSmVLrQ@public.gmane.org>
Several kthreads already handle signals some way. They do so
in different ways, search for allow_signal().
This patch allows to handle the signals in a more uniform way using
kthread_do_signal().
The main question is how much it should follow POSIX and the signal
handling of user space processes. On one hand, we want to be as close
as possible. On the other hand, we need to be very careful. All signals
were ignored until now, except for the few kthreads that somehow
handled them.
POSIX behavior might cause some surprises and crazy bug reports.
For example, imagine a home user stopping or killing kswapd because
it makes the system too busy. It is like shooting in its own leg.
Also the signals are already used a strange way. For example, klockd
drops all locks when it gets SIGKILL. This was added before initial
git commit, so the archaeology was not easy. The most likely explanation
is that it is used during the system shutdown. It would make sense
to drop all locks when user space processes are killed and before
filesystems get unmounted.
Now, the patch does the following compromise:
+ defines default actions for SIGSTOP, SIGCONT, and fatal signals
+ custom actions can be defined by kthread_sigaction()
+ all signals are still ignored by default
Well, fatal signals do not terminate the kthread immediately. They just
set a flag to terminate the kthread, flush all other pending signals,
and return to the main kthread cycle. The kthread is supposed to check
the flag, leave the main cycle, do some cleanup actions when necessary
and return from the kthread.
Note that kthreads are running in the kernel address space. It makes
the life much easier. The signal handler can be called directly and
we do not need any arch-specific code to process it in the userspace.
Also we do not care about ptrace.
Finally, kthread_do_signal() is called on a safe place in the main
iterant kthread cycle. Then we will not need any special code for
signals when using this kthread API.
This change does not affect any existing kthread. The plan is to
use them only in safe kthreads that can be converted into
the iterant kthread API.
Signed-off-by: Petr Mladek <pmladek-AlSwsSmVLrQ@public.gmane.org>
---
include/linux/signal.h | 1 +
kernel/kthread.c | 3 ++
kernel/signal.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 80 insertions(+)
diff --git a/include/linux/signal.h b/include/linux/signal.h
index 06e54762c281..41e30310bc3b 100644
--- a/include/linux/signal.h
+++ b/include/linux/signal.h
@@ -294,6 +294,7 @@ extern int get_signal(struct ksignal *ksig);
extern void signal_setup_done(int failed, struct ksignal *ksig, int stepping);
extern void exit_signals(struct task_struct *tsk);
extern void kthread_sigaction(int, __kthread_sighandler_t);
+extern int kthread_do_signal(void);
static inline void allow_signal(int sig)
{
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 688bb4cfd807..185902d0e293 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -426,6 +426,9 @@ static int kthread_iterant_fn(void *kti_ptr)
if (kti->func)
kti->func(data);
+ if (signal_pending(current))
+ kthread_do_signal();
+
/* this check is safe also for non-freezable kthreads */
} while (!kthread_freezable_should_stop(NULL));
diff --git a/kernel/signal.c b/kernel/signal.c
index ca6bdb411449..cdca53965c3d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -23,6 +23,7 @@
#include <linux/ptrace.h>
#include <linux/signal.h>
#include <linux/signalfd.h>
+#include <linux/kthread.h>
#include <linux/ratelimit.h>
#include <linux/tracehook.h>
#include <linux/capability.h>
@@ -2365,6 +2366,81 @@ relock:
}
/**
+ * kthread_do_signal - process signals delivered to kernel threads
+ *
+ * Kthreads are running in the kernel address space. It makes the life
+ * much easier. The signal handler can be called directly and we do not
+ * need any arch-specific code to process it in the userspace.
+ * Also we do not care about ptrace.
+ */
+int kthread_do_signal(void)
+{
+ struct ksignal ksig;
+ struct sighand_struct *sighand = current->sighand;
+ struct signal_struct *signal = current->signal;
+ unsigned long flags;
+ int signr;
+
+ try_to_freeze();
+relock:
+ spin_lock_irqsave(&sighand->siglock, flags);
+
+ if (unlikely(signal->flags & SIGNAL_CLD_MASK)) {
+ WARN(1, "there are no parents for kernel threads\n");
+ signal->flags &= ~SIGNAL_CLD_MASK;
+ }
+
+ for (;;) {
+ struct k_sigaction *ka;
+
+ signr = dequeue_signal(current, ¤t->blocked, &ksig.info);
+
+ if (!signr)
+ break;
+
+ ka = &sighand->action[signr-1];
+
+ /* Do nothing for ignored signals */
+ if (ka->sa.kthread_sa_handler == KTHREAD_SIG_IGN)
+ continue;
+
+ /* Run the custom handler if any */
+ if (ka->sa.kthread_sa_handler != KTHREAD_SIG_DFL) {
+ ksig.ka = *ka;
+
+ if (ka->sa.sa_flags & SA_ONESHOT)
+ ka->sa.kthread_sa_handler = KTHREAD_SIG_DFL;
+
+ spin_unlock_irqrestore(&sighand->siglock, flags);
+ /* could run directly for kthreads */
+ ksig.ka.sa.kthread_sa_handler(signr);
+ freezable_cond_resched();
+ goto relock;
+ }
+
+ /* Default actions */
+ if (sig_kernel_ignore(signr))
+ continue;
+
+ if (sig_kernel_stop(signr)) {
+ __set_current_state(TASK_STOPPED);
+ spin_unlock_irqrestore(&sighand->siglock, flags);
+ /* Don't run again until woken by SIGCONT or SIGKILL */
+ freezable_schedule();
+ goto relock;
+ }
+
+ /* Death signals, but try to terminate cleanly */
+ kthread_stop_current();
+ __flush_signals(current);
+ break;
+ }
+ spin_unlock_irqrestore(&sighand->siglock, flags);
+
+ return 0;
+}
+
+/**
* signal_delivered -
* @ksig: kernel signal struct
* @stepping: nonzero if debugger single-step or block-step in use
--
1.8.5.6
^ permalink raw reply related
* [RFC PATCH 07/18] kthread: Make iterant kthreads freezable by default
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse, linux-mtd,
Trond Myklebust, Anna Schumaker, linux-nfs, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko, live-patching, linux-api,
linux-kernel, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
Many kthreads already calls set_freezable() before they enter the main
cycle. One of the reasons for creating iterant kthreads is to create
a safe point for freezing and make even more kthreads properly
freezable. Therefore it would make sense to set all iterant
kthreads freezable by default.
However some kthreads might be hard to make properly freezable.
For example, if they do non-interruptible sleeps. They would
need to explicitly clear PF_NOFREEZE flag in the init() call.
But it should be avoided whenever possible.
Signed-off-by: Petr Mladek <pmladek@suse.cz>
---
kernel/kthread.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 185902d0e293..e34f67cb8ecf 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -412,13 +412,20 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
*
* This function defines the work flow of iterant kthreads. It calls
* the given callbacks. Also it defines and implements a common
- * check point for freezing and stopping.
+ * check point for freezing, stopping, and signal handling.
+ *
+ * IMPORTANT: Iterant kthreads are freezable by default. The functions
+ * defined in the given struct kthread_iterant still have to explicitly
+ * call try_to_freeze() after each interruptible sleep. They must avoid
+ * non-interruptible sleep if freezing is allowed.
*/
static int kthread_iterant_fn(void *kti_ptr)
{
struct kthread_iterant *kti = kti_ptr;
void *data = kti->data;
+ set_freezable();
+
if (kti->init)
kti->init(data);
--
1.8.5.6
^ permalink raw reply related
* [RFC PATCH 08/18] kthread: Allow to get struct kthread_iterant from task_struct
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Trond Myklebust,
Anna Schumaker, linux-nfs-u79uwXL29TY76Z2rM5mHXA, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko,
live-patching-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek-AlSwsSmVLrQ@public.gmane.org>
It is easy to make a mistake when one implements sleeping between kthread
iterations. We will want to do it a more uniform way. For this we will
want to set some flags in struct kthread_iterant from the current
task (kthread). This patch adds the basic infrastructure to make
it possible.
Signed-off-by: Petr Mladek <pmladek-AlSwsSmVLrQ@public.gmane.org>
---
kernel/kthread.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/kernel/kthread.c b/kernel/kthread.c
index e34f67cb8ecf..41fb6a43a1f1 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -44,6 +44,7 @@ struct kthread {
void *data;
struct completion parked;
struct completion exited;
+ struct kthread_iterant *kti;
};
enum KTHREAD_BITS {
@@ -69,6 +70,11 @@ static struct kthread *to_live_kthread(struct task_struct *k)
return NULL;
}
+static struct kthread_iterant *to_kthread_iterant(struct task_struct *k)
+{
+ return __to_kthread(k->vfork_done)->kti;
+}
+
/**
* kthread_stop_current - make the current kthread to terminate a safe way
*
@@ -199,6 +205,7 @@ static int kthread(void *_create)
self.data = data;
init_completion(&self.exited);
init_completion(&self.parked);
+ self.kti = NULL;
current->vfork_done = &self.exited;
/* If user was SIGKILLed, I release the structure. */
@@ -421,9 +428,12 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
*/
static int kthread_iterant_fn(void *kti_ptr)
{
+ struct kthread *kt = to_kthread(current);
struct kthread_iterant *kti = kti_ptr;
void *data = kti->data;
+ kt->kti = kti;
+
set_freezable();
if (kti->init)
--
1.8.5.6
^ permalink raw reply related
* [RFC PATCH 09/18] kthread: Make it easier to correctly sleep in iterant kthreads
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse, linux-mtd,
Trond Myklebust, Anna Schumaker, linux-nfs, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko, live-patching, linux-api,
linux-kernel, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
Many kthreads go into an interruptible sleep when there is nothing
to do. They should check if anyone did not requested the kthread
to terminate, freeze, or park in the meantime. It is easy to do
it a wrong way.
This patch adds an API to do the sleep easier and correct way.
The big advantage is that we will have all the checks on a single
place and will be able to fix all broken threads easily.
We need two steps. set_current_state(TASK_INTERRUPTIBLE)
is typically called under some lock together with a check for
a pending work. While schedule() has to be called outside
the lock.
We use the freezable variants of kthread_should_stop(), schedule(),
and cond_resched(). They are needed in freezable kthreads and they
do the right job also in non-freezable ones.
The API is ready to support more sleeping variants, e.g.
wait_event_freezable(), wait_event_freezable_timeout(). Well,
we will need to add some more items into the struct kthread_iterant
for them.
Signed-off-by: Petr Mladek <pmladek@suse.cz>
---
include/linux/kthread.h | 13 +++++++++
kernel/kthread.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 89 insertions(+)
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 100c1e006729..415178c20cde 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -48,14 +48,25 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
* must be released and non-interruptible work finished.
*/
+/* Flags that modify the default behavior of iterant kthreads. */
+/* Reset pause flags for the next iteration. */
+#define KTI_PAUSE_ONCE 0x00000001
+/* Do interruptible sleep between iterations. */
+#define KTI_INT_SLEEP 0x00000002
+
+#define KTI_PAUSE_MASK (KTI_INT_SLEEP | \
+ KTI_PAUSE_ONCE)
+
/**
* struct kthread_iterant - structure describing the function of the kthread
+ * @type: modifies the kthread behavior using extra flags.
* @data: pointer to a data passed to the functions.
* @init: function called when the kthread is created.
* @func: function called in the main cycle until the kthread is terminated.
* @destroy: function called when the kthread is being terminated.
*/
struct kthread_iterant {
+ unsigned int type;
void *data;
void (*init)(void *data);
void (*func)(void *data);
@@ -85,6 +96,8 @@ kthread_iterant_create_on_cpu(struct kthread_iterant *kti,
__k; \
})
+void set_kthread_iterant_int_sleep(void);
+
void kthread_bind(struct task_struct *k, unsigned int cpu);
void kthread_stop_current(void);
int kthread_stop(struct task_struct *k);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index 41fb6a43a1f1..fa40fb549e22 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -414,6 +414,80 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
}
/**
+ * set_kthread_iterant_pause_type - set the type of the pause before
+ * the next iteration
+ * @type: flags that define the type of the pause; they are the same
+ * as the flags used for @type in struct kthread_iterant
+ */
+static void set_kthread_iterant_pause_type(struct kthread_iterant *kti,
+ unsigned int type)
+{
+ WARN_ONCE(type & ~KTI_PAUSE_MASK,
+ "unknown pause type: 0x%x\n", type);
+ type &= KTI_PAUSE_MASK;
+
+ kti->type &= ~KTI_PAUSE_MASK;
+ kti->type |= type;
+ /* this function set the pause only for the next iteration */
+ kti->type |= KTI_PAUSE_ONCE;
+}
+
+/**
+ * set_kthread_iterant_int_sleep - do interruptible sleep before
+ * the next iteration
+ *
+ * This function is typically called under a lock when the main func()
+ * checks for the pending work.
+ *
+ * Kthreads should pause between iterations only when there is no work,
+ * signal pending, freezing, parking, or termination. We want to do most
+ * of these checks properly on a single place: kthread_iterant_fn().
+ * Only the checks for pending work need to be done in the main func()
+ * because they are not generic.
+ */
+void set_kthread_iterant_int_sleep(void)
+{
+ struct kthread_iterant *kti = to_kthread_iterant(current);
+
+ set_kthread_iterant_pause_type(kti, KTI_INT_SLEEP);
+ set_current_state(TASK_INTERRUPTIBLE);
+}
+EXPORT_SYMBOL(set_kthread_iterant_int_sleep);
+
+/**
+ * do_kthread_iterant_pause - do the selected pause before next iteration
+ *
+ * Most kthreads sleep or wait between iterations. This function
+ * allows to do it the right way. The particular pause variant
+ * is defined by @type flags in struct kthread_iterant. Anyway,
+ * this is a safe place to call cond_resched().
+ */
+static void do_kthread_iterant_pause(struct kthread_iterant *kti)
+{
+ unsigned int type = kti->type;
+
+ /*
+ * Explicitly set the task state when it was not set by
+ * set_kthread_iterant_int_sleep*() functions.
+ */
+ if (!(type & KTI_PAUSE_ONCE) && (type & KTI_INT_SLEEP))
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (kthread_freezable_should_stop(NULL)) {
+ set_current_state(TASK_RUNNING);
+ return;
+ }
+
+ if (type & KTI_INT_SLEEP)
+ freezable_schedule();
+ else
+ freezable_cond_resched();
+
+ if (type & KTI_PAUSE_ONCE)
+ kti->type &= ~KTI_PAUSE_MASK;
+}
+
+/**
* kthread_iterant_fn - kthread function to process an iterant kthread
* @kti_ptr: pointer to an initialized struct kthread_iterant.
*
@@ -443,6 +517,8 @@ static int kthread_iterant_fn(void *kti_ptr)
if (kti->func)
kti->func(data);
+ do_kthread_iterant_pause(kti);
+
if (signal_pending(current))
kthread_do_signal();
--
1.8.5.6
^ permalink raw reply related
* [RFC PATCH 10/18] jffs2: Remove forward definition of jffs2_garbage_collect_thread()
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse, linux-mtd,
Trond Myklebust, Anna Schumaker, linux-nfs, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko, live-patching, linux-api,
linux-kernel, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
This commit just moves the function definition and fixes few coding
style problems reported by checkpatch.pl. There are no changes in
the functionality.
The change will be useful when switching to the new iterant kthread API.
Signed-off-by: Petr Mladek <pmladek@suse.cz>
---
fs/jffs2/background.c | 101 +++++++++++++++++++++++++-------------------------
1 file changed, 50 insertions(+), 51 deletions(-)
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index bb9cebc9ca8a..6af076b8f60f 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -21,57 +21,6 @@
#include <linux/kthread.h>
#include "nodelist.h"
-
-static int jffs2_garbage_collect_thread(void *);
-
-void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
-{
- assert_spin_locked(&c->erase_completion_lock);
- if (c->gc_task && jffs2_thread_should_wake(c))
- send_sig(SIGHUP, c->gc_task, 1);
-}
-
-/* This must only ever be called when no GC thread is currently running */
-int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
-{
- struct task_struct *tsk;
- int ret = 0;
-
- BUG_ON(c->gc_task);
-
- init_completion(&c->gc_thread_start);
- init_completion(&c->gc_thread_exit);
-
- tsk = kthread_run(jffs2_garbage_collect_thread, c, "jffs2_gcd_mtd%d", c->mtd->index);
- if (IS_ERR(tsk)) {
- pr_warn("fork failed for JFFS2 garbage collect thread: %ld\n",
- -PTR_ERR(tsk));
- complete(&c->gc_thread_exit);
- ret = PTR_ERR(tsk);
- } else {
- /* Wait for it... */
- jffs2_dbg(1, "Garbage collect thread is pid %d\n", tsk->pid);
- wait_for_completion(&c->gc_thread_start);
- ret = tsk->pid;
- }
-
- return ret;
-}
-
-void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
-{
- int wait = 0;
- spin_lock(&c->erase_completion_lock);
- if (c->gc_task) {
- jffs2_dbg(1, "Killing GC task %d\n", c->gc_task->pid);
- send_sig(SIGKILL, c->gc_task, 1);
- wait = 1;
- }
- spin_unlock(&c->erase_completion_lock);
- if (wait)
- wait_for_completion(&c->gc_thread_exit);
-}
-
static int jffs2_garbage_collect_thread(void *_c)
{
struct jffs2_sb_info *c = _c;
@@ -166,3 +115,53 @@ static int jffs2_garbage_collect_thread(void *_c)
spin_unlock(&c->erase_completion_lock);
complete_and_exit(&c->gc_thread_exit, 0);
}
+
+void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
+{
+ assert_spin_locked(&c->erase_completion_lock);
+ if (c->gc_task && jffs2_thread_should_wake(c))
+ send_sig(SIGHUP, c->gc_task, 1);
+}
+
+/* This must only ever be called when no GC thread is currently running */
+int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
+{
+ struct task_struct *tsk;
+ int ret = 0;
+
+ BUG_ON(c->gc_task);
+
+ init_completion(&c->gc_thread_start);
+ init_completion(&c->gc_thread_exit);
+
+ tsk = kthread_run(jffs2_garbage_collect_thread, c,
+ "jffs2_gcd_mtd%d", c->mtd->index);
+ if (IS_ERR(tsk)) {
+ pr_warn("fork failed for JFFS2 garbage collect thread: %ld\n",
+ -PTR_ERR(tsk));
+ complete(&c->gc_thread_exit);
+ ret = PTR_ERR(tsk);
+ } else {
+ /* Wait for it... */
+ jffs2_dbg(1, "Garbage collect thread is pid %d\n", tsk->pid);
+ wait_for_completion(&c->gc_thread_start);
+ ret = tsk->pid;
+ }
+
+ return ret;
+}
+
+void jffs2_stop_garbage_collect_thread(struct jffs2_sb_info *c)
+{
+ int wait = 0;
+
+ spin_lock(&c->erase_completion_lock);
+ if (c->gc_task) {
+ jffs2_dbg(1, "Killing GC task %d\n", c->gc_task->pid);
+ send_sig(SIGKILL, c->gc_task, 1);
+ wait = 1;
+ }
+ spin_unlock(&c->erase_completion_lock);
+ if (wait)
+ wait_for_completion(&c->gc_thread_exit);
+}
--
1.8.5.6
^ permalink raw reply related
* [RFC PATCH 11/18] jffs2: Convert jffs2_gcd_mtd kthread into the iterant API
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse, linux-mtd,
Trond Myklebust, Anna Schumaker, linux-nfs, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko, live-patching, linux-api,
linux-kernel, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
The new iterant kthread API allows to define a common checkpoint for
freezing, parking, termination, and even signal handling. It will allow
to maintain kthreads more easily and make the operations more reliable[*].
The kthread function is split into optional init(), func(), destroy() parts
where func() is called in a cycle. The common check point is after
each func() finishes. See kthread_iterant_fn() for more details.
func() does not need to call schedule(). Instead, we call
set_kthread_iterant_int_sleep() and let the generic code
to handle the sleeping properly.
There are few small functional changes:
+ SIGSTOP uses the standard handler and could not print debug
messages any longer
+ there is no need to enable or define sighandler for SIGCONT;
it is handled by prepare_signal() and could not get disabled
+ the debug message for default signal handler was removed; It is
handled in kernel_do_signal() a standard way. In reality, this
never happens because all signals are disabled except for the
four ones enabled by kthread_sigaction();
+ we call complete() instead of complete_and_exit(); do_exit() is
called in kthread() anyway after the function returns.
[*] In fact, there was a bug in the original code. It tried to process
a non-existing signal when the system was freezing. See the common
check for pending signal and freezing.
Signed-off-by: Petr Mladek <pmladek@suse.cz>
---
fs/jffs2/background.c | 156 ++++++++++++++++++++++++--------------------------
1 file changed, 74 insertions(+), 82 deletions(-)
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 6af076b8f60f..50c16048ba2d 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -21,99 +21,86 @@
#include <linux/kthread.h>
#include "nodelist.h"
-static int jffs2_garbage_collect_thread(void *_c)
+static void jffs2_garbage_collect_thread_sighup(int sig)
+{
+ jffs2_dbg(1, "%s(): SIGHUP received\n", __func__);
+}
+
+static void jffs2_garbage_collect_thread_sigkill(int sig)
+{
+ jffs2_dbg(1, "%s(): SIGKILL received\n", __func__);
+ kthread_stop_current();
+}
+
+static void jffs2_garbage_collect_thread_init(void *_c)
{
struct jffs2_sb_info *c = _c;
- sigset_t hupmask;
- siginitset(&hupmask, sigmask(SIGHUP));
- allow_signal(SIGKILL);
- allow_signal(SIGSTOP);
- allow_signal(SIGCONT);
- allow_signal(SIGHUP);
+ kthread_sigaction(SIGKILL, jffs2_garbage_collect_thread_sigkill);
+ kthread_sigaction(SIGHUP, jffs2_garbage_collect_thread_sighup);
+ kthread_sigaction(SIGSTOP, KTHREAD_SIG_DFL);
c->gc_task = current;
complete(&c->gc_thread_start);
set_user_nice(current, 10);
+};
+
+static void jffs2_garbage_collect_thread_func(void *_c)
+{
+ struct jffs2_sb_info *c = _c;
+ sigset_t hupmask;
+
+ siginitset(&hupmask, sigmask(SIGHUP));
- set_freezable();
- for (;;) {
- sigprocmask(SIG_UNBLOCK, &hupmask, NULL);
- again:
- spin_lock(&c->erase_completion_lock);
- if (!jffs2_thread_should_wake(c)) {
- set_current_state (TASK_INTERRUPTIBLE);
- spin_unlock(&c->erase_completion_lock);
- jffs2_dbg(1, "%s(): sleeping...\n", __func__);
- schedule();
- } else {
- spin_unlock(&c->erase_completion_lock);
- }
- /* Problem - immediately after bootup, the GCD spends a lot
- * of time in places like jffs2_kill_fragtree(); so much so
- * that userspace processes (like gdm and X) are starved
- * despite plenty of cond_resched()s and renicing. Yield()
- * doesn't help, either (presumably because userspace and GCD
- * are generally competing for a higher latency resource -
- * disk).
- * This forces the GCD to slow the hell down. Pulling an
- * inode in with read_inode() is much preferable to having
- * the GC thread get there first. */
- schedule_timeout_interruptible(msecs_to_jiffies(50));
-
- if (kthread_should_stop()) {
- jffs2_dbg(1, "%s(): kthread_stop() called\n", __func__);
- goto die;
- }
-
- /* 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);
-
- switch(signr) {
- case SIGSTOP:
- jffs2_dbg(1, "%s(): SIGSTOP received\n",
- __func__);
- set_current_state(TASK_STOPPED);
- schedule();
- break;
-
- case SIGKILL:
- jffs2_dbg(1, "%s(): SIGKILL received\n",
- __func__);
- goto die;
-
- case SIGHUP:
- jffs2_dbg(1, "%s(): SIGHUP received\n",
- __func__);
- break;
- default:
- jffs2_dbg(1, "%s(): signal %ld received\n",
- __func__, signr);
- }
- }
- /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
- sigprocmask(SIG_BLOCK, &hupmask, NULL);
-
- jffs2_dbg(1, "%s(): pass\n", __func__);
- if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
- pr_notice("No space for garbage collection. Aborting GC thread\n");
- goto die;
- }
+ spin_lock(&c->erase_completion_lock);
+ if (!jffs2_thread_should_wake(c)) {
+ set_kthread_iterant_int_sleep();
+ spin_unlock(&c->erase_completion_lock);
+ jffs2_dbg(1, "%s(): sleeping...\n", __func__);
+ return;
+ }
+ spin_unlock(&c->erase_completion_lock);
+
+ /* Problem - immediately after bootup, the GCD spends a lot
+ * of time in places like jffs2_kill_fragtree(); so much so
+ * that userspace processes (like gdm and X) are starved
+ * despite plenty of cond_resched()s and renicing. Yield()
+ * doesn't help, either (presumably because userspace and GCD
+ * are generally competing for a higher latency resource -
+ * disk).
+ * This forces the GCD to slow the hell down. Pulling an
+ * inode in with read_inode() is much preferable to having
+ * the GC thread get there first.
+ */
+ schedule_timeout_interruptible(msecs_to_jiffies(50));
+
+ if (kthread_should_stop()) {
+ jffs2_dbg(1, "%s(): kthread_stop() called\n", __func__);
+ return;
}
- die:
+
+ try_to_freeze();
+
+ /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
+ sigprocmask(SIG_BLOCK, &hupmask, NULL);
+
+ jffs2_dbg(1, "%s(): pass\n", __func__);
+ if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
+ pr_notice("No space for garbage collection. Aborting GC thread\n");
+ kthread_stop_current();
+ }
+ sigprocmask(SIG_UNBLOCK, &hupmask, NULL);
+}
+
+static void jffs2_garbage_collect_thread_destroy(void *_c)
+{
+ struct jffs2_sb_info *c = _c;
+
spin_lock(&c->erase_completion_lock);
c->gc_task = NULL;
spin_unlock(&c->erase_completion_lock);
- complete_and_exit(&c->gc_thread_exit, 0);
+ complete(&c->gc_thread_exit);
}
void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
@@ -126,16 +113,21 @@ void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c)
/* This must only ever be called when no GC thread is currently running */
int jffs2_start_garbage_collect_thread(struct jffs2_sb_info *c)
{
+ static struct kthread_iterant kti = {
+ .init = jffs2_garbage_collect_thread_init,
+ .func = jffs2_garbage_collect_thread_func,
+ .destroy = jffs2_garbage_collect_thread_destroy,
+ };
struct task_struct *tsk;
int ret = 0;
BUG_ON(c->gc_task);
+ kti.data = c;
init_completion(&c->gc_thread_start);
init_completion(&c->gc_thread_exit);
- tsk = kthread_run(jffs2_garbage_collect_thread, c,
- "jffs2_gcd_mtd%d", c->mtd->index);
+ tsk = kthread_iterant_run(&kti, "jffs2_gcd_mtd%d", c->mtd->index);
if (IS_ERR(tsk)) {
pr_warn("fork failed for JFFS2 garbage collect thread: %ld\n",
-PTR_ERR(tsk));
--
1.8.5.6
^ permalink raw reply related
* [RFC PATCH 12/18] lockd: Convert the central lockd service to kthread_iterant API
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Trond Myklebust,
Anna Schumaker, linux-nfs-u79uwXL29TY76Z2rM5mHXA, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko,
live-patching-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek-AlSwsSmVLrQ@public.gmane.org>
The new iterant kthread API allows to define a common checkpoint for
freezing, parking, termination, and even signal handling. It will allow
to maintain kthreads more easily and make the operations more reliable.
The kthread function is split into optional init(), func(), destroy() parts
where func() is called in a cycle. The common check point is after
each func() function finishes. See kthread_iterant_fn() for more details.
This patch moves the action associated with the signal into a proper
signal handler.
It removes the obsolete set_freezable() call because iterant kthreads
are freezable by default.
struct kthread_iterant is stored into struct svc_rqst. We have already
stored there the pointer to the related task_struct.
The rest is just shuffling the code from the while cycle into _func().
Signed-off-by: Petr Mladek <pmladek-AlSwsSmVLrQ@public.gmane.org>
---
fs/lockd/svc.c | 80 ++++++++++++++++++++++++----------------------
include/linux/sunrpc/svc.h | 2 ++
2 files changed, 44 insertions(+), 38 deletions(-)
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 55505cbe11af..5b1efe509fcc 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -122,58 +122,55 @@ static void restart_grace(void)
}
/*
- * This is the lockd kernel thread
+ * Lockd kernel thread implementation using the iterant API
+ * We don't terminate until the last NFS mount or NFS daemon
+ * has gone away.
*/
-static int
-lockd(void *vrqstp)
+static void lockd_sigkill(int sig)
{
- int err = 0;
- struct svc_rqst *rqstp = vrqstp;
-
- /* try_to_freeze() is called from svc_recv() */
- set_freezable();
+ restart_grace();
+}
+static void lockd_init(void *vrqstp)
+{
/* Allow SIGKILL to tell lockd to drop all of its locks */
- allow_signal(SIGKILL);
+ kthread_sigaction(SIGKILL, lockd_sigkill);
dprintk("NFS locking service started (ver " LOCKD_VERSION ").\n");
+}
- /*
- * The main request loop. We don't terminate until the last
- * NFS mount or NFS daemon has gone away.
- */
- while (!kthread_should_stop()) {
- long timeout = MAX_SCHEDULE_TIMEOUT;
- RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
+static void lockd_func(void *vrqstp)
+{
+ int err = 0;
+ struct svc_rqst *rqstp = vrqstp;
- /* update sv_maxconn if it has changed */
- rqstp->rq_server->sv_maxconn = nlm_max_connections;
+ long timeout = MAX_SCHEDULE_TIMEOUT;
+ RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
- if (signalled()) {
- flush_signals(current);
- restart_grace();
- continue;
- }
+ /* update sv_maxconn if it has changed */
+ rqstp->rq_server->sv_maxconn = nlm_max_connections;
- timeout = nlmsvc_retry_blocked();
+ timeout = nlmsvc_retry_blocked();
- /*
- * Find a socket with data available and call its
- * recvfrom routine.
- */
- err = svc_recv(rqstp, timeout);
- if (err == -EAGAIN || err == -EINTR)
- continue;
- dprintk("lockd: request from %s\n",
- svc_print_addr(rqstp, buf, sizeof(buf)));
+ /*
+ * Find a socket with data available and call its
+ * recvfrom routine.
+ */
+ err = svc_recv(rqstp, timeout);
+ if (err == -EAGAIN || err == -EINTR)
+ return;
- svc_process(rqstp);
- }
- flush_signals(current);
+ dprintk("lockd: request from %s\n",
+ svc_print_addr(rqstp, buf, sizeof(buf)));
+
+ svc_process(rqstp);
+}
+
+static void lockd_destroy(void *vrqstp)
+{
if (nlmsvc_ops)
nlmsvc_invalidate_all();
nlm_shutdown_hosts();
- return 0;
}
static int create_lockd_listener(struct svc_serv *serv, const char *name,
@@ -301,7 +298,14 @@ static int lockd_start_svc(struct svc_serv *serv)
svc_sock_update_bufs(serv);
serv->sv_maxconn = nlm_max_connections;
- nlmsvc_task = kthread_create(lockd, nlmsvc_rqst, "%s", serv->sv_name);
+ nlmsvc_rqst->rq_kti.type = 0;
+ nlmsvc_rqst->rq_kti.data = nlmsvc_rqst;
+ nlmsvc_rqst->rq_kti.init = lockd_init;
+ nlmsvc_rqst->rq_kti.func = lockd_func;
+ nlmsvc_rqst->rq_kti.destroy = lockd_destroy;
+
+ nlmsvc_task = kthread_iterant_create(&nlmsvc_rqst->rq_kti,
+ "%s", serv->sv_name);
if (IS_ERR(nlmsvc_task)) {
error = PTR_ERR(nlmsvc_task);
printk(KERN_WARNING
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index fae6fb947fc8..6275e9b9df9b 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -16,6 +16,7 @@
#include <linux/sunrpc/xdr.h>
#include <linux/sunrpc/auth.h>
#include <linux/sunrpc/svcauth.h>
+#include <linux/kthread.h>
#include <linux/wait.h>
#include <linux/mm.h>
@@ -283,6 +284,7 @@ struct svc_rqst {
struct auth_domain * rq_client; /* RPC peer info */
struct auth_domain * rq_gssclient; /* "gss/"-style peer info */
struct svc_cacherep * rq_cacherep; /* cache info */
+ struct kthread_iterant rq_kti; /* info for iterant kthread */
struct task_struct *rq_task; /* service thread */
spinlock_t rq_lock; /* per-request lock */
};
--
1.8.5.6
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [RFC PATCH 13/18] ring_buffer: Use iterant kthreads API in the ring buffer benchmark
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse, linux-mtd,
Trond Myklebust, Anna Schumaker, linux-nfs, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko, live-patching, linux-api,
linux-kernel, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
The new iterant kthread API allows to define a common checkpoint for
freezing, parking, termination, and even signal handling. It will allow
to maintain kthreads more easily and make the operations more reliable.
The kthread function is split into optional init(), func(), destroy() parts
where func() is called in a cycle. The common check point is after
each func() function finishes. See kthread_iterant_fn() for more details.
This patch removes the wait_to_die() cycle. Instead it uses
the main cycle and func() does nothing in the kill_test state.
The threads are not safe for freezing because there is used schedule()
without try_to_freeze() inside the kthread. Let's fix it in separate
patch. In the meantime, we need to disable it explicitly in the init()
function.
Consumer does not need to call schedule in func(). Instead, it sets
KTI_INT_SLEEP type and lets the kthread iterant framework to do the sleep
between iterations.
On the other hand, the producer still need to implement the sleeping
in func() because the iterant kthread framework does not support
this type of sleep. But the plan is to make it possible later.
Signed-off-by: Petr Mladek <pmladek@suse.cz>
---
kernel/trace/ring_buffer_benchmark.c | 81 +++++++++++++++++-------------------
1 file changed, 39 insertions(+), 42 deletions(-)
diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c
index 13d945c0d03f..164f3762cc82 100644
--- a/kernel/trace/ring_buffer_benchmark.c
+++ b/kernel/trace/ring_buffer_benchmark.c
@@ -30,6 +30,8 @@ static struct completion read_done;
static struct ring_buffer *buffer;
static struct task_struct *producer;
static struct task_struct *consumer;
+static struct kthread_iterant producer_kti;
+static struct kthread_iterant consumer_kti;
static unsigned long read;
static int disable_reader;
@@ -354,61 +356,51 @@ static void ring_buffer_producer(void)
}
}
-static void wait_to_die(void)
+static void ring_buffer_consumer_thread_init(void *arg)
{
- set_current_state(TASK_INTERRUPTIBLE);
- while (!kthread_should_stop()) {
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- __set_current_state(TASK_RUNNING);
+ /* it does not matter where we freeze */
+ current->flags |= PF_NOFREEZE;
}
-static int ring_buffer_consumer_thread(void *arg)
+static void ring_buffer_consumer_thread_func(void *arg)
{
- while (!kthread_should_stop() && !kill_test) {
- complete(&read_start);
-
- ring_buffer_consumer();
-
- set_current_state(TASK_INTERRUPTIBLE);
- if (kthread_should_stop() || kill_test)
- break;
-
- schedule();
- }
- __set_current_state(TASK_RUNNING);
-
if (kill_test)
- wait_to_die();
+ return;
- return 0;
+ complete(&read_start);
+
+ ring_buffer_consumer();
}
-static int ring_buffer_producer_thread(void *arg)
+static void ring_buffer_producer_thread_init(void *arg)
{
init_completion(&read_start);
- while (!kthread_should_stop() && !kill_test) {
- ring_buffer_reset(buffer);
+ /* it does not matter where we freeze */
+ current->flags |= PF_NOFREEZE;
+}
- if (consumer) {
- smp_wmb();
- wake_up_process(consumer);
- wait_for_completion(&read_start);
- }
+static void ring_buffer_producer_thread_func(void *arg)
+{
+ if (kill_test) {
+ set_kthread_iterant_int_sleep();
+ return;
+ }
- ring_buffer_producer();
+ ring_buffer_reset(buffer);
- trace_printk("Sleeping for 10 secs\n");
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ * SLEEP_TIME);
+ if (consumer) {
+ /* reset ring buffer before waking up the consumer */
+ smp_wmb();
+ wake_up_process(consumer);
+ wait_for_completion(&read_start);
}
- if (kill_test)
- wait_to_die();
+ ring_buffer_producer();
- return 0;
+ trace_printk("Sleeping for 10 secs\n");
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(HZ * SLEEP_TIME);
}
static int __init ring_buffer_benchmark_init(void)
@@ -420,16 +412,21 @@ static int __init ring_buffer_benchmark_init(void)
if (!buffer)
return -ENOMEM;
+ consumer_kti.type = KTI_INT_SLEEP;
+ consumer_kti.func = ring_buffer_consumer_thread_init;
+ consumer_kti.func = ring_buffer_consumer_thread_func;
+
if (!disable_reader) {
- consumer = kthread_create(ring_buffer_consumer_thread,
- NULL, "rb_consumer");
+ consumer = kthread_iterant_create(&consumer_kti, "rb_consumer");
ret = PTR_ERR(consumer);
if (IS_ERR(consumer))
goto out_fail;
}
- producer = kthread_run(ring_buffer_producer_thread,
- NULL, "rb_producer");
+ producer_kti.init = ring_buffer_producer_thread_init;
+ producer_kti.func = ring_buffer_producer_thread_func;
+
+ producer = kthread_iterant_run(&producer_kti, "rb_producer");
ret = PTR_ERR(producer);
if (IS_ERR(producer))
--
1.8.5.6
^ permalink raw reply related
* [RFC PATCH 14/18] ring_buffer: Allow to cleanly freeze the ring buffer benchmark kthreads
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse, linux-mtd,
Trond Myklebust, Anna Schumaker, linux-nfs, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko, live-patching, linux-api,
linux-kernel, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
One target of the switch to the kthread iterant API is to make
most kthreads cleanly freezable.
This patch adds try_to_freeze() where appropriate and enables
freezing.
Signed-off-by: Petr Mladek <pmladek@suse.cz>
---
kernel/trace/ring_buffer_benchmark.c | 34 ++++++++++++++--------------------
1 file changed, 14 insertions(+), 20 deletions(-)
diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c
index 164f3762cc82..2d276b892aea 100644
--- a/kernel/trace/ring_buffer_benchmark.c
+++ b/kernel/trace/ring_buffer_benchmark.c
@@ -6,6 +6,7 @@
#include <linux/ring_buffer.h>
#include <linux/completion.h>
#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <linux/module.h>
#include <linux/ktime.h>
#include <asm/local.h>
@@ -207,6 +208,7 @@ static void ring_buffer_consumer(void)
break;
schedule();
+ try_to_freeze();
}
reader_finish = 0;
complete(&read_done);
@@ -252,19 +254,21 @@ static void ring_buffer_producer(void)
if (consumer && !(cnt % wakeup_interval))
wake_up_process(consumer);
+ if (cnt % wakeup_interval) {
#ifndef CONFIG_PREEMPT
- /*
- * If we are a non preempt kernel, the 10 second run will
- * stop everything while it runs. Instead, we will call
- * cond_resched and also add any time that was lost by a
- * rescedule.
- *
- * Do a cond resched at the same frequency we would wake up
- * the reader.
- */
- if (cnt % wakeup_interval)
+ /*
+ * If we are a non preempt kernel, the 10 second run
+ * will stop everything while it runs. Instead, we will
+ * call cond_resched and also add any time that was
+ * lost by a rescedule.
+ *
+ * Do a cond resched at the same frequency we would
+ * wake up the reader.
+ */
cond_resched();
#endif
+ try_to_freeze();
+ }
} while (ktime_before(end_time, timeout) && !kill_test);
trace_printk("End ring buffer hammer\n");
@@ -356,12 +360,6 @@ static void ring_buffer_producer(void)
}
}
-static void ring_buffer_consumer_thread_init(void *arg)
-{
- /* it does not matter where we freeze */
- current->flags |= PF_NOFREEZE;
-}
-
static void ring_buffer_consumer_thread_func(void *arg)
{
if (kill_test)
@@ -375,9 +373,6 @@ static void ring_buffer_consumer_thread_func(void *arg)
static void ring_buffer_producer_thread_init(void *arg)
{
init_completion(&read_start);
-
- /* it does not matter where we freeze */
- current->flags |= PF_NOFREEZE;
}
static void ring_buffer_producer_thread_func(void *arg)
@@ -413,7 +408,6 @@ static int __init ring_buffer_benchmark_init(void)
return -ENOMEM;
consumer_kti.type = KTI_INT_SLEEP;
- consumer_kti.func = ring_buffer_consumer_thread_init;
consumer_kti.func = ring_buffer_consumer_thread_func;
if (!disable_reader) {
--
1.8.5.6
^ permalink raw reply related
* [RFC PATCH 15/18] ring_buffer: Allow to exit the ring buffer benchmark immediately
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Trond Myklebust,
Anna Schumaker, linux-nfs-u79uwXL29TY76Z2rM5mHXA, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko,
live-patching-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek-AlSwsSmVLrQ@public.gmane.org>
It takes a while until the ring_buffer_benchmark module is removed
when the ring buffer hammer is running. It is because it takes
few seconds and kthread_should_terminate() is not being checked.
This patch adds the check for kthread termination into the producer.
It uses the existing kill_test flag to finish the kthreads as
cleanly as possible.
It disables printing the "ERROR" message when the kthread is going.
Also it makes sure that producer does not go into the 10sec sleep
when it is being killed.
Signed-off-by: Petr Mladek <pmladek-AlSwsSmVLrQ@public.gmane.org>
---
kernel/trace/ring_buffer_benchmark.c | 18 +++++++++++++-----
1 file changed, 13 insertions(+), 5 deletions(-)
diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c
index 2d276b892aea..4ecf7c4567e2 100644
--- a/kernel/trace/ring_buffer_benchmark.c
+++ b/kernel/trace/ring_buffer_benchmark.c
@@ -270,6 +270,9 @@ static void ring_buffer_producer(void)
try_to_freeze();
}
+ if (kthread_should_stop())
+ kill_test = 1;
+
} while (ktime_before(end_time, timeout) && !kill_test);
trace_printk("End ring buffer hammer\n");
@@ -291,7 +294,7 @@ static void ring_buffer_producer(void)
entries = ring_buffer_entries(buffer);
overruns = ring_buffer_overruns(buffer);
- if (kill_test)
+ if (kill_test && !kthread_should_stop())
trace_printk("ERROR!\n");
if (!disable_reader) {
@@ -377,10 +380,8 @@ static void ring_buffer_producer_thread_init(void *arg)
static void ring_buffer_producer_thread_func(void *arg)
{
- if (kill_test) {
- set_kthread_iterant_int_sleep();
- return;
- }
+ if (kill_test)
+ goto test_killed;
ring_buffer_reset(buffer);
@@ -393,9 +394,16 @@ static void ring_buffer_producer_thread_func(void *arg)
ring_buffer_producer();
+ if (kill_test)
+ goto test_killed;
+
trace_printk("Sleeping for 10 secs\n");
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ * SLEEP_TIME);
+ return;
+
+test_killed:
+ set_kthread_iterant_int_sleep();
}
static int __init ring_buffer_benchmark_init(void)
--
1.8.5.6
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [RFC PATCH 16/18] kthread: Support interruptible sleep with a timeout by iterant kthreads
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse, linux-mtd,
Trond Myklebust, Anna Schumaker, linux-nfs, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko, live-patching, linux-api,
linux-kernel, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
The aim of kthread iterant API is to maintain some non-trivial operations
on the single place. One of this operations is sleeping between iterations
because we need to handle properly system freezing, parking, and
kthread stopping.
This patch adds support for interruptible sleep with a timeout. It defines
the type, function to set and do the sleep. The timeout value is added
into the struct kthread_iterant.
Signed-off-by: Petr Mladek <pmladek@suse.cz>
---
include/linux/kthread.h | 5 +++++
kernel/kthread.c | 30 +++++++++++++++++++++++++++++-
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/include/linux/kthread.h b/include/linux/kthread.h
index 415178c20cde..e8f7c0106cfd 100644
--- a/include/linux/kthread.h
+++ b/include/linux/kthread.h
@@ -53,13 +53,16 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
#define KTI_PAUSE_ONCE 0x00000001
/* Do interruptible sleep between iterations. */
#define KTI_INT_SLEEP 0x00000002
+#define KTI_INT_SLEEP_TIMEOUT 0x00000004
#define KTI_PAUSE_MASK (KTI_INT_SLEEP | \
+ KTI_INT_SLEEP_TIMEOUT | \
KTI_PAUSE_ONCE)
/**
* struct kthread_iterant - structure describing the function of the kthread
* @type: modifies the kthread behavior using extra flags.
+ * @timeout: timeout value in jiffies.
* @data: pointer to a data passed to the functions.
* @init: function called when the kthread is created.
* @func: function called in the main cycle until the kthread is terminated.
@@ -67,6 +70,7 @@ struct task_struct *kthread_create_on_cpu(int (*threadfn)(void *data),
*/
struct kthread_iterant {
unsigned int type;
+ signed long timeout;
void *data;
void (*init)(void *data);
void (*func)(void *data);
@@ -97,6 +101,7 @@ kthread_iterant_create_on_cpu(struct kthread_iterant *kti,
})
void set_kthread_iterant_int_sleep(void);
+void set_kthread_iterant_int_sleep_timeout(signed long timeout);
void kthread_bind(struct task_struct *k, unsigned int cpu);
void kthread_stop_current(void);
diff --git a/kernel/kthread.c b/kernel/kthread.c
index fa40fb549e22..9a5845674419 100644
--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -455,6 +455,30 @@ void set_kthread_iterant_int_sleep(void)
EXPORT_SYMBOL(set_kthread_iterant_int_sleep);
/**
+ * set_kthread_iterant_int_sleep_timeout - do interuptible sleep
+ * with a timeout before the next iteration
+ * @timeout: timeout value in jiffies
+ *
+ * This function is typically called under a lock, when the main func()
+ * checks for the pending work.
+ *
+ * Kthreads should pause between iterations only when there is no work,
+ * signal pending, freezing, parking, or termination; we want to do most
+ * of these checks properly on a single place: kthread_iterant_fn().
+ * Only the check for pending work need to be done in the main func()
+ * because it is not generic.
+ */
+void set_kthread_iterant_int_sleep_timeout(signed long timeout)
+{
+ struct kthread_iterant *kti = to_kthread_iterant(current);
+
+ set_kthread_iterant_pause_type(kti, KTI_INT_SLEEP_TIMEOUT);
+ kti->timeout = timeout;
+ set_current_state(TASK_INTERRUPTIBLE);
+}
+EXPORT_SYMBOL(set_kthread_iterant_int_sleep_timeout);
+
+/**
* do_kthread_iterant_pause - do the selected pause before next iteration
*
* Most kthreads sleep or wait between iterations. This function
@@ -470,7 +494,9 @@ static void do_kthread_iterant_pause(struct kthread_iterant *kti)
* Explicitly set the task state when it was not set by
* set_kthread_iterant_int_sleep*() functions.
*/
- if (!(type & KTI_PAUSE_ONCE) && (type & KTI_INT_SLEEP))
+ if (!(type & KTI_PAUSE_ONCE) &&
+ ((type & KTI_INT_SLEEP) ||
+ (type & KTI_INT_SLEEP_TIMEOUT)))
set_current_state(TASK_INTERRUPTIBLE);
if (kthread_freezable_should_stop(NULL)) {
@@ -480,6 +506,8 @@ static void do_kthread_iterant_pause(struct kthread_iterant *kti)
if (type & KTI_INT_SLEEP)
freezable_schedule();
+ else if (type & KTI_INT_SLEEP_TIMEOUT)
+ freezable_schedule_timeout(kti->timeout);
else
freezable_cond_resched();
--
1.8.5.6
^ permalink raw reply related
* [RFC PATCH 17/18] ring_buffer: Use the new API for a sleep with a timeout in the benchmark
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Trond Myklebust,
Anna Schumaker, linux-nfs-u79uwXL29TY76Z2rM5mHXA, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko,
live-patching-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek-AlSwsSmVLrQ@public.gmane.org>
It will allow to maintain the checks for freezing, parking, and signal
handling on a single place.
Signed-off-by: Petr Mladek <pmladek-AlSwsSmVLrQ@public.gmane.org>
---
kernel/trace/ring_buffer_benchmark.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/kernel/trace/ring_buffer_benchmark.c b/kernel/trace/ring_buffer_benchmark.c
index 4ecf7c4567e2..ae6295d6e63f 100644
--- a/kernel/trace/ring_buffer_benchmark.c
+++ b/kernel/trace/ring_buffer_benchmark.c
@@ -398,8 +398,7 @@ static void ring_buffer_producer_thread_func(void *arg)
goto test_killed;
trace_printk("Sleeping for 10 secs\n");
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ * SLEEP_TIME);
+ set_kthread_iterant_int_sleep_timeout(HZ * SLEEP_TIME);
return;
test_killed:
--
1.8.5.6
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* [RFC PATCH 18/18] jffs2: Use the new API for a sleep with a timeout
From: Petr Mladek @ 2015-06-05 15:01 UTC (permalink / raw)
To: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Peter Zijlstra
Cc: Richard Weinberger, Steven Rostedt, David Woodhouse, linux-mtd,
Trond Myklebust, Anna Schumaker, linux-nfs, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko, live-patching, linux-api,
linux-kernel, Petr Mladek
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
It allows to maintain the checks for freezing, parking, and signal
handling on a single place.
Note that the sleep with the timeout is used here to slow down
the progress a bit. It does not matter if we do it before or after
calling jffs2_garbage_collect_pass().
Signed-off-by: Petr Mladek <pmladek@suse.cz>
---
fs/jffs2/background.c | 29 +++++++++++------------------
1 file changed, 11 insertions(+), 18 deletions(-)
diff --git a/fs/jffs2/background.c b/fs/jffs2/background.c
index 50c16048ba2d..2d38d40e0ad1 100644
--- a/fs/jffs2/background.c
+++ b/fs/jffs2/background.c
@@ -62,6 +62,16 @@ static void jffs2_garbage_collect_thread_func(void *_c)
}
spin_unlock(&c->erase_completion_lock);
+ /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
+ sigprocmask(SIG_BLOCK, &hupmask, NULL);
+
+ jffs2_dbg(1, "%s(): pass\n", __func__);
+ if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
+ pr_notice("No space for garbage collection. Aborting GC thread\n");
+ kthread_stop_current();
+ }
+ sigprocmask(SIG_UNBLOCK, &hupmask, NULL);
+
/* Problem - immediately after bootup, the GCD spends a lot
* of time in places like jffs2_kill_fragtree(); so much so
* that userspace processes (like gdm and X) are starved
@@ -73,24 +83,7 @@ static void jffs2_garbage_collect_thread_func(void *_c)
* inode in with read_inode() is much preferable to having
* the GC thread get there first.
*/
- schedule_timeout_interruptible(msecs_to_jiffies(50));
-
- if (kthread_should_stop()) {
- jffs2_dbg(1, "%s(): kthread_stop() called\n", __func__);
- return;
- }
-
- try_to_freeze();
-
- /* We don't want SIGHUP to interrupt us. STOP and KILL are OK though. */
- sigprocmask(SIG_BLOCK, &hupmask, NULL);
-
- jffs2_dbg(1, "%s(): pass\n", __func__);
- if (jffs2_garbage_collect_pass(c) == -ENOSPC) {
- pr_notice("No space for garbage collection. Aborting GC thread\n");
- kthread_stop_current();
- }
- sigprocmask(SIG_UNBLOCK, &hupmask, NULL);
+ set_kthread_iterant_int_sleep_timeout(msecs_to_jiffies(50));
}
static void jffs2_garbage_collect_thread_destroy(void *_c)
--
1.8.5.6
^ permalink raw reply related
* Re: [RFC PATCH 09/18] kthread: Make it easier to correctly sleep in iterant kthreads
From: Peter Zijlstra @ 2015-06-05 16:10 UTC (permalink / raw)
To: Petr Mladek
Cc: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Richard Weinberger, Steven Rostedt, David Woodhouse,
linux-mtd-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r, Trond Myklebust,
Anna Schumaker, linux-nfs-u79uwXL29TY76Z2rM5mHXA, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko,
live-patching-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA
In-Reply-To: <1433516477-5153-10-git-send-email-pmladek-AlSwsSmVLrQ@public.gmane.org>
On Fri, Jun 05, 2015 at 05:01:08PM +0200, Petr Mladek wrote:
> Many kthreads go into an interruptible sleep when there is nothing
> to do. They should check if anyone did not requested the kthread
> to terminate, freeze, or park in the meantime. It is easy to do
> it a wrong way.
INTERRUPTIBLE is the wrong state to idle in for kthreads, use
TASK_IDLE.
---
commit 80ed87c8a9ca0cad7ca66cf3bbdfb17559a66dcf
Author: Peter Zijlstra <peterz-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
Date: Fri May 8 14:23:45 2015 +0200
sched/wait: Introduce TASK_NOLOAD and TASK_IDLE
Currently people use TASK_INTERRUPTIBLE to idle kthreads and wait for
'work' because TASK_UNINTERRUPTIBLE contributes to the loadavg. Having
all idle kthreads contribute to the loadavg is somewhat silly.
Now mostly this works OK, because kthreads have all their signals
masked. However there's a few sites where this is causing problems and
TASK_UNINTERRUPTIBLE should be used, except for that loadavg issue.
This patch adds TASK_NOLOAD which, when combined with
TASK_UNINTERRUPTIBLE avoids the loadavg accounting.
As most of imagined usage sites are loops where a thread wants to
idle, waiting for work, a helper TASK_IDLE is introduced.
Signed-off-by: Peter Zijlstra (Intel) <peterz-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
Cc: Julian Anastasov <ja-FgGsKACvmQM@public.gmane.org>
Cc: Linus Torvalds <torvalds-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
Cc: NeilBrown <neilb-l3A5Bk7waGM@public.gmane.org>
Cc: Oleg Nesterov <oleg-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
Cc: Peter Zijlstra <peterz-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
Cc: Thomas Gleixner <tglx-hfZtesqFncYOwBW4kG4KsQ@public.gmane.org>
Signed-off-by: Ingo Molnar <mingo-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
diff --git a/include/linux/sched.h b/include/linux/sched.h
index dd07ac03f82a..7de815c6fa78 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -218,9 +218,10 @@ print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq);
#define TASK_WAKEKILL 128
#define TASK_WAKING 256
#define TASK_PARKED 512
-#define TASK_STATE_MAX 1024
+#define TASK_NOLOAD 1024
+#define TASK_STATE_MAX 2048
-#define TASK_STATE_TO_CHAR_STR "RSDTtXZxKWP"
+#define TASK_STATE_TO_CHAR_STR "RSDTtXZxKWPN"
extern char ___assert_task_state[1 - 2*!!(
sizeof(TASK_STATE_TO_CHAR_STR)-1 != ilog2(TASK_STATE_MAX)+1)];
@@ -230,6 +231,8 @@ extern char ___assert_task_state[1 - 2*!!(
#define TASK_STOPPED (TASK_WAKEKILL | __TASK_STOPPED)
#define TASK_TRACED (TASK_WAKEKILL | __TASK_TRACED)
+#define TASK_IDLE (TASK_UNINTERRUPTIBLE | TASK_NOLOAD)
+
/* Convenience macros for the sake of wake_up */
#define TASK_NORMAL (TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE)
#define TASK_ALL (TASK_NORMAL | __TASK_STOPPED | __TASK_TRACED)
@@ -245,7 +248,8 @@ extern char ___assert_task_state[1 - 2*!!(
((task->state & (__TASK_STOPPED | __TASK_TRACED)) != 0)
#define task_contributes_to_load(task) \
((task->state & TASK_UNINTERRUPTIBLE) != 0 && \
- (task->flags & PF_FROZEN) == 0)
+ (task->flags & PF_FROZEN) == 0 && \
+ (task->state & TASK_NOLOAD) == 0)
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 30fedaf3e56a..d57a575fe31f 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -147,7 +147,8 @@ TRACE_EVENT(sched_switch,
__print_flags(__entry->prev_state & (TASK_STATE_MAX-1), "|",
{ 1, "S"} , { 2, "D" }, { 4, "T" }, { 8, "t" },
{ 16, "Z" }, { 32, "X" }, { 64, "x" },
- { 128, "K" }, { 256, "W" }, { 512, "P" }) : "R",
+ { 128, "K" }, { 256, "W" }, { 512, "P" },
+ { 1024, "N" }) : "R",
__entry->prev_state & TASK_STATE_MAX ? "+" : "",
__entry->next_comm, __entry->next_pid, __entry->next_prio)
);
--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply related
* Re: [RFC PATCH 00/18] kthreads/signal: Safer kthread API and signal handling
From: Peter Zijlstra @ 2015-06-05 16:22 UTC (permalink / raw)
To: Petr Mladek
Cc: Andrew Morton, Oleg Nesterov, Tejun Heo, Ingo Molnar,
Richard Weinberger, Steven Rostedt, David Woodhouse, linux-mtd,
Trond Myklebust, Anna Schumaker, linux-nfs, Chris Mason,
Paul E. McKenney, Thomas Gleixner, Linus Torvalds, Jiri Kosina,
Borislav Petkov, Michal Hocko, live-patching, linux-api,
linux-kernel
In-Reply-To: <1433516477-5153-1-git-send-email-pmladek@suse.cz>
On Fri, Jun 05, 2015 at 05:00:59PM +0200, Petr Mladek wrote:
> Workqueue
>
>
> Workqueues are quite popular and many kthreads have already been
> converted into them.
>
> Work queues allow to split the function into even more pieces and
> reach the common check point more often. It is especially useful
> when a kthread handles more tasks and is woken when some work
> is needed. Then we could queue the appropriate work instead
> of waking the whole kthread and checking what exactly needs
> to be done.
>
> But there are many kthreads that need to cycle many times
> until some work is finished, e.g. khugepaged, virtio_balloon,
> jffs2_garbage_collect_thread. They would need to queue the
> work item repeatedly from the same work item or between
> more work items. It would be a strange semantic.
>
> Work queues allow to share the same kthread between more users.
> It helps to reduce the number of running kthreads. It is especially
> useful if you would need a kthread for each CPU.
>
> But this might also be a disadvantage. Just look into the output
> of the command "ps" and see the many [kworker*] processes. One
> might see this a black hole. If a kworker makes the system busy,
> it is less obvious what the problem is in compare with the old
> "simple" and dedicated kthreads.
>
> Yes, we could add some debugging tools for work queues but
> it would be another non-standard thing that developers and
> system administrators would need to understand.
>
> Another thing is that work queues have their own scheduler. If we
> move even more tasks there it might need even more love. Anyway,
> the extra scheduler adds another level of complexity when
> debugging problems.
There's a lot more problems with workqueues:
- they're not regular tasks and all the task controls don't work on
them. This means all things scheduler, like cpu-affinity, nice, and
RT/deadline scheduling policies. Instead there is some half baked
secondary interface for some of these.
But this also very much includes things like cgroups, which brings me
to the second point.
- its oblivious to cgroups (as it is to RT priority for example) both
leading to priority inversion. A work enqueued from a deep/limited
cgroup does not inherit the task's cgroup. Instead this work is ran
from the root cgroup.
This breaks cgroup isolation, more significantly so when a large part
of the actual work is done from workqueues (as some workloads end up
being). Instead of being able to control the work, it all ends up in
the root cgroup outside of control.
^ permalink raw reply
* Re: [PATCH v2] seccomp: add ptrace options for suspend/resume
From: Oleg Nesterov @ 2015-06-05 21:16 UTC (permalink / raw)
To: Tycho Andersen
Cc: linux-kernel, linux-api, Kees Cook, Andy Lutomirski, Will Drewry,
Roland McGrath, Pavel Emelyanov, Serge E. Hallyn
In-Reply-To: <20150604210529.GJ3160@smitten>
Hi Tycho,
On 06/04, Tycho Andersen wrote:
>
> On Thu, Jun 04, 2015 at 08:31:49PM +0200, Oleg Nesterov wrote:
> > Also. Suppose that the tracer sets SUSPEND_SECCOMP and then drops
> > CAP_SYS_ADMIN. After that it can't set or clear other ptrace options.
>
> Is this a case we're concerned about? I think this should be ok (i.e.
> "don't do that" :).
Sure, I won't insist. Just this looks a bit confusing. I mean, if you
read this code it is not clear why may_suspend_seccomp() is called even
if the tracer changes other bits, and "data & PTRACE_O_SUSPEND" is true
only because the tracer does _not_ change this option.
IOW, imo the code will just look better if may_suspend_seccomp() is
called only when PTRACE_O_SUSPEND is set. But this is minor, feel free
to ignore.
> > > +#ifdef CONFIG_CHECKPOINT_RESTORE
> > > +bool may_suspend_seccomp(void)
> > > +{
> > > + if (!capable(CAP_SYS_ADMIN))
> > > + return false;
> > > +
> > > + if (current->seccomp.mode != SECCOMP_MODE_DISABLED)
> > > + return false;
> >
> > Heh. OK, I won't argue with the new check too ;)
>
> Actually now that I think about it I agree with you, these checks
> don't seem necessary. Even inside a user namespace, if you can ptrace
> a process you can make it do whatever you want irrespective of
> seccomp, as long as it has the necessary capabilities. Once the
> seccomp checks are run after ptrace, they'll be enforced so you
> couldn't have it call whatever you want in the first place.
Good ;)
> Still, perhaps I'm missing something...
Kees, Andy?
Oleg.
^ permalink raw reply
* [PATCH v3] seccomp: add ptrace options for suspend/resume
From: Tycho Andersen @ 2015-06-05 21:21 UTC (permalink / raw)
To: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA
Cc: Tycho Andersen, Kees Cook, Andy Lutomirski, Will Drewry,
Roland McGrath, Oleg Nesterov, Pavel Emelyanov, Serge E. Hallyn
This patch is the first step in enabling checkpoint/restore of processes
with seccomp enabled.
One of the things CRIU does while dumping tasks is inject code into them
via ptrace to collect information that is only available to the process
itself. However, if we are in a seccomp mode where these processes are
prohibited from making these syscalls, then what CRIU does kills the task.
This patch adds a new ptrace option, PTRACE_O_SUSPEND_SECCOMP, that enables
a task from the init user namespace which has CAP_SYS_ADMIN and no seccomp
filters to disable (and re-enable) seccomp filters for another task so that
they can be successfully dumped (and restored). We restrict the set of
processes that can disable seccomp through ptrace because although today
ptrace can be used to bypass seccomp, there is some discussion of closing
this loophole in the future and we would like this patch to not depend on
that behavior and be future proofed for when it is removed.
Note that seccomp can be suspended before any filters are actually
installed; this behavior is useful on criu restore, so that we can suspend
seccomp, restore the filters, unmap our restore code from the restored
process' address space, and then resume the task by detaching and have the
filters resumed as well.
v2 changes:
* require that the tracer have no seccomp filters installed
* drop TIF_NOTSC manipulation from the patch
* change from ptrace command to a ptrace option and use this ptrace option
as the flag to check. This means that as soon as the tracer
detaches/dies, seccomp is re-enabled and as a corrollary that one can not
disable seccomp across PTRACE_ATTACHs.
v3 changes:
* get rid of various #ifdefs everywhere
* report more sensible errors when PTRACE_O_SUSPEND_SECCOMP is incorrectly
used
Signed-off-by: Tycho Andersen <tycho.andersen-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
CC: Kees Cook <keescook-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
CC: Andy Lutomirski <luto-kltTT9wpgjJwATOyAt5JVQ@public.gmane.org>
CC: Will Drewry <wad-F7+t8E8rja9g9hUCZPvPmw@public.gmane.org>
CC: Roland McGrath <roland-/Z5OmTQCD9xF6kxbq+BtvQ@public.gmane.org>
CC: Oleg Nesterov <oleg-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
CC: Pavel Emelyanov <xemul-bzQdu9zFT3WakBO8gow8eQ@public.gmane.org>
CC: Serge E. Hallyn <serge.hallyn-GeWIH/nMZzLQT0dZR+AlfA@public.gmane.org>
---
include/linux/ptrace.h | 1 +
include/linux/seccomp.h | 10 ++++++++++
include/uapi/linux/ptrace.h | 6 ++++--
kernel/ptrace.c | 10 ++++++++++
kernel/seccomp.c | 22 ++++++++++++++++++++++
5 files changed, 47 insertions(+), 2 deletions(-)
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index 987a73a..061265f 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -34,6 +34,7 @@
#define PT_TRACE_SECCOMP PT_EVENT_FLAG(PTRACE_EVENT_SECCOMP)
#define PT_EXITKILL (PTRACE_O_EXITKILL << PT_OPT_FLAG_SHIFT)
+#define PT_SUSPEND_SECCOMP (PTRACE_O_SUSPEND_SECCOMP << PT_OPT_FLAG_SHIFT)
/* single stepping state bits (used on ARM and PA-RISC) */
#define PT_SINGLESTEP_BIT 31
diff --git a/include/linux/seccomp.h b/include/linux/seccomp.h
index a19ddac..1d55cd9 100644
--- a/include/linux/seccomp.h
+++ b/include/linux/seccomp.h
@@ -95,4 +95,14 @@ static inline void get_seccomp_filter(struct task_struct *tsk)
return;
}
#endif /* CONFIG_SECCOMP_FILTER */
+
+#ifdef CONFIG_CHECKPOINT_RESTORE
+extern bool may_suspend_seccomp(void);
+#else
+static inline bool may_suspend_seccomp(void)
+{
+ return false;
+}
+#endif
+
#endif /* _LINUX_SECCOMP_H */
diff --git a/include/uapi/linux/ptrace.h b/include/uapi/linux/ptrace.h
index cf1019e..a7a6979 100644
--- a/include/uapi/linux/ptrace.h
+++ b/include/uapi/linux/ptrace.h
@@ -89,9 +89,11 @@ struct ptrace_peeksiginfo_args {
#define PTRACE_O_TRACESECCOMP (1 << PTRACE_EVENT_SECCOMP)
/* eventless options */
-#define PTRACE_O_EXITKILL (1 << 20)
+#define PTRACE_O_EXITKILL (1 << 20)
+#define PTRACE_O_SUSPEND_SECCOMP (1 << 21)
-#define PTRACE_O_MASK (0x000000ff | PTRACE_O_EXITKILL)
+#define PTRACE_O_MASK (\
+ 0x000000ff | PTRACE_O_EXITKILL | PTRACE_O_SUSPEND_SECCOMP)
#include <asm/ptrace.h>
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index c8e0e05..a860deb 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -15,6 +15,7 @@
#include <linux/highmem.h>
#include <linux/pagemap.h>
#include <linux/ptrace.h>
+#include <linux/seccomp.h>
#include <linux/security.h>
#include <linux/signal.h>
#include <linux/uio.h>
@@ -556,6 +557,15 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data)
if (data & ~(unsigned long)PTRACE_O_MASK)
return -EINVAL;
+ if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) {
+ if (!config_enabled(CONFIG_CHECKPOINT_RESTORE) ||
+ !config_enabled(CONFIG_SECCOMP))
+ return -EINVAL;
+
+ if (!may_suspend_seccomp())
+ return -EPERM;
+ }
+
/* Avoid intermediate state when all opts are cleared */
flags = child->ptrace;
flags &= ~(PTRACE_O_MASK << PT_OPT_FLAG_SHIFT);
diff --git a/kernel/seccomp.c b/kernel/seccomp.c
index 980fd26..cdd97f6 100644
--- a/kernel/seccomp.c
+++ b/kernel/seccomp.c
@@ -590,6 +590,10 @@ void secure_computing_strict(int this_syscall)
{
int mode = current->seccomp.mode;
+ if (config_enabled(CONFIG_CHECKPOINT_RESTORE) &&
+ unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
+ return;
+
if (mode == 0)
return;
else if (mode == SECCOMP_MODE_STRICT)
@@ -691,6 +695,10 @@ u32 seccomp_phase1(struct seccomp_data *sd)
int this_syscall = sd ? sd->nr :
syscall_get_nr(current, task_pt_regs(current));
+ if (config_enabled(CONFIG_CHECKPOINT_RESTORE) &&
+ unlikely(current->ptrace & PT_SUSPEND_SECCOMP))
+ return SECCOMP_PHASE1_OK;
+
switch (mode) {
case SECCOMP_MODE_STRICT:
__secure_computing_strict(this_syscall); /* may call do_exit */
@@ -901,3 +909,17 @@ long prctl_set_seccomp(unsigned long seccomp_mode, char __user *filter)
/* prctl interface doesn't have flags, so they are always zero. */
return do_seccomp(op, 0, uargs);
}
+
+#ifdef CONFIG_CHECKPOINT_RESTORE
+bool may_suspend_seccomp(void)
+{
+ if (!capable(CAP_SYS_ADMIN))
+ return false;
+
+ if (current->seccomp.mode != SECCOMP_MODE_DISABLED ||
+ current->ptrace & PT_SUSPEND_SECCOMP)
+ return false;
+
+ return true;
+}
+#endif /* CONFIG_CHECKPOINT_RESTORE */
--
2.1.4
^ permalink raw reply related
* Re: [PATCH v2] seccomp: add ptrace options for suspend/resume
From: Tycho Andersen @ 2015-06-05 21:26 UTC (permalink / raw)
To: Oleg Nesterov
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Kees Cook, Andy Lutomirski,
Will Drewry, Roland McGrath, Pavel Emelyanov, Serge E. Hallyn
In-Reply-To: <20150605211650.GA25718-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
On Fri, Jun 05, 2015 at 11:16:50PM +0200, Oleg Nesterov wrote:
> Hi Tycho,
>
> On 06/04, Tycho Andersen wrote:
> >
> > On Thu, Jun 04, 2015 at 08:31:49PM +0200, Oleg Nesterov wrote:
> > > Also. Suppose that the tracer sets SUSPEND_SECCOMP and then drops
> > > CAP_SYS_ADMIN. After that it can't set or clear other ptrace options.
> >
> > Is this a case we're concerned about? I think this should be ok (i.e.
> > "don't do that" :).
>
> Sure, I won't insist. Just this looks a bit confusing. I mean, if you
> read this code it is not clear why may_suspend_seccomp() is called even
> if the tracer changes other bits, and "data & PTRACE_O_SUSPEND" is true
> only because the tracer does _not_ change this option.
>
> IOW, imo the code will just look better if may_suspend_seccomp() is
> called only when PTRACE_O_SUSPEND is set. But this is minor, feel free
> to ignore.
Oh, I understand now. I think this is fixed in v3 that I just sent,
but may go away in any case if we remove the checks...
> > > > +#ifdef CONFIG_CHECKPOINT_RESTORE
> > > > +bool may_suspend_seccomp(void)
> > > > +{
> > > > + if (!capable(CAP_SYS_ADMIN))
> > > > + return false;
> > > > +
> > > > + if (current->seccomp.mode != SECCOMP_MODE_DISABLED)
> > > > + return false;
> > >
> > > Heh. OK, I won't argue with the new check too ;)
> >
> > Actually now that I think about it I agree with you, these checks
> > don't seem necessary. Even inside a user namespace, if you can ptrace
> > a process you can make it do whatever you want irrespective of
> > seccomp, as long as it has the necessary capabilities. Once the
> > seccomp checks are run after ptrace, they'll be enforced so you
> > couldn't have it call whatever you want in the first place.
>
> Good ;)
>
> > Still, perhaps I'm missing something...
>
> Kees, Andy?
Doh, just sent v3. If you guys are convinced too, then I can send v4
with these checks removed.
Tycho
^ permalink raw reply
* Re: [PATCH v3] seccomp: add ptrace options for suspend/resume
From: Oleg Nesterov @ 2015-06-05 21:52 UTC (permalink / raw)
To: Tycho Andersen
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Kees Cook, Andy Lutomirski,
Will Drewry, Roland McGrath, Pavel Emelyanov, Serge E. Hallyn
In-Reply-To: <1433539312-3999-1-git-send-email-tycho.andersen-Z7WLFzj8eWMS+FvcfC7Uqw@public.gmane.org>
Tycho,
I hate myself, but I have another nit ;) again, it is not that I think
you should updtate the patch, just fyi...
On 06/05, Tycho Andersen wrote:
>
> --- a/include/linux/seccomp.h
> +++ b/include/linux/seccomp.h
> @@ -95,4 +95,14 @@ static inline void get_seccomp_filter(struct task_struct *tsk)
> return;
> }
> #endif /* CONFIG_SECCOMP_FILTER */
> +
> +#ifdef CONFIG_CHECKPOINT_RESTORE
> +extern bool may_suspend_seccomp(void);
> +#else
> +static inline bool may_suspend_seccomp(void)
> +{
> + return false;
> +}
> +#endif
This looks wrong. There is no "extern may_suspend_seccomp()" if
CONFIG_SECCOMP=n, kernel/seccomp.c is not compiled. So you need another
ifdef(CONFIG_SECCOMP).
At the same time this does not matter and you do not need the dummy
"inline" version at all:
> @@ -556,6 +557,15 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data)
> if (data & ~(unsigned long)PTRACE_O_MASK)
> return -EINVAL;
>
> + if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) {
> + if (!config_enabled(CONFIG_CHECKPOINT_RESTORE) ||
> + !config_enabled(CONFIG_SECCOMP))
> + return -EINVAL;
> +
> + if (!may_suspend_seccomp())
> + return -EPERM;
gcc will optimize out may_suspend_seccomp() unless both options are
enabled.
Oleg.
^ permalink raw reply
* Re: [PATCH v3] seccomp: add ptrace options for suspend/resume
From: Tycho Andersen @ 2015-06-05 22:06 UTC (permalink / raw)
To: Oleg Nesterov
Cc: linux-kernel, linux-api, Kees Cook, Andy Lutomirski, Will Drewry,
Roland McGrath, Pavel Emelyanov, Serge E. Hallyn
In-Reply-To: <20150605215208.GA27105@redhat.com>
On Fri, Jun 05, 2015 at 11:52:08PM +0200, Oleg Nesterov wrote:
> Tycho,
>
> I hate myself, but I have another nit ;) again, it is not that I think
> you should updtate the patch, just fyi...
No worries :)
> On 06/05, Tycho Andersen wrote:
> >
> > --- a/include/linux/seccomp.h
> > +++ b/include/linux/seccomp.h
> > @@ -95,4 +95,14 @@ static inline void get_seccomp_filter(struct task_struct *tsk)
> > return;
> > }
> > #endif /* CONFIG_SECCOMP_FILTER */
> > +
> > +#ifdef CONFIG_CHECKPOINT_RESTORE
> > +extern bool may_suspend_seccomp(void);
> > +#else
> > +static inline bool may_suspend_seccomp(void)
> > +{
> > + return false;
> > +}
> > +#endif
>
> This looks wrong. There is no "extern may_suspend_seccomp()" if
> CONFIG_SECCOMP=n, kernel/seccomp.c is not compiled. So you need another
> ifdef(CONFIG_SECCOMP).
>
> At the same time this does not matter and you do not need the dummy
> "inline" version at all:
>
> > @@ -556,6 +557,15 @@ static int ptrace_setoptions(struct task_struct *child, unsigned long data)
> > if (data & ~(unsigned long)PTRACE_O_MASK)
> > return -EINVAL;
> >
> > + if (unlikely(data & PTRACE_O_SUSPEND_SECCOMP)) {
> > + if (!config_enabled(CONFIG_CHECKPOINT_RESTORE) ||
> > + !config_enabled(CONFIG_SECCOMP))
> > + return -EINVAL;
> > +
> > + if (!may_suspend_seccomp())
> > + return -EPERM;
>
> gcc will optimize out may_suspend_seccomp() unless both options are
> enabled.
Whoops, yes, you're right. I did build test in all the configurations
to catch stuff like this, but gcc was too smart for me. What's the
right thing to do, just leave out the definition of
may_suspend_seccomp all together, or add in another if defined() in
the header?
Maybe we will get rid of this pesky function all together though...
Tycho
^ permalink raw reply
* Re: [PATCH v3] seccomp: add ptrace options for suspend/resume
From: Oleg Nesterov @ 2015-06-05 23:48 UTC (permalink / raw)
To: Tycho Andersen
Cc: linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-api-u79uwXL29TY76Z2rM5mHXA, Kees Cook, Andy Lutomirski,
Will Drewry, Roland McGrath, Pavel Emelyanov, Serge E. Hallyn
In-Reply-To: <20150605220619.GI31599@hopstrocity>
On 06/05, Tycho Andersen wrote:
>
> right thing to do, just leave out the definition of
> may_suspend_seccomp all together, or add in another if defined() in
> the header?
Just declare it unconditionally in .h. The kernel relies on this kind
of dead-code elimination anyway. For example, please look at
"extern void __put_user_bad(void)" in uaccess.h.
IOW,
extern void undefined_func(void);
if (0)
undefined_func();
should be safe.
> Maybe we will get rid of this pesky function all together though...
Yes ;)
Oleg.
^ permalink raw reply
* Re: [CFT][PATCH 00/10] Making new mounts of proc and sysfs as safe as bind mounts (take 2)
From: Eric W. Biederman @ 2015-06-06 18:56 UTC (permalink / raw)
To: Richard Weinberger
Cc: Serge Hallyn, Andy Lutomirski, Seth Forshee, Linux API,
Linux Containers, Greg Kroah-Hartman, Kenton Varda,
Michael Kerrisk-manpages, Linux FS Devel, Tejun Heo,
libvir-list@redhat.com, Daniel P. Berrange, Cedric Bosdonnat
In-Reply-To: <556831CF.9040600@nod.at>
Richard Weinberger <richard@nod.at> writes:
> [CC'ing libvirt-lxc folks]
>
> Am 28.05.2015 um 23:32 schrieb Eric W. Biederman:
>> Richard Weinberger <richard@nod.at> writes:
>>
>>> Am 28.05.2015 um 21:57 schrieb Eric W. Biederman:
>>>>> FWIW, it breaks also libvirt-lxc:
>>>>> Error: internal error: guest failed to start: Failed to re-mount /proc/sys on /proc/sys flags=1021: Operation not permitted
>>>>
>>>> Interesting. I had not anticipated a failure there? And it is failing
>>>> in remount? Oh that is interesting.
>>>>
>>>> That implies that there is some flag of the original mount of /proc that
>>>> the remount of /proc/sys is clearing, and that previously
>>>>
>>>> The flags specified are current rdonly,remount,bind so I expect there
>>>> are some other flags on proc that libvirt-lxc is clearing by accident
>>>> and we did not fail before because the kernel was not enforcing things.
>>>
>>> Please see:
>>> http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l933
>>> lxcContainerMountBasicFS()
>>>
>>> and:
>>> http://libvirt.org/git/?p=libvirt.git;a=blob;f=src/lxc/lxc_container.c;h=9a9ae5c2aaf0f90ff472f24fda43c077b44998c7;hb=HEAD#l850
>>> lxcBasicMounts
>>>
>>>> What are the mount flags in a working libvirt-lxc?
>>>
>>> See:
>>> test1:~ # cat /proc/self/mountinfo
>>> 149 147 0:56 / /proc rw,nosuid,nodev,noexec,relatime - proc proc rw
>>> 150 149 0:56 /sys /proc/sys ro,nodev,relatime - proc proc rw
>>
>>> If you need more info, please let me know. :-)
>>
>> Oh interesting I had not realized libvirt-lxc had grown an unprivileged
>> mode using user namespaces.
>>
>> This does appear to be a classic remount bug, where you are not
>> preserving the permissions. It appears the fact that the code
>> failed to enforce locked permissions on the fresh mount of proc
>> was hiding this bug until now.
>>
>> I expect what you actually want is the code below:
>>
>> diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
>> index 9a9ae5c2aaf0..f008a7484bfe 100644
>> --- a/src/lxc/lxc_container.c
>> +++ b/src/lxc/lxc_container.c
>> @@ -850,7 +850,7 @@ typedef struct {
>>
>> static const virLXCBasicMountInfo lxcBasicMounts[] = {
>> { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
>> - { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
>> + { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
>> { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
>> { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
>> { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
>>
>> Or possibly just:
>>
>> diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
>> index 9a9ae5c2aaf0..a60ccbd12bfc 100644
>> --- a/src/lxc/lxc_container.c
>> +++ b/src/lxc/lxc_container.c
>> @@ -850,7 +850,7 @@ typedef struct {
>>
>> static const virLXCBasicMountInfo lxcBasicMounts[] = {
>> { "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
>> - { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
>> + { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, true, false, false },
>> { "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
>> { "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
>> { "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
>>
>> As the there is little point in making /proc/sys read-only in a
>> user-namespace, as the permission checks are uid based and no-one should
>> have the global uid 0 in your container. Making mounting /proc/sys
>> read-only rather pointless.
>
> Eric, using the patch below I was able to spawn a user-namespace enabled container
> using libvirt-lxc. :-)
>
> I had to:
> 1. Disable the read-only mount of /proc/sys which is anyway useless in the user-namespace case.
> 2. Disable the /proc/sys/net/ipv{4,6} bind mounts, this ugly hack is only needed for the non user-namespace case.
> 3. Remove MS_RDONLY from the sysfs mount (For the non user-namespace case we'd have to keep this, though).
>
> Daniel, I'd take this as a chance to disable all the MS_RDONLY games if user-namespace are configured.
> With Eric's fixes they hurt us. And as I wrote many times before if root within the user-namespace
> is able to do nasty things in /sys and /proc that's a plain kernel bug which needs fixing. There is no
> point in mounting these read-only. Except for the case then no user-namespace is used.
>
For clarity the patch below appears to be the minimal change needed to
fix this security issue.
AKA add mnt_mflags in when remounting something read-only.
/proc/sys needed to be updated so it had the proper flags to be added
back in.
I hope this helps.
diff --git a/src/lxc/lxc_container.c b/src/lxc/lxc_container.c
index 9a9ae5c2aaf0..11e9514e0761 100644
--- a/src/lxc/lxc_container.c
+++ b/src/lxc/lxc_container.c
@@ -850,7 +850,7 @@ typedef struct {
static const virLXCBasicMountInfo lxcBasicMounts[] = {
{ "proc", "/proc", "proc", MS_NOSUID|MS_NOEXEC|MS_NODEV, false, false, false },
- { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_RDONLY, false, false, false },
+ { "/proc/sys", "/proc/sys", NULL, MS_BIND|MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
{ "/.oldroot/proc/sys/net/ipv4", "/proc/sys/net/ipv4", NULL, MS_BIND, false, false, true },
{ "/.oldroot/proc/sys/net/ipv6", "/proc/sys/net/ipv6", NULL, MS_BIND, false, false, true },
{ "sysfs", "/sys", "sysfs", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false, false, false },
@@ -1030,7 +1030,7 @@ static int lxcContainerMountBasicFS(bool userns_enabled,
if (bindOverReadonly &&
mount(mnt_src, mnt->dst, NULL,
- MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
+ MS_BIND|MS_REMOUNT|mnt_mflags|MS_RDONLY, NULL) < 0) {
virReportSystemError(errno,
_("Failed to re-mount %s on %s flags=%x"),
mnt_src, mnt->dst,
Eric
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox