From: Hans-Joachim Picht <hpicht@redhat.com> Date: Tue, 20 Jan 2009 16:59:37 +0100 Subject: [s390] cio: I/O error after cable pulls Message-id: 20090120155937.GH21694@redhat.com O-Subject: [RHEL5 U4 PATCH 8/8] s390 - cio: I/O error after cable pulls Bugzilla: 479878 RH-Acked-by: Pete Zaitcev <zaitcev@redhat.com> Description ============ After some cables to a dasd device have been pulled, the dasd unsuccessfully tries to submit I/O. After the retries for the error recovery have been exhausted, an I/O error is generated. This leads to a machine crash during disk mirroring caused by adevice mapper failure. This is the backport of a upstream patch provided by Alasdair G Kergon <agk@redhat.com>. dm: detect lost queue author Alasdair G Kergon <agk@redhat.com> Fri, 10 Oct 2008 12:37:13 +0000 (13:37 +0100) committer Alasdair G Kergon <agk@redhat.com> Fri, 10 Oct 2008 12:37:13 +0000 (13:37 +0100) commit 0c2322e4ce144e130c03d813fe92de3798662c5e Detect and report buggy drivers that destroy their request_queue. Signed-off-by: Alasdair G Kergon <agk@redhat.com> Cc: Stefan Raspl <raspl@linux.vnet.ibm.com> Cc: Jens Axboe <jens.axboe@oracle.com> Cc: Andrew Morton <akpm@linux-foundation.org> AFAIK the problem is currently only applicable on s390. Bugzilla ========= BZ 479878 https://bugzilla.redhat.com/show_bug.cgi?id=479878 Upstream status of the patch: ============================= The patch provided by Alasdair G Kergon <agk@redhat.com> is upstream as of git commit 0c2322e4ce144e130c03d813fe92de3798662c5e Test status: ============ The patch has been tested and fixes the problem. The fix has been verified by the IBM test department. Please ACK. With best regards, --Hans diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 2a01dfd..afac24b 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -980,7 +980,14 @@ int dm_table_any_congested(struct dm_table *t, int bdi_bits) for (d = devices->next; d != devices; d = d->next) { struct dm_dev *dd = list_entry(d, struct dm_dev, list); request_queue_t *q = bdev_get_queue(dd->bdev); - r |= bdi_congested(&q->backing_dev_info, bdi_bits); + char b[BDEVNAME_SIZE]; + + if (likely(q)) + r |= bdi_congested(&q->backing_dev_info, bdi_bits); + else + DMWARN("%s: any_congested: nonexistent device %s", + dm_device_name(t->md), + bdevname(dd->bdev, b)); } return r; @@ -994,8 +1001,16 @@ void dm_table_unplug_all(struct dm_table *t) struct dm_dev *dd = list_entry(d, struct dm_dev, list); request_queue_t *q = bdev_get_queue(dd->bdev); - if (q->unplug_fn) - q->unplug_fn(q); + if (likely(q)) { + if (q->unplug_fn) + q->unplug_fn(q); + } + else { + char b[BDEVNAME_SIZE]; + DMWARN("%s: Cannot unplug nonexistent device %s", + dm_device_name(t->md), + bdevname(dd->bdev, b)); + } } } @@ -1007,12 +1022,21 @@ int dm_table_flush_all(struct dm_table *t) for (d = devices->next; d != devices; d = d->next) { struct dm_dev *dd = list_entry(d, struct dm_dev, list); request_queue_t *q = bdev_get_queue(dd->bdev); - int err; - - if (!q->issue_flush_fn) - err = -EOPNOTSUPP; - else - err = q->issue_flush_fn(q, dd->bdev->bd_disk, NULL); + int err = 0; + + if (likely(q)) { + if (!q->issue_flush_fn) + err = -EOPNOTSUPP; + else + err = q->issue_flush_fn(q, dd->bdev->bd_disk, + NULL); + } + else { + char b[BDEVNAME_SIZE]; + DMWARN("%s: Cannot flush nonexistent device %s", + dm_device_name(t->md), + bdevname(dd->bdev, b)); + } if (!ret) ret = err;