Skip to content

Commit

Permalink
Merge branch 'stable/for-jens-4.2' of git://git.kernel.org/pub/scm/li…
Browse files Browse the repository at this point in the history
…nux/kernel/git/konrad/xen into for-linus

Konrad writes:

"There are three bugs that have been found in the xen-blkfront (and
backend). Two of them have the stable tree CC-ed. They have been found
where an guest is migrating to a host that is missing
'feature-persistent' support (from one that has it enabled). We end up
hitting an BUG() in the driver code."
  • Loading branch information
Jens Axboe committed Jul 27, 2015
2 parents cbfe8fa + 53bc7dc commit e162b21
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 58 deletions.
4 changes: 2 additions & 2 deletions drivers/block/xen-blkback/blkback.c
Original file line number Diff line number Diff line change
Expand Up @@ -369,8 +369,8 @@ static void purge_persistent_gnt(struct xen_blkif *blkif)
return;
}

if (work_pending(&blkif->persistent_purge_work)) {
pr_alert_ratelimited("Scheduled work from previous purge is still pending, cannot purge list\n");
if (work_busy(&blkif->persistent_purge_work)) {
pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n");
return;
}

Expand Down
128 changes: 72 additions & 56 deletions drivers/block/xen-blkfront.c
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ static DEFINE_SPINLOCK(minor_lock);
((_segs + SEGS_PER_INDIRECT_FRAME - 1)/SEGS_PER_INDIRECT_FRAME)

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)
{
Expand Down Expand Up @@ -1128,8 +1129,10 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
* Add the used indirect page back to the list of
* available pages for indirect grefs.
*/
indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
list_add(&indirect_page->lru, &info->indirect_pages);
if (!info->feature_persistent) {
indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
list_add(&indirect_page->lru, &info->indirect_pages);
}
s->indirect_grants[i]->gref = GRANT_INVALID_REF;
list_add_tail(&s->indirect_grants[i]->node, &info->grants);
}
Expand Down Expand Up @@ -1519,7 +1522,7 @@ static int blkif_recover(struct blkfront_info *info)
info->shadow_free = info->ring.req_prod_pvt;
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) {
kfree(copy);
return rc;
Expand Down Expand Up @@ -1720,20 +1723,13 @@ static void blkfront_setup_discard(struct blkfront_info *info)

static int blkfront_setup_indirect(struct blkfront_info *info)
{
unsigned int indirect_segments, segs;
unsigned int segs;
int err, i;

err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-max-indirect-segments", "%u", &indirect_segments,
NULL);
if (err) {
info->max_indirect_segments = 0;
if (info->max_indirect_segments == 0)
segs = BLKIF_MAX_SEGMENTS_PER_REQUEST;
} else {
info->max_indirect_segments = min(indirect_segments,
xen_blkif_max_segments);
else
segs = info->max_indirect_segments;
}

err = fill_grant_buffer(info, (segs + INDIRECT_GREFS(segs)) * BLK_RING_SIZE(info));
if (err)
Expand Down Expand Up @@ -1796,6 +1792,68 @@ static int blkfront_setup_indirect(struct blkfront_info *info)
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
* the details about the physical device - #sectors, size, etc).
Expand All @@ -1807,7 +1865,6 @@ static void blkfront_connect(struct blkfront_info *info)
unsigned int physical_sector_size;
unsigned int binfo;
int err;
int barrier, flush, discard, persistent;

switch (info->connected) {
case BLKIF_STATE_CONNECTED:
Expand Down Expand Up @@ -1864,48 +1921,7 @@ static void blkfront_connect(struct blkfront_info *info)
if (err != 1)
physical_sector_size = sector_size;

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 = blkfront_setup_indirect(info);
err = blkfront_gather_backend_features(info);
if (err) {
xenbus_dev_fatal(info->xbdev, err, "setup_indirect at %s",
info->xbdev->otherend);
Expand Down

0 comments on commit e162b21

Please sign in to comment.