Re: [PATCH v6 09/18] s390/dasd: Extend prepare_itcw() to support WRITE_FULL_TRACK

[email protected] Sat, 01 Aug 2026 11:37:15 +0000
Newsgroups org.kernel.vger.linux-s390
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] The newly added DASD_ECKD_CCW_WRITE_FULL_TRACK case correctly initializes fields but they are unconditionally overwritten by trailing common code in prepare_itcw().
- [High] Uninitialized `start_trk` and `end_trk` in non-format requests cause false-positive collision detection when track 0 is formatted.
--

--- Patch [9]: [PATCH v6 09/18] s390/dasd: Extend prepare_itcw() to support WRITE_FULL_TRACK ---
commit c073fedc91e7807d5ec588cea865d8b63661d671
Author: Stefan Haberland <[email protected]>

s390/dasd: Extend prepare_itcw() to support WRITE_FULL_TRACK

This commit extends prepare_itcw() to build the FCX prefix block (PFX +
LRE) for the new DASD_ECKD_CCW_WRITE_FULL_TRACK track-mode I/O command. It
allocates the prefix buffer on the stack to prevent memory allocation
failures under pressure during the writeback path.

> diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
> index 77ceba151560b..01c6cdc8430fe 100644
> --- a/drivers/s390/block/dasd_eckd.c
> +++ b/drivers/s390/block/dasd_eckd.c
> @@ -4383,11 +4383,13 @@ static int prepare_itcw(struct itcw *itcw,

[ ... ]

>  	switch (cmd) {
> @@ -4446,7 +4453,38 @@ static int prepare_itcw(struct itcw *itcw,
>  		 * data as well.
>  		 */
>  		if (dedata->ga_extended & 0x08 && dedata->ga_extended & 0x02)
> -			pfxdata.validity.time_stamp = 1; /* 'Time Stamp Valid' */
> +			pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */
> +		pfx_cmd = DASD_ECKD_CCW_PFX;
> +		break;
> +	case DASD_ECKD_CCW_WRITE_FULL_TRACK:
> +		dedata->mask.perm = 0x3;
> +		dedata->mask.auth = 0x00;
> +		dedata->attributes.operation = basepriv->attrib.operation;
> +		dedata->blk_size = blksize;
> +		dedata->ga_extended |= 0x42;
> +		rc = set_timestamp(NULL, dedata, basedev);
> +		lredata->operation.orientation = 0x0;
> +		lredata->operation.operation = 0x3F;
> +		lredata->extended_operation = 0x11;
> +		lredata->auxiliary.check_bytes = 0x2;
> +		lredata->extended_parameter_length = 0x02;
> +		if (count > 8) {
> +			lredata->extended_parameter[0] = 0xFF;
> +			lredata->extended_parameter[1] = 0xFF;
> +			lredata->extended_parameter[1] <<= (16 - count);
> +		} else {
> +			lredata->extended_parameter[0] = 0xFF;
> +			lredata->extended_parameter[0] <<= (8 - count);
> +			lredata->extended_parameter[1] = 0x00;
> +		}
> +		sector = 0xFF;
> +		/*
> +		 * If XRC is supported the System Time Stamp is set. The
> +		 * validity of the time stamp must be reflected in the prefix
> +		 * data as well.
> +		 */
> +		if (dedata->ga_extended & 0x08 && dedata->ga_extended & 0x02)
> +			pfxdata->validity.time_stamp = 1; /* 'Time Stamp Valid' */
>  		pfx_cmd = DASD_ECKD_CCW_PFX;
>  		break;
>  	case DASD_ECKD_CCW_READ_COUNT_MT:

[Severity: High]
Does the trailing code in prepare_itcw() overwrite these initialized fields
for the new full-track write command?

In the trailing code further down in prepare_itcw():

	if (cmd == DASD_ECKD_CCW_READ_COUNT_MT) {
		lredata->auxiliary.length_valid = 0;
		lredata->auxiliary.length_scope = 0;
		lredata->sector = 0xff;
	} else {
		lredata->auxiliary.length_valid = 1;
		lredata->auxiliary.length_scope = 1;
		lredata->sector = sector;
	}

If rec_on_trk is non-zero, it will recalculate sector and overwrite the 0xFF
initialized above, and it will unconditionally set length_valid = 1 which is
incorrect for WRITE_FULL_TRACK. Should the exception condition be updated to
also exclude the new full-track write command?

[ ... ]

Additional note regarding track-based collision detection introduced in this
series:

[Severity: High]
Can uninitialized start_trk and end_trk in non-format requests cause
false-positive collision detection when track 0 is formatted?

Standard read/write requests are allocated via dasd_smalloc_request(), which
zeroes the request struct, but start_trk and end_trk are never initialized for
normal I/O requests (leaving them at 0).

When a format request completes on track 0 (format->start_trk == 0),
dasd_return_cqr_cb() evaluates dasd_req_conflict() against all in-flight
requests:

drivers/s390/block/dasd_int.h:dasd_req_conflict() {
	...
	return !(cqr1->format->end_trk < cqr2->start_trk ||
		 cqr2->end_trk < cqr1->format->start_trk);
}

For uninitialized standard I/O requests, the overlap condition
!(0 < 0 || 0 < 0) evaluates to true, erroneously flagging all in-flight
standard I/O requests with collision = true. 

If those requests later receive an NRF error and require formatting, their
collision flag incorrectly tells test_and_set_format_track() they collided,
causing an immediate I/O retry without actually formatting the track. Does
this result in infinite retry loops and I/O failures on track 0?

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=9