diff mbox series

[pynfs,2/2] nfs4.1: add two CB_GETATTR tests

Message ID 20240905-cb_getattr-v1-2-0af05c68234f@kernel.org (mailing list archive)
State New
Headers show
Series pynfs: add CB_GETATTR tests | expand

Commit Message

Jeff Layton Sept. 5, 2024, 6:16 p.m. UTC
Add tests for CB_GETATTR support.

Open a file r/w and request a write delegation. Do a getattr against it
to get the current size and change attr. From a second client, issue a
GETATTR against the file.

One test does this and has the delegation holder send back the same
attrs, another has it send back updated ones.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 nfs4.1/nfs4client.py                  |  6 +++
 nfs4.1/server41tests/st_delegation.py | 72 ++++++++++++++++++++++++++++++++++-
 2 files changed, 77 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/nfs4.1/nfs4client.py b/nfs4.1/nfs4client.py
index 8ce64dd639c7..941cf4000a5f 100644
--- a/nfs4.1/nfs4client.py
+++ b/nfs4.1/nfs4client.py
@@ -271,6 +271,12 @@  class NFS4Client(rpc.Client, rpc.Server):
         res = self.posthook(arg, env, res)
         return encode_status(NFS4_OK, res)
 
+    def op_cb_getattr(self, arg, env):
+        log_cb.info("In CB_GETATTR")
+        self.prehook(arg, env)
+        res = self.posthook(arg, env, res=CB_GETATTR4resok())
+        return encode_status(NFS4_OK, res)
+
     def op_cb_recall(self, arg, env):
         log_cb.info("In CB_RECALL")
         self.prehook(arg, env)
diff --git a/nfs4.1/server41tests/st_delegation.py b/nfs4.1/server41tests/st_delegation.py
index 80b0da28fbad..2aa73ba7acd0 100644
--- a/nfs4.1/server41tests/st_delegation.py
+++ b/nfs4.1/server41tests/st_delegation.py
@@ -2,7 +2,7 @@  from .st_create_session import create_session
 from .st_open import open_claim4
 from xdrdef.nfs4_const import *
 
-from .environment import check, fail, create_file, open_file, close_file
+from .environment import check, fail, create_file, open_file, close_file, do_getattrdict
 from xdrdef.nfs4_type import *
 import nfs_ops
 op = nfs_ops.NFS4ops()
@@ -289,3 +289,73 @@  def testServerSelfConflict3(t, env):
     check(res, [NFS4_OK, NFS4ERR_DELAY])
     if not completed:
         fail("delegation break not received")
+
+def _testCbGetattr(t, env, change=0, size=0):
+    cb = threading.Event()
+    cbattrs = {}
+    def getattr_post_hook(arg, env, res):
+        res.obj_attributes = cbattrs
+        env.notify = cb.set
+        return res
+
+    sess1 = env.c1.new_client_session(b"%s_1" % env.testname(t))
+    sess1.client.cb_post_hook(OP_CB_GETATTR, getattr_post_hook)
+
+    fh, deleg = __create_file_with_deleg(sess1, env.testname(t),
+                                                OPEN4_SHARE_ACCESS_READ  |
+                                                OPEN4_SHARE_ACCESS_WRITE |
+                                                OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG)
+    print("__create_file_with_deleg: ", fh, deleg)
+    attrs1 = do_getattrdict(sess1, fh, [FATTR4_CHANGE, FATTR4_SIZE])
+    cbattrs = dict(attrs1)
+
+    if change != 0:
+        cbattrs[FATTR4_CHANGE] += 1
+        if size > 0:
+            cbattrs[FATTR4_SIZE] = size
+
+    # create a new client session and do a GETATTR
+    sess2 = env.c1.new_client_session(b"%s_2" % env.testname(t))
+    slot = sess2.compound_async([op.putfh(fh), op.getattr(1<<FATTR4_CHANGE | 1<<FATTR4_SIZE)])
+
+    # wait for the CB_GETATTR
+    completed = cb.wait(2)
+    res = sess2.listen(slot)
+    attrs2 = res.resarray[-1].obj_attributes
+    sess1.compound([op.putfh(fh), op.delegreturn(deleg.write.stateid)])
+    check(res, [NFS4_OK, NFS4ERR_DELAY])
+    if not completed:
+        fail("CB_GETATTR not received")
+    return attrs1, attrs2
+
+def testCbGetattrNoChange(t, env):
+    """Test CB_GETATTR with no changes
+
+    Get a write delegation, then do a getattr from a second client. Have the
+    client regurgitate back the same attrs (indicating no changes). Then test
+    that the attrs that the second client gets back match the first.
+
+    FLAGS: deleg
+    CODE: DELEG24
+    """
+    attrs1, attrs2 = _testCbGetattr(t, env)
+    if attrs1[FATTR4_SIZE] != attrs2[FATTR4_SIZE]:
+        fail("Bad size: %u != %u" % (attrs1[FATTR4_SIZE], attrs2[FATTR4_SIZE]))
+    if attrs1[FATTR4_CHANGE] != attrs2[FATTR4_CHANGE]:
+        fail("Bad change attribute: %u != %u" % (attrs1[FATTR4_CHANGE], attrs2[FATTR4_CHANGE]))
+
+def testCbGetattrWithChange(t, env):
+    """Test CB_GETATTR with simulated changes to file
+
+    Get a write delegation, then do a getattr from a second client. Modify the
+    attrs before sending them back to the server. Test that the second client
+    sees different attrs than the original one.
+
+    FLAGS: deleg
+    CODE: DELEG25
+    """
+    attrs1, attrs2 = _testCbGetattr(t, env, change=1, size=5)
+    if attrs2[FATTR4_SIZE] != 5:
+        fail("Bad size: %u != 5" % attrs2[FATTR4_SIZE])
+    if attrs1[FATTR4_CHANGE] == attrs2[FATTR4_CHANGE]:
+        fail("Bad change attribute: %u == %u" % (attrs1[FATTR4_CHANGE], attrs2[FATTR4_CHANGE]))