public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 1/6] block: Avoid that blk_exit_rl() triggers a use-after-free
       [not found] <20170531214350.31157-1-bart.vanassche@sandisk.com>
@ 2017-05-31 21:43 ` Bart Van Assche
  2017-06-01 19:09   ` Jens Axboe
  2017-06-13 17:54   ` Ross Zwisler
  0 siblings, 2 replies; 7+ messages in thread
From: Bart Van Assche @ 2017-05-31 21:43 UTC (permalink / raw)
  To: Jens Axboe
  Cc: linux-block, Christoph Hellwig, Bart Van Assche, Jan Kara, stable

Since the introduction of .init_rq_fn() and .exit_rq_fn() it is
essential that the memory allocated for struct request_queue
stays around until all blk_exit_rl() calls have finished. Hence
make blk_init_rl() take a reference on struct request_queue.

This patch fixes the following crash:

general protection fault: 0000 [#2] SMP
CPU: 3 PID: 28 Comm: ksoftirqd/3 Tainted: G      D         4.12.0-rc2-dbg+ #2
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014
task: ffff88013a108040 task.stack: ffffc9000071c000
RIP: 0010:free_request_size+0x1a/0x30
RSP: 0018:ffffc9000071fd38 EFLAGS: 00010202
RAX: 6b6b6b6b6b6b6b6b RBX: ffff880067362a88 RCX: 0000000000000003
RDX: ffff880067464178 RSI: ffff880067362a88 RDI: ffff880135ea4418
RBP: ffffc9000071fd40 R08: 0000000000000000 R09: 0000000100180009
R10: ffffc9000071fd38 R11: ffffffff81110800 R12: ffff88006752d3d8
R13: ffff88006752d3d8 R14: ffff88013a108040 R15: 000000000000000a
FS:  0000000000000000(0000) GS:ffff88013fd80000(0000) knlGS:0000000000000000
CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007fa8ec1edb00 CR3: 0000000138ee8000 CR4: 00000000001406e0
Call Trace:
 mempool_destroy.part.10+0x21/0x40
 mempool_destroy+0xe/0x10
 blk_exit_rl+0x12/0x20
 blkg_free+0x4d/0xa0
 __blkg_release_rcu+0x59/0x170
 rcu_process_callbacks+0x260/0x4e0
 __do_softirq+0x116/0x250
 smpboot_thread_fn+0x123/0x1e0
 kthread+0x109/0x140
 ret_from_fork+0x31/0x40

Fixes: commit e9c787e65c0c ("scsi: allocate scsi_cmnd structures as part of struct request")
Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Acked-by: Tejun Heo <tj@kernel.org>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: Jan Kara <jack@suse.cz>
Cc: <stable@vger.kernel.org> # v4.11+
---
 block/blk-cgroup.c |  2 +-
 block/blk-core.c   | 10 ++++++++--
 block/blk-sysfs.c  |  2 +-
 block/blk.h        |  2 +-
 4 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
index 7c2947128f58..0480892e97e5 100644
--- a/block/blk-cgroup.c
+++ b/block/blk-cgroup.c
@@ -74,7 +74,7 @@ static void blkg_free(struct blkcg_gq *blkg)
 			blkcg_policy[i]->pd_free_fn(blkg->pd[i]);
 
 	if (blkg->blkcg != &blkcg_root)
-		blk_exit_rl(&blkg->rl);
+		blk_exit_rl(blkg->q, &blkg->rl);
 
 	blkg_rwstat_exit(&blkg->stat_ios);
 	blkg_rwstat_exit(&blkg->stat_bytes);
diff --git a/block/blk-core.c b/block/blk-core.c
index c7068520794b..a7421b772d0e 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -648,13 +648,19 @@ int blk_init_rl(struct request_list *rl, struct request_queue *q,
 	if (!rl->rq_pool)
 		return -ENOMEM;
 
+	if (rl != &q->root_rl)
+		WARN_ON_ONCE(!blk_get_queue(q));
+
 	return 0;
 }
 
-void blk_exit_rl(struct request_list *rl)
+void blk_exit_rl(struct request_queue *q, struct request_list *rl)
 {
-	if (rl->rq_pool)
+	if (rl->rq_pool) {
 		mempool_destroy(rl->rq_pool);
+		if (rl != &q->root_rl)
+			blk_put_queue(q);
+	}
 }
 
 struct request_queue *blk_alloc_queue(gfp_t gfp_mask)
diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 712b018e9f54..283da7fbe034 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -809,7 +809,7 @@ static void blk_release_queue(struct kobject *kobj)
 
 	blk_free_queue_stats(q->stats);
 
-	blk_exit_rl(&q->root_rl);
+	blk_exit_rl(q, &q->root_rl);
 
 	if (q->queue_tags)
 		__blk_queue_free_tags(q);
diff --git a/block/blk.h b/block/blk.h
index 2ed70228e44f..83c8e1100525 100644
--- a/block/blk.h
+++ b/block/blk.h
@@ -59,7 +59,7 @@ void blk_free_flush_queue(struct blk_flush_queue *q);
 
 int blk_init_rl(struct request_list *rl, struct request_queue *q,
 		gfp_t gfp_mask);
-void blk_exit_rl(struct request_list *rl);
+void blk_exit_rl(struct request_queue *q, struct request_list *rl);
 void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
 			struct bio *bio);
 void blk_queue_bypass_start(struct request_queue *q);
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 1/6] block: Avoid that blk_exit_rl() triggers a use-after-free
  2017-05-31 21:43 ` [PATCH v2 1/6] block: Avoid that blk_exit_rl() triggers a use-after-free Bart Van Assche
@ 2017-06-01 19:09   ` Jens Axboe
  2017-06-13 17:54   ` Ross Zwisler
  1 sibling, 0 replies; 7+ messages in thread
From: Jens Axboe @ 2017-06-01 19:09 UTC (permalink / raw)
  To: Bart Van Assche; +Cc: linux-block, Christoph Hellwig, Jan Kara, stable

On 05/31/2017 02:43 PM, Bart Van Assche wrote:
> Since the introduction of .init_rq_fn() and .exit_rq_fn() it is
> essential that the memory allocated for struct request_queue
> stays around until all blk_exit_rl() calls have finished. Hence
> make blk_init_rl() take a reference on struct request_queue.
> 
> This patch fixes the following crash:
> 
> general protection fault: 0000 [#2] SMP
> CPU: 3 PID: 28 Comm: ksoftirqd/3 Tainted: G      D         4.12.0-rc2-dbg+ #2
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014
> task: ffff88013a108040 task.stack: ffffc9000071c000
> RIP: 0010:free_request_size+0x1a/0x30
> RSP: 0018:ffffc9000071fd38 EFLAGS: 00010202
> RAX: 6b6b6b6b6b6b6b6b RBX: ffff880067362a88 RCX: 0000000000000003
> RDX: ffff880067464178 RSI: ffff880067362a88 RDI: ffff880135ea4418
> RBP: ffffc9000071fd40 R08: 0000000000000000 R09: 0000000100180009
> R10: ffffc9000071fd38 R11: ffffffff81110800 R12: ffff88006752d3d8
> R13: ffff88006752d3d8 R14: ffff88013a108040 R15: 000000000000000a
> FS:  0000000000000000(0000) GS:ffff88013fd80000(0000) knlGS:0000000000000000
> CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00007fa8ec1edb00 CR3: 0000000138ee8000 CR4: 00000000001406e0
> Call Trace:
>  mempool_destroy.part.10+0x21/0x40
>  mempool_destroy+0xe/0x10
>  blk_exit_rl+0x12/0x20
>  blkg_free+0x4d/0xa0
>  __blkg_release_rcu+0x59/0x170
>  rcu_process_callbacks+0x260/0x4e0
>  __do_softirq+0x116/0x250
>  smpboot_thread_fn+0x123/0x1e0
>  kthread+0x109/0x140
>  ret_from_fork+0x31/0x40
> 
> Fixes: commit e9c787e65c0c ("scsi: allocate scsi_cmnd structures as part of struct request")
> Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
> Acked-by: Tejun Heo <tj@kernel.org>
> Reviewed-by: Hannes Reinecke <hare@suse.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Cc: Jan Kara <jack@suse.cz>
> Cc: <stable@vger.kernel.org> # v4.11+

Added this one for 4.12.

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 1/6] block: Avoid that blk_exit_rl() triggers a use-after-free
  2017-05-31 21:43 ` [PATCH v2 1/6] block: Avoid that blk_exit_rl() triggers a use-after-free Bart Van Assche
  2017-06-01 19:09   ` Jens Axboe
@ 2017-06-13 17:54   ` Ross Zwisler
  2017-06-14 15:19     ` Bart Van Assche
  1 sibling, 1 reply; 7+ messages in thread
From: Ross Zwisler @ 2017-06-13 17:54 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: Jens Axboe, linux-block, Christoph Hellwig, Jan Kara, stable

On Wed, May 31, 2017 at 3:43 PM, Bart Van Assche
<bart.vanassche@sandisk.com> wrote:
> Since the introduction of .init_rq_fn() and .exit_rq_fn() it is
> essential that the memory allocated for struct request_queue
> stays around until all blk_exit_rl() calls have finished. Hence
> make blk_init_rl() take a reference on struct request_queue.
>
> This patch fixes the following crash:
>
> general protection fault: 0000 [#2] SMP
> CPU: 3 PID: 28 Comm: ksoftirqd/3 Tainted: G      D         4.12.0-rc2-dbg+ #2
> Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.0.0-prebuilt.qemu-project.org 04/01/2014
> task: ffff88013a108040 task.stack: ffffc9000071c000
> RIP: 0010:free_request_size+0x1a/0x30
> RSP: 0018:ffffc9000071fd38 EFLAGS: 00010202
> RAX: 6b6b6b6b6b6b6b6b RBX: ffff880067362a88 RCX: 0000000000000003
> RDX: ffff880067464178 RSI: ffff880067362a88 RDI: ffff880135ea4418
> RBP: ffffc9000071fd40 R08: 0000000000000000 R09: 0000000100180009
> R10: ffffc9000071fd38 R11: ffffffff81110800 R12: ffff88006752d3d8
> R13: ffff88006752d3d8 R14: ffff88013a108040 R15: 000000000000000a
> FS:  0000000000000000(0000) GS:ffff88013fd80000(0000) knlGS:0000000000000000
> CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
> CR2: 00007fa8ec1edb00 CR3: 0000000138ee8000 CR4: 00000000001406e0
> Call Trace:
>  mempool_destroy.part.10+0x21/0x40
>  mempool_destroy+0xe/0x10
>  blk_exit_rl+0x12/0x20
>  blkg_free+0x4d/0xa0
>  __blkg_release_rcu+0x59/0x170
>  rcu_process_callbacks+0x260/0x4e0
>  __do_softirq+0x116/0x250
>  smpboot_thread_fn+0x123/0x1e0
>  kthread+0x109/0x140
>  ret_from_fork+0x31/0x40
>
> Fixes: commit e9c787e65c0c ("scsi: allocate scsi_cmnd structures as part of struct request")
> Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
> Acked-by: Tejun Heo <tj@kernel.org>
> Reviewed-by: Hannes Reinecke <hare@suse.com>
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> Cc: Jan Kara <jack@suse.cz>
> Cc: <stable@vger.kernel.org> # v4.11+
> ---
>  block/blk-cgroup.c |  2 +-
>  block/blk-core.c   | 10 ++++++++--
>  block/blk-sysfs.c  |  2 +-
>  block/blk.h        |  2 +-
>  4 files changed, 11 insertions(+), 5 deletions(-)
>
> diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c
> index 7c2947128f58..0480892e97e5 100644
> --- a/block/blk-cgroup.c
> +++ b/block/blk-cgroup.c
> @@ -74,7 +74,7 @@ static void blkg_free(struct blkcg_gq *blkg)
>                         blkcg_policy[i]->pd_free_fn(blkg->pd[i]);
>
>         if (blkg->blkcg != &blkcg_root)
> -               blk_exit_rl(&blkg->rl);
> +               blk_exit_rl(blkg->q, &blkg->rl);
>
>         blkg_rwstat_exit(&blkg->stat_ios);
>         blkg_rwstat_exit(&blkg->stat_bytes);
> diff --git a/block/blk-core.c b/block/blk-core.c
> index c7068520794b..a7421b772d0e 100644
> --- a/block/blk-core.c
> +++ b/block/blk-core.c
> @@ -648,13 +648,19 @@ int blk_init_rl(struct request_list *rl, struct request_queue *q,
>         if (!rl->rq_pool)
>                 return -ENOMEM;
>
> +       if (rl != &q->root_rl)
> +               WARN_ON_ONCE(!blk_get_queue(q));
> +
>         return 0;
>  }
>
> -void blk_exit_rl(struct request_list *rl)
> +void blk_exit_rl(struct request_queue *q, struct request_list *rl)
>  {
> -       if (rl->rq_pool)
> +       if (rl->rq_pool) {
>                 mempool_destroy(rl->rq_pool);
> +               if (rl != &q->root_rl)
> +                       blk_put_queue(q);
> +       }
>  }

This commit is causing the following kernel BUG for me when I shut
down my systems:

  BUG: sleeping function called from invalid context at kernel/workqueue.c:2790
  in_atomic(): 1, irqs_disabled(): 0, pid: 41, name: rcuop/3
  1 lock held by rcuop/3/41:
   #0:  (rcu_callback){......}, at: [<ffffffff8111f9a2>]
rcu_nocb_kthread+0x282/0x500
  Preemption disabled at:
  [<ffffffff8111f9b3>] rcu_nocb_kthread+0x293/0x500
  CPU: 2 PID: 41 Comm: rcuop/3 Not tainted 4.12.0-rc5 #1
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.9.3-1.fc25 04/01/2014
  Call Trace:
   dump_stack+0x86/0xcf
   ___might_sleep+0x174/0x260
   __might_sleep+0x4a/0x80
   flush_work+0x7e/0x2e0
   ? blk_throtl_update_limit_valid.isra.14+0x192/0x240
   ? blkg_destroy_all+0x63/0xc0
   ? __cancel_work_timer+0x123/0x1c0
   __cancel_work_timer+0x143/0x1c0
   ? blkcg_exit_queue+0x2d/0x40
   ? _raw_spin_unlock_irq+0x2c/0x60
   cancel_work_sync+0x10/0x20
   blk_throtl_exit+0x25/0x60
   blkcg_exit_queue+0x35/0x40
   blk_release_queue+0x42/0x130
   kobject_put+0xa9/0x190
  kauditd_printk_skb: 60 callbacks suppressed
  audit: type=1131 audit(1497375715.762:263): pid=1 uid=0
auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0
msg='unit=auditd comm="systemd" exe="/usr/lib/systemd/systemd"
hostname=? addr=? terminal=? res=success'
  audit: type=1131 audit(1497375715.765:264): pid=1 uid=0
auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0
msg='unit=systemd-tmpfiles-setup comm="systemd"
exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=?
res=success'
  audit: type=1131 audit(1497375715.767:265): pid=1 uid=0
auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0
msg='unit=fedora-import-state comm="systemd"
exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=?
res=success'
   blk_exit_rl+0x35/0x40
   blkg_free+0x56/0xb0
   __blkg_release_rcu+0x5e/0x190
   ? blkcg_css_offline+0xa0/0xa0
   rcu_nocb_kthread+0x33d/0x500
   kthread+0x117/0x150
   ? rcu_all_qs+0xe0/0xe0
   ? kthread_create_on_node+0x70/0x70
   ret_from_fork+0x2a/0x40
  BUG: scheduling while atomic: rcuop/3/41/0x00000201
  1 lock held by rcuop/3/41:
   #0:  (rcu_callback){......}, at: [<ffffffff8111f9a2>]
rcu_nocb_kthread+0x282/0x500
  Modules linked in: nd_pmem nd_btt dax_pmem device_dax nfit libnvdimm
  Preemption disabled at:
  [<ffffffff8111f9b3>] rcu_nocb_kthread+0x293/0x500
  CPU: 2 PID: 41 Comm: rcuop/3 Tainted: G        W       4.12.0-rc5 #1
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.9.3-1.fc25 04/01/2014
  Call Trace:
   dump_stack+0x86/0xcf
   ? rcu_nocb_kthread+0x293/0x500
   __schedule_bug+0x88/0xe0
   __schedule+0x77a/0xb10
   ? wait_for_completion+0x10b/0x1a0
   schedule+0x40/0x90
   schedule_timeout+0x2ac/0x510
   ? wait_for_completion+0x122/0x1a0
   ? wait_for_completion+0x122/0x1a0
   ? _raw_spin_unlock_irq+0x2c/0x60
   ? wait_for_completion+0x10b/0x1a0
   ? wait_for_completion+0x10b/0x1a0
   wait_for_completion+0x12a/0x1a0
   ? wait_for_completion+0x12a/0x1a0
   ? wake_up_q+0x80/0x80
   __wait_rcu_gp+0xca/0x100
   synchronize_rcu.part.67+0x41/0x60
   ? rcu_barrier+0x20/0x20
   ? trace_raw_output_rcu_utilization+0x50/0x50
   ? wait_for_completion+0x47/0x1a0
   synchronize_rcu+0x2c/0xa0
   blk_queue_bypass_start+0x7f/0xa0
   blkcg_deactivate_policy+0x110/0x120
   blk_throtl_exit+0x34/0x60
   blkcg_exit_queue+0x35/0x40
   blk_release_queue+0x42/0x130
   kobject_put+0xa9/0x190
   blk_exit_rl+0x35/0x40
   blkg_free+0x56/0xb0
   __blkg_release_rcu+0x5e/0x190
   ? blkcg_css_offline+0xa0/0xa0
   rcu_nocb_kthread+0x33d/0x500
   kthread+0x117/0x150
   ? rcu_all_qs+0xe0/0xe0
   ? kthread_create_on_node+0x70/0x70
   ret_from_fork+0x2a/0x40
  NOHZ: local_softirq_pending 202
  DEBUG_LOCKS_WARN_ON(val > preempt_count())
  ------------[ cut here ]------------
  WARNING: CPU: 2 PID: 41 at kernel/sched/core.c:3202
preempt_count_sub+0x5f/0xa0
  Modules linked in: nd_pmem nd_btt dax_pmem device_dax nfit libnvdimm
  CPU: 2 PID: 41 Comm: rcuop/3 Tainted: G        W       4.12.0-rc5 #1
  Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS
1.9.3-1.fc25 04/01/2014
  task: ffff880210790000 task.stack: ffffc90000dbc000
  RIP: 0010:preempt_count_sub+0x5f/0xa0
  RSP: 0000:ffffc90000dbfe58 EFLAGS: 00010082
  RAX: 000000000000002a RBX: 0000000000000200 RCX: 0000000000000001
  RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffffffff8110dad7
  RBP: ffffc90000dbfe58 R08: 0000000000000000 R09: 0000000000000001
  R10: 0000000000000000 R11: 0000000000000000 R12: ffffffff8111fa08
  R13: 0000000000000026 R14: ffff880210790000 R15: ffff88020880c4c0
  FS:  0000000000000000(0000) GS:ffff880211400000(0000) knlGS:0000000000000000
  CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
  CR2: 000055c7110f4148 CR3: 000000020c1bc000 CR4: 00000000000006e0
  Call Trace:
   __local_bh_enable_ip+0x52/0xb0
   rcu_nocb_kthread+0x2fe/0x500
   kthread+0x117/0x150
   ? rcu_all_qs+0xe0/0xe0
   ? kthread_create_on_node+0x70/0x70
   ret_from_fork+0x2a/0x40
  Code: 37 f4 7e 5d c3 e8 52 d2 56 00 85 c0 74 f5 8b 15 b8 2b 51 02 85
d2 75 eb 48 c7 c6 9a f9 ef 81 48 c7 c7 c2 87 ee 81 e8 e8 34 12 00 <0f>
ff 5d c3 84 d2 75 c7 e8 24 d2 56 00 85 c0 74 c7 8b 05 8a 2b
  ---[ end trace f7877221a24ce5d5 ]---

I think essentially the problem is that blk_exit_rl() is called from
atomic context, and the work done by the newly added blk_put_queue()
call can sleep.

This is reproducible 100% of the time by running a single xfstest
(generic/085 is what I've been using) against a pair simulated of PMEM
block devices (without DAX), and by shutting down or rebooting the
system.

Sometimes it is relatively harmless, and you just get a splat during shutdown.
Sometimes the shutdown stops making forward progress and the machine
fails to reboot.

I am able to reproduce this consistently with v4.12-rc5, and reverting
this one commit removes the behavior.

- Ross

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 1/6] block: Avoid that blk_exit_rl() triggers a use-after-free
  2017-06-13 17:54   ` Ross Zwisler
@ 2017-06-14 15:19     ` Bart Van Assche
  2017-06-14 18:04       ` Ross Zwisler
  2017-06-14 19:28       ` Jens Axboe
  0 siblings, 2 replies; 7+ messages in thread
From: Bart Van Assche @ 2017-06-14 15:19 UTC (permalink / raw)
  To: Ross Zwisler; +Cc: Jens Axboe, linux-block, Christoph Hellwig, Jan Kara, stable

On 06/13/17 10:54, Ross Zwisler wrote:
> This commit is causing the following kernel BUG for me when I shut
> down my systems:
> 
>   BUG: sleeping function called from invalid context at kernel/workqueue.c:2790
>   in_atomic(): 1, irqs_disabled(): 0, pid: 41, name: rcuop/3

Thanks Ross for the testing and for the report. Can you check whether
the patch below is sufficient to fix this?


Subject: [PATCH] block: Fix a blk_exit_rl() regression

Avoid that the following complaint is reported:

 BUG: sleeping function called from invalid context at kernel/workqueue.c:2790
 in_atomic(): 1, irqs_disabled(): 0, pid: 41, name: rcuop/3
 1 lock held by rcuop/3/41:
  #0:  (rcu_callback){......}, at: [<ffffffff8111f9a2>] rcu_nocb_kthread+0x282/0x500
 Call Trace:
  dump_stack+0x86/0xcf
  ___might_sleep+0x174/0x260
  __might_sleep+0x4a/0x80
  flush_work+0x7e/0x2e0
  __cancel_work_timer+0x143/0x1c0
  cancel_work_sync+0x10/0x20
  blk_throtl_exit+0x25/0x60
  blkcg_exit_queue+0x35/0x40
  blk_release_queue+0x42/0x130
  kobject_put+0xa9/0x190

Reported-by: Ross Zwisler <zwisler@gmail.com>
Fixes: commit b425e5049258 ("block: Avoid that blk_exit_rl() triggers a use-after-free")
Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
Cc: Ross Zwisler <zwisler@gmail.com>
---
 block/blk-sysfs.c      | 34 ++++++++++++++++++++++------------
 include/linux/blkdev.h |  2 ++
 2 files changed, 24 insertions(+), 12 deletions(-)

diff --git a/block/blk-sysfs.c b/block/blk-sysfs.c
index 283da7fbe034..27aceab1cc31 100644
--- a/block/blk-sysfs.c
+++ b/block/blk-sysfs.c
@@ -777,24 +777,25 @@ static void blk_free_queue_rcu(struct rcu_head *rcu_head)
 }
 
 /**
- * blk_release_queue: - release a &struct request_queue when it is no longer needed
- * @kobj:    the kobj belonging to the request queue to be released
+ * __blk_release_queue - release a request queue when it is no longer needed
+ * @work: pointer to the release_work member of the request queue to be released
  *
  * Description:
- *     blk_release_queue is the pair to blk_init_queue() or
- *     blk_queue_make_request().  It should be called when a request queue is
- *     being released; typically when a block device is being de-registered.
- *     Currently, its primary task it to free all the &struct request
- *     structures that were allocated to the queue and the queue itself.
+ *     blk_release_queue is the counterpart of blk_init_queue(). It should be
+ *     called when a request queue is being released; typically when a block
+ *     device is being de-registered. Its primary task it to free the queue
+ *     itself.
  *
- * Note:
+ * Notes:
  *     The low level driver must have finished any outstanding requests first
  *     via blk_cleanup_queue().
- **/
-static void blk_release_queue(struct kobject *kobj)
+ *
+ *     Although blk_release_queue() may be called with preemption disabled,
+ *     __blk_release_queue() may sleep.
+ */
+static void __blk_release_queue(struct work_struct *work)
 {
-	struct request_queue *q =
-		container_of(kobj, struct request_queue, kobj);
+	struct request_queue *q = container_of(work, typeof(*q), release_work);
 
 	if (test_bit(QUEUE_FLAG_POLL_STATS, &q->queue_flags))
 		blk_stat_remove_callback(q, q->poll_cb);
@@ -834,6 +835,15 @@ static void blk_release_queue(struct kobject *kobj)
 	call_rcu(&q->rcu_head, blk_free_queue_rcu);
 }
 
+static void blk_release_queue(struct kobject *kobj)
+{
+	struct request_queue *q =
+		container_of(kobj, struct request_queue, kobj);
+
+	INIT_WORK(&q->release_work, __blk_release_queue);
+	schedule_work(&q->release_work);
+}
+
 static const struct sysfs_ops queue_sysfs_ops = {
 	.show	= queue_attr_show,
 	.store	= queue_attr_store,
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index cc75407881e4..07a26414fdfc 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -590,6 +590,8 @@ struct request_queue {
 
 	size_t			cmd_size;
 	void			*rq_alloc_data;
+
+	struct work_struct	release_work;
 };
 
 #define QUEUE_FLAG_QUEUED	1	/* uses generic tag queueing */
-- 
2.12.2

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 1/6] block: Avoid that blk_exit_rl() triggers a use-after-free
  2017-06-14 15:19     ` Bart Van Assche
@ 2017-06-14 18:04       ` Ross Zwisler
  2017-06-14 19:28       ` Jens Axboe
  1 sibling, 0 replies; 7+ messages in thread
From: Ross Zwisler @ 2017-06-14 18:04 UTC (permalink / raw)
  To: Bart Van Assche
  Cc: Jens Axboe, linux-block, Christoph Hellwig, Jan Kara, stable

On Wed, Jun 14, 2017 at 9:19 AM, Bart Van Assche
<bart.vanassche@sandisk.com> wrote:
> On 06/13/17 10:54, Ross Zwisler wrote:
>> This commit is causing the following kernel BUG for me when I shut
>> down my systems:
>>
>>   BUG: sleeping function called from invalid context at kernel/workqueue.c:2790
>>   in_atomic(): 1, irqs_disabled(): 0, pid: 41, name: rcuop/3
>
> Thanks Ross for the testing and for the report. Can you check whether
> the patch below is sufficient to fix this?
>
>
> Subject: [PATCH] block: Fix a blk_exit_rl() regression
>
> Avoid that the following complaint is reported:
>
>  BUG: sleeping function called from invalid context at kernel/workqueue.c:2790
>  in_atomic(): 1, irqs_disabled(): 0, pid: 41, name: rcuop/3
>  1 lock held by rcuop/3/41:
>   #0:  (rcu_callback){......}, at: [<ffffffff8111f9a2>] rcu_nocb_kthread+0x282/0x500
>  Call Trace:
>   dump_stack+0x86/0xcf
>   ___might_sleep+0x174/0x260
>   __might_sleep+0x4a/0x80
>   flush_work+0x7e/0x2e0
>   __cancel_work_timer+0x143/0x1c0
>   cancel_work_sync+0x10/0x20
>   blk_throtl_exit+0x25/0x60
>   blkcg_exit_queue+0x35/0x40
>   blk_release_queue+0x42/0x130
>   kobject_put+0xa9/0x190
>
> Reported-by: Ross Zwisler <zwisler@gmail.com>
> Fixes: commit b425e5049258 ("block: Avoid that blk_exit_rl() triggers a use-after-free")
> Signed-off-by: Bart Van Assche <bart.vanassche@sandisk.com>
> Cc: Ross Zwisler <zwisler@gmail.com>

Yep, this solves the issue for me, thanks!

Tested-by: Ross Zwisler <ross.zwisler@linux.intel.com>

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 1/6] block: Avoid that blk_exit_rl() triggers a use-after-free
  2017-06-14 15:19     ` Bart Van Assche
  2017-06-14 18:04       ` Ross Zwisler
@ 2017-06-14 19:28       ` Jens Axboe
  2017-06-14 19:32         ` Bart Van Assche
  1 sibling, 1 reply; 7+ messages in thread
From: Jens Axboe @ 2017-06-14 19:28 UTC (permalink / raw)
  To: Bart Van Assche, Ross Zwisler
  Cc: linux-block, Christoph Hellwig, Jan Kara, stable

On 06/14/2017 09:19 AM, Bart Van Assche wrote:
> Subject: [PATCH] block: Fix a blk_exit_rl() regression
> 
> Avoid that the following complaint is reported:
> 
>  BUG: sleeping function called from invalid context at kernel/workqueue.c:2790
>  in_atomic(): 1, irqs_disabled(): 0, pid: 41, name: rcuop/3
>  1 lock held by rcuop/3/41:
>   #0:  (rcu_callback){......}, at: [<ffffffff8111f9a2>] rcu_nocb_kthread+0x282/0x500
>  Call Trace:
>   dump_stack+0x86/0xcf
>   ___might_sleep+0x174/0x260
>   __might_sleep+0x4a/0x80
>   flush_work+0x7e/0x2e0
>   __cancel_work_timer+0x143/0x1c0
>   cancel_work_sync+0x10/0x20
>   blk_throtl_exit+0x25/0x60
>   blkcg_exit_queue+0x35/0x40
>   blk_release_queue+0x42/0x130
>   kobject_put+0xa9/0x190

I added this, but the above is really a horrible changelog. It doesn't
say how the problem is fixed. I added some verbiage to that effect.

-- 
Jens Axboe

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2 1/6] block: Avoid that blk_exit_rl() triggers a use-after-free
  2017-06-14 19:28       ` Jens Axboe
@ 2017-06-14 19:32         ` Bart Van Assche
  0 siblings, 0 replies; 7+ messages in thread
From: Bart Van Assche @ 2017-06-14 19:32 UTC (permalink / raw)
  To: Jens Axboe, Ross Zwisler; +Cc: linux-block, Christoph Hellwig, Jan Kara, stable

On 06/14/17 12:28, Jens Axboe wrote:
> I added this, but the above is really a horrible changelog. It doesn't
> say how the problem is fixed. I added some verbiage to that effect.

Hello Jens,

Thanks for having fixed up the changelog and for already having picked
up this patch. I was going to repost the patch and write a proper
changelog but apparently you were faster than I :-)

BTW, since last night I can finally receive and send e-mails with a
@wdc.com suffix (thirteen months after the acquisition closed).

Bart.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-06-14 19:33 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <20170531214350.31157-1-bart.vanassche@sandisk.com>
2017-05-31 21:43 ` [PATCH v2 1/6] block: Avoid that blk_exit_rl() triggers a use-after-free Bart Van Assche
2017-06-01 19:09   ` Jens Axboe
2017-06-13 17:54   ` Ross Zwisler
2017-06-14 15:19     ` Bart Van Assche
2017-06-14 18:04       ` Ross Zwisler
2017-06-14 19:28       ` Jens Axboe
2017-06-14 19:32         ` Bart Van Assche

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox