Commit d50babbe authored by Bob Liu's avatar Bob Liu Committed by Konrad Rzeszutek Wilk

xen-blkfront: introduce blkfront_gather_backend_features()

There is a bug when migrate from !feature-persistent host to feature-persistent
host, because domU still thinks new host/backend doesn't support persistent.
Dmesg like:
backed has not unmapped grant: 839
backed has not unmapped grant: 773
backed has not unmapped grant: 773
backed has not unmapped grant: 773
backed has not unmapped grant: 839

The fix is to recheck feature-persistent of new backend in blkif_recover().
See: https://lkml.org/lkml/2015/5/25/469

As Roger suggested, we can split the part of blkfront_connect that checks for
optional features, like persistent grants, indirect descriptors and
flush/barrier features to a separate function and call it from both
blkfront_connect and blkif_recover
Acked-by: default avatarRoger Pau Monné <roger.pau@citrix.com>
Signed-off-by: default avatarBob Liu <bob.liu@oracle.com>
Signed-off-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
parent a9b54bb9
...@@ -179,6 +179,7 @@ static DEFINE_SPINLOCK(minor_lock); ...@@ -179,6 +179,7 @@ static DEFINE_SPINLOCK(minor_lock);
((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME) ((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)
static int blkfront_setup_indirect(struct blkfront_info *info); static int blkfront_setup_indirect(struct blkfront_info *info);
static int blkfront_gather_backend_features(struct blkfront_info *info);
static int get_id_from_freelist(struct blkfront_info *info) static int get_id_from_freelist(struct blkfront_info *info)
{ {
...@@ -1525,7 +1526,7 @@ static int blkif_recover(struct blkfront_info *info) ...@@ -1525,7 +1526,7 @@ static int blkif_recover(struct blkfront_info *info)
info->shadow_free = info->ring.req_prod_pvt; info->shadow_free = info->ring.req_prod_pvt;
info->shadow[BLK_RING_SIZE(info)-1].req.u.rw.id = 0x0fffffff; info->shadow[BLK_RING_SIZE(info)-1].req.u.rw.id = 0x0fffffff;
rc = blkfront_setup_indirect(info); rc = blkfront_gather_backend_features(info);
if (rc) { if (rc) {
kfree(copy); kfree(copy);
return rc; return rc;
...@@ -1726,20 +1727,13 @@ static void blkfront_setup_discard(struct blkfront_info *info) ...@@ -1726,20 +1727,13 @@ static void blkfront_setup_discard(struct blkfront_info *info)
static int blkfront_setup_indirect(struct blkfront_info *info) static int blkfront_setup_indirect(struct blkfront_info *info)
{ {
unsigned int indirect_segments, segs; unsigned int segs;
int err, i; int err, i;
err = xenbus_gather(XBT_NIL, info->xbdev->otherend, if (info->max_indirect_segments == 0)
"feature-max-indirect-segments", "%u", &indirect_segments,
NULL);
if (err) {
info->max_indirect_segments = 0;
segs = BLKIF_MAX_SEGMENTS_PER_REQUEST; segs = BLKIF_MAX_SEGMENTS_PER_REQUEST;
} else { else
info->max_indirect_segments = min(indirect_segments,
xen_blkif_max_segments);
segs = info->max_indirect_segments; segs = info->max_indirect_segments;
}
err = fill_grant_buffer(info, (segs + INDIRECT_GREFS(segs)) * BLK_RING_SIZE(info)); err = fill_grant_buffer(info, (segs + INDIRECT_GREFS(segs)) * BLK_RING_SIZE(info));
if (err) if (err)
...@@ -1802,6 +1796,68 @@ static int blkfront_setup_indirect(struct blkfront_info *info) ...@@ -1802,6 +1796,68 @@ static int blkfront_setup_indirect(struct blkfront_info *info)
return -ENOMEM; return -ENOMEM;
} }
/*
* Gather all backend feature-*
*/
static int blkfront_gather_backend_features(struct blkfront_info *info)
{
int err;
int barrier, flush, discard, persistent;
unsigned int indirect_segments;
info->feature_flush = 0;
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-barrier", "%d", &barrier,
NULL);
/*
* If there's no "feature-barrier" defined, then it means
* we're dealing with a very old backend which writes
* synchronously; nothing to do.
*
* If there are barriers, then we use flush.
*/
if (!err && barrier)
info->feature_flush = REQ_FLUSH | REQ_FUA;
/*
* And if there is "feature-flush-cache" use that above
* barriers.
*/
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-flush-cache", "%d", &flush,
NULL);
if (!err && flush)
info->feature_flush = REQ_FLUSH;
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-discard", "%d", &discard,
NULL);
if (!err && discard)
blkfront_setup_discard(info);
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-persistent", "%u", &persistent,
NULL);
if (err)
info->feature_persistent = 0;
else
info->feature_persistent = persistent;
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-max-indirect-segments", "%u", &indirect_segments,
NULL);
if (err)
info->max_indirect_segments = 0;
else
info->max_indirect_segments = min(indirect_segments,
xen_blkif_max_segments);
return blkfront_setup_indirect(info);
}
/* /*
* Invoked when the backend is finally 'ready' (and has told produced * Invoked when the backend is finally 'ready' (and has told produced
* the details about the physical device - #sectors, size, etc). * the details about the physical device - #sectors, size, etc).
...@@ -1813,7 +1869,6 @@ static void blkfront_connect(struct blkfront_info *info) ...@@ -1813,7 +1869,6 @@ static void blkfront_connect(struct blkfront_info *info)
unsigned int physical_sector_size; unsigned int physical_sector_size;
unsigned int binfo; unsigned int binfo;
int err; int err;
int barrier, flush, discard, persistent;
switch (info->connected) { switch (info->connected) {
case BLKIF_STATE_CONNECTED: case BLKIF_STATE_CONNECTED:
...@@ -1870,48 +1925,7 @@ static void blkfront_connect(struct blkfront_info *info) ...@@ -1870,48 +1925,7 @@ static void blkfront_connect(struct blkfront_info *info)
if (err != 1) if (err != 1)
physical_sector_size = sector_size; physical_sector_size = sector_size;
info->feature_flush = 0; err = blkfront_gather_backend_features(info);
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-barrier", "%d", &barrier,
NULL);
/*
* If there's no "feature-barrier" defined, then it means
* we're dealing with a very old backend which writes
* synchronously; nothing to do.
*
* If there are barriers, then we use flush.
*/
if (!err && barrier)
info->feature_flush = REQ_FLUSH | REQ_FUA;
/*
* And if there is "feature-flush-cache" use that above
* barriers.
*/
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-flush-cache", "%d", &flush,
NULL);
if (!err && flush)
info->feature_flush = REQ_FLUSH;
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-discard", "%d", &discard,
NULL);
if (!err && discard)
blkfront_setup_discard(info);
err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-persistent", "%u", &persistent,
NULL);
if (err)
info->feature_persistent = 0;
else
info->feature_persistent = persistent;
err = blkfront_setup_indirect(info);
if (err) { if (err) {
xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s", xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s",
info->xbdev->otherend); info->xbdev->otherend);
......
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