<div dir="ltr"><div dir="ltr"><div>On qemu-5.2.0-4.fc34.x86_64, libvirt v6.10.0-262-gbed50bcbbb with this patch series, by following script:</div><div>#!/bin/bash - <br>set -o nounset                              # Treat unset variables as an error<br>VM=test<br>NFS_EXPORT=/tmp/nfs<br>IMG=disk1<br>DISK_XML=/tmp/nfs.xml<br>mkdir -p $NFS_EXPORT<br>echo "$NFS_EXPORT *(rw,no_root_squash,insecure)" > /etc/exports<br><br>systemctl restart nfs-server<br><br>qemu-img create nfs://localhost"$NFS_EXPORT/$IMG" 100M<br>chmod 777 $NFS_EXPORT -R<br><br>virsh start $VM --console<br><br>echo "<disk type='network' device='disk'><br>      <driver name='qemu' type='raw' cache='none'/><br>      <source protocol='nfs' name='$NFS_EXPORT/$IMG'><br>        <host name='localhost'/><br>        <nfs user='+107' group='+107'/><br>      </source><br>      <target dev='vdb' bus='virtio'/><br>    </disk>" > $DISK_XML<br>virsh attach-device $VM $DISK_XML<br>virsh console $VM<br>virsh detach-device $VM $DISK_XML<br>virsh console $VM<br><br>virsh destroy $VM<br>virsh attach-device $VM $DISK_XML --config<br>virsh start $VM --console<br>virsh destroy $VM<br>virsh detach-device $VM $DISK_XML --config</div><div><br></div><div>It works for me. All attach/detach tests have passed.<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Dec 30, 2020 at 5:23 AM Ryan Gahagan <<a href="mailto:rgahagan@cs.utexas.edu">rgahagan@cs.utexas.edu</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Signed-off-by: Ryan Gahagan <<a href="mailto:rgahagan@cs.utexas.edu" target="_blank">rgahagan@cs.utexas.edu</a>><br>
---<br>
 src/qemu/qemu_block.c  | 79 +++++++++++++++++++++++++++++++++++++++++-<br>
 src/qemu/qemu_domain.c | 47 +++++++++++++++++++++++++<br>
 2 files changed, 125 insertions(+), 1 deletion(-)<br>
<br>
diff --git a/src/qemu/qemu_block.c b/src/qemu/qemu_block.c<br>
index b224a550f3..5413a4f0e8 100644<br>
--- a/src/qemu/qemu_block.c<br>
+++ b/src/qemu/qemu_block.c<br>
@@ -574,6 +574,35 @@ qemuBlockStorageSourceBuildJSONInetSocketAddress(virStorageNetHostDefPtr host)<br>
 }<br>
<br>
<br>
+/**<br>
+ * qemuBlockStorageSourceBuildJSONNFSServer(virStorageNetHostDefPtr host)<br>
+ * @host: the virStorageNetHostDefPtr definition to build<br>
+ *<br>
+ * Formats @hosts into a json object conforming to the 'NFSServer' type<br>
+ * in qemu.<br>
+ *<br>
+ * Returns a virJSONValuePtr for a single server.<br>
+ */<br>
+static virJSONValuePtr<br>
+qemuBlockStorageSourceBuildJSONNFSServer(virStorageNetHostDefPtr host)<br>
+{<br>
+    virJSONValuePtr ret = NULL;<br>
+<br>
+    if (host->transport != VIR_STORAGE_NET_HOST_TRANS_TCP) {<br>
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",<br>
+                       _("only TCP protocol can be converted to NFSServer"));<br>
+        return NULL;<br>
+    }<br>
+<br>
+    ignore_value(virJSONValueObjectCreate(&ret,<br>
+                                          "s:host", host->name,<br>
+                                          "s:type", "inet",<br>
+                                          NULL));<br>
+<br>
+    return ret;<br>
+}<br>
+<br>
+<br>
 /**<br>
  * qemuBlockStorageSourceBuildHostsJSONInetSocketAddress:<br>
  * @src: disk storage source<br>
@@ -674,6 +703,44 @@ qemuBlockStorageSourceGetVxHSProps(virStorageSourcePtr src,<br>
 }<br>
<br>
<br>
+static virJSONValuePtr<br>
+qemuBlockStorageSourceGetNFSProps(virStorageSourcePtr src)<br>
+{<br>
+    g_autoptr(virJSONValue) server = NULL;<br>
+    virJSONValuePtr ret = NULL;<br>
+<br>
+    if (src->nhosts != 1) {<br>
+        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",<br>
+                       _("NFS protocol accepts only one host"));<br>
+        return NULL;<br>
+    }<br>
+<br>
+    if (!(server = qemuBlockStorageSourceBuildJSONNFSServer(&src->hosts[0])))<br>
+        return NULL;<br>
+<br>
+    /* NFS disk specification example:<br>
+     * { driver:"nfs",<br>
+     *   user: "0",<br>
+     *   group: "0",<br>
+     *   path: "/foo/bar/baz",<br>
+     *   server: {type:"tcp", host:"1.2.3.4"}}<br>
+     */<br>
+    ignore_value(virJSONValueObjectCreate(&ret,<br>
+                                          "a:server", &server,<br>
+                                          "S:path", src->path, NULL));<br>
+<br>
+    if (src->nfs_uid != -1 &&<br>
+        virJSONValueObjectAdd(ret, "i:user", src->nfs_uid, NULL) < 0)<br>
+        return NULL;<br>
+<br>
+    if (src->nfs_gid != -1 &&<br>
+        virJSONValueObjectAdd(ret, "i:group", src->nfs_gid, NULL) < 0)<br>
+        return NULL;<br>
+<br>
+    return ret;<br>
+}<br>
+<br>
+<br>
 static virJSONValuePtr<br>
 qemuBlockStorageSourceGetCURLProps(virStorageSourcePtr src,<br>
                                    bool onlytarget)<br>
@@ -1181,6 +1248,11 @@ qemuBlockStorageSourceGetBackendProps(virStorageSourcePtr src,<br>
             break;<br>
<br>
         case VIR_STORAGE_NET_PROTOCOL_NFS:<br>
+            driver = "nfs";<br>
+            if (!(fileprops = qemuBlockStorageSourceGetNFSProps(src)))<br>
+                return NULL;<br>
+            break;<br>
+<br>
         case VIR_STORAGE_NET_PROTOCOL_NONE:<br>
         case VIR_STORAGE_NET_PROTOCOL_LAST:<br>
             virReportEnumRangeError(virStorageNetProtocol, src->protocol);<br>
@@ -2500,11 +2572,16 @@ qemuBlockStorageSourceCreateGetStorageProps(virStorageSourcePtr src,<br>
                 return -1;<br>
             break;<br>
<br>
+        case VIR_STORAGE_NET_PROTOCOL_NFS:<br>
+            driver = "nfs";<br>
+            if (!(location = qemuBlockStorageSourceGetNFSProps(src)))<br>
+                return -1;<br>
+            break;<br>
+<br>
             /* unsupported/impossible */<br>
         case VIR_STORAGE_NET_PROTOCOL_NBD:<br>
         case VIR_STORAGE_NET_PROTOCOL_ISCSI:<br>
         case VIR_STORAGE_NET_PROTOCOL_VXHS:<br>
-        case VIR_STORAGE_NET_PROTOCOL_NFS:<br>
         case VIR_STORAGE_NET_PROTOCOL_HTTP:<br>
         case VIR_STORAGE_NET_PROTOCOL_HTTPS:<br>
         case VIR_STORAGE_NET_PROTOCOL_FTP:<br>
diff --git a/src/qemu/qemu_domain.c b/src/qemu/qemu_domain.c<br>
index d91c32b2c5..8812df5138 100644<br>
--- a/src/qemu/qemu_domain.c<br>
+++ b/src/qemu/qemu_domain.c<br>
@@ -4626,6 +4626,14 @@ qemuDomainValidateStorageSource(virStorageSourcePtr src,<br>
         return -1;<br>
     }<br>
<br>
+    /* NFS protocol may only be used if current QEMU supports blockdev */<br>
+    if (actualType == VIR_STORAGE_TYPE_NETWORK &&<br>
+        src->protocol == VIR_STORAGE_NET_PROTOCOL_NFS &&<br>
+        !blockdev) {<br>
+        virReportError(VIR_ERR_CONFIG_UNSUPPORTED, "%s",<br>
+                       _("'nfs' protocol is not supported with this QEMU binary"));<br>
+    }<br>
+<br>
     return 0;<br>
 }<br>
<br>
@@ -9590,6 +9598,42 @@ qemuProcessPrepareStorageSourceTLSNBD(virStorageSourcePtr src,<br>
 }<br>
<br>
<br>
+/* qemuPrepareStorageSourceNFS:<br>
+ * @src: source for a disk<br>
+ *<br>
+ * If src is an NFS source, translate nfs_user and nfs_group<br>
+ * into a uid and gid field. If these strings are empty (ie "")<br>
+ * then provide the hypervisor default uid and gid.<br>
+ */<br>
+static int<br>
+qemuDomainPrepareStorageSourceNFS(virStorageSourcePtr src)<br>
+{<br>
+    if (virStorageSourceGetActualType(src) != VIR_STORAGE_TYPE_NETWORK)<br>
+        return 0;<br>
+<br>
+    if ((virStorageNetProtocol) src->protocol != VIR_STORAGE_NET_PROTOCOL_NFS)<br>
+        return 0;<br>
+<br>
+    if (src->nfs_user) {<br>
+        if (virGetUserID(src->nfs_user, &src->nfs_uid) < 0)<br>
+            return -1;<br>
+    } else {<br>
+        /* -1 indicates default UID */<br>
+        src->nfs_uid = -1;<br>
+    }<br>
+<br>
+    if (src->nfs_group) {<br>
+        if (virGetGroupID(src->nfs_group, &src->nfs_gid) < 0)<br>
+            return -1;<br>
+    } else {<br>
+        /* -1 indicates default GID */<br>
+        src->nfs_gid = -1;<br>
+    }<br>
+<br>
+    return 0;<br>
+}<br>
+<br>
+<br>
 /* qemuProcessPrepareStorageSourceTLS:<br>
  * @source: source for a disk<br>
  * @cfg: driver configuration<br>
@@ -10401,6 +10445,9 @@ qemuDomainPrepareStorageSourceBlockdev(virDomainDiskDefPtr disk,<br>
                                           priv) < 0)<br>
         return -1;<br>
<br>
+    if (qemuDomainPrepareStorageSourceNFS(src) < 0)<br>
+        return -1;<br>
+<br>
     return 0;<br>
 }<br>
<br>
-- <br>
2.29.2<br>
<br>
</blockquote></div><br clear="all"><br>-- <br><div dir="ltr" class="gmail_signature"><div dir="ltr">Tested-by: Han Han <<a href="mailto:hhan@redhat.com" target="_blank">hhan@redhat.com</a>></div></div></div>