aio: protect reqs_available updates from changes in interrupt handlers
Subsystems (3)
Benjamin LaHaise
maintainerPATCH 1/1 aio: protect reqs_available updates from changes in interrupt handlers
Hello everyone,
Please pull the following commit (263782c1c95bbddbb022dc092fd89a36bb8d5577) from git://git.kvack.org/aio-fixes.git to fix an aio bug reported by Robert Elliot.
---
As of commit f8567a3845ac05bb28f3c1b478ef752762bd39ef it is now possible to have put_reqs_available() called from irq context. While put_reqs_available() is per cpu, it did not protect itself from interrupts on the same CPU. This lead to aio_complete() corrupting the available io requests count when run under a heavy O_DIRECT workloads as reported by Robert Elliott. Fix this by disabling irq updates around the per cpu batch updates of reqs_available.
Many thanks to Robert and folks for testing and tracking this down.
--- fs/aio.c | 7 +++++++ 1 file changed, 7 insertions(+)
fs/aio.c +7 -0
@@ -830,16 +830,20 @@ void exit_aio(struct mm_struct *mm)static void put_reqs_available (struct kioctx *ctx,unsigned nr) {struct kioctx_cpu *kcpu; +unsigned long flags;preempt_disable (); kcpu =this_cpu_ptr (ctx->cpu); +local_irq_save (flags); kcpu->reqs_available += nr; +while (kcpu->reqs_available >= ctx->req_batch *2 ) { kcpu->reqs_available -= ctx->req_batch;atomic_add (ctx->req_batch, &ctx->reqs_available); } +local_irq_restore (flags);preempt_enable (); }
@@ -847,10 +851,12 @@ static bool get_reqs_available(struct kioctx *ctx) {struct kioctx_cpu *kcpu;bool ret = false; +unsigned long flags;preempt_disable (); kcpu =this_cpu_ptr (ctx->cpu); +local_irq_save (flags);if (!kcpu->reqs_available) {int old, avail =atomic_read (&ctx->reqs_available);
@@ -869,6 +875,7 @@ static bool get_reqs_available(struct kioctx *ctx) ret = true; kcpu->reqs_available--; out: +local_irq_restore (flags);preempt_enable ();return ret; }
Signature · 4 lines
1.8.2.1 -- "Thought is the essence of where you are now."
Quoted 29 lines · Benjamin LaHaise
Hello everyone,
Please pull the following commit (
263782c1c95bbddbb022dc092fd89a36bb8d5577) fromgit://git.kvack.org/aio-fixes.gitto fix an aio bug reported by Robert Elliot.
---
As of commitf8567a3845ac05bb28f3c1b478ef752762bd39efit is now possible to haveput_reqs_available()called from irq context. Whileput_reqs_available()is per cpu, it did not protect itself from interrupts on the same CPU. This lead toaio_complete()corrupting the available io requests count when run under a heavyO_DIRECTworkloads as reported by Robert Elliott. Fix this by disabling irq updates around the per cpu batch updates ofreqs_available.Many thanks to Robert and folks for testing and tracking this down.
Reported-by Robert Elliot <[email protected]>Tested-by Robert Elliot <[email protected]>Signed-off-by Benjamin LaHaise <[email protected]>Cc Jens Axboe <[email protected]>, Christoph Hellwig <[email protected]>--- fs/aio.c | 7 +++++++ 1 file changed, 7 insertions(+)fs/aio.c +0
-0
fs/aio.c void exit_aio(struct mm_struct *mm) · line 839
Quoted 10 lines
fs/aio.c +2
-0@@ -830,16 +830,20 @@ void exit_aio(struct mm_struct *mm)static void put_reqs_available (struct kioctx *ctx,unsigned nr) {struct kioctx_cpu *kcpu; +unsigned long flags;preempt_disable (); kcpu =this_cpu_ptr (ctx->cpu); +local_irq_save (flags); kcpu->reqs_available += nr;
Why not just makes this:
local_irq_save(flags); kcpu = this_put_ptr(...); ...
and get rid of the preemption bits, it's a bit redundant now you need to kill local interrupts anyway.
Signature · 1 line
Jens Axboe
Benjamin LaHaise
maintainerQuoted 8 lines · Jens Axboe
Why not just makes this:
local_irq_save(flags); kcpu = this_put_ptr(...); ...and get rid of the preemption bits, it's a bit redundant now you need to kill local interrupts anyway.
*nod*. I'll add the following cleanup patch, as the first version already got merged into another tree.
-ben
fs/aio.c +2 -8
@@ -832,10 +832,8 @@ static void put_reqs_available(struct kioctx *ctx, unsigned nr)struct kioctx_cpu *kcpu;unsigned long flags; -preempt_disable (); - kcpu =this_cpu_ptr (ctx->cpu); -local_irq_save (flags); + kcpu =this_cpu_ptr (ctx->cpu); kcpu->reqs_available += nr;while (kcpu->reqs_available >= ctx->req_batch *2 ) {
@@ -844,7 +842,6 @@ static void put_reqs_available(struct kioctx *ctx, unsigned nr) }local_irq_restore (flags); -preempt_enable (); }static bool get_reqs_available (struct kioctx *ctx)
@@ -853,10 +850,8 @@ static bool get_reqs_available(struct kioctx *ctx)bool ret = false;unsigned long flags; -preempt_disable (); - kcpu =this_cpu_ptr (ctx->cpu); -local_irq_save (flags); + kcpu =this_cpu_ptr (ctx->cpu);if (!kcpu->reqs_available) {int old, avail =atomic_read (&ctx->reqs_available);
@@ -876,7 +871,6 @@ static bool get_reqs_available(struct kioctx *ctx) kcpu->reqs_available--; out:local_irq_restore (flags); -preempt_enable ();return ret; }
-ben
Signature · 1 line
"Thought is the essence of where you are now."