Commit d642daf6 authored by Roger Pau Monne's avatar Roger Pau Monne Committed by Greg Kroah-Hartman

xen-blkfront: restore the non-persistent data path

commit bfe11d6d upstream.

When persistent grants were added they were always used, even if the
backend doesn't have this feature (there's no harm in always using the
same set of pages). This restores the old data path when the backend
doesn't have persistent grants, removing the burden of doing a memcpy
when it is not actually needed.
Signed-off-by: default avatarRoger Pau Monné <roger.pau@citrix.com>
Reported-by: default avatarFelipe Franciosi <felipe.franciosi@citrix.com>
Cc: Felipe Franciosi <felipe.franciosi@citrix.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Cc: David Vrabel <david.vrabel@citrix.com>
Signed-off-by: default avatarKonrad Rzeszutek Wilk <konrad.wilk@oracle.com>
[v2: Fix up whitespace issues]
Tested-by: default avatarFelipe Franciosi <felipe@paradoxo.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent ba4abe2e
...@@ -104,7 +104,7 @@ struct blkfront_info ...@@ -104,7 +104,7 @@ struct blkfront_info
struct work_struct work; struct work_struct work;
struct gnttab_free_callback callback; struct gnttab_free_callback callback;
struct blk_shadow shadow[BLK_RING_SIZE]; struct blk_shadow shadow[BLK_RING_SIZE];
struct list_head persistent_gnts; struct list_head grants;
unsigned int persistent_gnts_c; unsigned int persistent_gnts_c;
unsigned long shadow_free; unsigned long shadow_free;
unsigned int feature_flush; unsigned int feature_flush;
...@@ -175,15 +175,17 @@ static int fill_grant_buffer(struct blkfront_info *info, int num) ...@@ -175,15 +175,17 @@ static int fill_grant_buffer(struct blkfront_info *info, int num)
if (!gnt_list_entry) if (!gnt_list_entry)
goto out_of_memory; goto out_of_memory;
if (info->feature_persistent) {
granted_page = alloc_page(GFP_NOIO); granted_page = alloc_page(GFP_NOIO);
if (!granted_page) { if (!granted_page) {
kfree(gnt_list_entry); kfree(gnt_list_entry);
goto out_of_memory; goto out_of_memory;
} }
gnt_list_entry->pfn = page_to_pfn(granted_page); gnt_list_entry->pfn = page_to_pfn(granted_page);
}
gnt_list_entry->gref = GRANT_INVALID_REF; gnt_list_entry->gref = GRANT_INVALID_REF;
list_add(&gnt_list_entry->node, &info->persistent_gnts); list_add(&gnt_list_entry->node, &info->grants);
i++; i++;
} }
...@@ -191,8 +193,9 @@ static int fill_grant_buffer(struct blkfront_info *info, int num) ...@@ -191,8 +193,9 @@ static int fill_grant_buffer(struct blkfront_info *info, int num)
out_of_memory: out_of_memory:
list_for_each_entry_safe(gnt_list_entry, n, list_for_each_entry_safe(gnt_list_entry, n,
&info->persistent_gnts, node) { &info->grants, node) {
list_del(&gnt_list_entry->node); list_del(&gnt_list_entry->node);
if (info->feature_persistent)
__free_page(pfn_to_page(gnt_list_entry->pfn)); __free_page(pfn_to_page(gnt_list_entry->pfn));
kfree(gnt_list_entry); kfree(gnt_list_entry);
i--; i--;
...@@ -202,14 +205,14 @@ static int fill_grant_buffer(struct blkfront_info *info, int num) ...@@ -202,14 +205,14 @@ static int fill_grant_buffer(struct blkfront_info *info, int num)
} }
static struct grant *get_grant(grant_ref_t *gref_head, static struct grant *get_grant(grant_ref_t *gref_head,
unsigned long pfn,
struct blkfront_info *info) struct blkfront_info *info)
{ {
struct grant *gnt_list_entry; struct grant *gnt_list_entry;
unsigned long buffer_mfn; unsigned long buffer_mfn;
BUG_ON(list_empty(&info->persistent_gnts)); BUG_ON(list_empty(&info->grants));
gnt_list_entry = list_first_entry(&info->persistent_gnts, struct grant, gnt_list_entry = list_first_entry(&info->grants, struct grant, node);
node);
list_del(&gnt_list_entry->node); list_del(&gnt_list_entry->node);
if (gnt_list_entry->gref != GRANT_INVALID_REF) { if (gnt_list_entry->gref != GRANT_INVALID_REF) {
...@@ -220,6 +223,10 @@ static struct grant *get_grant(grant_ref_t *gref_head, ...@@ -220,6 +223,10 @@ static struct grant *get_grant(grant_ref_t *gref_head,
/* Assign a gref to this page */ /* Assign a gref to this page */
gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head); gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head);
BUG_ON(gnt_list_entry->gref == -ENOSPC); BUG_ON(gnt_list_entry->gref == -ENOSPC);
if (!info->feature_persistent) {
BUG_ON(!pfn);
gnt_list_entry->pfn = pfn;
}
buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn); buffer_mfn = pfn_to_mfn(gnt_list_entry->pfn);
gnttab_grant_foreign_access_ref(gnt_list_entry->gref, gnttab_grant_foreign_access_ref(gnt_list_entry->gref,
info->xbdev->otherend_id, info->xbdev->otherend_id,
...@@ -430,12 +437,12 @@ static int blkif_queue_request(struct request *req) ...@@ -430,12 +437,12 @@ static int blkif_queue_request(struct request *req)
fsect = sg->offset >> 9; fsect = sg->offset >> 9;
lsect = fsect + (sg->length >> 9) - 1; lsect = fsect + (sg->length >> 9) - 1;
gnt_list_entry = get_grant(&gref_head, info); gnt_list_entry = get_grant(&gref_head, page_to_pfn(sg_page(sg)), info);
ref = gnt_list_entry->gref; ref = gnt_list_entry->gref;
info->shadow[id].grants_used[i] = gnt_list_entry; info->shadow[id].grants_used[i] = gnt_list_entry;
if (rq_data_dir(req)) { if (rq_data_dir(req) && info->feature_persistent) {
char *bvec_data; char *bvec_data;
void *shared_data; void *shared_data;
...@@ -828,15 +835,16 @@ static void blkif_free(struct blkfront_info *info, int suspend) ...@@ -828,15 +835,16 @@ static void blkif_free(struct blkfront_info *info, int suspend)
blk_stop_queue(info->rq); blk_stop_queue(info->rq);
/* Remove all persistent grants */ /* Remove all persistent grants */
if (!list_empty(&info->persistent_gnts)) { if (!list_empty(&info->grants)) {
list_for_each_entry_safe(persistent_gnt, n, list_for_each_entry_safe(persistent_gnt, n,
&info->persistent_gnts, node) { &info->grants, node) {
list_del(&persistent_gnt->node); list_del(&persistent_gnt->node);
if (persistent_gnt->gref != GRANT_INVALID_REF) { if (persistent_gnt->gref != GRANT_INVALID_REF) {
gnttab_end_foreign_access(persistent_gnt->gref, gnttab_end_foreign_access(persistent_gnt->gref,
0, 0UL); 0, 0UL);
info->persistent_gnts_c--; info->persistent_gnts_c--;
} }
if (info->feature_persistent)
__free_page(pfn_to_page(persistent_gnt->pfn)); __free_page(pfn_to_page(persistent_gnt->pfn));
kfree(persistent_gnt); kfree(persistent_gnt);
} }
...@@ -874,7 +882,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, ...@@ -874,7 +882,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
nseg = s->req.u.rw.nr_segments; nseg = s->req.u.rw.nr_segments;
if (bret->operation == BLKIF_OP_READ) { if (bret->operation == BLKIF_OP_READ && info->feature_persistent) {
/* /*
* Copy the data received from the backend into the bvec. * Copy the data received from the backend into the bvec.
* Since bv_offset can be different than 0, and bv_len different * Since bv_offset can be different than 0, and bv_len different
...@@ -902,7 +910,10 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, ...@@ -902,7 +910,10 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
* we add it at the head of the list, so it will be * we add it at the head of the list, so it will be
* reused first. * reused first.
*/ */
list_add(&s->grants_used[i]->node, &info->persistent_gnts); if (!info->feature_persistent)
pr_alert_ratelimited("backed has not unmapped grant: %u\n",
s->grants_used[i]->gref);
list_add(&s->grants_used[i]->node, &info->grants);
info->persistent_gnts_c++; info->persistent_gnts_c++;
} else { } else {
/* /*
...@@ -913,7 +924,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info, ...@@ -913,7 +924,7 @@ static void blkif_completion(struct blk_shadow *s, struct blkfront_info *info,
*/ */
gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL); gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL);
s->grants_used[i]->gref = GRANT_INVALID_REF; s->grants_used[i]->gref = GRANT_INVALID_REF;
list_add_tail(&s->grants_used[i]->node, &info->persistent_gnts); list_add_tail(&s->grants_used[i]->node, &info->grants);
} }
} }
} }
...@@ -1052,12 +1063,6 @@ static int setup_blkring(struct xenbus_device *dev, ...@@ -1052,12 +1063,6 @@ static int setup_blkring(struct xenbus_device *dev,
for (i = 0; i < BLK_RING_SIZE; i++) for (i = 0; i < BLK_RING_SIZE; i++)
sg_init_table(info->shadow[i].sg, BLKIF_MAX_SEGMENTS_PER_REQUEST); sg_init_table(info->shadow[i].sg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
/* Allocate memory for grants */
err = fill_grant_buffer(info, BLK_RING_SIZE *
BLKIF_MAX_SEGMENTS_PER_REQUEST);
if (err)
goto fail;
err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring)); err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
if (err < 0) { if (err < 0) {
free_page((unsigned long)sring); free_page((unsigned long)sring);
...@@ -1216,7 +1221,7 @@ static int blkfront_probe(struct xenbus_device *dev, ...@@ -1216,7 +1221,7 @@ static int blkfront_probe(struct xenbus_device *dev,
spin_lock_init(&info->io_lock); spin_lock_init(&info->io_lock);
info->xbdev = dev; info->xbdev = dev;
info->vdevice = vdevice; info->vdevice = vdevice;
INIT_LIST_HEAD(&info->persistent_gnts); INIT_LIST_HEAD(&info->grants);
info->persistent_gnts_c = 0; info->persistent_gnts_c = 0;
info->connected = BLKIF_STATE_DISCONNECTED; info->connected = BLKIF_STATE_DISCONNECTED;
INIT_WORK(&info->work, blkif_restart_queue); INIT_WORK(&info->work, blkif_restart_queue);
...@@ -1245,7 +1250,8 @@ static int blkif_recover(struct blkfront_info *info) ...@@ -1245,7 +1250,8 @@ static int blkif_recover(struct blkfront_info *info)
int i; int i;
struct blkif_request *req; struct blkif_request *req;
struct blk_shadow *copy; struct blk_shadow *copy;
int j; unsigned int persistent;
int j, rc;
/* Stage 1: Make a safe copy of the shadow state. */ /* Stage 1: Make a safe copy of the shadow state. */
copy = kmemdup(info->shadow, sizeof(info->shadow), copy = kmemdup(info->shadow, sizeof(info->shadow),
...@@ -1260,6 +1266,24 @@ static int blkif_recover(struct blkfront_info *info) ...@@ -1260,6 +1266,24 @@ 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-1].req.u.rw.id = 0x0fffffff; info->shadow[BLK_RING_SIZE-1].req.u.rw.id = 0x0fffffff;
/* Check if the backend supports persistent grants */
rc = xenbus_gather(XBT_NIL, info->xbdev->otherend,
"feature-persistent", "%u", &persistent,
NULL);
if (rc)
info->feature_persistent = 0;
else
info->feature_persistent = persistent;
/* Allocate memory for grants */
rc = fill_grant_buffer(info, BLK_RING_SIZE *
BLKIF_MAX_SEGMENTS_PER_REQUEST);
if (rc) {
xenbus_dev_fatal(info->xbdev, rc, "setting grant buffer failed");
kfree(copy);
return rc;
}
/* Stage 3: Find pending requests and requeue them. */ /* Stage 3: Find pending requests and requeue them. */
for (i = 0; i < BLK_RING_SIZE; i++) { for (i = 0; i < BLK_RING_SIZE; i++) {
/* Not in use? */ /* Not in use? */
...@@ -1324,8 +1348,12 @@ static int blkfront_resume(struct xenbus_device *dev) ...@@ -1324,8 +1348,12 @@ static int blkfront_resume(struct xenbus_device *dev)
blkif_free(info, info->connected == BLKIF_STATE_CONNECTED); blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
err = talk_to_blkback(dev, info); err = talk_to_blkback(dev, info);
if (info->connected == BLKIF_STATE_SUSPENDED && !err)
err = blkif_recover(info); /*
* We have to wait for the backend to switch to
* connected state, since we want to read which
* features it supports.
*/
return err; return err;
} }
...@@ -1429,9 +1457,16 @@ static void blkfront_connect(struct blkfront_info *info) ...@@ -1429,9 +1457,16 @@ static void blkfront_connect(struct blkfront_info *info)
sectors); sectors);
set_capacity(info->gd, sectors); set_capacity(info->gd, sectors);
revalidate_disk(info->gd); revalidate_disk(info->gd);
return;
/* fall through */
case BLKIF_STATE_SUSPENDED: case BLKIF_STATE_SUSPENDED:
/*
* If we are recovering from suspension, we need to wait
* for the backend to announce it's features before
* reconnecting, we need to know if the backend supports
* persistent grants.
*/
blkif_recover(info);
return; return;
default: default:
...@@ -1499,6 +1534,14 @@ static void blkfront_connect(struct blkfront_info *info) ...@@ -1499,6 +1534,14 @@ static void blkfront_connect(struct blkfront_info *info)
else else
info->feature_persistent = persistent; info->feature_persistent = persistent;
/* Allocate memory for grants */
err = fill_grant_buffer(info, BLK_RING_SIZE *
BLKIF_MAX_SEGMENTS_PER_REQUEST);
if (err) {
xenbus_dev_fatal(info->xbdev, err, "setting grant buffer failed");
return;
}
err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size); err = xlvbd_alloc_gendisk(sectors, info, binfo, sector_size);
if (err) { if (err) {
xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s", xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
......
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