| From oliver.pntr@gmail.com Fri Aug 1 16:51:47 2008 |
| From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> |
| Date: Thu, 31 Jul 2008 13:31:33 +0200 |
| Subject: SCSI: bsg: fix bsg_mutex hang with device removal |
| To: "FUJITA Tomonori" <fujita.tomonori@lab.ntt.co.jp>, stable@kernel.org |
| Cc: James Bottomley <James.Bottomley@hansenpartnership.com>, Pete Wyckoff <pw@osc.edu> |
| Message-ID: <6101e8c40807310431i500829d6ud1e383d1e2bdf714@mail.gmail.com> |
| Content-Disposition: inline |
| |
| From: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> |
| |
| commit 3f27e3ed11e67c5ee19d560a50eafd93cf8c6682 upstream |
| |
| [SCSI] bsg: fix bsg_mutex hang with device removal |
| |
| We don't need to hold bsg_mutex during bsg_complete_all_commands(). It |
| leads to a problem that we block bsg_unregister_queue during |
| bsg_complete_all_commands (untill all the outstanding commands |
| complete). |
| |
| Thanks to Pete Wyckoff for finding the bug and testing the patch. |
| |
| The detailed bug report is: |
| |
| http://marc.info/?l=linux-scsi&m=121182137132145&w=2 |
| |
| Tested-by: Pete Wyckoff <pw@osc.edu> |
| Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> |
| Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com> |
| CC: Oliver Pinter <oliver.pntr@gmail.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| |
| --- |
| block/bsg.c | 9 ++++++--- |
| 1 file changed, 6 insertions(+), 3 deletions(-) |
| |
| --- a/block/bsg.c |
| +++ b/block/bsg.c |
| @@ -725,8 +725,13 @@ static int bsg_put_device(struct bsg_dev |
| mutex_lock(&bsg_mutex); |
| |
| do_free = atomic_dec_and_test(&bd->ref_count); |
| - if (!do_free) |
| + if (!do_free) { |
| + mutex_unlock(&bsg_mutex); |
| goto out; |
| + } |
| + |
| + hlist_del(&bd->dev_list); |
| + mutex_unlock(&bsg_mutex); |
| |
| dprintk("%s: tearing down\n", bd->name); |
| |
| @@ -742,10 +747,8 @@ static int bsg_put_device(struct bsg_dev |
| */ |
| ret = bsg_complete_all_commands(bd); |
| |
| - hlist_del(&bd->dev_list); |
| kfree(bd); |
| out: |
| - mutex_unlock(&bsg_mutex); |
| kref_put(&q->bsg_dev.ref, bsg_kref_release_function); |
| if (do_free) |
| blk_put_queue(q); |