| From bfe11d6de1c416cea4f3f0f35f864162063ce3fa Mon Sep 17 00:00:00 2001 |
| From: Roger Pau Monne <roger.pau@citrix.com> |
| Date: Tue, 29 Oct 2013 18:31:14 +0100 |
| Subject: xen-blkfront: restore the non-persistent data path |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Roger Pau Monne <roger.pau@citrix.com> |
| |
| commit bfe11d6de1c416cea4f3f0f35f864162063ce3fa 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: Roger Pau Monné <roger.pau@citrix.com> |
| Reported-by: Felipe 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: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> |
| [v2: Fix up whitespace issues] |
| Tested-by: Felipe Franciosi <felipe@paradoxo.org> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/block/xen-blkfront.c | 105 ++++++++++++++++++++++++++++++------------- |
| 1 file changed, 74 insertions(+), 31 deletions(-) |
| |
| --- a/drivers/block/xen-blkfront.c |
| +++ b/drivers/block/xen-blkfront.c |
| @@ -104,7 +104,7 @@ struct blkfront_info |
| struct work_struct work; |
| struct gnttab_free_callback callback; |
| struct blk_shadow shadow[BLK_RING_SIZE]; |
| - struct list_head persistent_gnts; |
| + struct list_head grants; |
| unsigned int persistent_gnts_c; |
| unsigned long shadow_free; |
| unsigned int feature_flush; |
| @@ -175,15 +175,17 @@ static int fill_grant_buffer(struct blkf |
| if (!gnt_list_entry) |
| goto out_of_memory; |
| |
| - granted_page = alloc_page(GFP_NOIO); |
| - if (!granted_page) { |
| - kfree(gnt_list_entry); |
| - goto out_of_memory; |
| + if (info->feature_persistent) { |
| + granted_page = alloc_page(GFP_NOIO); |
| + if (!granted_page) { |
| + kfree(gnt_list_entry); |
| + 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; |
| - list_add(&gnt_list_entry->node, &info->persistent_gnts); |
| + list_add(&gnt_list_entry->node, &info->grants); |
| i++; |
| } |
| |
| @@ -191,9 +193,10 @@ static int fill_grant_buffer(struct blkf |
| |
| out_of_memory: |
| list_for_each_entry_safe(gnt_list_entry, n, |
| - &info->persistent_gnts, node) { |
| + &info->grants, node) { |
| list_del(&gnt_list_entry->node); |
| - __free_page(pfn_to_page(gnt_list_entry->pfn)); |
| + if (info->feature_persistent) |
| + __free_page(pfn_to_page(gnt_list_entry->pfn)); |
| kfree(gnt_list_entry); |
| i--; |
| } |
| @@ -202,14 +205,14 @@ out_of_memory: |
| } |
| |
| static struct grant *get_grant(grant_ref_t *gref_head, |
| + unsigned long pfn, |
| struct blkfront_info *info) |
| { |
| struct grant *gnt_list_entry; |
| unsigned long buffer_mfn; |
| |
| - BUG_ON(list_empty(&info->persistent_gnts)); |
| - gnt_list_entry = list_first_entry(&info->persistent_gnts, struct grant, |
| - node); |
| + BUG_ON(list_empty(&info->grants)); |
| + gnt_list_entry = list_first_entry(&info->grants, struct grant, node); |
| list_del(&gnt_list_entry->node); |
| |
| if (gnt_list_entry->gref != GRANT_INVALID_REF) { |
| @@ -220,6 +223,10 @@ static struct grant *get_grant(grant_ref |
| /* Assign a gref to this page */ |
| gnt_list_entry->gref = gnttab_claim_grant_reference(gref_head); |
| 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); |
| gnttab_grant_foreign_access_ref(gnt_list_entry->gref, |
| info->xbdev->otherend_id, |
| @@ -430,12 +437,12 @@ static int blkif_queue_request(struct re |
| fsect = sg->offset >> 9; |
| 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; |
| |
| 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; |
| void *shared_data; |
| |
| @@ -828,16 +835,17 @@ static void blkif_free(struct blkfront_i |
| blk_stop_queue(info->rq); |
| |
| /* Remove all persistent grants */ |
| - if (!list_empty(&info->persistent_gnts)) { |
| + if (!list_empty(&info->grants)) { |
| list_for_each_entry_safe(persistent_gnt, n, |
| - &info->persistent_gnts, node) { |
| + &info->grants, node) { |
| list_del(&persistent_gnt->node); |
| if (persistent_gnt->gref != GRANT_INVALID_REF) { |
| gnttab_end_foreign_access(persistent_gnt->gref, |
| 0, 0UL); |
| info->persistent_gnts_c--; |
| } |
| - __free_page(pfn_to_page(persistent_gnt->pfn)); |
| + if (info->feature_persistent) |
| + __free_page(pfn_to_page(persistent_gnt->pfn)); |
| kfree(persistent_gnt); |
| } |
| } |
| @@ -874,7 +882,7 @@ static void blkif_completion(struct blk_ |
| |
| 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. |
| * Since bv_offset can be different than 0, and bv_len different |
| @@ -902,7 +910,10 @@ static void blkif_completion(struct blk_ |
| * we add it at the head of the list, so it will be |
| * 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++; |
| } else { |
| /* |
| @@ -913,7 +924,7 @@ static void blkif_completion(struct blk_ |
| */ |
| gnttab_end_foreign_access(s->grants_used[i]->gref, 0, 0UL); |
| 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_d |
| for (i = 0; i < BLK_RING_SIZE; i++) |
| 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)); |
| if (err < 0) { |
| free_page((unsigned long)sring); |
| @@ -1216,7 +1221,7 @@ static int blkfront_probe(struct xenbus_ |
| spin_lock_init(&info->io_lock); |
| info->xbdev = dev; |
| info->vdevice = vdevice; |
| - INIT_LIST_HEAD(&info->persistent_gnts); |
| + INIT_LIST_HEAD(&info->grants); |
| info->persistent_gnts_c = 0; |
| info->connected = BLKIF_STATE_DISCONNECTED; |
| INIT_WORK(&info->work, blkif_restart_queue); |
| @@ -1245,7 +1250,8 @@ static int blkif_recover(struct blkfront |
| int i; |
| struct blkif_request *req; |
| struct blk_shadow *copy; |
| - int j; |
| + unsigned int persistent; |
| + int j, rc; |
| |
| /* Stage 1: Make a safe copy of the shadow state. */ |
| copy = kmemdup(info->shadow, sizeof(info->shadow), |
| @@ -1260,6 +1266,24 @@ static int blkif_recover(struct blkfront |
| info->shadow_free = info->ring.req_prod_pvt; |
| 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. */ |
| for (i = 0; i < BLK_RING_SIZE; i++) { |
| /* Not in use? */ |
| @@ -1324,8 +1348,12 @@ static int blkfront_resume(struct xenbus |
| blkif_free(info, info->connected == BLKIF_STATE_CONNECTED); |
| |
| 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; |
| } |
| @@ -1429,9 +1457,16 @@ static void blkfront_connect(struct blkf |
| sectors); |
| set_capacity(info->gd, sectors); |
| revalidate_disk(info->gd); |
| + return; |
| |
| - /* fall through */ |
| 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; |
| |
| default: |
| @@ -1499,6 +1534,14 @@ static void blkfront_connect(struct blkf |
| else |
| 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); |
| if (err) { |
| xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s", |