On Tue, Dec 29, 2020 at 15:21:27 -0600, Ryan Gahagan wrote:
Signed-off-by: Ryan Gahagan <rgahagan(a)cs.utexas.edu>
---
src/qemu/qemu_block.c | 79 +++++++++++++++++++++++++++++++++++++++++-
src/qemu/qemu_domain.c | 47 +++++++++++++++++++++++++
2 files changed, 125 insertions(+), 1 deletion(-)
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c
index b224a550f3..5413a4f0e8 100644
--- a/src/qemu/qemu_block.c
+++ b/src/qemu/qemu_block.c
@@ -574,6 +574,35 @@
qemuBlockStorageSourceBuildJSONInetSocketAddress(virStorageNetHostDefPtr host)
}
+/**
+ * qemuBlockStorageSourceBuildJSONNFSServer(virStorageNetHostDefPtr host)
+ * @host: the virStorageNetHostDefPtr definition to build
+ *
+ * Formats @hosts into a json object conforming to the 'NFSServer' type
+ * in qemu.
+ *
+ * Returns a virJSONValuePtr for a single server.
+ */
+static virJSONValuePtr
+qemuBlockStorageSourceBuildJSONNFSServer(virStorageNetHostDefPtr host)
+{
+ virJSONValuePtr ret = NULL;
+
+ if (host->transport != VIR_STORAGE_NET_HOST_TRANS_TCP) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("only TCP protocol can be converted to NFSServer"));
+ return NULL;
This check belongs into the validation function.
+ }
+
+ ignore_value(virJSONValueObjectCreate(&ret,
+ "s:host", host->name,
+ "s:type", "inet",
+ NULL));
+
+ return ret;
+}
+
+
/**
* qemuBlockStorageSourceBuildHostsJSONInetSocketAddress:
* @src: disk storage source
@@ -674,6 +703,44 @@ qemuBlockStorageSourceGetVxHSProps(virStorageSourcePtr src,
}
+static virJSONValuePtr
+qemuBlockStorageSourceGetNFSProps(virStorageSourcePtr src)
+{
+ g_autoptr(virJSONValue) server = NULL;
+ virJSONValuePtr ret = NULL;
+
+ if (src->nhosts != 1) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("NFS protocol accepts only one host"));
+ return NULL;
+ }
This check belongs to the validation function.
+
+ if (!(server = qemuBlockStorageSourceBuildJSONNFSServer(&src->hosts[0])))
+ return NULL;
+
+ /* NFS disk specification example:
+ * { driver:"nfs",
+ * user: "0",
+ * group: "0",
+ * path: "/foo/bar/baz",
+ * server: {type:"tcp", host:"1.2.3.4"}}
+ */
+ ignore_value(virJSONValueObjectCreate(&ret,
+ "a:server", &server,
+ "S:path", src->path, NULL));
+
+ if (src->nfs_uid != -1 &&
+ virJSONValueObjectAdd(ret, "i:user", src->nfs_uid, NULL) < 0)
+ return NULL;
+
+ if (src->nfs_gid != -1 &&
+ virJSONValueObjectAdd(ret, "i:group", src->nfs_gid, NULL) < 0)
+ return NULL;
+
+ return ret;
+}
+
+
static virJSONValuePtr
qemuBlockStorageSourceGetCURLProps(virStorageSourcePtr src,
bool onlytarget)
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c
index d91c32b2c5..8812df5138 100644
--- a/src/qemu/qemu_domain.c
+++ b/src/qemu/qemu_domain.c
@@ -4626,6 +4626,14 @@ qemuDomainValidateStorageSource(virStorageSourcePtr src,
return -1;
}
+ /* NFS protocol may only be used if current QEMU supports blockdev */
+ if (actualType == VIR_STORAGE_TYPE_NETWORK &&
+ src->protocol == VIR_STORAGE_NET_PROTOCOL_NFS &&
+ !blockdev) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",
+ _("'nfs' protocol is not supported with this QEMU
binary"));
Here you must also check that the 'port' is not provided and that the
protocol is TCP. Otherwise you'd accept configurations which can't be
represented in qemu silently.
+ }
+
return 0;
}
@@ -9590,6 +9598,42 @@ qemuProcessPrepareStorageSourceTLSNBD(virStorageSourcePtr src,
}
+/* qemuPrepareStorageSourceNFS:
+ * @src: source for a disk
+ *
+ * If src is an NFS source, translate nfs_user and nfs_group
+ * into a uid and gid field. If these strings are empty (ie "")
+ * then provide the hypervisor default uid and gid.
+ */
+static int
+qemuDomainPrepareStorageSourceNFS(virStorageSourcePtr src)
+{
+ if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK)
+ return 0;
+
+ if ((virStorageNetProtocol) src->protocol != VIR_STORAGE_NET_PROTOCOL_NFS)
The typecast to virStorageNetProtocol is required only when you want to
use a 'switch' statement so that the complier checks that all cases are
handled. It's not necessary in a single if-condition.
+ return 0;
+
+ if (src->nfs_user) {
+ if (virGetUserID(src->nfs_user, &src->nfs_uid) < 0)
+ return -1;
+ } else {
+ /* -1 indicates default UID */
+ src->nfs_uid = -1;
+ }