diff options
author | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2015-12-18 16:28:53 -0500 |
---|---|---|
committer | Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> | 2016-01-04 12:21:26 -0500 |
commit | c31ecf6c126dbc7f30234eaf6c4a079649a38de7 (patch) | |
tree | 8d51cdb3d3c3ea4ee8a801b6d44c88e35518ab35 | |
parent | 93bb277f97a6d319361766bde228717faf4abdeb (diff) |
xen/blkfront: Fix crash if backend doesn't follow the right states.
We have split the setting up of all the resources in two steps:
1) talk_to_blkback - which figures out the num_ring_pages (from
the default value of zero), sets up shadow and so
2) blkfront_connect - does the real part of filling out the
internal structures.
The problem is if we bypass the 1) step and go straight to 2)
and call blkfront_setup_indirect where we use the macro
BLK_RING_SIZE - which returns an negative value (because
sz is zero - since num_ring_pages is zero - since it has never
been set).
We can fix this by making sure that we always have called
talk_to_blkback before going to blkfront_connect.
Or we could set in blkfront_probe info->nr_ring_pages = 1
to have a default value. But that looks odd - as we haven't
actually negotiated any ring size.
This patch changes XenbusStateConnected state to detect if
we haven't done the initial handshake - and if so continue
on as if were in XenbusStateInitWait state.
We also roll the error recovery (freeing the structure) into
talk_to_blkback error path - which is safe since that function
is only called from blkback_changed.
Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
-rw-r--r-- | drivers/block/xen-blkfront.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c index f3d0d4758641..8a8dc91c39f7 100644 --- a/drivers/block/xen-blkfront.c +++ b/drivers/block/xen-blkfront.c | |||
@@ -1867,6 +1867,9 @@ again: | |||
1867 | destroy_blkring: | 1867 | destroy_blkring: |
1868 | blkif_free(info, 0); | 1868 | blkif_free(info, 0); |
1869 | 1869 | ||
1870 | kfree(info); | ||
1871 | dev_set_drvdata(&dev->dev, NULL); | ||
1872 | |||
1870 | return err; | 1873 | return err; |
1871 | } | 1874 | } |
1872 | 1875 | ||
@@ -2453,11 +2456,8 @@ static void blkback_changed(struct xenbus_device *dev, | |||
2453 | case XenbusStateInitWait: | 2456 | case XenbusStateInitWait: |
2454 | if (dev->state != XenbusStateInitialising) | 2457 | if (dev->state != XenbusStateInitialising) |
2455 | break; | 2458 | break; |
2456 | if (talk_to_blkback(dev, info)) { | 2459 | if (talk_to_blkback(dev, info)) |
2457 | kfree(info); | ||
2458 | dev_set_drvdata(&dev->dev, NULL); | ||
2459 | break; | 2460 | break; |
2460 | } | ||
2461 | case XenbusStateInitialising: | 2461 | case XenbusStateInitialising: |
2462 | case XenbusStateInitialised: | 2462 | case XenbusStateInitialised: |
2463 | case XenbusStateReconfiguring: | 2463 | case XenbusStateReconfiguring: |
@@ -2466,6 +2466,10 @@ static void blkback_changed(struct xenbus_device *dev, | |||
2466 | break; | 2466 | break; |
2467 | 2467 | ||
2468 | case XenbusStateConnected: | 2468 | case XenbusStateConnected: |
2469 | if (dev->state != XenbusStateInitialised) { | ||
2470 | if (talk_to_blkback(dev, info)) | ||
2471 | break; | ||
2472 | } | ||
2469 | blkfront_connect(info); | 2473 | blkfront_connect(info); |
2470 | break; | 2474 | break; |
2471 | 2475 | ||