On Tue, Dec 29, 2020 at 15:21:27 -0600, Ryan Gahagan wrote: > Signed-off-by: Ryan Gahagan <rgahagan@xxxxxxxxxxxxx> > --- > 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; > + }