diff --git a/drivers/s390/block/dasd_eckd.c b/drivers/s390/block/dasd_eckd.c
index 5c1f328b7c8d..fd23ac25a7da 100644
--- a/drivers/s390/block/dasd_eckd.c
+++ b/drivers/s390/block/dasd_eckd.c
@@ -589,8 +589,9 @@ static int prefix_LRE(struct ccw1 *ccw, struct PFX_eckd_data *pfxdata,
return -EINVAL;
}
pfxdata->format = format;
- pfxdata->base_address = basepriv->conf.ned->unit_addr;
- pfxdata->base_lss = basepriv->conf.ned->ID;
+ /* cached copies - conf.ned may be freed under us by the reload worker */
+ pfxdata->base_address = READ_ONCE(basepriv->ned_ua);
+ pfxdata->base_lss = READ_ONCE(basepriv->ned_lss);
pfxdata->validity.define_extent = 1;
/* private uid is kept up to date, conf_data may be outdated */
@@ -807,6 +808,9 @@ static int dasd_eckd_generate_uid(struct dasd_device *device)
return -ENODEV;
spin_lock_irqsave(get_ccwdev_lock(device->cdev), flags);
create_uid(&private->conf, &private->uid);
+ /* cache LSS and unit address for the lockless CCW-build path */
+ WRITE_ONCE(private->ned_lss, private->conf.ned->ID);
+ WRITE_ONCE(private->ned_ua, private->conf.ned->unit_addr);
spin_unlock_irqrestore(get_ccwdev_lock(device->cdev), flags);
return 0;
}
@@ -1632,8 +1636,8 @@ static int dasd_eckd_read_vol_info(struct dasd_device *device)
prssdp = cqr->data;
prssdp->order = PSF_ORDER_PRSSD;
prssdp->suborder = PSF_SUBORDER_VSQ; /* Volume Storage Query */
- prssdp->lss = private->conf.ned->ID;
- prssdp->volume = private->conf.ned->unit_addr;
+ prssdp->lss = READ_ONCE(private->ned_lss);
+ prssdp->volume = READ_ONCE(private->ned_ua);
ccw = cqr->cpaddr;
ccw->cmd_code = DASD_ECKD_CCW_PSF;
@@ -4250,8 +4254,9 @@ dasd_eckd_dso_ras(struct dasd_device *device, struct dasd_block *block,
if (!req && features->feature[56] & 0x01 && !copy_relation)
ras_data->op_flags.guarantee_init = 1;
- ras_data->lss = private->conf.ned->ID;
- ras_data->dev_addr = private->conf.ned->unit_addr;
+ /* cached copies - conf.ned may be freed under us by the reload worker */
+ ras_data->lss = READ_ONCE(private->ned_lss);
+ ras_data->dev_addr = READ_ONCE(private->ned_ua);
ras_data->nr_exts = nr_exts;
if (by_extent) {@@ -4822,8 +4827,9 @@ static int prepare_itcw(struct itcw *itcw,
lredata = &pfxdata->locate_record;
pfxdata->format = 1; /* PFX with LRE */
- pfxdata->base_address = basepriv->conf.ned->unit_addr;
- pfxdata->base_lss = basepriv->conf.ned->ID;
+ /* cached copies - conf.ned may be freed under us by the reload worker */
+ pfxdata->base_address = READ_ONCE(basepriv->ned_ua);
+ pfxdata->base_lss = READ_ONCE(basepriv->ned_lss);
pfxdata->validity.define_extent = 1;
/* private uid is kept up to date, conf_data may be outdated */
@@ -6905,8 +6911,8 @@ static int dasd_eckd_query_host_access(struct dasd_device *device,
prssdp->order = PSF_ORDER_PRSSD;
prssdp->suborder = PSF_SUBORDER_QHA; /* query host access */
/* LSS and Volume that will be queried */
- prssdp->lss = private->conf.ned->ID;
- prssdp->volume = private->conf.ned->unit_addr;
+ prssdp->lss = READ_ONCE(private->ned_lss);
+ prssdp->volume = READ_ONCE(private->ned_ua);
/* all other bytes of prssdp must be zero */
ccw = cqr->cpaddr;
diff --git a/drivers/s390/block/dasd_eckd.h b/drivers/s390/block/dasd_eckd.h
index 30745f62402b..8e6f09e9ca7e 100644
--- a/drivers/s390/block/dasd_eckd.h
+++ b/drivers/s390/block/dasd_eckd.h
@@ -736,6 +736,14 @@ struct dasd_eckd_private {
/* alias management */
struct dasd_uid uid;
+ /*
+ * Cached copies of conf.ned->ID (the LSS) and conf.ned->unit_addr,
+ * refreshed under ccwdev_lock. Kept outside uid because create_uid()
+ * memsets uid before repopulating it, which would expose a transient
+ * zero to the lockless CCW-build readers.
+ */
+ __u8 ned_lss;
+ __u8 ned_ua;
struct alias_pav_group *pavgroup;
struct alias_lcu *lcu;
int count;--
2.53.0