Re: [PATCH v7 14/19] s390/dasd: Derive adaptive ESE fulltrack heuristic from ft_bias
[email protected] Sat, 01 Aug 2026 18:17:51 +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: - [Medium] sysfs attribute `ese_heuristic_state` incorrectly reports 'fulltrack active' for non-ESE devices. - [Medium] Flawed lockless synchronization in `dasd_ese_heuristic_tick` allows multiple threads to bypass the early return, resulting in spurious state transitions based on tiny probe windows. -- --- Patch [14]: [PATCH v7 14/19] s390/dasd: Derive adaptive ESE fulltrack heuristic from ft_bias --- commit e1b43c6c6e91c681aa16c723f5cbd3e86ae30516 Author: Stefan Haberland <[email protected]> s390/dasd: Derive adaptive ESE fulltrack heuristic from ft_bias Turn the middle of the ft_bias range (1..99) into an adaptive heuristic that switches between fulltrack write (ft1) and plain write ft0 depending on how sparse the device still is. A sparse device benefits from fulltrack writes (it avoids the format/retry cycle); once enough tracks are formatted the per-write overhead of ft1 outweighs that. An state machine measures the NRF rate in short ft0 probe windows and flips back to ft1 when it is high (FT1_ACTIVE -> PROBING -> FT0_STABLE, with a backing-off reprobe interval). > diff --git a/drivers/s390/block/dasd_devmap.c b/drivers/s390/block/dasd_devmap.c > index 035c022255b68..50301e545bbe8 100644 > --- a/drivers/s390/block/dasd_devmap.c > +++ b/drivers/s390/block/dasd_devmap.c [ ... ] > @@ -1668,6 +1674,41 @@ static ssize_t full_track_bias_store(struct device *dev, > > static DEVICE_ATTR_RW(full_track_bias); > > +static const char * const dasd_ese_heu_state_names[] = { > + [DASD_ESE_HEU_FT1_ACTIVE] = "fulltrack active", > + [DASD_ESE_HEU_PROBING] = "probing", > + [DASD_ESE_HEU_FT0_STABLE] = "fulltrack inactive", > +}; > + > +/* read-only: current full-track mode / adaptive FSM state, for observability */ > +static ssize_t > +ese_heuristic_state_show(struct device *dev, struct device_attribute *attr, > + char *buf) > +{ > + struct dasd_device *device; > + unsigned int state; > + int len; > + > + device = dasd_device_from_cdev(to_ccwdev(dev)); > + if (IS_ERR(device)) > + return -ENODEV; > + if (device->ft_bias == 0) { > + len = sysfs_emit(buf, "fulltrack deactivated\n"); > + } else if (device->ft_bias >= DASD_FT_BIAS_MAX) { > + len = sysfs_emit(buf, "fulltrack permanent active\n"); > + } else { > + state = device->ese_probe_state; > + if (state < ARRAY_SIZE(dasd_ese_heu_state_names)) > + len = sysfs_emit(buf, "%s\n", dasd_ese_heu_state_names[state]); > + else > + len = sysfs_emit(buf, "unknown\n"); > + } [Severity: Medium] Will this incorrectly report "fulltrack active" for non-ESE devices? If ft_bias is set in the adaptive range (which defaults to 50), this falls into the else block and reads ese_probe_state. For standard non-ESE devices, dasd_ft_bias_apply() initializes this state to DASD_ESE_HEU_FT1_ACTIVE (0). Should this check dasd_ese_adaptive(device) before printing the state to avoid exposing misleading observability statistics to user space? > + dasd_put_device(device); > + return len; > +} > + > +static DEVICE_ATTR_RO(ese_heuristic_state); [ ... ] > diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c > index 0247e9a6d7929..dc30c4395b0cc 100644 > --- a/drivers/s390/block/dasd_eckd.c > +++ b/drivers/s390/block/dasd_eckd.c [ ... ] > @@ -3230,6 +3239,69 @@ static void clear_format_track(struct dasd_format_entry *format, > spin_unlock_irqrestore(&block->format_lock, flags); > } > > +/* > + * Adaptive ft_bias heuristic, called once per IO from dasd_eckd_build_cp(). > + * Probes the device formatting state by briefly switching to ft0 and measuring > + * the NRF rate; parameters are derived from ft_bias. > + */ > +static void dasd_ese_heuristic_tick(struct dasd_device *basedev) > +{ > + int ios, nrf, rate; > + > + if (atomic_inc_return(&basedev->ese_io_cnt) < (int)basedev->ese_probe_interval) > + return; > + > + /* > + * One wins the race to evaluate, the rest see ios == 0 after the > + * xchg and return early, preventing redundant state transitions. > + */ > + ios = atomic_xchg(&basedev->ese_io_cnt, 0); > + if (ios <= 0) > + return; [Severity: Medium] Is it possible for multiple threads to bypass the early return and cause spurious state transitions? If multiple threads concurrently evaluate atomic_inc_return(&basedev->ese_io_cnt) < interval and see a value >= interval, they both proceed. The first thread zeroes the counter via atomic_xchg. If another I/O increments the counter to 1 before the second thread performs its atomic_xchg, the second thread will read 1, bypass the ios <= 0 check, and evaluate the heuristic using ios = 1. Could this lead to the ESE heuristic state machine evaluating on tiny probe windows, causing thrashing between FT0 and FT1 under concurrent I/O submission? > + > + switch (basedev->ese_probe_state) { > + case DASD_ESE_HEU_FT1_ACTIVE: -- Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=14