From patchwork Thu Apr 13 09:35:08 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Wang, Wei W" X-Patchwork-Id: 9679059 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 63E5A60326 for ; Thu, 13 Apr 2017 09:48:12 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 6028D27F90 for ; Thu, 13 Apr 2017 09:48:12 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 549F02865A; Thu, 13 Apr 2017 09:48:12 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 8399D27F90 for ; Thu, 13 Apr 2017 09:48:11 +0000 (UTC) Received: from localhost ([::1]:48315 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cybMI-0005uB-PR for patchwork-qemu-devel@patchwork.kernel.org; Thu, 13 Apr 2017 05:48:10 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:40294) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cybF2-0000Sx-Ot for qemu-devel@nongnu.org; Thu, 13 Apr 2017 05:40:42 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cybEz-0000Du-O0 for qemu-devel@nongnu.org; Thu, 13 Apr 2017 05:40:40 -0400 Received: from mga02.intel.com ([134.134.136.20]:22809) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1cybEz-0000DT-Ay for qemu-devel@nongnu.org; Thu, 13 Apr 2017 05:40:37 -0400 Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga101.jf.intel.com with ESMTP/TLS/DHE-RSA-AES256-GCM-SHA384; 13 Apr 2017 02:40:17 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.37,194,1488873600"; d="scan'208";a="76894519" Received: from devel-ww.sh.intel.com ([10.239.48.105]) by orsmga004.jf.intel.com with ESMTP; 13 Apr 2017 02:40:14 -0700 From: Wei Wang To: virtio-dev@lists.oasis-open.org, linux-kernel@vger.kernel.org, qemu-devel@nongnu.org, virtualization@lists.linux-foundation.org, kvm@vger.kernel.org, linux-mm@kvack.org, mst@redhat.com, david@redhat.com, dave.hansen@intel.com, cornelia.huck@de.ibm.com, akpm@linux-foundation.org, mgorman@techsingularity.net, aarcange@redhat.com, amit.shah@redhat.com, pbonzini@redhat.com, wei.w.wang@intel.com, liliang.opensource@gmail.com Date: Thu, 13 Apr 2017 17:35:08 +0800 Message-Id: <1492076108-117229-6-git-send-email-wei.w.wang@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1492076108-117229-1-git-send-email-wei.w.wang@intel.com> References: <1492076108-117229-1-git-send-email-wei.w.wang@intel.com> X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 134.134.136.20 Subject: [Qemu-devel] [PATCH v9 5/5] virtio-balloon: VIRTIO_BALLOON_F_MISC_VQ X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP Add a new vq, miscq, to handle miscellaneous requests between the device and the driver. This patch implemnts the VIRTIO_BALLOON_MISCQ_INQUIRE_UNUSED_PAGES request sent from the device. Upon receiving this request from the miscq, the driver offers to the device the guest unused pages. Tests have shown that skipping the transfer of unused pages of a 32G guest can get the live migration time reduced to 1/8. Signed-off-by: Wei Wang Signed-off-by: Liang Li --- drivers/virtio/virtio_balloon.c | 209 +++++++++++++++++++++++++++++++++--- include/uapi/linux/virtio_balloon.h | 8 ++ 2 files changed, 204 insertions(+), 13 deletions(-) diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c index 5e2e7cc..95c703e 100644 --- a/drivers/virtio/virtio_balloon.c +++ b/drivers/virtio/virtio_balloon.c @@ -56,11 +56,12 @@ static struct vfsmount *balloon_mnt; /* Types of pages to chunk */ #define PAGE_CHUNK_TYPE_BALLOON 0 +#define PAGE_CHUNK_TYPE_UNUSED 1 #define MAX_PAGE_CHUNKS 4096 struct virtio_balloon { struct virtio_device *vdev; - struct virtqueue *inflate_vq, *deflate_vq, *stats_vq; + struct virtqueue *inflate_vq, *deflate_vq, *stats_vq, *miscq; /* The balloon servicing is delegated to a freezable workqueue. */ struct work_struct update_balloon_stats_work; @@ -94,6 +95,19 @@ struct virtio_balloon { struct virtio_balloon_page_chunk_hdr *balloon_page_chunk_hdr; struct virtio_balloon_page_chunk *balloon_page_chunk; + /* + * Buffer for PAGE_CHUNK_TYPE_UNUSED: + * virtio_balloon_miscq_hdr + + * virtio_balloon_page_chunk_hdr + + * virtio_balloon_page_chunk * MAX_PAGE_CHUNKS + */ + struct virtio_balloon_miscq_hdr *miscq_out_hdr; + struct virtio_balloon_page_chunk_hdr *unused_page_chunk_hdr; + struct virtio_balloon_page_chunk *unused_page_chunk; + + /* Buffer for host to send cmd to miscq */ + struct virtio_balloon_miscq_hdr *miscq_in_hdr; + /* Bitmap used to record pages */ unsigned long *page_bmap[PAGE_BMAP_COUNT_MAX]; /* Number of the allocated page_bmap */ @@ -220,6 +234,10 @@ static void send_page_chunks(struct virtio_balloon *vb, struct virtqueue *vq, hdr = vb->balloon_page_chunk_hdr; len = 0; break; + case PAGE_CHUNK_TYPE_UNUSED: + hdr = vb->unused_page_chunk_hdr; + len = sizeof(struct virtio_balloon_miscq_hdr); + break; default: dev_warn(&vb->vdev->dev, "%s: chunk %d of unknown pages\n", __func__, type); @@ -254,6 +272,10 @@ static void add_one_chunk(struct virtio_balloon *vb, struct virtqueue *vq, hdr = vb->balloon_page_chunk_hdr; chunk = vb->balloon_page_chunk; break; + case PAGE_CHUNK_TYPE_UNUSED: + hdr = vb->unused_page_chunk_hdr; + chunk = vb->unused_page_chunk; + break; default: dev_warn(&vb->vdev->dev, "%s: chunk %d of unknown pages\n", __func__, type); @@ -686,28 +708,139 @@ static void update_balloon_size_func(struct work_struct *work) queue_work(system_freezable_wq, work); } +static void miscq_in_hdr_add(struct virtio_balloon *vb) +{ + struct scatterlist sg_in; + + sg_init_one(&sg_in, vb->miscq_in_hdr, + sizeof(struct virtio_balloon_miscq_hdr)); + if (virtqueue_add_inbuf(vb->miscq, &sg_in, 1, vb->miscq_in_hdr, + GFP_KERNEL) < 0) { + __virtio_clear_bit(vb->vdev, + VIRTIO_BALLOON_F_MISC_VQ); + dev_warn(&vb->vdev->dev, "%s: add miscq_in_hdr err\n", + __func__); + return; + } + virtqueue_kick(vb->miscq); +} + +static void miscq_send_unused_pages(struct virtio_balloon *vb) +{ + struct virtio_balloon_miscq_hdr *miscq_out_hdr = vb->miscq_out_hdr; + struct virtqueue *vq = vb->miscq; + int ret = 0; + unsigned int order = 0, migratetype = 0; + struct zone *zone = NULL; + struct page *page = NULL; + u64 pfn; + + miscq_out_hdr->cmd = VIRTIO_BALLOON_MISCQ_INQUIRE_UNUSED_PAGES; + miscq_out_hdr->flags = 0; + + for_each_populated_zone(zone) { + for (order = MAX_ORDER - 1; order > 0; order--) { + for (migratetype = 0; migratetype < MIGRATE_TYPES; + migratetype++) { + do { + ret = inquire_unused_page_block(zone, + order, migratetype, &page); + if (!ret) { + pfn = (u64)page_to_pfn(page); + add_one_chunk(vb, vq, + PAGE_CHUNK_TYPE_UNUSED, + pfn, + (u64)(1 << order)); + } + } while (!ret); + } + } + } + miscq_out_hdr->flags |= VIRTIO_BALLOON_MISCQ_F_COMPLETE; + send_page_chunks(vb, vq, PAGE_CHUNK_TYPE_UNUSED, true); +} + +static void miscq_handle(struct virtqueue *vq) +{ + struct virtio_balloon *vb = vq->vdev->priv; + struct virtio_balloon_miscq_hdr *hdr; + unsigned int len; + + hdr = virtqueue_get_buf(vb->miscq, &len); + if (!hdr || len != sizeof(struct virtio_balloon_miscq_hdr)) { + dev_warn(&vb->vdev->dev, "%s: invalid miscq hdr len\n", + __func__); + miscq_in_hdr_add(vb); + return; + } + switch (hdr->cmd) { + case VIRTIO_BALLOON_MISCQ_INQUIRE_UNUSED_PAGES: + miscq_send_unused_pages(vb); + break; + default: + dev_warn(&vb->vdev->dev, "%s: miscq cmd %d not supported\n", + __func__, hdr->cmd); + } + miscq_in_hdr_add(vb); +} + static int init_vqs(struct virtio_balloon *vb) { - struct virtqueue *vqs[3]; - vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request }; - static const char * const names[] = { "inflate", "deflate", "stats" }; - int err, nvqs; + struct virtqueue **vqs; + vq_callback_t **callbacks; + const char **names; + int err = -ENOMEM; + int i, nvqs; + + /* Inflateq and deflateq are used unconditionally */ + nvqs = 2; + + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) + nvqs++; + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_MISC_VQ)) + nvqs++; + + /* Allocate space for find_vqs parameters */ + vqs = kcalloc(nvqs, sizeof(*vqs), GFP_KERNEL); + if (!vqs) + goto err_vq; + callbacks = kmalloc_array(nvqs, sizeof(*callbacks), GFP_KERNEL); + if (!callbacks) + goto err_callback; + names = kmalloc_array(nvqs, sizeof(*names), GFP_KERNEL); + if (!names) + goto err_names; + + callbacks[0] = balloon_ack; + names[0] = "inflate"; + callbacks[1] = balloon_ack; + names[1] = "deflate"; + + i = 2; + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) { + callbacks[i] = stats_request; + names[i] = "stats"; + i++; + } - /* - * We expect two virtqueues: inflate and deflate, and - * optionally stat. - */ - nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2; - err = vb->vdev->config->find_vqs(vb->vdev, nvqs, vqs, callbacks, names); + if (virtio_has_feature(vb->vdev, + VIRTIO_BALLOON_F_MISC_VQ)) { + callbacks[i] = miscq_handle; + names[i] = "miscq"; + } + + err = vb->vdev->config->find_vqs(vb->vdev, nvqs, vqs, callbacks, + names); if (err) - return err; + goto err_find; vb->inflate_vq = vqs[0]; vb->deflate_vq = vqs[1]; + i = 2; if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) { struct scatterlist sg; - vb->stats_vq = vqs[2]; + vb->stats_vq = vqs[i++]; /* * Prime this virtqueue with one buffer so the hypervisor can * use it to signal us later (it can't be broken yet!). @@ -718,7 +851,25 @@ static int init_vqs(struct virtio_balloon *vb) BUG(); virtqueue_kick(vb->stats_vq); } + + if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_MISC_VQ)) { + vb->miscq = vqs[i]; + miscq_in_hdr_add(vb); + } + + kfree(names); + kfree(callbacks); + kfree(vqs); return 0; + +err_find: + kfree(names); +err_names: + kfree(callbacks); +err_callback: + kfree(vqs); +err_vq: + return err; } #ifdef CONFIG_BALLOON_COMPACTION @@ -843,6 +994,32 @@ static void balloon_page_chunk_init(struct virtio_balloon *vb) } } +static void miscq_init(struct virtio_balloon *vb) +{ + void *buf; + + vb->miscq_in_hdr = kmalloc(sizeof(struct virtio_balloon_miscq_hdr), + GFP_KERNEL); + buf = kmalloc(sizeof(struct virtio_balloon_miscq_hdr) + + sizeof(struct virtio_balloon_page_chunk_hdr) + + sizeof(struct virtio_balloon_page_chunk) * + MAX_PAGE_CHUNKS, GFP_KERNEL); + if (!vb->miscq_in_hdr || !buf) { + kfree(buf); + kfree(vb->miscq_in_hdr); + __virtio_clear_bit(vb->vdev, VIRTIO_BALLOON_F_MISC_VQ); + dev_warn(&vb->vdev->dev, "%s: failed\n", __func__); + } else { + vb->miscq_out_hdr = buf; + vb->unused_page_chunk_hdr = buf + + sizeof(struct virtio_balloon_miscq_hdr); + vb->unused_page_chunk_hdr->chunks = 0; + vb->unused_page_chunk = buf + + sizeof(struct virtio_balloon_miscq_hdr) + + sizeof(struct virtio_balloon_page_chunk_hdr); + } +} + static int virtballoon_probe(struct virtio_device *vdev) { struct virtio_balloon *vb; @@ -869,6 +1046,9 @@ static int virtballoon_probe(struct virtio_device *vdev) if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_BALLOON_CHUNKS)) balloon_page_chunk_init(vb); + if (virtio_has_feature(vdev, VIRTIO_BALLOON_F_MISC_VQ)) + miscq_init(vb); + mutex_init(&vb->balloon_lock); init_waitqueue_head(&vb->acked); vb->vdev = vdev; @@ -946,6 +1126,8 @@ static void virtballoon_remove(struct virtio_device *vdev) remove_common(vb); free_page_bmap(vb); + kfree(vb->miscq_out_hdr); + kfree(vb->miscq_in_hdr); if (vb->vb_dev_info.inode) iput(vb->vb_dev_info.inode); kfree(vb); @@ -987,6 +1169,7 @@ static unsigned int features[] = { VIRTIO_BALLOON_F_STATS_VQ, VIRTIO_BALLOON_F_DEFLATE_ON_OOM, VIRTIO_BALLOON_F_BALLOON_CHUNKS, + VIRTIO_BALLOON_F_MISC_VQ, }; static struct virtio_driver virtio_balloon_driver = { diff --git a/include/uapi/linux/virtio_balloon.h b/include/uapi/linux/virtio_balloon.h index be317b7..96bdc86 100644 --- a/include/uapi/linux/virtio_balloon.h +++ b/include/uapi/linux/virtio_balloon.h @@ -35,6 +35,7 @@ #define VIRTIO_BALLOON_F_STATS_VQ 1 /* Memory Stats virtqueue */ #define VIRTIO_BALLOON_F_DEFLATE_ON_OOM 2 /* Deflate balloon on OOM */ #define VIRTIO_BALLOON_F_BALLOON_CHUNKS 3 /* Inflate/Deflate pages in chunks */ +#define VIRTIO_BALLOON_F_MISC_VQ 4 /* Virtqueue for misc. requests */ /* Size of a PFN in the balloon interface. */ #define VIRTIO_BALLOON_PFN_SHIFT 12 @@ -95,4 +96,11 @@ struct virtio_balloon_page_chunk { __le64 size; }; +#define VIRTIO_BALLOON_MISCQ_INQUIRE_UNUSED_PAGES 0 +#define VIRTIO_BALLOON_MISCQ_F_COMPLETE 0x1 +struct virtio_balloon_miscq_hdr { + __le16 cmd; + __le16 flags; +}; + #endif /* _LINUX_VIRTIO_BALLOON_H */