Commit c31ecf6c authored by Konrad Rzeszutek Wilk's avatar Konrad Rzeszutek Wilk

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: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
parent 93bb277f
...@@ -1867,6 +1867,9 @@ static int talk_to_blkback(struct xenbus_device *dev, ...@@ -1867,6 +1867,9 @@ static int talk_to_blkback(struct xenbus_device *dev,
destroy_blkring: destroy_blkring:
blkif_free(info, 0); blkif_free(info, 0);
kfree(info);
dev_set_drvdata(&dev->dev, NULL);
return err; return err;
} }
...@@ -2453,11 +2456,8 @@ static void blkback_changed(struct xenbus_device *dev, ...@@ -2453,11 +2456,8 @@ static void blkback_changed(struct xenbus_device *dev,
case XenbusStateInitWait: case XenbusStateInitWait:
if (dev->state != XenbusStateInitialising) if (dev->state != XenbusStateInitialising)
break; break;
if (talk_to_blkback(dev, info)) { if (talk_to_blkback(dev, info))
kfree(info);
dev_set_drvdata(&dev->dev, NULL);
break; break;
}
case XenbusStateInitialising: case XenbusStateInitialising:
case XenbusStateInitialised: case XenbusStateInitialised:
case XenbusStateReconfiguring: case XenbusStateReconfiguring:
...@@ -2466,6 +2466,10 @@ static void blkback_changed(struct xenbus_device *dev, ...@@ -2466,6 +2466,10 @@ static void blkback_changed(struct xenbus_device *dev,
break; break;
case XenbusStateConnected: case XenbusStateConnected:
if (dev->state != XenbusStateInitialised) {
if (talk_to_blkback(dev, info))
break;
}
blkfront_connect(info); blkfront_connect(info);
break; break;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment