mirror of
https://github.com/torvalds/linux.git
synced 2026-10-13 05:41:02 +02:00
s390/cio: Guard PMCW field accesses with dnv check
When PMCW.DNV is 0, no I/O device is associated with the subchannel.
However, several code paths access PMCW fields directly from the cached
sch->schib without first invoking the update helper. Add explicit DNV
validation before accessing PMCW fields from the cached SCHIB to avoid
using invalid data.
Reported-by: William Bezenah <wbezenah@linux.ibm.com>
Signed-off-by: Vineeth Vijayan <vneethv@linux.ibm.com>
Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
Fixes: 8c58a22968 ("s390/cio: Do not unregister the subchannel based on DNV")
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
parent
f6f2985eab
commit
9590f4d838
|
|
@ -78,6 +78,9 @@ u8 chp_get_sch_opm(struct subchannel *sch)
|
|||
int opm;
|
||||
int i;
|
||||
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return 0;
|
||||
|
||||
opm = 0;
|
||||
chp_id_init(&chpid);
|
||||
for (i = 0; i < 8; i++) {
|
||||
|
|
|
|||
|
|
@ -922,7 +922,7 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev,
|
|||
|
||||
if (!sch_is_pseudo_sch(old_sch)) {
|
||||
spin_lock_irq(&old_sch->lock);
|
||||
old_enabled = old_sch->schib.pmcw.ena;
|
||||
old_enabled = old_sch->schib.pmcw.dnv && old_sch->schib.pmcw.ena;
|
||||
rc = 0;
|
||||
if (old_enabled)
|
||||
rc = cio_disable_subchannel(old_sch);
|
||||
|
|
@ -941,7 +941,7 @@ static int ccw_device_move_to_sch(struct ccw_device *cdev,
|
|||
CIO_MSG_EVENT(0, "device_move(0.%x.%04x,0.%x.%04x)=%d\n",
|
||||
cdev->private->dev_id.ssid,
|
||||
cdev->private->dev_id.devno, sch->schid.ssid,
|
||||
sch->schib.pmcw.dev, rc);
|
||||
sch->schid.sch_no, rc);
|
||||
if (old_enabled) {
|
||||
/* Try to re-enable the old subchannel. */
|
||||
spin_lock_irq(&old_sch->lock);
|
||||
|
|
@ -1207,7 +1207,7 @@ static void io_subchannel_quiesce(struct subchannel *sch)
|
|||
cdev = sch_get_cdev(sch);
|
||||
if (cio_is_console(sch->schid))
|
||||
goto out_unlock;
|
||||
if (!sch->schib.pmcw.ena)
|
||||
if (!sch->schib.pmcw.dnv || !sch->schib.pmcw.ena)
|
||||
goto out_unlock;
|
||||
ret = cio_disable_subchannel(sch);
|
||||
if (ret != -EBUSY)
|
||||
|
|
@ -1254,7 +1254,8 @@ static int recovery_check(struct device *dev, void *data)
|
|||
switch (cdev->private->state) {
|
||||
case DEV_STATE_ONLINE:
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
if ((sch->schib.pmcw.pam & sch->opm) == sch->vpm)
|
||||
if (sch->schib.pmcw.dnv &&
|
||||
(sch->schib.pmcw.pam & sch->opm) == sch->vpm)
|
||||
break;
|
||||
fallthrough;
|
||||
case DEV_STATE_DISCONNECTED:
|
||||
|
|
|
|||
|
|
@ -170,6 +170,9 @@ __recover_lost_chpids(struct subchannel *sch, int old_lpm)
|
|||
int mask, i;
|
||||
struct chp_id chpid;
|
||||
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return;
|
||||
|
||||
chp_id_init(&chpid);
|
||||
for (i = 0; i<8; i++) {
|
||||
mask = 0x80 >> i;
|
||||
|
|
|
|||
|
|
@ -490,6 +490,8 @@ struct channel_path_desc_fmt0 *ccw_device_get_chp_desc(struct ccw_device *cdev,
|
|||
struct chp_id chpid;
|
||||
|
||||
sch = to_subchannel(cdev->dev.parent);
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return NULL;
|
||||
chp_id_init(&chpid);
|
||||
chpid.id = sch->schib.pmcw.chpid[chp_idx];
|
||||
return chp_get_chp_desc(chpid);
|
||||
|
|
@ -510,6 +512,8 @@ u8 *ccw_device_get_util_str(struct ccw_device *cdev, int chp_idx)
|
|||
struct chp_id chpid;
|
||||
u8 *util_str;
|
||||
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return NULL;
|
||||
chp_id_init(&chpid);
|
||||
chpid.id = sch->schib.pmcw.chpid[chp_idx];
|
||||
chp = chpid_to_chp(chpid);
|
||||
|
|
@ -662,6 +666,9 @@ int ccw_device_get_mdc(struct ccw_device *cdev, u8 mask)
|
|||
struct chp_id chpid;
|
||||
int mdc = 0, i;
|
||||
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return 0;
|
||||
|
||||
/* Adjust requested path mask to excluded varied off paths. */
|
||||
if (mask)
|
||||
mask &= sch->lpm;
|
||||
|
|
@ -798,6 +805,8 @@ int ccw_device_get_chpid(struct ccw_device *cdev, int chp_idx, u8 *chpid)
|
|||
|
||||
if ((chp_idx < 0) || (chp_idx > 7))
|
||||
return -EINVAL;
|
||||
if (!sch->schib.pmcw.dnv)
|
||||
return -ENODEV;
|
||||
mask = 0x80 >> chp_idx;
|
||||
if (!(sch->schib.pmcw.pim & mask))
|
||||
return -ENODEV;
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ static void fsm_close(struct vfio_ccw_private *private,
|
|||
|
||||
spin_lock_irq(&sch->lock);
|
||||
|
||||
if (!sch->schib.pmcw.ena)
|
||||
if (!sch->schib.pmcw.dnv || !sch->schib.pmcw.ena)
|
||||
goto err_unlock;
|
||||
|
||||
ret = cio_disable_subchannel(sch);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user