Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1511250 > unrolled thread
| Started by | Tejun Heo <tj@kernel.org> |
|---|---|
| First post | 2016-10-28 19:00 +0200 |
| Last post | 2016-11-09 00:00 +0100 |
| Articles | 9 — 3 participants |
Back to article view | Back to linux.kernel
[PATCHSET RFC] sched, jbd2: mark sleeps on journal->j_checkpoint_mutex as iowait Tejun Heo <tj@kernel.org> - 2016-10-28 19:00 +0200
[PATCH 2/4] sched: separate out io_schedule_prepare() and io_schedule_finish() Tejun Heo <tj@kernel.org> - 2016-10-28 19:00 +0200
[PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() Tejun Heo <tj@kernel.org> - 2016-10-28 19:10 +0200
Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() Peter Zijlstra <peterz@infradead.org> - 2016-10-28 20:30 +0200
Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() Peter Zijlstra <peterz@infradead.org> - 2016-10-28 21:10 +0200
Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() Peter Zijlstra <peterz@infradead.org> - 2016-10-29 05:30 +0200
Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() Tejun Heo <tj@kernel.org> - 2016-10-31 17:50 +0100
Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() Pavan Kondeti <pkondeti@codeaurora.org> - 2016-11-03 16:40 +0100
Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() Tejun Heo <tj@kernel.org> - 2016-11-09 00:00 +0100
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2016-10-28 19:00 +0200 |
| Subject | [PATCHSET RFC] sched, jbd2: mark sleeps on journal->j_checkpoint_mutex as iowait |
| Message-ID | <sxiFA-2q3-15@gated-at.bofh.it> |
Hello, When there's heavy metadata operation traffic on ext4, the journal gets filled soon and majority of filesystem users end up blocking on journal->j_checkpoint_mutex with a stacktrace similar to the following. [<ffffffff8c32e758>] __jbd2_log_wait_for_space+0xb8/0x1d0 [<ffffffff8c3285f6>] add_transaction_credits+0x286/0x2a0 [<ffffffff8c32876c>] start_this_handle+0x10c/0x400 [<ffffffff8c328c5b>] jbd2__journal_start+0xdb/0x1e0 [<ffffffff8c30ee5d>] __ext4_journal_start_sb+0x6d/0x120 [<ffffffff8c2d713e>] __ext4_new_inode+0x64e/0x1330 [<ffffffff8c2e9bf0>] ext4_create+0xc0/0x1c0 [<ffffffff8c2570fd>] path_openat+0x124d/0x1380 [<ffffffff8c258501>] do_filp_open+0x91/0x100 [<ffffffff8c2462d0>] do_sys_open+0x130/0x220 [<ffffffff8c2463de>] SyS_open+0x1e/0x20 [<ffffffff8c7ec5b2>] entry_SYSCALL_64_fastpath+0x1a/0xa4 [<ffffffffffffffff>] 0xffffffffffffffff Because the sleeps on the mutex aren't accounted as iowait, the system doesn't show the usual signs of being bogged down by IOs - both iowait and /proc/stat:procs_blocked stay misleadingly low. While propagation of iowait through locking constructs is far from being strict, heavy contention on j_checkpoint_mutex is easy to trigger, obviously iowait and getting it right can help users in tracking down the issue quite a bit. Due to the way io_schedule() is implemented, it currently is hairy to add an io variant to an existing interface - the schedule() call itself, which is usually buried deep, should be replaced with io_schedule(). As we already have current->in_iowait to mark the task as sleeping for iowait, this can be made easy by breaking up io_schedule() into multiple steps so that the preparation and marking can be done before calling an existing interafce and the actual iowait accounting can be done from inside the scheduler. What do you think? This patch contains the following four patches. 0001-sched-move-IO-scheduling-accounting-from-io_schedule.patch 0002-sched-separate-out-io_schedule_prepare-and-io_schedu.patch 0003-mutex-add-mutex_lock_io.patch 0004-jbd2-use-mutex_lock_io-for-journal-j_checkpoint_mute.patch 0001-0002 implement io_schedule_prepare/finish(). 0003 implements mutex_lock_io() using io_schedule_prepare/finish(). 0004 uses mutex_lock_io() on journal->j_checkpoint_mutex. This patchset is also available in the following git branch. git://git.kernel.org/pub/scm/linux/kernel/git/tj/misc.git review-mutex_lock_io Thanks, diffstat follows. fs/jbd2/commit.c | 2 - fs/jbd2/journal.c | 14 ++++++------- include/linux/mutex.h | 4 +++ include/linux/sched.h | 8 ++----- kernel/locking/mutex.c | 24 ++++++++++++++++++++++ kernel/sched/core.c | 52 +++++++++++++++++++++++++++++++++++++------------ 6 files changed, 79 insertions(+), 25 deletions(-) -- tejun
[toc] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2016-10-28 19:00 +0200 |
| Subject | [PATCH 2/4] sched: separate out io_schedule_prepare() and io_schedule_finish() |
| Message-ID | <sxiFA-2q3-51@gated-at.bofh.it> |
| In reply to | #1511250 |
Now that IO schedule accounting is done inside __schedule(),
io_schedule() can be split into three steps - prep, schedule, and
finish - where the schedule part doesn't need any special annotation.
This allows marking a sleep as iowait by simply wrapping an existing
blocking function with io_schedule_prepare() and io_schedule_finish().
Because task_struct->in_iowait is single bit, the caller of
io_schedule_prepare() needs to record and the pass its state to
io_schedule_finish() to be safe regarding nesting. While this isn't
the prettiest, these functions are mostly gonna be used by core
functions and we don't want to use more space for ->in_iowait.
While at it, as it's simple to do now, reimplement io_schedule()
without unnecessarily going through io_schedule_timeout().
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Jens Axboe <axboe@kernel.dk>
---
include/linux/sched.h | 8 +++-----
kernel/sched/core.c | 33 ++++++++++++++++++++++++++++-----
2 files changed, 31 insertions(+), 10 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 348f51b..c025f77 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -441,12 +441,10 @@ extern signed long schedule_timeout_idle(signed long timeout);
asmlinkage void schedule(void);
extern void schedule_preempt_disabled(void);
+extern int __must_check io_schedule_prepare(void);
+extern void io_schedule_finish(int token);
extern long io_schedule_timeout(long timeout);
-
-static inline void io_schedule(void)
-{
- io_schedule_timeout(MAX_SCHEDULE_TIMEOUT);
-}
+extern void io_schedule(void);
void __noreturn do_task_dead(void);
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index f6baa38..30d3185 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5067,25 +5067,48 @@ int __sched yield_to(struct task_struct *p, bool preempt)
}
EXPORT_SYMBOL_GPL(yield_to);
+int io_schedule_prepare(void)
+{
+ int old_iowait = current->in_iowait;
+
+ current->in_iowait = 1;
+ blk_schedule_flush_plug(current);
+
+ return old_iowait;
+}
+
+void io_schedule_finish(int token)
+{
+ current->in_iowait = token;
+}
+
/*
* This task is about to go to sleep on IO. Increment rq->nr_iowait so
* that process accounting knows that this is a task in IO wait state.
*/
long __sched io_schedule_timeout(long timeout)
{
- int old_iowait = current->in_iowait;
+ int token;
long ret;
- current->in_iowait = 1;
- blk_schedule_flush_plug(current);
-
+ token = io_schedule_prepare();
ret = schedule_timeout(timeout);
- current->in_iowait = old_iowait;
+ io_schedule_finish(token);
return ret;
}
EXPORT_SYMBOL(io_schedule_timeout);
+void io_schedule(void)
+{
+ int token;
+
+ token = io_schedule_prepare();
+ schedule();
+ io_schedule_finish(token);
+}
+EXPORT_SYMBOL(io_schedule);
+
/**
* sys_sched_get_priority_max - return maximum RT priority.
* @policy: scheduling class.
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2016-10-28 19:10 +0200 |
| Subject | [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() |
| Message-ID | <sxiPg-2Iq-25@gated-at.bofh.it> |
| In reply to | #1511250 |
For an interface to support blocking for IOs, it must call
io_schedule() instead of schedule(). This makes it tedious to add IO
blocking to existing interfaces as the switching between schedule()
and io_schedule() is often buried deep.
As we already have a way to mark the task as IO scheduling, this can
be made easier by separating out io_schedule() into multiple steps so
that IO schedule preparation can be performed before invoking a
blocking interface and the actual accounting happens inside
schedule().
io_schedule_timeout() does the following three things prior to calling
schedule_timeout().
1. Mark the task as scheduling for IO.
2. Flush out plugged IOs.
3. Account the IO scheduling.
#1 and #2 can be performed in the prepartaion step while #3 must be
done close to the actual scheduling. This patch moves #3 into
__schedule() so that later patches can separate out preparation and
finish steps from io_schedule().
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Jens Axboe <axboe@kernel.dk>
---
kernel/sched/core.c | 19 ++++++++++++-------
1 file changed, 12 insertions(+), 7 deletions(-)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 94732d1..f6baa38 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -3336,11 +3336,17 @@ static void __sched notrace __schedule(bool preempt)
unsigned long *switch_count;
struct pin_cookie cookie;
struct rq *rq;
- int cpu;
+ int cpu, in_iowait;
cpu = smp_processor_id();
rq = cpu_rq(cpu);
prev = rq->curr;
+ in_iowait = prev->in_iowait;
+
+ if (in_iowait) {
+ delayacct_blkio_start();
+ atomic_inc(&rq->nr_iowait);
+ }
schedule_debug(prev);
@@ -3406,6 +3412,11 @@ static void __sched notrace __schedule(bool preempt)
}
balance_callback(rq);
+
+ if (in_iowait) {
+ atomic_dec(&rq->nr_iowait);
+ delayacct_blkio_end();
+ }
}
void __noreturn do_task_dead(void)
@@ -5063,19 +5074,13 @@ EXPORT_SYMBOL_GPL(yield_to);
long __sched io_schedule_timeout(long timeout)
{
int old_iowait = current->in_iowait;
- struct rq *rq;
long ret;
current->in_iowait = 1;
blk_schedule_flush_plug(current);
- delayacct_blkio_start();
- rq = raw_rq();
- atomic_inc(&rq->nr_iowait);
ret = schedule_timeout(timeout);
current->in_iowait = old_iowait;
- atomic_dec(&rq->nr_iowait);
- delayacct_blkio_end();
return ret;
}
--
2.7.4
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-10-28 20:30 +0200 |
| Subject | Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() |
| Message-ID | <sxk4L-3ru-25@gated-at.bofh.it> |
| In reply to | #1511269 |
On Fri, Oct 28, 2016 at 12:58:09PM -0400, Tejun Heo wrote:
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -3336,11 +3336,17 @@ static void __sched notrace __schedule(bool preempt)
> unsigned long *switch_count;
> struct pin_cookie cookie;
> struct rq *rq;
> - int cpu;
> + int cpu, in_iowait;
>
> cpu = smp_processor_id();
> rq = cpu_rq(cpu);
> prev = rq->curr;
> + in_iowait = prev->in_iowait;
> +
> + if (in_iowait) {
> + delayacct_blkio_start();
> + atomic_inc(&rq->nr_iowait);
> + }
>
> schedule_debug(prev);
>
> @@ -3406,6 +3412,11 @@ static void __sched notrace __schedule(bool preempt)
> }
>
> balance_callback(rq);
> +
> + if (in_iowait) {
> + atomic_dec(&rq->nr_iowait);
> + delayacct_blkio_end();
> + }
> }
>
> void __noreturn do_task_dead(void)
Urgh, can't say I like this much. It moves two branches into the
schedule path.
Nor do I really like the idea of having to annotate special mutexes for
the iowait crap.
I'll think more after KS/LPC etc..
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-10-28 21:10 +0200 |
| Subject | Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() |
| Message-ID | <sxkHn-3Tx-3@gated-at.bofh.it> |
| In reply to | #1511328 |
On Fri, Oct 28, 2016 at 08:27:12PM +0200, Peter Zijlstra wrote:
> On Fri, Oct 28, 2016 at 12:58:09PM -0400, Tejun Heo wrote:
> > --- a/kernel/sched/core.c
> > +++ b/kernel/sched/core.c
> > @@ -3336,11 +3336,17 @@ static void __sched notrace __schedule(bool preempt)
> > unsigned long *switch_count;
> > struct pin_cookie cookie;
> > struct rq *rq;
> > - int cpu;
> > + int cpu, in_iowait;
> >
> > cpu = smp_processor_id();
> > rq = cpu_rq(cpu);
> > prev = rq->curr;
> > + in_iowait = prev->in_iowait;
> > +
> > + if (in_iowait) {
> > + delayacct_blkio_start();
> > + atomic_inc(&rq->nr_iowait);
> > + }
> >
> > schedule_debug(prev);
> >
> > @@ -3406,6 +3412,11 @@ static void __sched notrace __schedule(bool preempt)
> > }
> >
> > balance_callback(rq);
> > +
> > + if (in_iowait) {
> > + atomic_dec(&rq->nr_iowait);
> > + delayacct_blkio_end();
> > + }
> > }
> >
> > void __noreturn do_task_dead(void)
>
> Urgh, can't say I like this much. It moves two branches into the
> schedule path.
>
> Nor do I really like the idea of having to annotate special mutexes for
> the iowait crap.
>
> I'll think more after KS/LPC etc..
One alternative is to inherit the iowait state of the task we block on.
That'll not get rid of the branches much, but it will remove the new
mutex APIs.
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-10-29 05:30 +0200 |
| Subject | Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() |
| Message-ID | <sxsvg-tH-5@gated-at.bofh.it> |
| In reply to | #1511361 |
On Fri, Oct 28, 2016 at 03:12:32PM -0400, Tejun Heo wrote: > Hello, Peter. > > On Fri, Oct 28, 2016 at 09:07:02PM +0200, Peter Zijlstra wrote: > > One alternative is to inherit the iowait state of the task we block on. > > That'll not get rid of the branches much, but it will remove the new > > mutex APIs. > > Yeah, thought about that briefly but we don't necessarily track mutex This one I actually fixed and should be in -next. And it would be sufficient to cover the use case here. > or other synchronization construct owners, things get gnarly with > rwsems (the inode ones sometimes end up in a similar situation), and > we'll probably end up dealing with some surprising propagations down > the line. rwsems could be done for writers only.
[toc] | [prev] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2016-10-31 17:50 +0100 |
| Subject | Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() |
| Message-ID | <synWx-4Wn-1@gated-at.bofh.it> |
| In reply to | #1511505 |
Hello, On Sat, Oct 29, 2016 at 05:21:26AM +0200, Peter Zijlstra wrote: > On Fri, Oct 28, 2016 at 03:12:32PM -0400, Tejun Heo wrote: > > Hello, Peter. > > > > On Fri, Oct 28, 2016 at 09:07:02PM +0200, Peter Zijlstra wrote: > > > One alternative is to inherit the iowait state of the task we block on. > > > That'll not get rid of the branches much, but it will remove the new > > > mutex APIs. > > > > Yeah, thought about that briefly but we don't necessarily track mutex > > This one I actually fixed and should be in -next. And it would be > sufficient to cover the use case here. Tracking the owners of mutexes and rwsems does help quite a bit. I don't think it's as simple as inheriting io sleep state from the current owner tho. The owner might be running or in a non-IO sleep when others try to grab the mutex. It is an option to ignore those cases but this would have a real possibility to lead to surprising results in some corner cases. If we choose to propagate dynamically, it becomes an a lot more complex problem and I don't think it'd be justfiable. Unless there can be a simple enough and reliable solution, I think it'd be better to stick with explicit marking. Thanks. -- tejun
[toc] | [prev] | [next] | [standalone]
| From | Pavan Kondeti <pkondeti@codeaurora.org> |
|---|---|
| Date | 2016-11-03 16:40 +0100 |
| Subject | Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() |
| Message-ID | <szshs-5Fc-7@gated-at.bofh.it> |
| In reply to | #1511269 |
Hi Tejun,
> diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> index 94732d1..f6baa38 100644
> --- a/kernel/sched/core.c
> +++ b/kernel/sched/core.c
> @@ -3336,11 +3336,17 @@ static void __sched notrace __schedule(bool preempt)
> unsigned long *switch_count;
> struct pin_cookie cookie;
> struct rq *rq;
> - int cpu;
> + int cpu, in_iowait;
>
> cpu = smp_processor_id();
> rq = cpu_rq(cpu);
> prev = rq->curr;
> + in_iowait = prev->in_iowait;
> +
> + if (in_iowait) {
> + delayacct_blkio_start();
> + atomic_inc(&rq->nr_iowait);
> + }
>
> schedule_debug(prev);
>
> @@ -3406,6 +3412,11 @@ static void __sched notrace __schedule(bool preempt)
> }
>
> balance_callback(rq);
> +
> + if (in_iowait) {
> + atomic_dec(&rq->nr_iowait);
> + delayacct_blkio_end();
> + }
> }
I think, the nr_iowait update can go wrong here.
When the task migrates to a different CPU upon wakeup, this rq points
to a different CPU from the one on which nr_iowait is incremented
before.
Thanks,
Pavan
--
Qualcomm India Private Limited, on behalf of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a
Linux Foundation Collaborative Project
[toc] | [prev] | [next] | [standalone]
| From | Tejun Heo <tj@kernel.org> |
|---|---|
| Date | 2016-11-09 00:00 +0100 |
| Subject | Re: [PATCH 1/4] sched: move IO scheduling accounting from io_schedule_timeout() to __schedule() |
| Message-ID | <sBnwZ-7iq-27@gated-at.bofh.it> |
| In reply to | #1514615 |
Hello,
On Thu, Nov 03, 2016 at 09:03:45PM +0530, Pavan Kondeti wrote:
> > diff --git a/kernel/sched/core.c b/kernel/sched/core.c
> > index 94732d1..f6baa38 100644
> > --- a/kernel/sched/core.c
> > +++ b/kernel/sched/core.c
> > @@ -3336,11 +3336,17 @@ static void __sched notrace __schedule(bool preempt)
> > unsigned long *switch_count;
> > struct pin_cookie cookie;
> > struct rq *rq;
> > - int cpu;
> > + int cpu, in_iowait;
> >
> > cpu = smp_processor_id();
> > rq = cpu_rq(cpu);
> > prev = rq->curr;
> > + in_iowait = prev->in_iowait;
> > +
> > + if (in_iowait) {
> > + delayacct_blkio_start();
> > + atomic_inc(&rq->nr_iowait);
> > + }
> >
> > schedule_debug(prev);
> >
> > @@ -3406,6 +3412,11 @@ static void __sched notrace __schedule(bool preempt)
> > }
> >
> > balance_callback(rq);
> > +
> > + if (in_iowait) {
> > + atomic_dec(&rq->nr_iowait);
> > + delayacct_blkio_end();
> > + }
> > }
>
> I think, the nr_iowait update can go wrong here.
>
> When the task migrates to a different CPU upon wakeup, this rq points
> to a different CPU from the one on which nr_iowait is incremented
> before.
Ah, you're right, it should remember the original rq.
Thanks.
--
tejun
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web