mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-15 13:22:55 +00:00
Merge branch 'stable/for-jens-4.2' of git://git.kernel.org/pub/scm/linux/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."
This commit is contained in:
commit
e162b219ae
@ -369,8 +369,8 @@ static void purge_persistent_gnt(struct xen_blkif *blkif)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (work_pending(&blkif->persistent_purge_work)) {
|
if (work_busy(&blkif->persistent_purge_work)) {
|
||||||
pr_alert_ratelimited("Scheduled work from previous purge is still pending, cannot purge list\n");
|
pr_alert_ratelimited("Scheduled work from previous purge is still busy, cannot purge list\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
{
|
{
|
||||||
@ -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
|
* Add the used indirect page back to the list of
|
||||||
* available pages for indirect grefs.
|
* available pages for indirect grefs.
|
||||||
*/
|
*/
|
||||||
indirect_page = pfn_to_page(s->indirect_grants[i]->pfn);
|
if (!info->feature_persistent) {
|
||||||
list_add(&indirect_page->lru, &info->indirect_pages);
|
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;
|
s->indirect_grants[i]->gref = GRANT_INVALID_REF;
|
||||||
list_add_tail(&s->indirect_grants[i]->node, &info->grants);
|
list_add_tail(&s->indirect_grants[i]->node, &info->grants);
|
||||||
}
|
}
|
||||||
@ -1519,7 +1522,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;
|
||||||
@ -1720,20 +1723,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)
|
||||||
@ -1796,6 +1792,68 @@ out_of_memory:
|
|||||||
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).
|
||||||
@ -1807,7 +1865,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:
|
||||||
@ -1864,48 +1921,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);
|
||||||
|
Loading…
Reference in New Issue
Block a user