--- /dev/null
+commit b04df88d41f64fc6b56d193b6e90fb840cedb1d3
+Author: Roger Pau Monne <roger.pau@citrix.com>
+Commit: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+
+ xen_disk: fix unmapping of persistent grants
+
+ This patch fixes two issues with persistent grants and the disk PV backend
+ (Qdisk):
+
+ - Keep track of memory regions where persistent grants have been mapped
+ since we need to unmap them as a whole. It is not possible to unmap a
+ single grant if it has been batch-mapped. A new check has also been added
+ to make sure persistent grants are only used if the whole mapped region
+ can be persistently mapped in the batch_maps case.
+ - Unmap persistent grants before switching to the closed state, so the
+ frontend can also free them.
+
+ upstream-commit-id: 2f01dfacb56bc7a0d4639adc9dff9aae131e6216
+
+ Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
+ Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
+ Release-Acked-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+ Reported-by: George Dunlap <george.dunlap@eu.citrix.com>
+ Cc: Kevin Wolf <kwolf@redhat.com>
+ Cc: Stefan Hajnoczi <stefanha@redhat.com>
+ Cc: George Dunlap <george.dunlap@eu.citrix.com>
+ Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
+
+diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
+index 03e30d7..7abecb7 100644
+--- a/hw/block/xen_disk.c
++++ b/hw/block/xen_disk.c
+@@ -58,6 +58,13 @@ struct PersistentGrant {
+
+ typedef struct PersistentGrant PersistentGrant;
+
++struct PersistentRegion {
++ void *addr;
++ int num;
++};
++
++typedef struct PersistentRegion PersistentRegion;
++
+ struct ioreq {
+ blkif_request_t req;
+ int16_t status;
+@@ -116,6 +123,7 @@ struct XenBlkDev {
+ /* Persistent grants extension */
+ gboolean feature_persistent;
+ GTree *persistent_gnts;
++ GSList *persistent_regions;
+ unsigned int persistent_gnt_count;
+ unsigned int max_grants;
+
+@@ -175,6 +183,23 @@ static void destroy_grant(gpointer pgnt)
+ g_free(grant);
+ }
+
++static void remove_persistent_region(gpointer data, gpointer dev)
++{
++ PersistentRegion *region = data;
++ struct XenBlkDev *blkdev = dev;
++ XenGnttab gnt = blkdev->xendev.gnttabdev;
++
++ if (xc_gnttab_munmap(gnt, region->addr, region->num) != 0) {
++ xen_be_printf(&blkdev->xendev, 0,
++ "xc_gnttab_munmap region %p failed: %s\n",
++ region->addr, strerror(errno));
++ }
++ xen_be_printf(&blkdev->xendev, 3,
++ "unmapped grant region %p with %d pages\n",
++ region->addr, region->num);
++ g_free(region);
++}
++
+ static struct ioreq *ioreq_start(struct XenBlkDev *blkdev)
+ {
+ struct ioreq *ioreq = NULL;
+@@ -339,6 +364,7 @@ static int ioreq_map(struct ioreq *ioreq)
+ void *page[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ int i, j, new_maps = 0;
+ PersistentGrant *grant;
++ PersistentRegion *region;
+ /* domids and refs variables will contain the information necessary
+ * to map the grants that are needed to fulfill this request.
+ *
+@@ -417,7 +443,22 @@ static int ioreq_map(struct ioreq *ioreq)
+ }
+ }
+ }
+- if (ioreq->blkdev->feature_persistent) {
++ if (ioreq->blkdev->feature_persistent && new_maps != 0 &&
++ (!batch_maps || (ioreq->blkdev->persistent_gnt_count + new_maps <=
++ ioreq->blkdev->max_grants))) {
++ /*
++ * If we are using persistent grants and batch mappings only
++ * add the new maps to the list of persistent grants if the whole
++ * area can be persistently mapped.
++ */
++ if (batch_maps) {
++ region = g_malloc0(sizeof(*region));
++ region->addr = ioreq->pages;
++ region->num = new_maps;
++ ioreq->blkdev->persistent_regions = g_slist_append(
++ ioreq->blkdev->persistent_regions,
++ region);
++ }
+ while ((ioreq->blkdev->persistent_gnt_count < ioreq->blkdev->max_grants)
+ && new_maps) {
+ /* Go through the list of newly mapped grants and add as many
+@@ -443,6 +484,7 @@ static int ioreq_map(struct ioreq *ioreq)
+ grant);
+ ioreq->blkdev->persistent_gnt_count++;
+ }
++ assert(!batch_maps || new_maps == 0);
+ }
+ for (i = 0; i < ioreq->v.niov; i++) {
+ ioreq->v.iov[i].iov_base += (uintptr_t)page[i];
+@@ -905,7 +947,10 @@ static int blk_connect(struct XenDevice *xendev)
+ blkdev->max_grants = max_requests * BLKIF_MAX_SEGMENTS_PER_REQUEST;
+ blkdev->persistent_gnts = g_tree_new_full((GCompareDataFunc)int_cmp,
+ NULL, NULL,
++ batch_maps ?
++ (GDestroyNotify)g_free :
+ (GDestroyNotify)destroy_grant);
++ blkdev->persistent_regions = NULL;
+ blkdev->persistent_gnt_count = 0;
+ }
+
+@@ -938,6 +983,26 @@ static void blk_disconnect(struct XenDevice *xendev)
+ blkdev->cnt_map--;
+ blkdev->sring = NULL;
+ }
++
++ /*
++ * Unmap persistent grants before switching to the closed state
++ * so the frontend can free them.
++ *
++ * In the !batch_maps case g_tree_destroy will take care of unmapping
++ * the grant, but in the batch_maps case we need to iterate over every
++ * region in persistent_regions and unmap it.
++ */
++ if (blkdev->feature_persistent) {
++ g_tree_destroy(blkdev->persistent_gnts);
++ assert(batch_maps || blkdev->persistent_gnt_count == 0);
++ if (batch_maps) {
++ blkdev->persistent_gnt_count = 0;
++ g_slist_foreach(blkdev->persistent_regions,
++ (GFunc)remove_persistent_region, blkdev);
++ g_slist_free(blkdev->persistent_regions);
++ }
++ blkdev->feature_persistent = false;
++ }
+ }
+
+ static int blk_free(struct XenDevice *xendev)
+@@ -949,11 +1014,6 @@ static int blk_free(struct XenDevice *xendev)
+ blk_disconnect(xendev);
+ }
+
+- /* Free persistent grants */
+- if (blkdev->feature_persistent) {
+- g_tree_destroy(blkdev->persistent_gnts);
+- }
+-
+ while (!QLIST_EMPTY(&blkdev->freelist)) {
+ ioreq = QLIST_FIRST(&blkdev->freelist);
+ QLIST_REMOVE(ioreq, list);