Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 061a424d authored by Stefan Haberland's avatar Stefan Haberland Committed by Greg Kroah-Hartman
Browse files

s390/dasd: fix data corruption for ESE devices



commit 5b53a405e4658580e1faf7c217db3f55a21ba849 upstream.

For ESE devices we get an error when accessing an unformatted track.
The handling of this error will return zero data for read requests and
format the track on demand before writing to it. To do this the code needs
to distinguish between read and write requests. This is done with data from
the blocklayer request. A pointer to the blocklayer request is stored in
the CQR.

If there is an error on the device an ERP request is built to do error
recovery. While the ERP request is mostly a copy of the original CQR the
pointer to the blocklayer request is not copied to not accidentally pass
it back to the blocklayer without cleanup.

This leads to the error that during ESE handling after an ERP request was
built it is not possible to determine the IO direction. This leads to the
formatting of a track for read requests which might in turn lead to data
corruption.

Fixes: 5e2b17e7 ("s390/dasd: Add dynamic formatting support for ESE volumes")
Cc: stable@vger.kernel.org # 5.3+
Signed-off-by: default avatarStefan Haberland <sth@linux.ibm.com>
Reviewed-by: default avatarJan Hoeppner <hoeppner@linux.ibm.com>
Link: https://lore.kernel.org/r/20220505141733.1989450-2-sth@linux.ibm.com


Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 860db6cd
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -1680,6 +1680,7 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
	unsigned long now;
	int nrf_suppressed = 0;
	int fp_suppressed = 0;
	struct request *req;
	u8 *sense = NULL;
	int expires;

@@ -1780,7 +1781,12 @@ void dasd_int_handler(struct ccw_device *cdev, unsigned long intparm,
	}

	if (dasd_ese_needs_format(cqr->block, irb)) {
		if (rq_data_dir((struct request *)cqr->callback_data) == READ) {
		req = dasd_get_callback_data(cqr);
		if (!req) {
			cqr->status = DASD_CQR_ERROR;
			return;
		}
		if (rq_data_dir(req) == READ) {
			device->discipline->ese_read(cqr, irb);
			cqr->status = DASD_CQR_SUCCESS;
			cqr->stopclk = now;
+1 −1
Original line number Diff line number Diff line
@@ -3088,7 +3088,7 @@ dasd_eckd_ese_format(struct dasd_device *startdev, struct dasd_ccw_req *cqr,
	sector_t curr_trk;
	int rc;

	req = cqr->callback_data;
	req = dasd_get_callback_data(cqr);
	block = cqr->block;
	base = block->base;
	private = base->private;
+12 −0
Original line number Diff line number Diff line
@@ -723,6 +723,18 @@ dasd_check_blocksize(int bsize)
	return 0;
}

/*
 * return the callback data of the original request in case there are
 * ERP requests build on top of it
 */
static inline void *dasd_get_callback_data(struct dasd_ccw_req *cqr)
{
	while (cqr->refers)
		cqr = cqr->refers;

	return cqr->callback_data;
}

/* externals in dasd.c */
#define DASD_PROFILE_OFF	 0
#define DASD_PROFILE_ON 	 1