From: Roger Pau Monne <roger.pau@citrix.com>
To: xen-devel@lists.xenproject.org, qemu-devel@nongnu.org
Cc: Kevin Wolf <kwolf@redhat.com>,
Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>,
George Dunlap <george.dunlap@eu.citrix.com>,
Stefano Stabellini <stefano.stabellini@eu.citrix.com>,
Stefan Hajnoczi <stefanha@redhat.com>,
Roger Pau Monne <roger.pau@citrix.com>
Subject: [Qemu-devel] [PATCH v2 for-xen-4.5] xen_disk: fix unmapping of persistent grants
Date: Thu, 13 Nov 2014 15:58:23 +0100 [thread overview]
Message-ID: <1415890703-10147-1-git-send-email-roger.pau@citrix.com> (raw)
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.
- Unmap persistent grants before switching to the closed state, so the
frontend can also free them.
Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reported-by: George Dunlap <george.dunlap@eu.citrix.com>
Cc: Stefano Stabellini <stefano.stabellini@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>
---
Xen release exception: this is obviously an important bug-fix that should be
included in 4.5. Without this fix, trying to do a block-detach of a Qdisk
from a running guest can lead to guest crash depending on the blkfront
implementation.
---
Changes since v1:
- Instead of disabling batch mappings when using persistent grants, keep
track of the persistently mapped regions and unmap them on disconnection.
This prevents unmapping single persistent grants, but the current
implementation doesn't require it.
This new version is slightly faster than the previous one, the following
test results are in IOPS from 20 runs of a block-attach, fio run,
block-detach test loop:
x batch
+ no_batch
+----------------------------------------------------------------------+
| + + x x + + + x xx x |
|+ + x x+ *+++ * +x* +++x* x xx x *|
| |_____________A_____M______||
| |________________A_____M___________| |
+----------------------------------------------------------------------+
N Min Max Median Avg Stddev
x 20 52941 63822 62396 61180.15 2673.6497
+ 20 49967 63849 60322 59116.9 3456.3455
Difference at 95.0% confidence
-2063.25 +/- 1977.66
-3.37242% +/- 3.23252%
(Student's t, pooled s = 3089.88)
---
hw/block/xen_disk.c | 77 ++++++++++++++++++++++++++++++++++++++++++++---------
1 file changed, 64 insertions(+), 13 deletions(-)
diff --git a/hw/block/xen_disk.c b/hw/block/xen_disk.c
index 231e9a7..75bdc16 100644
--- a/hw/block/xen_disk.c
+++ b/hw/block/xen_disk.c
@@ -59,6 +59,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;
@@ -118,6 +125,7 @@ struct XenBlkDev {
gboolean feature_discard;
gboolean feature_persistent;
GTree *persistent_gnts;
+ GSList *persistent_regions;
unsigned int persistent_gnt_count;
unsigned int max_grants;
@@ -164,19 +172,41 @@ static gint int_cmp(gconstpointer a, gconstpointer b, gpointer user_data)
static void destroy_grant(gpointer pgnt)
{
PersistentGrant *grant = pgnt;
- XenGnttab gnt = grant->blkdev->xendev.gnttabdev;
- if (xc_gnttab_munmap(gnt, grant->page, 1) != 0) {
- xen_be_printf(&grant->blkdev->xendev, 0,
- "xc_gnttab_munmap failed: %s\n",
- strerror(errno));
- }
grant->blkdev->persistent_gnt_count--;
xen_be_printf(&grant->blkdev->xendev, 3,
- "unmapped grant %p\n", grant->page);
+ "removed grant %p\n", grant->page);
g_free(grant);
}
+static void add_persistent_region(struct XenBlkDev *blkdev, void *addr, int num)
+{
+ PersistentRegion *region;
+
+ region = g_malloc0(sizeof(*region));
+ region->addr = addr;
+ region->num = num;
+ blkdev->persistent_regions = g_slist_append(blkdev->persistent_regions,
+ region);
+}
+
+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;
@@ -421,7 +451,17 @@ static int ioreq_map(struct ioreq *ioreq)
}
}
}
- if (ioreq->blkdev->feature_persistent) {
+ if (ioreq->blkdev->feature_persistent && new_maps &&
+ (!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 && new_maps) {
+ add_persistent_region(ioreq->blkdev, ioreq->pages, new_maps);
+ }
while ((ioreq->blkdev->persistent_gnt_count < ioreq->blkdev->max_grants)
&& new_maps) {
/* Go through the list of newly mapped grants and add as many
@@ -437,6 +477,7 @@ static int ioreq_map(struct ioreq *ioreq)
grant->page = ioreq->pages + (new_maps) * XC_PAGE_SIZE;
} else {
grant->page = ioreq->page[new_maps];
+ add_persistent_region(ioreq->blkdev, ioreq->page[new_maps], 1);
}
grant->blkdev = ioreq->blkdev;
xen_be_printf(&ioreq->blkdev->xendev, 3,
@@ -447,6 +488,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];
@@ -972,6 +1014,7 @@ static int blk_connect(struct XenDevice *xendev)
blkdev->persistent_gnts = g_tree_new_full((GCompareDataFunc)int_cmp,
NULL, NULL,
(GDestroyNotify)destroy_grant);
+ blkdev->persistent_regions = NULL;
blkdev->persistent_gnt_count = 0;
}
@@ -1000,6 +1043,19 @@ 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.
+ */
+ if (blkdev->feature_persistent) {
+ g_tree_destroy(blkdev->persistent_gnts);
+ assert(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)
@@ -1011,11 +1067,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);
--
1.9.3 (Apple Git-50)
next reply other threads:[~2014-11-13 14:58 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-11-13 14:58 Roger Pau Monne [this message]
2014-11-13 15:36 ` [Qemu-devel] [PATCH v2 for-xen-4.5] xen_disk: fix unmapping of persistent grants Stefano Stabellini
2014-11-13 16:19 ` Roger Pau Monné
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1415890703-10147-1-git-send-email-roger.pau@citrix.com \
--to=roger.pau@citrix.com \
--cc=george.dunlap@eu.citrix.com \
--cc=konrad.wilk@oracle.com \
--cc=kwolf@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.com \
--cc=stefano.stabellini@eu.citrix.com \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).