diff options
author | Bob Liu <bob.liu@oracle.com> | 2015-06-19 07:23:00 +0300 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2015-06-22 17:06:29 +0300 |
commit | a9b54bb95176cd27f952cd9647849022c4c998d6 (patch) | |
tree | 80cd735b3b9c175ca1dbccba75042b0735337647 /drivers/block | |
parent | 86839c56dee28c315a4c19b7bfee450ccd84cd25 (diff) | |
download | linux-a9b54bb95176cd27f952cd9647849022c4c998d6.tar.xz |
drivers: xen-blkfront: only talk_to_blkback() when in XenbusStateInitialising
Patch 69b91ede5cab843dcf345c28bd1f4b5a99dacd9b
"drivers: xen-blkback: delay pending_req allocation to connect_ring"
exposed an problem that Xen blkfront has. There is a race
with XenStored and the drivers such that we can see two:
vbd vbd-268440320: blkfront:blkback_changed to state 2.
vbd vbd-268440320: blkfront:blkback_changed to state 2.
vbd vbd-268440320: blkfront:blkback_changed to state 4.
state changes to XenbusStateInitWait ('2'). The end result is that
blkback_changed() receives two notify and calls twice setup_blkring().
While the backend driver may only get the first setup_blkring() which is
wrong and reads out-dated (or reads them as they are being updated
with new ring-ref values).
The end result is that the ring ends up being incorrectly set.
The other drivers in the tree have such checks already in.
Reported-and-Tested-by: Robert Butera <robert.butera@oracle.com>
Signed-off-by: Bob Liu <bob.liu@oracle.com>
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Diffstat (limited to 'drivers/block')
-rw-r--r-- | drivers/block/xen-blkfront.c | 2 |
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index d3c1a9523d1f..fc770b7d3beb 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c @@ -1951,6 +1951,8 @@ static void blkback_changed(struct xenbus_device *dev, switch (backend_state) { case XenbusStateInitWait: + if (dev->state != XenbusStateInitialising) + break; if (talk_to_blkback(dev, info)) { kfree(info); dev_set_drvdata(&dev->dev, NULL); |