| From 41995342b40c418a47603e1321256d2c4a2ed0fb Mon Sep 17 00:00:00 2001 |
| From: Stefan Haberland <sth@linux.ibm.com> |
| Date: Thu, 1 Aug 2019 13:06:30 +0200 |
| Subject: s390/dasd: fix endless loop after read unit address configuration |
| |
| From: Stefan Haberland <sth@linux.ibm.com> |
| |
| commit 41995342b40c418a47603e1321256d2c4a2ed0fb upstream. |
| |
| After getting a storage server event that causes the DASD device driver |
| to update its unit address configuration during a device shutdown there is |
| the possibility of an endless loop in the device driver. |
| |
| In the system log there will be ongoing DASD error messages with RC: -19. |
| |
| The reason is that the loop starting the ruac request only terminates when |
| the retry counter is decreased to 0. But in the sleep_on function there are |
| early exit paths that do not decrease the retry counter. |
| |
| Prevent an endless loop by handling those cases separately. |
| |
| Remove the unnecessary do..while loop since the sleep_on function takes |
| care of retries by itself. |
| |
| Fixes: 8e09f21574ea ("[S390] dasd: add hyper PAV support to DASD device driver, part 1") |
| Cc: stable@vger.kernel.org # 2.6.25+ |
| Signed-off-by: Stefan Haberland <sth@linux.ibm.com> |
| Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com> |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/s390/block/dasd_alias.c | 22 ++++++++++++++++------ |
| 1 file changed, 16 insertions(+), 6 deletions(-) |
| |
| --- a/drivers/s390/block/dasd_alias.c |
| +++ b/drivers/s390/block/dasd_alias.c |
| @@ -383,6 +383,20 @@ suborder_not_supported(struct dasd_ccw_r |
| char msg_format; |
| char msg_no; |
| |
| + /* |
| + * intrc values ENODEV, ENOLINK and EPERM |
| + * will be optained from sleep_on to indicate that no |
| + * IO operation can be started |
| + */ |
| + if (cqr->intrc == -ENODEV) |
| + return 1; |
| + |
| + if (cqr->intrc == -ENOLINK) |
| + return 1; |
| + |
| + if (cqr->intrc == -EPERM) |
| + return 1; |
| + |
| sense = dasd_get_sense(&cqr->irb); |
| if (!sense) |
| return 0; |
| @@ -447,12 +461,8 @@ static int read_unit_address_configurati |
| lcu->flags &= ~NEED_UAC_UPDATE; |
| spin_unlock_irqrestore(&lcu->lock, flags); |
| |
| - do { |
| - rc = dasd_sleep_on(cqr); |
| - if (rc && suborder_not_supported(cqr)) |
| - return -EOPNOTSUPP; |
| - } while (rc && (cqr->retries > 0)); |
| - if (rc) { |
| + rc = dasd_sleep_on(cqr); |
| + if (rc && !suborder_not_supported(cqr)) { |
| spin_lock_irqsave(&lcu->lock, flags); |
| lcu->flags |= NEED_UAC_UPDATE; |
| spin_unlock_irqrestore(&lcu->lock, flags); |