Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/dasd: fix error recovery leading to data corruption on ESE devices

Extent Space Efficient (ESE) or thin provisioned volumes need to be
formatted on demand during usual IO processing.

The dasd_ese_needs_format function checks for error codes that signal
the non existence of a proper track format.

The check for incorrect length is to imprecise since other error cases
leading to transport of insufficient data also have this flag set.
This might lead to data corruption in certain error cases for example
during a storage server warmstart.

Fix by removing the check for incorrect length and replacing by
explicitly checking for invalid track format in transport mode.

Also remove the check for file protected since this is not a valid
ESE handling case.

Cc: stable@vger.kernel.org # 5.3+
Fixes: 5e2b17e712cf ("s390/dasd: Add dynamic formatting support for ESE volumes")
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
Link: https://lore.kernel.org/r/20240812125733.126431-3-sth@linux.ibm.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Stefan Haberland and committed by
Jens Axboe
7db40423 2a07bb64

+51 -54
+23 -13
drivers/s390/block/dasd.c
··· 1601 1601 if (!sense) 1602 1602 return 0; 1603 1603 1604 - return !!(sense[1] & SNS1_NO_REC_FOUND) || 1605 - !!(sense[1] & SNS1_FILE_PROTECTED) || 1606 - scsw_cstat(&irb->scsw) == SCHN_STAT_INCORR_LEN; 1604 + if (sense[1] & SNS1_NO_REC_FOUND) 1605 + return 1; 1606 + 1607 + if ((sense[1] & SNS1_INV_TRACK_FORMAT) && 1608 + scsw_is_tm(&irb->scsw) && 1609 + !(sense[2] & SNS2_ENV_DATA_PRESENT)) 1610 + return 1; 1611 + 1612 + return 0; 1607 1613 } 1608 1614 1609 1615 static int dasd_ese_oos_cond(u8 *sense) ··· 1630 1624 struct dasd_device *device; 1631 1625 unsigned long now; 1632 1626 int nrf_suppressed = 0; 1633 - int fp_suppressed = 0; 1627 + int it_suppressed = 0; 1634 1628 struct request *req; 1635 1629 u8 *sense = NULL; 1636 1630 int expires; ··· 1685 1679 */ 1686 1680 sense = dasd_get_sense(irb); 1687 1681 if (sense) { 1688 - fp_suppressed = (sense[1] & SNS1_FILE_PROTECTED) && 1689 - test_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags); 1682 + it_suppressed = (sense[1] & SNS1_INV_TRACK_FORMAT) && 1683 + !(sense[2] & SNS2_ENV_DATA_PRESENT) && 1684 + test_bit(DASD_CQR_SUPPRESS_IT, &cqr->flags); 1690 1685 nrf_suppressed = (sense[1] & SNS1_NO_REC_FOUND) && 1691 1686 test_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); 1692 1687 ··· 1702 1695 return; 1703 1696 } 1704 1697 } 1705 - if (!(fp_suppressed || nrf_suppressed)) 1698 + if (!(it_suppressed || nrf_suppressed)) 1706 1699 device->discipline->dump_sense_dbf(device, irb, "int"); 1707 1700 1708 1701 if (device->features & DASD_FEATURE_ERPLOG) ··· 2466 2459 rc = 0; 2467 2460 list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) { 2468 2461 /* 2469 - * In some cases the 'File Protected' or 'Incorrect Length' 2470 - * error might be expected and error recovery would be 2471 - * unnecessary in these cases. Check if the according suppress 2472 - * bit is set. 2462 + * In some cases certain errors might be expected and 2463 + * error recovery would be unnecessary in these cases. 2464 + * Check if the according suppress bit is set. 2473 2465 */ 2474 2466 sense = dasd_get_sense(&cqr->irb); 2475 - if (sense && sense[1] & SNS1_FILE_PROTECTED && 2476 - test_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags)) 2467 + if (sense && (sense[1] & SNS1_INV_TRACK_FORMAT) && 2468 + !(sense[2] & SNS2_ENV_DATA_PRESENT) && 2469 + test_bit(DASD_CQR_SUPPRESS_IT, &cqr->flags)) 2470 + continue; 2471 + if (sense && (sense[1] & SNS1_NO_REC_FOUND) && 2472 + test_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags)) 2477 2473 continue; 2478 2474 if (scsw_cstat(&cqr->irb.scsw) == 0x40 && 2479 2475 test_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags))
+2 -8
drivers/s390/block/dasd_3990_erp.c
··· 1386 1386 1387 1387 struct dasd_device *device = erp->startdev; 1388 1388 1389 - /* 1390 - * In some cases the 'File Protected' error might be expected and 1391 - * log messages shouldn't be written then. 1392 - * Check if the according suppress bit is set. 1393 - */ 1394 - if (!test_bit(DASD_CQR_SUPPRESS_FP, &erp->flags)) 1395 - dev_err(&device->cdev->dev, 1396 - "Accessing the DASD failed because of a hardware error\n"); 1389 + dev_err(&device->cdev->dev, 1390 + "Accessing the DASD failed because of a hardware error\n"); 1397 1391 1398 1392 return dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED); 1399 1393
+25 -32
drivers/s390/block/dasd_eckd.c
··· 2275 2275 cqr->status = DASD_CQR_FILLED; 2276 2276 /* Set flags to suppress output for expected errors */ 2277 2277 set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); 2278 + set_bit(DASD_CQR_SUPPRESS_IT, &cqr->flags); 2278 2279 2279 2280 return cqr; 2280 2281 } ··· 2557 2556 cqr->buildclk = get_tod_clock(); 2558 2557 cqr->status = DASD_CQR_FILLED; 2559 2558 /* Set flags to suppress output for expected errors */ 2560 - set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags); 2561 2559 set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags); 2562 2560 2563 2561 return cqr; ··· 4130 4130 4131 4131 /* Set flags to suppress output for expected errors */ 4132 4132 if (dasd_eckd_is_ese(basedev)) { 4133 - set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags); 4134 - set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags); 4135 4133 set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); 4136 4134 } 4137 4135 ··· 4631 4633 4632 4634 /* Set flags to suppress output for expected errors */ 4633 4635 if (dasd_eckd_is_ese(basedev)) { 4634 - set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags); 4635 - set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags); 4636 4636 set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags); 4637 + set_bit(DASD_CQR_SUPPRESS_IT, &cqr->flags); 4637 4638 } 4638 4639 4639 4640 return cqr; ··· 5777 5780 { 5778 5781 u8 *sense = dasd_get_sense(irb); 5779 5782 5780 - if (scsw_is_tm(&irb->scsw)) { 5781 - /* 5782 - * In some cases the 'File Protected' or 'Incorrect Length' 5783 - * error might be expected and log messages shouldn't be written 5784 - * then. Check if the according suppress bit is set. 5785 - */ 5786 - if (sense && (sense[1] & SNS1_FILE_PROTECTED) && 5787 - test_bit(DASD_CQR_SUPPRESS_FP, &req->flags)) 5788 - return; 5789 - if (scsw_cstat(&irb->scsw) == 0x40 && 5790 - test_bit(DASD_CQR_SUPPRESS_IL, &req->flags)) 5791 - return; 5783 + /* 5784 + * In some cases certain errors might be expected and 5785 + * log messages shouldn't be written then. 5786 + * Check if the according suppress bit is set. 5787 + */ 5788 + if (sense && (sense[1] & SNS1_INV_TRACK_FORMAT) && 5789 + !(sense[2] & SNS2_ENV_DATA_PRESENT) && 5790 + test_bit(DASD_CQR_SUPPRESS_IT, &req->flags)) 5791 + return; 5792 5792 5793 + if (sense && sense[0] & SNS0_CMD_REJECT && 5794 + test_bit(DASD_CQR_SUPPRESS_CR, &req->flags)) 5795 + return; 5796 + 5797 + if (sense && sense[1] & SNS1_NO_REC_FOUND && 5798 + test_bit(DASD_CQR_SUPPRESS_NRF, &req->flags)) 5799 + return; 5800 + 5801 + if (scsw_cstat(&irb->scsw) == 0x40 && 5802 + test_bit(DASD_CQR_SUPPRESS_IL, &req->flags)) 5803 + return; 5804 + 5805 + if (scsw_is_tm(&irb->scsw)) 5793 5806 dasd_eckd_dump_sense_tcw(device, req, irb); 5794 - } else { 5795 - /* 5796 - * In some cases the 'Command Reject' or 'No Record Found' 5797 - * error might be expected and log messages shouldn't be 5798 - * written then. Check if the according suppress bit is set. 5799 - */ 5800 - if (sense && sense[0] & SNS0_CMD_REJECT && 5801 - test_bit(DASD_CQR_SUPPRESS_CR, &req->flags)) 5802 - return; 5803 - 5804 - if (sense && sense[1] & SNS1_NO_REC_FOUND && 5805 - test_bit(DASD_CQR_SUPPRESS_NRF, &req->flags)) 5806 - return; 5807 - 5807 + else 5808 5808 dasd_eckd_dump_sense_ccw(device, req, irb); 5809 - } 5810 5809 } 5811 5810 5812 5811 static int dasd_eckd_reload_device(struct dasd_device *device)
+1 -1
drivers/s390/block/dasd_int.h
··· 196 196 * The following flags are used to suppress output of certain errors. 197 197 */ 198 198 #define DASD_CQR_SUPPRESS_NRF 4 /* Suppress 'No Record Found' error */ 199 - #define DASD_CQR_SUPPRESS_FP 5 /* Suppress 'File Protected' error*/ 199 + #define DASD_CQR_SUPPRESS_IT 5 /* Suppress 'Invalid Track' error*/ 200 200 #define DASD_CQR_SUPPRESS_IL 6 /* Suppress 'Incorrect Length' error */ 201 201 #define DASD_CQR_SUPPRESS_CR 7 /* Suppress 'Command Reject' error */ 202 202