[PATCH pynfs 13/13] server41tests: test inter-server COPY

Jeff Layton <[email protected]>
Newsgroups gmane.linux.nfs
Message-ID <[email protected]>
Add INTERCOPY1, a full NFSv4.2 server-to-server COPY across two servers.
The source file is created on the second server and the destination on
the primary server; the client issues COPY_NOTIFY to the source, then
COPY to the destination naming the source via ca_source_server, and
verifies the copied data.

The test requires --server2 SERVER:/PATH and is reported as unsupported
when no second server is configured or when either server lacks the
inter-server copy operations.

Signed-off-by: Jeff Layton <[email protected]>
---
 nfs4.1/server41tests/st_copy.py | 80 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 80 insertions(+)

diff --git a/nfs4.1/server41tests/st_copy.py b/nfs4.1/server41tests/st_copy.py
index 7eb6e2c98c4d..9cb9c199a025 100644
--- a/nfs4.1/server41tests/st_copy.py
+++ b/nfs4.1/server41tests/st_copy.py
@@ -436,3 +436,83 @@ def testCopyNotifyNoFh(t, env):
         t.fail_support("Server does not support COPY_NOTIFY "
                        "(inter-server copy source)")
     check(res, NFS4ERR_NOFILEHANDLE, msg="COPY_NOTIFY with no filehandle")
+
+def _inter_copy_ops(src_fh, src_stateid, dst_fh, dst_stateid, source_server,
+                    src_offset=0, dst_offset=0, count=0,
+                    consecutive=0, synchronous=1):
+    """COMPOUND for an inter-server COPY, sent to the destination server.
+
+    SAVED_FH is the source file's filehandle as known to the source server;
+    the destination server treats it as opaque and forwards it to the source
+    named by source_server (a non-empty ca_source_server list is what marks
+    the copy as inter-server).
+    """
+    return [op.putfh(src_fh), op.savefh(), op.putfh(dst_fh),
+            op.copy(src_stateid, dst_stateid, src_offset, dst_offset,
+                    count, consecutive, synchronous, source_server)]
+
+def testInterServerCopy(t, env):
+    """server-to-server (inter-server) COPY across two servers
+
+    Requires a second server: pass --server2 SERVER:/PATH.  The source file
+    is created on the second server (env.c2, the copy source) and the
+    destination file on the primary server (env.c1, the copy destination).
+    The client issues COPY_NOTIFY to the source to authorize the destination,
+    then COPY to the destination naming the source via ca_source_server.
+
+    FLAGS: copy
+    CODE: INTERCOPY1
+    VERS: 2-
+    """
+    if env.c2 is None:
+        t.fail_support("No second server configured "
+                       "(pass --server2 SERVER:/PATH to enable)")
+
+    # Source file on the second server (the copy source).
+    src_sess = env.c2.new_client_session(env.testname(t) + b"_src")
+    src_fh, src_stateid = _create_and_open(src_sess, env.testname(t))
+    data = b"inter-server copy payload " * 4096
+    _write_data(src_sess, src_fh, src_stateid, data)
+
+    # Ask the source to authorize the primary server as the copy destination.
+    dest_netloc = _server_netloc(env)   # names the primary server (env.c1)
+    res = src_sess.compound([op.putfh(src_fh),
+                             op.copy_notify(src_stateid, dest_netloc)])
+    check(res, [NFS4_OK, NFS4ERR_NOTSUPP], msg="COPY_NOTIFY on source server")
+    if res.status == NFS4ERR_NOTSUPP:
+        t.fail_support("Source server does not support COPY_NOTIFY")
+    cnr = res.resarray[-1]
+    copy_src_stateid = cnr.cnr_stateid
+    source_server = cnr.cnr_source_server
+    if not source_server:
+        fail("COPY_NOTIFY returned an empty cnr_source_server list")
+
+    # Destination file on the primary server (the copy destination).
+    dst_sess = env.c1.new_client_session(env.testname(t) + b"_dst")
+    dst_fh, dst_stateid = _create_and_open(dst_sess, env.testname(t))
+
+    # COPY to the destination, naming the source via ca_source_server.
+    # Inter-server copy is asynchronous on the Linux server (a synchronous
+    # request returns NFS4ERR_NOTSUPP), so ask for async and poll below.
+    ops = _inter_copy_ops(src_fh, copy_src_stateid, dst_fh, dst_stateid,
+                          source_server, count=len(data), synchronous=0)
+    res = dst_sess.compound(ops)
+    check(res, [NFS4_OK, NFS4ERR_NOTSUPP], msg="inter-server COPY")
+    if res.status == NFS4ERR_NOTSUPP:
+        t.fail_support("Destination server does not support inter-server COPY")
+    cr = res.resarray[-1]
+
+    if cr.cr_resok4.cr_requirements.cr_synchronous:
+        if cr.cr_response.wr_count != len(data):
+            fail("Inter-server copy expected %d bytes, got %d" %
+                 (len(data), cr.cr_response.wr_count))
+    else:
+        copy_stateid = cr.cr_response.wr_callback_id[0]
+        status = _poll_offload_status(dst_sess, dst_fh, copy_stateid)
+        if status.osr_complete[0] != NFS4_OK:
+            fail("Async inter-server copy error: %d" % status.osr_complete[0])
+        if status.osr_count != len(data):
+            fail("Expected %d bytes copied, got %d" %
+                 (len(data), status.osr_count))
+
+    _verify_data(dst_sess, dst_fh, dst_stateid, data)

-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.