From nobody Wed Nov 5 14:58:27 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1535722693723179.59801304934763; Fri, 31 Aug 2018 06:38:13 -0700 (PDT) Received: from localhost ([::1]:53731 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fvjcm-0007Oh-PG for importer@patchew.org; Fri, 31 Aug 2018 09:38:08 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56935) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fvjad-0005g5-2h for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:35:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fvjVf-0005wS-O4 for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:30:48 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:48468 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fvjVf-0005wK-JU for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:30:47 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 399C580823E3; Fri, 31 Aug 2018 13:30:47 +0000 (UTC) Received: from dhcp201-121.englab.pnq.redhat.com (dhcp193-198.pnq.redhat.com [10.65.193.198]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7F6D7F3D01; Fri, 31 Aug 2018 13:30:38 +0000 (UTC) From: Pankaj Gupta To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, qemu-devel@nongnu.org, linux-nvdimm@ml01.01.org Date: Fri, 31 Aug 2018 19:00:16 +0530 Message-Id: <20180831133019.27579-2-pagupta@redhat.com> In-Reply-To: <20180831133019.27579-1-pagupta@redhat.com> References: <20180831133019.27579-1-pagupta@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 31 Aug 2018 13:30:47 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Fri, 31 Aug 2018 13:30:47 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'pagupta@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH 1/3] nd: move nd_region to common header 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: , Cc: kwolf@redhat.com, pagupta@redhat.com, jack@suse.cz, xiaoguangrong.eric@gmail.com, riel@surriel.com, niteshnarayanlal@hotmail.com, david@redhat.com, ross.zwisler@intel.com, lcapitulino@redhat.com, hch@infradead.org, mst@redhat.com, stefanha@redhat.com, imammedo@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, nilal@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RDMRC_1 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch moves nd_region definition to common header include/linux/nd.h file. This is required for flush callback=20 support for both virtio-pmem & pmem driver. Signed-off-by: Pankaj Gupta --- drivers/nvdimm/nd.h | 39 --------------------------------------- include/linux/nd.h | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/drivers/nvdimm/nd.h b/drivers/nvdimm/nd.h index 98317e7..d079a2b 100644 --- a/drivers/nvdimm/nd.h +++ b/drivers/nvdimm/nd.h @@ -123,45 +123,6 @@ enum nd_mapping_lock_class { ND_MAPPING_UUID_SCAN, }; =20 -struct nd_mapping { - struct nvdimm *nvdimm; - u64 start; - u64 size; - int position; - struct list_head labels; - struct mutex lock; - /* - * @ndd is for private use at region enable / disable time for - * get_ndd() + put_ndd(), all other nd_mapping to ndd - * conversions use to_ndd() which respects enabled state of the - * nvdimm. - */ - struct nvdimm_drvdata *ndd; -}; - -struct nd_region { - struct device dev; - struct ida ns_ida; - struct ida btt_ida; - struct ida pfn_ida; - struct ida dax_ida; - unsigned long flags; - struct device *ns_seed; - struct device *btt_seed; - struct device *pfn_seed; - struct device *dax_seed; - u16 ndr_mappings; - u64 ndr_size; - u64 ndr_start; - int id, num_lanes, ro, numa_node; - void *provider_data; - struct kernfs_node *bb_state; - struct badblocks bb; - struct nd_interleave_set *nd_set; - struct nd_percpu_lane __percpu *lane; - struct nd_mapping mapping[0]; -}; - struct nd_blk_region { int (*enable)(struct nvdimm_bus *nvdimm_bus, struct device *dev); int (*do_io)(struct nd_blk_region *ndbr, resource_size_t dpa, diff --git a/include/linux/nd.h b/include/linux/nd.h index 43c181a..b9da9f7 100644 --- a/include/linux/nd.h +++ b/include/linux/nd.h @@ -120,6 +120,46 @@ struct nd_namespace_blk { struct resource **res; }; =20 +struct nd_mapping { + struct nvdimm *nvdimm; + u64 start; + u64 size; + int position; + struct list_head labels; + struct mutex lock; + /* + * @ndd is for private use at region enable / disable time for + * get_ndd() + put_ndd(), all other nd_mapping to ndd + * conversions use to_ndd() which respects enabled state of the + * nvdimm. + */ + struct nvdimm_drvdata *ndd; +}; + +struct nd_region { + struct device dev; + struct ida ns_ida; + struct ida btt_ida; + struct ida pfn_ida; + struct ida dax_ida; + unsigned long flags; + struct device *ns_seed; + struct device *btt_seed; + struct device *pfn_seed; + struct device *dax_seed; + u16 ndr_mappings; + u64 ndr_size; + u64 ndr_start; + int id, num_lanes, ro, numa_node; + void *provider_data; + struct kernfs_node *bb_state; + struct badblocks bb; + struct nd_interleave_set *nd_set; + struct nd_percpu_lane __percpu *lane; + int (*flush)(struct nd_region *nd_region); + struct nd_mapping mapping[0]; +}; + static inline struct nd_namespace_io *to_nd_namespace_io(const struct devi= ce *dev) { return container_of(dev, struct nd_namespace_io, common.dev); --=20 2.9.3 From nobody Wed Nov 5 14:58:27 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1535723024023719.4880916421572; Fri, 31 Aug 2018 06:43:44 -0700 (PDT) Received: from localhost ([::1]:53764 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fvjiB-0005BP-0s for importer@patchew.org; Fri, 31 Aug 2018 09:43:43 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56935) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fvjaa-0005g5-Pk for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:35:54 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fvjVs-00069Q-U7 for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:31:05 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34398 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fvjVs-00069H-P1 for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:31:00 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5D8DC40216E7; Fri, 31 Aug 2018 13:31:00 +0000 (UTC) Received: from dhcp201-121.englab.pnq.redhat.com (dhcp193-198.pnq.redhat.com [10.65.193.198]) by smtp.corp.redhat.com (Postfix) with ESMTP id A7002F3D01; Fri, 31 Aug 2018 13:30:47 +0000 (UTC) From: Pankaj Gupta To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, qemu-devel@nongnu.org, linux-nvdimm@ml01.01.org Date: Fri, 31 Aug 2018 19:00:17 +0530 Message-Id: <20180831133019.27579-3-pagupta@redhat.com> In-Reply-To: <20180831133019.27579-1-pagupta@redhat.com> References: <20180831133019.27579-1-pagupta@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Fri, 31 Aug 2018 13:31:00 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Fri, 31 Aug 2018 13:31:00 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'pagupta@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH 2/3] libnvdimm: nd_region flush callback support 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: , Cc: kwolf@redhat.com, pagupta@redhat.com, jack@suse.cz, xiaoguangrong.eric@gmail.com, riel@surriel.com, niteshnarayanlal@hotmail.com, david@redhat.com, ross.zwisler@intel.com, lcapitulino@redhat.com, hch@infradead.org, mst@redhat.com, stefanha@redhat.com, imammedo@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, nilal@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RDMRC_1 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch adds functionality to perform flush from guest to host over VIRTIO. We are registering a callback based on 'nd_region' type. virtio_pmem driver requires this special=20 flush function. For rest of the region types we are registering=20 existing flush function. Report error returned by host fsync=20 failure to userspace. Signed-off-by: Pankaj Gupta --- drivers/acpi/nfit/core.c | 7 +++++-- drivers/nvdimm/claim.c | 3 ++- drivers/nvdimm/pmem.c | 12 ++++++++---- drivers/nvdimm/region_devs.c | 12 ++++++++++-- include/linux/libnvdimm.h | 4 +++- 5 files changed, 28 insertions(+), 10 deletions(-) diff --git a/drivers/acpi/nfit/core.c b/drivers/acpi/nfit/core.c index b072cfc..cd63b69 100644 --- a/drivers/acpi/nfit/core.c +++ b/drivers/acpi/nfit/core.c @@ -2216,6 +2216,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, = unsigned int bw, { u64 cmd, offset; struct nfit_blk_mmio *mmio =3D &nfit_blk->mmio[DCR]; + struct nd_region *nd_region =3D nfit_blk->nd_region; =20 enum { BCW_OFFSET_MASK =3D (1ULL << 48)-1, @@ -2234,7 +2235,7 @@ static void write_blk_ctl(struct nfit_blk *nfit_blk, = unsigned int bw, offset =3D to_interleave_offset(offset, mmio); =20 writeq(cmd, mmio->addr.base + offset); - nvdimm_flush(nfit_blk->nd_region); + nd_region->flush(nd_region); =20 if (nfit_blk->dimm_flags & NFIT_BLK_DCR_LATCH) readq(mmio->addr.base + offset); @@ -2245,6 +2246,7 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *n= fit_blk, unsigned int lane) { struct nfit_blk_mmio *mmio =3D &nfit_blk->mmio[BDW]; + struct nd_region *nd_region =3D nfit_blk->nd_region; unsigned int copied =3D 0; u64 base_offset; int rc; @@ -2283,7 +2285,8 @@ static int acpi_nfit_blk_single_io(struct nfit_blk *n= fit_blk, } =20 if (rw) - nvdimm_flush(nfit_blk->nd_region); + nd_region->flush(nd_region); + =20 rc =3D read_blk_stat(nfit_blk, lane) ? -EIO : 0; return rc; diff --git a/drivers/nvdimm/claim.c b/drivers/nvdimm/claim.c index fb667bf..49dce9c 100644 --- a/drivers/nvdimm/claim.c +++ b/drivers/nvdimm/claim.c @@ -262,6 +262,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *nd= ns, { struct nd_namespace_io *nsio =3D to_nd_namespace_io(&ndns->dev); unsigned int sz_align =3D ALIGN(size + (offset & (512 - 1)), 512); + struct nd_region *nd_region =3D to_nd_region(ndns->dev.parent); sector_t sector =3D offset >> 9; int rc =3D 0; =20 @@ -301,7 +302,7 @@ static int nsio_rw_bytes(struct nd_namespace_common *nd= ns, } =20 memcpy_flushcache(nsio->addr + offset, buf, size); - nvdimm_flush(to_nd_region(ndns->dev.parent)); + nd_region->flush(nd_region); =20 return rc; } diff --git a/drivers/nvdimm/pmem.c b/drivers/nvdimm/pmem.c index 6071e29..ba57cfa 100644 --- a/drivers/nvdimm/pmem.c +++ b/drivers/nvdimm/pmem.c @@ -201,7 +201,8 @@ static blk_qc_t pmem_make_request(struct request_queue = *q, struct bio *bio) struct nd_region *nd_region =3D to_region(pmem); =20 if (bio->bi_opf & REQ_PREFLUSH) - nvdimm_flush(nd_region); + bio->bi_status =3D nd_region->flush(nd_region); + =20 do_acct =3D nd_iostat_start(bio, &start); bio_for_each_segment(bvec, bio, iter) { @@ -216,7 +217,7 @@ static blk_qc_t pmem_make_request(struct request_queue = *q, struct bio *bio) nd_iostat_end(bio, start); =20 if (bio->bi_opf & REQ_FUA) - nvdimm_flush(nd_region); + bio->bi_status =3D nd_region->flush(nd_region); =20 bio_endio(bio); return BLK_QC_T_NONE; @@ -517,6 +518,7 @@ static int nd_pmem_probe(struct device *dev) static int nd_pmem_remove(struct device *dev) { struct pmem_device *pmem =3D dev_get_drvdata(dev); + struct nd_region *nd_region =3D to_region(pmem); =20 if (is_nd_btt(dev)) nvdimm_namespace_detach_btt(to_nd_btt(dev)); @@ -528,14 +530,16 @@ static int nd_pmem_remove(struct device *dev) sysfs_put(pmem->bb_state); pmem->bb_state =3D NULL; } - nvdimm_flush(to_nd_region(dev->parent)); + nd_region->flush(nd_region); =20 return 0; } =20 static void nd_pmem_shutdown(struct device *dev) { - nvdimm_flush(to_nd_region(dev->parent)); + struct nd_region *nd_region =3D to_nd_region(dev->parent); + + nd_region->flush(nd_region); } =20 static void nd_pmem_notify(struct device *dev, enum nvdimm_event event) diff --git a/drivers/nvdimm/region_devs.c b/drivers/nvdimm/region_devs.c index fa37afc..a170a6b 100644 --- a/drivers/nvdimm/region_devs.c +++ b/drivers/nvdimm/region_devs.c @@ -290,7 +290,7 @@ static ssize_t deep_flush_store(struct device *dev, str= uct device_attribute *att return rc; if (!flush) return -EINVAL; - nvdimm_flush(nd_region); + nd_region->flush(nd_region); =20 return len; } @@ -1065,6 +1065,11 @@ static struct nd_region *nd_region_create(struct nvd= imm_bus *nvdimm_bus, dev->of_node =3D ndr_desc->of_node; nd_region->ndr_size =3D resource_size(ndr_desc->res); nd_region->ndr_start =3D ndr_desc->res->start; + if (ndr_desc->flush) + nd_region->flush =3D ndr_desc->flush; + else + nd_region->flush =3D nvdimm_flush; + nd_device_register(dev); =20 return nd_region; @@ -1109,7 +1114,7 @@ EXPORT_SYMBOL_GPL(nvdimm_volatile_region_create); * nvdimm_flush - flush any posted write queues between the cpu and pmem m= edia * @nd_region: blk or interleaved pmem region */ -void nvdimm_flush(struct nd_region *nd_region) +int nvdimm_flush(struct nd_region *nd_region) { struct nd_region_data *ndrd =3D dev_get_drvdata(&nd_region->dev); int i, idx; @@ -1133,7 +1138,10 @@ void nvdimm_flush(struct nd_region *nd_region) if (ndrd_get_flush_wpq(ndrd, i, 0)) writeq(1, ndrd_get_flush_wpq(ndrd, i, idx)); wmb(); + + return 0; } + EXPORT_SYMBOL_GPL(nvdimm_flush); =20 /** diff --git a/include/linux/libnvdimm.h b/include/linux/libnvdimm.h index 097072c..3af7177 100644 --- a/include/linux/libnvdimm.h +++ b/include/linux/libnvdimm.h @@ -115,6 +115,7 @@ struct nd_mapping_desc { int position; }; =20 +struct nd_region; struct nd_region_desc { struct resource *res; struct nd_mapping_desc *mapping; @@ -126,6 +127,7 @@ struct nd_region_desc { int numa_node; unsigned long flags; struct device_node *of_node; + int (*flush)(struct nd_region *nd_region); }; =20 struct device; @@ -201,7 +203,7 @@ unsigned long nd_blk_memremap_flags(struct nd_blk_regio= n *ndbr); unsigned int nd_region_acquire_lane(struct nd_region *nd_region); void nd_region_release_lane(struct nd_region *nd_region, unsigned int lane= ); u64 nd_fletcher64(void *addr, size_t len, bool le); -void nvdimm_flush(struct nd_region *nd_region); +int nvdimm_flush(struct nd_region *nd_region); int nvdimm_has_flush(struct nd_region *nd_region); int nvdimm_has_cache(struct nd_region *nd_region); =20 --=20 2.9.3 From nobody Wed Nov 5 14:58:27 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1535722787261253.72739117336107; Fri, 31 Aug 2018 06:39:47 -0700 (PDT) Received: from localhost ([::1]:53739 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fvjeM-0001Az-4B for importer@patchew.org; Fri, 31 Aug 2018 09:39:46 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56919) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fvjaX-0005fz-SI for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:35:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fvjVz-0006BG-7q for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:31:08 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:46016 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fvjVz-0006B8-2Y for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:31:07 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id A1BED40201BD; Fri, 31 Aug 2018 13:31:06 +0000 (UTC) Received: from dhcp201-121.englab.pnq.redhat.com (dhcp193-198.pnq.redhat.com [10.65.193.198]) by smtp.corp.redhat.com (Postfix) with ESMTP id CA9D2F3D01; Fri, 31 Aug 2018 13:31:00 +0000 (UTC) From: Pankaj Gupta To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, qemu-devel@nongnu.org, linux-nvdimm@ml01.01.org Date: Fri, 31 Aug 2018 19:00:18 +0530 Message-Id: <20180831133019.27579-4-pagupta@redhat.com> In-Reply-To: <20180831133019.27579-1-pagupta@redhat.com> References: <20180831133019.27579-1-pagupta@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Fri, 31 Aug 2018 13:31:06 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Fri, 31 Aug 2018 13:31:06 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'pagupta@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH 3/3] virtio-pmem: Add virtio pmem driver 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: , Cc: kwolf@redhat.com, pagupta@redhat.com, jack@suse.cz, xiaoguangrong.eric@gmail.com, riel@surriel.com, niteshnarayanlal@hotmail.com, david@redhat.com, ross.zwisler@intel.com, lcapitulino@redhat.com, hch@infradead.org, mst@redhat.com, stefanha@redhat.com, imammedo@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, nilal@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RDMRC_1 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch adds virtio-pmem driver for KVM guest. Guest reads the persistent memory range information from Qemu over VIRTIO and registers it on nvdimm_bus. It also creates a nd_region object with the persistent memory range information so that existing 'nvdimm/pmem' driver can reserve this into system memory map. This way 'virtio-pmem' driver uses existing functionality of pmem driver to register persistent memory compatible for DAX capable filesystems. This also provides function to perform guest flush over VIRTIO from 'pmem' driver when userspace performs flush on DAX memory range. Signed-off-by: Pankaj Gupta --- drivers/virtio/Kconfig | 9 ++ drivers/virtio/Makefile | 1 + drivers/virtio/virtio_pmem.c | 255 +++++++++++++++++++++++++++++++++++= ++++ include/uapi/linux/virtio_ids.h | 1 + include/uapi/linux/virtio_pmem.h | 40 ++++++ 5 files changed, 306 insertions(+) create mode 100644 drivers/virtio/virtio_pmem.c create mode 100644 include/uapi/linux/virtio_pmem.h diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig index 3589764..a331e23 100644 --- a/drivers/virtio/Kconfig +++ b/drivers/virtio/Kconfig @@ -42,6 +42,15 @@ config VIRTIO_PCI_LEGACY =20 If unsure, say Y. =20 +config VIRTIO_PMEM + tristate "Support for virtio pmem driver" + depends on VIRTIO + help + This driver provides support for virtio based flushing interface + for persistent memory range. + + If unsure, say M. + config VIRTIO_BALLOON tristate "Virtio balloon driver" depends on VIRTIO diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile index 3a2b5c5..cbe91c6 100644 --- a/drivers/virtio/Makefile +++ b/drivers/virtio/Makefile @@ -6,3 +6,4 @@ virtio_pci-y :=3D virtio_pci_modern.o virtio_pci_common.o virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) +=3D virtio_pci_legacy.o obj-$(CONFIG_VIRTIO_BALLOON) +=3D virtio_balloon.o obj-$(CONFIG_VIRTIO_INPUT) +=3D virtio_input.o +obj-$(CONFIG_VIRTIO_PMEM) +=3D virtio_pmem.o diff --git a/drivers/virtio/virtio_pmem.c b/drivers/virtio/virtio_pmem.c new file mode 100644 index 0000000..c22cc87 --- /dev/null +++ b/drivers/virtio/virtio_pmem.c @@ -0,0 +1,255 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * virtio_pmem.c: Virtio pmem Driver + * + * Discovers persistent memory range information + * from host and provides a virtio based flushing + * interface. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +struct virtio_pmem_request { + /* Host return status corresponding to flush request */ + int ret; + + /* command name*/ + char name[16]; + + /* Wait queue to process deferred work after ack from host */ + wait_queue_head_t host_acked; + bool done; + + /* Wait queue to process deferred work after virt queue buffer avail */ + wait_queue_head_t wq_buf; + bool wq_buf_avail; + struct list_head list; +}; + +struct virtio_pmem { + struct virtio_device *vdev; + + /* Virtio pmem request queue */ + struct virtqueue *req_vq; + + /* nvdimm bus registers virtio pmem device */ + struct nvdimm_bus *nvdimm_bus; + struct nvdimm_bus_descriptor nd_desc; + + /* List to store deferred work if virtqueue is full */ + struct list_head req_list; + + /* Synchronize virtqueue data */ + spinlock_t pmem_lock; + + /* Memory region information */ + uint64_t start; + uint64_t size; +}; + +static struct virtio_device_id id_table[] =3D { + { VIRTIO_ID_PMEM, VIRTIO_DEV_ANY_ID }, + { 0 }, +}; + + /* The interrupt handler */ +static void host_ack(struct virtqueue *vq) +{ + unsigned int len; + unsigned long flags; + struct virtio_pmem_request *req, *req_buf; + struct virtio_pmem *vpmem =3D vq->vdev->priv; + + spin_lock_irqsave(&vpmem->pmem_lock, flags); + while ((req =3D virtqueue_get_buf(vq, &len)) !=3D NULL) { + req->done =3D true; + wake_up(&req->host_acked); + + if (!list_empty(&vpmem->req_list)) { + req_buf =3D list_first_entry(&vpmem->req_list, + struct virtio_pmem_request, list); + list_del(&vpmem->req_list); + req_buf->wq_buf_avail =3D true; + wake_up(&req_buf->wq_buf); + } + } + spin_unlock_irqrestore(&vpmem->pmem_lock, flags); +} + /* Initialize virt queue */ +static int init_vq(struct virtio_pmem *vpmem) +{ + struct virtqueue *vq; + + /* single vq */ + vpmem->req_vq =3D vq =3D virtio_find_single_vq(vpmem->vdev, + host_ack, "flush_queue"); + if (IS_ERR(vq)) + return PTR_ERR(vq); + + spin_lock_init(&vpmem->pmem_lock); + INIT_LIST_HEAD(&vpmem->req_list); + + return 0; +}; + + /* The request submission function */ +static int virtio_pmem_flush(struct nd_region *nd_region) +{ + int err; + unsigned long flags; + struct scatterlist *sgs[2], sg, ret; + struct virtio_device *vdev =3D + dev_to_virtio(nd_region->dev.parent->parent); + struct virtio_pmem *vpmem =3D vdev->priv; + struct virtio_pmem_request *req =3D kmalloc(sizeof(*req), GFP_KERNEL); + + if (!req) + return -ENOMEM; + + req->done =3D req->wq_buf_avail =3D false; + strcpy(req->name, "FLUSH"); + init_waitqueue_head(&req->host_acked); + init_waitqueue_head(&req->wq_buf); + + spin_lock_irqsave(&vpmem->pmem_lock, flags); + sg_init_one(&sg, req->name, strlen(req->name)); + sgs[0] =3D &sg; + sg_init_one(&ret, &req->ret, sizeof(req->ret)); + sgs[1] =3D &ret; + err =3D virtqueue_add_sgs(vpmem->req_vq, sgs, 1, 1, req, GFP_ATOMIC); + if (err) { + dev_err(&vdev->dev, "failed to send command to virtio pmem device\n"); + + list_add_tail(&vpmem->req_list, &req->list); + spin_unlock_irqrestore(&vpmem->pmem_lock, flags); + + /* When host has read buffer, this completes via host_ack */ + wait_event(req->wq_buf, req->wq_buf_avail); + spin_lock_irqsave(&vpmem->pmem_lock, flags); + } + virtqueue_kick(vpmem->req_vq); + spin_unlock_irqrestore(&vpmem->pmem_lock, flags); + + /* When host has read buffer, this completes via host_ack */ + wait_event(req->host_acked, req->done); + err =3D req->ret; + kfree(req); + + return err; +}; +EXPORT_SYMBOL_GPL(virtio_pmem_flush); + +static int virtio_pmem_probe(struct virtio_device *vdev) +{ + int err =3D 0; + struct resource res; + struct virtio_pmem *vpmem; + struct nvdimm_bus *nvdimm_bus; + struct nd_region_desc ndr_desc; + int nid =3D dev_to_node(&vdev->dev); + struct nd_region *nd_region; + + if (!vdev->config->get) { + dev_err(&vdev->dev, "%s failure: config disabled\n", + __func__); + return -EINVAL; + } + + vdev->priv =3D vpmem =3D devm_kzalloc(&vdev->dev, sizeof(*vpmem), + GFP_KERNEL); + if (!vpmem) { + err =3D -ENOMEM; + goto out_err; + } + + vpmem->vdev =3D vdev; + err =3D init_vq(vpmem); + if (err) + goto out_err; + + virtio_cread(vpmem->vdev, struct virtio_pmem_config, + start, &vpmem->start); + virtio_cread(vpmem->vdev, struct virtio_pmem_config, + size, &vpmem->size); + + res.start =3D vpmem->start; + res.end =3D vpmem->start + vpmem->size-1; + vpmem->nd_desc.provider_name =3D "virtio-pmem"; + vpmem->nd_desc.module =3D THIS_MODULE; + + vpmem->nvdimm_bus =3D nvdimm_bus =3D nvdimm_bus_register(&vdev->dev, + &vpmem->nd_desc); + if (!nvdimm_bus) + goto out_vq; + + dev_set_drvdata(&vdev->dev, nvdimm_bus); + memset(&ndr_desc, 0, sizeof(ndr_desc)); + + ndr_desc.res =3D &res; + ndr_desc.numa_node =3D nid; + ndr_desc.flush =3D virtio_pmem_flush; + set_bit(ND_REGION_PAGEMAP, &ndr_desc.flags); + nd_region =3D nvdimm_pmem_region_create(nvdimm_bus, &ndr_desc); + + if (!nd_region) + goto out_nd; + + //virtio_device_ready(vdev); + return 0; +out_nd: + err =3D -ENXIO; + nvdimm_bus_unregister(nvdimm_bus); +out_vq: + vdev->config->del_vqs(vdev); +out_err: + dev_err(&vdev->dev, "failed to register virtio pmem memory\n"); + return err; +} + +static void virtio_pmem_remove(struct virtio_device *vdev) +{ + struct virtio_pmem *vpmem =3D vdev->priv; + struct nvdimm_bus *nvdimm_bus =3D dev_get_drvdata(&vdev->dev); + + nvdimm_bus_unregister(nvdimm_bus); + vdev->config->del_vqs(vdev); + kfree(vpmem); +} + +#ifdef CONFIG_PM_SLEEP +static int virtio_pmem_freeze(struct virtio_device *vdev) +{ + /* todo: handle freeze function */ + return -EPERM; +} + +static int virtio_pmem_restore(struct virtio_device *vdev) +{ + /* todo: handle restore function */ + return -EPERM; +} +#endif + + +static struct virtio_driver virtio_pmem_driver =3D { + .driver.name =3D KBUILD_MODNAME, + .driver.owner =3D THIS_MODULE, + .id_table =3D id_table, + .probe =3D virtio_pmem_probe, + .remove =3D virtio_pmem_remove, +#ifdef CONFIG_PM_SLEEP + .freeze =3D virtio_pmem_freeze, + .restore =3D virtio_pmem_restore, +#endif +}; + +module_virtio_driver(virtio_pmem_driver); +MODULE_DEVICE_TABLE(virtio, id_table); +MODULE_DESCRIPTION("Virtio pmem driver"); +MODULE_LICENSE("GPL"); diff --git a/include/uapi/linux/virtio_ids.h b/include/uapi/linux/virtio_id= s.h index 6d5c3b2..3463895 100644 --- a/include/uapi/linux/virtio_ids.h +++ b/include/uapi/linux/virtio_ids.h @@ -43,5 +43,6 @@ #define VIRTIO_ID_INPUT 18 /* virtio input */ #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */ +#define VIRTIO_ID_PMEM 25 /* virtio pmem */ =20 #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/include/uapi/linux/virtio_pmem.h b/include/uapi/linux/virtio_p= mem.h new file mode 100644 index 0000000..c7c22a5 --- /dev/null +++ b/include/uapi/linux/virtio_pmem.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so + * anyone can use the definitions to implement compatible drivers/servers: + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of IBM nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``A= S IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, T= HE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURP= OSE + * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENT= IAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STR= ICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY W= AY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * Copyright (C) Red Hat, Inc., 2018-2019 + * Copyright (C) Pankaj Gupta , 2018 + */ +#ifndef _UAPI_LINUX_VIRTIO_PMEM_H +#define _UAPI_LINUX_VIRTIO_PMEM_H + +struct virtio_pmem_config { + __le64 start; + __le64 size; +}; +#endif --=20 2.9.3 From nobody Wed Nov 5 14:58:27 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1535722859729811.9853115241111; Fri, 31 Aug 2018 06:40:59 -0700 (PDT) Received: from localhost ([::1]:53750 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fvjfW-0002Sw-HT for importer@patchew.org; Fri, 31 Aug 2018 09:40:58 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:56935) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1fvjaW-0005g5-Qu for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:35:52 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1fvjWD-0006Kh-1K for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:31:25 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:47196 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1fvjWC-0006KZ-Ru for qemu-devel@nongnu.org; Fri, 31 Aug 2018 09:31:20 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 74ACF40241DE; Fri, 31 Aug 2018 13:31:20 +0000 (UTC) Received: from dhcp201-121.englab.pnq.redhat.com (dhcp193-198.pnq.redhat.com [10.65.193.198]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1A32BF3D01; Fri, 31 Aug 2018 13:31:06 +0000 (UTC) From: Pankaj Gupta To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org, qemu-devel@nongnu.org, linux-nvdimm@ml01.01.org Date: Fri, 31 Aug 2018 19:00:19 +0530 Message-Id: <20180831133019.27579-5-pagupta@redhat.com> In-Reply-To: <20180831133019.27579-1-pagupta@redhat.com> References: <20180831133019.27579-1-pagupta@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Fri, 31 Aug 2018 13:31:20 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Fri, 31 Aug 2018 13:31:20 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'pagupta@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PATCH] qemu: Add virtio pmem device 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: , Cc: kwolf@redhat.com, pagupta@redhat.com, jack@suse.cz, xiaoguangrong.eric@gmail.com, riel@surriel.com, niteshnarayanlal@hotmail.com, david@redhat.com, ross.zwisler@intel.com, lcapitulino@redhat.com, hch@infradead.org, mst@redhat.com, stefanha@redhat.com, imammedo@redhat.com, pbonzini@redhat.com, dan.j.williams@intel.com, nilal@redhat.com Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RDMRC_1 RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" This patch adds virtio-pmem Qemu device. This device presents memory address range information to guest which is backed by file backend type. It acts like persistent memory device for KVM guest. Guest can perform read and=20 persistent write operations on this memory range with the help=20 of DAX capable filesystem. Persistent guest writes are assured with the help of virtio=20 based flushing interface. When guest userspace space performs=20 fsync on file fd on pmem device, a flush command is send to=20 Qemu over VIRTIO and host side flush/sync is done on backing=20 image file. Signed-off-by: Pankaj Gupta --- Changes from RFC v3: - Return EIO for host fsync failure instead of errno - Luiz, Stefan - Change version for inclusion to Qemu 3.1 - Eric Changes from RFC v2: - Use aio_worker() to avoid Qemu from hanging with blocking fsync call - Stefan - Use virtio_st*_p() for endianess - Stefan - Correct indentation in qapi/misc.json - Eric hw/virtio/Makefile.objs | 3 + hw/virtio/virtio-pci.c | 44 +++++ hw/virtio/virtio-pci.h | 14 ++ hw/virtio/virtio-pmem.c | 241 ++++++++++++++++++++++++= ++++ include/hw/pci/pci.h | 1 + include/hw/virtio/virtio-pmem.h | 42 +++++ include/standard-headers/linux/virtio_ids.h | 1 + qapi/misc.json | 26 ++- 8 files changed, 371 insertions(+), 1 deletion(-) create mode 100644 hw/virtio/virtio-pmem.c create mode 100644 include/hw/virtio/virtio-pmem.h diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 1b2799cfd8..7f914d45d0 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -10,6 +10,9 @@ obj-$(CONFIG_VIRTIO_CRYPTO) +=3D virtio-crypto.o obj-$(call land,$(CONFIG_VIRTIO_CRYPTO),$(CONFIG_VIRTIO_PCI)) +=3D virtio-= crypto-pci.o =20 obj-$(CONFIG_LINUX) +=3D vhost.o vhost-backend.o vhost-user.o +ifeq ($(CONFIG_MEM_HOTPLUG),y) +obj-$(CONFIG_LINUX) +=3D virtio-pmem.o +endif obj-$(CONFIG_VHOST_VSOCK) +=3D vhost-vsock.o endif =20 diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 3a01fe90f0..93d3fc05c7 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -2521,6 +2521,49 @@ static const TypeInfo virtio_rng_pci_info =3D { .class_init =3D virtio_rng_pci_class_init, }; =20 +/* virtio-pmem-pci */ + +static void virtio_pmem_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) +{ + VirtIOPMEMPCI *vpmem =3D VIRTIO_PMEM_PCI(vpci_dev); + DeviceState *vdev =3D DEVICE(&vpmem->vdev); + + qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + +static void virtio_pmem_pci_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc =3D DEVICE_CLASS(klass); + VirtioPCIClass *k =3D VIRTIO_PCI_CLASS(klass); + PCIDeviceClass *pcidev_k =3D PCI_DEVICE_CLASS(klass); + k->realize =3D virtio_pmem_pci_realize; + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + pcidev_k->vendor_id =3D PCI_VENDOR_ID_REDHAT_QUMRANET; + pcidev_k->device_id =3D PCI_DEVICE_ID_VIRTIO_PMEM; + pcidev_k->revision =3D VIRTIO_PCI_ABI_VERSION; + pcidev_k->class_id =3D PCI_CLASS_OTHERS; +} + +static void virtio_pmem_pci_instance_init(Object *obj) +{ + VirtIOPMEMPCI *dev =3D VIRTIO_PMEM_PCI(obj); + + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_PMEM); + object_property_add_alias(obj, "memdev", OBJECT(&dev->vdev), "memdev", + &error_abort); +} + +static const TypeInfo virtio_pmem_pci_info =3D { + .name =3D TYPE_VIRTIO_PMEM_PCI, + .parent =3D TYPE_VIRTIO_PCI, + .instance_size =3D sizeof(VirtIOPMEMPCI), + .instance_init =3D virtio_pmem_pci_instance_init, + .class_init =3D virtio_pmem_pci_class_init, +}; + + /* virtio-input-pci */ =20 static Property virtio_input_pci_properties[] =3D { @@ -2714,6 +2757,7 @@ static void virtio_pci_register_types(void) type_register_static(&virtio_balloon_pci_info); type_register_static(&virtio_serial_pci_info); type_register_static(&virtio_net_pci_info); + type_register_static(&virtio_pmem_pci_info); #ifdef CONFIG_VHOST_SCSI type_register_static(&vhost_scsi_pci_info); #endif diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 813082b0d7..fe74fcad3f 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -19,6 +19,7 @@ #include "hw/virtio/virtio-blk.h" #include "hw/virtio/virtio-net.h" #include "hw/virtio/virtio-rng.h" +#include "hw/virtio/virtio-pmem.h" #include "hw/virtio/virtio-serial.h" #include "hw/virtio/virtio-scsi.h" #include "hw/virtio/virtio-balloon.h" @@ -57,6 +58,7 @@ typedef struct VirtIOInputHostPCI VirtIOInputHostPCI; typedef struct VirtIOGPUPCI VirtIOGPUPCI; typedef struct VHostVSockPCI VHostVSockPCI; typedef struct VirtIOCryptoPCI VirtIOCryptoPCI; +typedef struct VirtIOPMEMPCI VirtIOPMEMPCI; =20 /* virtio-pci-bus */ =20 @@ -274,6 +276,18 @@ struct VirtIOBlkPCI { VirtIOBlock vdev; }; =20 +/* + * virtio-pmem-pci: This extends VirtioPCIProxy. + */ +#define TYPE_VIRTIO_PMEM_PCI "virtio-pmem-pci" +#define VIRTIO_PMEM_PCI(obj) \ + OBJECT_CHECK(VirtIOPMEMPCI, (obj), TYPE_VIRTIO_PMEM_PCI) + +struct VirtIOPMEMPCI { + VirtIOPCIProxy parent_obj; + VirtIOPMEM vdev; +}; + /* * virtio-balloon-pci: This extends VirtioPCIProxy. */ diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c new file mode 100644 index 0000000000..69ae4c0a50 --- /dev/null +++ b/hw/virtio/virtio-pmem.c @@ -0,0 +1,241 @@ +/* + * Virtio pmem device + * + * Copyright (C) 2018 Red Hat, Inc. + * Copyright (C) 2018 Pankaj Gupta + * + * This work is licensed under the terms of the GNU GPL, version 2. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qemu-common.h" +#include "qemu/error-report.h" +#include "hw/virtio/virtio-access.h" +#include "hw/virtio/virtio-pmem.h" +#include "hw/mem/memory-device.h" +#include "block/aio.h" +#include "block/thread-pool.h" + +typedef struct VirtIOPMEMresp { + int ret; +} VirtIOPMEMResp; + +typedef struct VirtIODeviceRequest { + VirtQueueElement elem; + int fd; + VirtIOPMEM *pmem; + VirtIOPMEMResp resp; +} VirtIODeviceRequest; + +static int worker_cb(void *opaque) +{ + VirtIODeviceRequest *req =3D opaque; + int err =3D 0; + + /* flush raw backing image */ + err =3D fsync(req->fd); + if (err !=3D 0) { + err =3D EIO; + } + req->resp.ret =3D err; + + return 0; +} + +static void done_cb(void *opaque, int ret) +{ + VirtIODeviceRequest *req =3D opaque; + int len =3D iov_from_buf(req->elem.in_sg, req->elem.in_num, 0, + &req->resp, sizeof(VirtIOPMEMResp)); + + /* Callbacks are serialized, so no need to use atomic ops. */ + virtqueue_push(req->pmem->rq_vq, &req->elem, len); + virtio_notify((VirtIODevice *)req->pmem, req->pmem->rq_vq); + g_free(req); +} + +static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtIODeviceRequest *req; + VirtIOPMEM *pmem =3D VIRTIO_PMEM(vdev); + HostMemoryBackend *backend =3D MEMORY_BACKEND(pmem->memdev); + ThreadPool *pool =3D aio_get_thread_pool(qemu_get_aio_context()); + + req =3D virtqueue_pop(vq, sizeof(VirtIODeviceRequest)); + if (!req) { + virtio_error(vdev, "virtio-pmem missing request data"); + return; + } + + if (req->elem.out_num < 1 || req->elem.in_num < 1) { + virtio_error(vdev, "virtio-pmem request not proper"); + g_free(req); + return; + } + req->fd =3D memory_region_get_fd(&backend->mr); + req->pmem =3D pmem; + thread_pool_submit_aio(pool, worker_cb, req, done_cb, req); +} + +static void virtio_pmem_get_config(VirtIODevice *vdev, uint8_t *config) +{ + VirtIOPMEM *pmem =3D VIRTIO_PMEM(vdev); + struct virtio_pmem_config *pmemcfg =3D (struct virtio_pmem_config *) c= onfig; + + virtio_stq_p(vdev, &pmemcfg->start, pmem->start); + virtio_stq_p(vdev, &pmemcfg->size, pmem->size); +} + +static uint64_t virtio_pmem_get_features(VirtIODevice *vdev, uint64_t feat= ures, + Error **errp) +{ + return features; +} + +static void virtio_pmem_realize(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev =3D VIRTIO_DEVICE(dev); + VirtIOPMEM *pmem =3D VIRTIO_PMEM(dev); + MachineState *ms =3D MACHINE(qdev_get_machine()); + uint64_t align; + Error *local_err =3D NULL; + MemoryRegion *mr; + + if (!pmem->memdev) { + error_setg(errp, "virtio-pmem memdev not set"); + return; + } + + mr =3D host_memory_backend_get_memory(pmem->memdev); + align =3D memory_region_get_alignment(mr); + pmem->size =3D QEMU_ALIGN_DOWN(memory_region_size(mr), align); + pmem->start =3D memory_device_get_free_addr(ms, NULL, align, pmem->siz= e, + &local_err); + if (local_err) { + error_setg(errp, "Can't get free address in mem device"); + return; + } + memory_region_init_alias(&pmem->mr, OBJECT(pmem), + "virtio_pmem-memory", mr, 0, pmem->size); + memory_device_plug_region(ms, &pmem->mr, pmem->start); + + host_memory_backend_set_mapped(pmem->memdev, true); + virtio_init(vdev, TYPE_VIRTIO_PMEM, VIRTIO_ID_PMEM, + sizeof(struct virtio_pmem_config= )); + pmem->rq_vq =3D virtio_add_queue(vdev, 128, virtio_pmem_flush); +} + +static void virtio_mem_check_memdev(Object *obj, const char *name, Object = *val, + Error **errp) +{ + if (host_memory_backend_is_mapped(MEMORY_BACKEND(val))) { + char *path =3D object_get_canonical_path_component(val); + error_setg(errp, "Can't use already busy memdev: %s", path); + g_free(path); + return; + } + + qdev_prop_allow_set_link_before_realize(obj, name, val, errp); +} + +static const char *virtio_pmem_get_device_id(VirtIOPMEM *vm) +{ + Object *obj =3D OBJECT(vm); + DeviceState *parent_dev; + + /* always use the ID of the proxy device */ + if (obj->parent && object_dynamic_cast(obj->parent, TYPE_DEVICE)) { + parent_dev =3D DEVICE(obj->parent); + return parent_dev->id; + } + return NULL; +} + +static void virtio_pmem_md_fill_device_info(const MemoryDeviceState *md, + MemoryDeviceInfo *info) +{ + VirtioPMemDeviceInfo *vi =3D g_new0(VirtioPMemDeviceInfo, 1); + VirtIOPMEM *vm =3D VIRTIO_PMEM(md); + const char *id =3D virtio_pmem_get_device_id(vm); + + if (id) { + vi->has_id =3D true; + vi->id =3D g_strdup(id); + } + + vi->start =3D vm->start; + vi->size =3D vm->size; + vi->memdev =3D object_get_canonical_path(OBJECT(vm->memdev)); + + info->u.virtio_pmem.data =3D vi; + info->type =3D MEMORY_DEVICE_INFO_KIND_VIRTIO_PMEM; +} + +static uint64_t virtio_pmem_md_get_addr(const MemoryDeviceState *md) +{ + VirtIOPMEM *vm =3D VIRTIO_PMEM(md); + + return vm->start; +} + +static uint64_t virtio_pmem_md_get_plugged_size(const MemoryDeviceState *m= d) +{ + VirtIOPMEM *vm =3D VIRTIO_PMEM(md); + + return vm->size; +} + +static uint64_t virtio_pmem_md_get_region_size(const MemoryDeviceState *md) +{ + VirtIOPMEM *vm =3D VIRTIO_PMEM(md); + + return vm->size; +} + +static void virtio_pmem_instance_init(Object *obj) +{ + VirtIOPMEM *vm =3D VIRTIO_PMEM(obj); + object_property_add_link(obj, "memdev", TYPE_MEMORY_BACKEND, + (Object **)&vm->memdev, + (void *) virtio_mem_check_memdev, + OBJ_PROP_LINK_STRONG, + &error_abort); +} + + +static void virtio_pmem_class_init(ObjectClass *klass, void *data) +{ + VirtioDeviceClass *vdc =3D VIRTIO_DEVICE_CLASS(klass); + MemoryDeviceClass *mdc =3D MEMORY_DEVICE_CLASS(klass); + + vdc->realize =3D virtio_pmem_realize; + vdc->get_config =3D virtio_pmem_get_config; + vdc->get_features =3D virtio_pmem_get_features; + + mdc->get_addr =3D virtio_pmem_md_get_addr; + mdc->get_plugged_size =3D virtio_pmem_md_get_plugged_size; + mdc->get_region_size =3D virtio_pmem_md_get_region_size; + mdc->fill_device_info =3D virtio_pmem_md_fill_device_info; +} + +static TypeInfo virtio_pmem_info =3D { + .name =3D TYPE_VIRTIO_PMEM, + .parent =3D TYPE_VIRTIO_DEVICE, + .class_init =3D virtio_pmem_class_init, + .instance_size =3D sizeof(VirtIOPMEM), + .instance_init =3D virtio_pmem_instance_init, + .interfaces =3D (InterfaceInfo[]) { + { TYPE_MEMORY_DEVICE }, + { } + }, +}; + +static void virtio_register_types(void) +{ + type_register_static(&virtio_pmem_info); +} + +type_init(virtio_register_types) diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h index 990d6fcbde..28829b6437 100644 --- a/include/hw/pci/pci.h +++ b/include/hw/pci/pci.h @@ -85,6 +85,7 @@ extern bool pci_available; #define PCI_DEVICE_ID_VIRTIO_RNG 0x1005 #define PCI_DEVICE_ID_VIRTIO_9P 0x1009 #define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012 +#define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013 =20 #define PCI_VENDOR_ID_REDHAT 0x1b36 #define PCI_DEVICE_ID_REDHAT_BRIDGE 0x0001 diff --git a/include/hw/virtio/virtio-pmem.h b/include/hw/virtio/virtio-pme= m.h new file mode 100644 index 0000000000..fda3ee691c --- /dev/null +++ b/include/hw/virtio/virtio-pmem.h @@ -0,0 +1,42 @@ +/* + * Virtio pmem Device + * + * Copyright Red Hat, Inc. 2018 + * Copyright Pankaj Gupta + * + * This work is licensed under the terms of the GNU GPL, version 2 or + * (at your option) any later version. See the COPYING file in the + * top-level directory. + */ + +#ifndef QEMU_VIRTIO_PMEM_H +#define QEMU_VIRTIO_PMEM_H + +#include "hw/virtio/virtio.h" +#include "exec/memory.h" +#include "sysemu/hostmem.h" +#include "standard-headers/linux/virtio_ids.h" +#include "hw/boards.h" +#include "hw/i386/pc.h" + +#define TYPE_VIRTIO_PMEM "virtio-pmem" + +#define VIRTIO_PMEM(obj) \ + OBJECT_CHECK(VirtIOPMEM, (obj), TYPE_VIRTIO_PMEM) + +/* VirtIOPMEM device structure */ +typedef struct VirtIOPMEM { + VirtIODevice parent_obj; + + VirtQueue *rq_vq; + uint64_t start; + uint64_t size; + MemoryRegion mr; + HostMemoryBackend *memdev; +} VirtIOPMEM; + +struct virtio_pmem_config { + uint64_t start; + uint64_t size; +}; +#endif diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard= -headers/linux/virtio_ids.h index 6d5c3b2d4f..346389565a 100644 --- a/include/standard-headers/linux/virtio_ids.h +++ b/include/standard-headers/linux/virtio_ids.h @@ -43,5 +43,6 @@ #define VIRTIO_ID_INPUT 18 /* virtio input */ #define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */ #define VIRTIO_ID_CRYPTO 20 /* virtio crypto */ +#define VIRTIO_ID_PMEM 25 /* virtio pmem */ =20 #endif /* _LINUX_VIRTIO_IDS_H */ diff --git a/qapi/misc.json b/qapi/misc.json index d450cfef21..517376b866 100644 --- a/qapi/misc.json +++ b/qapi/misc.json @@ -2907,6 +2907,29 @@ } } =20 +## +# @VirtioPMemDeviceInfo: +# +# VirtioPMem state information +# +# @id: device's ID +# +# @start: physical address, where device is mapped +# +# @size: size of memory that the device provides +# +# @memdev: memory backend linked with device +# +# Since: 3.1 +## +{ 'struct': 'VirtioPMemDeviceInfo', + 'data': { '*id': 'str', + 'start': 'size', + 'size': 'size', + 'memdev': 'str' + } +} + ## # @MemoryDeviceInfo: # @@ -2916,7 +2939,8 @@ ## { 'union': 'MemoryDeviceInfo', 'data': { 'dimm': 'PCDIMMDeviceInfo', - 'nvdimm': 'PCDIMMDeviceInfo' + 'nvdimm': 'PCDIMMDeviceInfo', + 'virtio-pmem': 'VirtioPMemDeviceInfo' } } =20 --=20 2.14.3