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@xxxxxxxxxx> --- nfs4.1/nfs4client.py | 6 +++ nfs4.1/server41tests/st_delegation.py | 72 ++++++++++++++++++++++++++++++++++- 2 files changed, 77 insertions(+), 1 deletion(-) 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])) -- 2.46.0