diff options
author | Sebastian Ott <sebott@linux.vnet.ibm.com> | 2012-11-30 10:48:59 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2012-12-03 10:43:58 -0500 |
commit | d99e79ec5574fc556c988f613ed6175f6de66f4a (patch) | |
tree | 50657d29de857267b5fe5cacc5b240d0275dc05c /drivers/s390/cio | |
parent | 1150f25441a7dad818fa4366d01c45c2fef1cbe8 (diff) |
s390/cio: fix pgid reserved check
The check to whom a device is reserved is done by checking the path
state of the affected channel paths. If it turns out that one path is
flagged as reserved by someone else the whole device is marked as such.
However the meaning of the RESVD_ELSE bit is that the addressed device
is reserved to a different pathgroup (and not reserved to a different
LPAR). If we do this test on a path which is currently not a member of
the pathgroup we could erroneously mark the device as reserved to
someone else.
To fix this collect the reserved state for all potential members of the
pathgroup and only mark the device as reserved if all of those potential
members have the RESVD_ELSE bit set.
Cc: stable@vger.kernel.org
Acked-by: Peter Oberparleiter <peter.oberparleiter@de.ibm.com>
Signed-off-by: Sebastian Ott <sebott@linux.vnet.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio')
-rw-r--r-- | drivers/s390/cio/device_pgid.c | 10 |
1 files changed, 5 insertions, 5 deletions
diff --git a/drivers/s390/cio/device_pgid.c b/drivers/s390/cio/device_pgid.c index 368368fe04b2..908d287f66c1 100644 --- a/drivers/s390/cio/device_pgid.c +++ b/drivers/s390/cio/device_pgid.c | |||
@@ -234,7 +234,7 @@ static int pgid_cmp(struct pgid *p1, struct pgid *p2) | |||
234 | * Determine pathgroup state from PGID data. | 234 | * Determine pathgroup state from PGID data. |
235 | */ | 235 | */ |
236 | static void pgid_analyze(struct ccw_device *cdev, struct pgid **p, | 236 | static void pgid_analyze(struct ccw_device *cdev, struct pgid **p, |
237 | int *mismatch, int *reserved, u8 *reset) | 237 | int *mismatch, u8 *reserved, u8 *reset) |
238 | { | 238 | { |
239 | struct pgid *pgid = &cdev->private->pgid[0]; | 239 | struct pgid *pgid = &cdev->private->pgid[0]; |
240 | struct pgid *first = NULL; | 240 | struct pgid *first = NULL; |
@@ -248,7 +248,7 @@ static void pgid_analyze(struct ccw_device *cdev, struct pgid **p, | |||
248 | if ((cdev->private->pgid_valid_mask & lpm) == 0) | 248 | if ((cdev->private->pgid_valid_mask & lpm) == 0) |
249 | continue; | 249 | continue; |
250 | if (pgid->inf.ps.state2 == SNID_STATE2_RESVD_ELSE) | 250 | if (pgid->inf.ps.state2 == SNID_STATE2_RESVD_ELSE) |
251 | *reserved = 1; | 251 | *reserved |= lpm; |
252 | if (pgid_is_reset(pgid)) { | 252 | if (pgid_is_reset(pgid)) { |
253 | *reset |= lpm; | 253 | *reset |= lpm; |
254 | continue; | 254 | continue; |
@@ -316,14 +316,14 @@ static void snid_done(struct ccw_device *cdev, int rc) | |||
316 | struct subchannel *sch = to_subchannel(cdev->dev.parent); | 316 | struct subchannel *sch = to_subchannel(cdev->dev.parent); |
317 | struct pgid *pgid; | 317 | struct pgid *pgid; |
318 | int mismatch = 0; | 318 | int mismatch = 0; |
319 | int reserved = 0; | 319 | u8 reserved = 0; |
320 | u8 reset = 0; | 320 | u8 reset = 0; |
321 | u8 donepm; | 321 | u8 donepm; |
322 | 322 | ||
323 | if (rc) | 323 | if (rc) |
324 | goto out; | 324 | goto out; |
325 | pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset); | 325 | pgid_analyze(cdev, &pgid, &mismatch, &reserved, &reset); |
326 | if (reserved) | 326 | if (reserved == cdev->private->pgid_valid_mask) |
327 | rc = -EUSERS; | 327 | rc = -EUSERS; |
328 | else if (mismatch) | 328 | else if (mismatch) |
329 | rc = -EOPNOTSUPP; | 329 | rc = -EOPNOTSUPP; |
@@ -336,7 +336,7 @@ static void snid_done(struct ccw_device *cdev, int rc) | |||
336 | } | 336 | } |
337 | out: | 337 | out: |
338 | CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x " | 338 | CIO_MSG_EVENT(2, "snid: device 0.%x.%04x: rc=%d pvm=%02x vpm=%02x " |
339 | "todo=%02x mism=%d rsvd=%d reset=%02x\n", id->ssid, | 339 | "todo=%02x mism=%d rsvd=%02x reset=%02x\n", id->ssid, |
340 | id->devno, rc, cdev->private->pgid_valid_mask, sch->vpm, | 340 | id->devno, rc, cdev->private->pgid_valid_mask, sch->vpm, |
341 | cdev->private->pgid_todo_mask, mismatch, reserved, reset); | 341 | cdev->private->pgid_todo_mask, mismatch, reserved, reset); |
342 | switch (rc) { | 342 | switch (rc) { |