Skip to content

Commit 7db4042

Browse files
Stefan Haberlandaxboe
authored andcommitted
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: [email protected] # 5.3+ Fixes: 5e2b17e ("s390/dasd: Add dynamic formatting support for ESE volumes") Reviewed-by: Jan Hoeppner <[email protected]> Signed-off-by: Stefan Haberland <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jens Axboe <[email protected]>
1 parent 2a07bb6 commit 7db4042

File tree

4 files changed

+50
-53
lines changed

4 files changed

+50
-53
lines changed

drivers/s390/block/dasd.c

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1601,9 +1601,15 @@ static int dasd_ese_needs_format(struct dasd_block *block, struct irb *irb)
16011601
if (!sense)
16021602
return 0;
16031603

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;
16071613
}
16081614

16091615
static int dasd_ese_oos_cond(u8 *sense)
@@ -1624,7 +1630,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
16241630
struct dasd_device *device;
16251631
unsigned long now;
16261632
int nrf_suppressed = 0;
1627-
int fp_suppressed = 0;
1633+
int it_suppressed = 0;
16281634
struct request *req;
16291635
u8 *sense = NULL;
16301636
int expires;
@@ -1679,8 +1685,9 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
16791685
*/
16801686
sense = dasd_get_sense(irb);
16811687
if (sense) {
1682-
fp_suppressed = (sense[1] & SNS1_FILE_PROTECTED) &&
1683-
test_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
1688+
it_suppressed = (sense[1] & SNS1_INV_TRACK_FORMAT) &&
1689+
!(sense[2] & SNS2_ENV_DATA_PRESENT) &&
1690+
test_bit(DASD_CQR_SUPPRESS_IT, &cqr->flags);
16841691
nrf_suppressed = (sense[1] & SNS1_NO_REC_FOUND) &&
16851692
test_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
16861693

@@ -1695,7 +1702,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
16951702
return;
16961703
}
16971704
}
1698-
if (!(fp_suppressed || nrf_suppressed))
1705+
if (!(it_suppressed || nrf_suppressed))
16991706
device->discipline->dump_sense_dbf(device, irb, "int");
17001707

17011708
if (device->features & DASD_FEATURE_ERPLOG)
@@ -2459,14 +2466,17 @@ static int _dasd_sleep_on_queue(struct list_head *ccw_queue, int interruptible)
24592466
rc = 0;
24602467
list_for_each_entry_safe(cqr, n, ccw_queue, blocklist) {
24612468
/*
2462-
* In some cases the 'File Protected' or 'Incorrect Length'
2463-
* error might be expected and error recovery would be
2464-
* unnecessary in these cases. Check if the according suppress
2465-
* bit is set.
2469+
* In some cases certain errors might be expected and
2470+
* error recovery would be unnecessary in these cases.
2471+
* Check if the according suppress bit is set.
24662472
*/
24672473
sense = dasd_get_sense(&cqr->irb);
2468-
if (sense && sense[1] & SNS1_FILE_PROTECTED &&
2469-
test_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags))
2474+
if (sense && (sense[1] & SNS1_INV_TRACK_FORMAT) &&
2475+
!(sense[2] & SNS2_ENV_DATA_PRESENT) &&
2476+
test_bit(DASD_CQR_SUPPRESS_IT, &cqr->flags))
2477+
continue;
2478+
if (sense && (sense[1] & SNS1_NO_REC_FOUND) &&
2479+
test_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags))
24702480
continue;
24712481
if (scsw_cstat(&cqr->irb.scsw) == 0x40 &&
24722482
test_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags))

drivers/s390/block/dasd_3990_erp.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1386,14 +1386,8 @@ dasd_3990_erp_file_prot(struct dasd_ccw_req * erp)
13861386

13871387
struct dasd_device *device = erp->startdev;
13881388

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");
13971391

13981392
return dasd_3990_erp_cleanup(erp, DASD_CQR_FAILED);
13991393

drivers/s390/block/dasd_eckd.c

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2275,6 +2275,7 @@ dasd_eckd_analysis_ccw(struct dasd_device *device)
22752275
cqr->status = DASD_CQR_FILLED;
22762276
/* Set flags to suppress output for expected errors */
22772277
set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
2278+
set_bit(DASD_CQR_SUPPRESS_IT, &cqr->flags);
22782279

22792280
return cqr;
22802281
}
@@ -2556,7 +2557,6 @@ dasd_eckd_build_check_tcw(struct dasd_device *base, struct format_data_t *fdata,
25562557
cqr->buildclk = get_tod_clock();
25572558
cqr->status = DASD_CQR_FILLED;
25582559
/* Set flags to suppress output for expected errors */
2559-
set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
25602560
set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags);
25612561

25622562
return cqr;
@@ -4130,8 +4130,6 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
41304130

41314131
/* Set flags to suppress output for expected errors */
41324132
if (dasd_eckd_is_ese(basedev)) {
4133-
set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
4134-
set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags);
41354133
set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
41364134
}
41374135

@@ -4633,9 +4631,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
46334631

46344632
/* Set flags to suppress output for expected errors */
46354633
if (dasd_eckd_is_ese(basedev)) {
4636-
set_bit(DASD_CQR_SUPPRESS_FP, &cqr->flags);
4637-
set_bit(DASD_CQR_SUPPRESS_IL, &cqr->flags);
46384634
set_bit(DASD_CQR_SUPPRESS_NRF, &cqr->flags);
4635+
set_bit(DASD_CQR_SUPPRESS_IT, &cqr->flags);
46394636
}
46404637

46414638
return cqr;
@@ -5780,36 +5777,32 @@ static void dasd_eckd_dump_sense(struct dasd_device *device,
57805777
{
57815778
u8 *sense = dasd_get_sense(irb);
57825779

5783-
if (scsw_is_tm(&irb->scsw)) {
5784-
/*
5785-
* In some cases the 'File Protected' or 'Incorrect Length'
5786-
* error might be expected and log messages shouldn't be written
5787-
* then. Check if the according suppress bit is set.
5788-
*/
5789-
if (sense && (sense[1] & SNS1_FILE_PROTECTED) &&
5790-
test_bit(DASD_CQR_SUPPRESS_FP, &req->flags))
5791-
return;
5792-
if (scsw_cstat(&irb->scsw) == 0x40 &&
5793-
test_bit(DASD_CQR_SUPPRESS_IL, &req->flags))
5794-
return;
5780+
/*
5781+
* In some cases certain errors might be expected and
5782+
* log messages shouldn't be written then.
5783+
* Check if the according suppress bit is set.
5784+
*/
5785+
if (sense && (sense[1] & SNS1_INV_TRACK_FORMAT) &&
5786+
!(sense[2] & SNS2_ENV_DATA_PRESENT) &&
5787+
test_bit(DASD_CQR_SUPPRESS_IT, &req->flags))
5788+
return;
57955789

5796-
dasd_eckd_dump_sense_tcw(device, req, irb);
5797-
} else {
5798-
/*
5799-
* In some cases the 'Command Reject' or 'No Record Found'
5800-
* error might be expected and log messages shouldn't be
5801-
* written then. Check if the according suppress bit is set.
5802-
*/
5803-
if (sense && sense[0] & SNS0_CMD_REJECT &&
5804-
test_bit(DASD_CQR_SUPPRESS_CR, &req->flags))
5805-
return;
5790+
if (sense && sense[0] & SNS0_CMD_REJECT &&
5791+
test_bit(DASD_CQR_SUPPRESS_CR, &req->flags))
5792+
return;
58065793

5807-
if (sense && sense[1] & SNS1_NO_REC_FOUND &&
5808-
test_bit(DASD_CQR_SUPPRESS_NRF, &req->flags))
5809-
return;
5794+
if (sense && sense[1] & SNS1_NO_REC_FOUND &&
5795+
test_bit(DASD_CQR_SUPPRESS_NRF, &req->flags))
5796+
return;
58105797

5798+
if (scsw_cstat(&irb->scsw) == 0x40 &&
5799+
test_bit(DASD_CQR_SUPPRESS_IL, &req->flags))
5800+
return;
5801+
5802+
if (scsw_is_tm(&irb->scsw))
5803+
dasd_eckd_dump_sense_tcw(device, req, irb);
5804+
else
58115805
dasd_eckd_dump_sense_ccw(device, req, irb);
5812-
}
58135806
}
58145807

58155808
static int dasd_eckd_reload_device(struct dasd_device *device)

drivers/s390/block/dasd_int.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ struct dasd_ccw_req {
196196
* The following flags are used to suppress output of certain errors.
197197
*/
198198
#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*/
200200
#define DASD_CQR_SUPPRESS_IL 6 /* Suppress 'Incorrect Length' error */
201201
#define DASD_CQR_SUPPRESS_CR 7 /* Suppress 'Command Reject' error */
202202

0 commit comments

Comments
 (0)