def testReadWrite(t, env): """Do a simple READ and WRITE FLAGS: open all CODE: OPEN400 """ c1 = env.c1.new_client(env.testname(t)) sess1 = c1.create_session() owner = open_owner4(0, "My Open Owner") how = openflag4(OPEN4_CREATE, createhow4(GUARDED4, {FATTR4_SIZE: 0})) claim = open_claim4(CLAIM_NULL, env.testname(t)) open_op = op.open(0, OPEN4_SHARE_ACCESS_BOTH, OPEN4_SHARE_DENY_NONE, owner, how, claim) fh_op = op.putrootfh() res = sess1.compound([fh_op, open_op, op.getfh()]) # OPEN print res check(res) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid stateid.seqid = 0 res = sess1.compound( [op.putfh(fh), op.write(stateid, 5, FILE_SYNC4, "write test data")]) print res check(res) res = sess1.compound([op.putfh(fh), op.read(stateid, 0, 1000)]) print res check(res)
def testLayoutReturnFile(t, env): """ Return a file's layout FLAGS: pnfs DEPEND: GETLAYOUT1 CODE: LAYOUTRET1 """ # Make sure E_ID returns MDS capabilities c1 = env.c1.new_client(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) if not c1.flags & EXCHGID4_FLAG_USE_PNFS_MDS: fail("Server can not be used as pnfs metadata server") sess = c1.create_session() # Create the file res = create_file(sess, env.testname(t)) check(res) # Get layout fh = res.resarray[-1].object open_stateid = res.resarray[-2].stateid ops = [op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_READ, 0, 0xffffffffffffffff, 0, open_stateid, 0xffff)] res = sess.compound(ops) check(res) # Return layout layout_stateid = res.resarray[-1].logr_stateid ops = [op.putfh(fh), op.layoutreturn(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_ANY, layoutreturn4(LAYOUTRETURN4_FILE, layoutreturn_file4(0, 0xffffffffffffffff, layout_stateid, "")))] res = sess.compound(ops) check(res)
def testReadWrite(t, env): """Do a simple READ and WRITE FLAGS: open all CODE: OPEN400 """ c1 = env.c1.new_client(env.testname(t)) sess1 = c1.create_session() owner = open_owner4(0, "My Open Owner") how = openflag4(OPEN4_CREATE, createhow4(GUARDED4, {FATTR4_SIZE:0})) claim = open_claim4(CLAIM_NULL, env.testname(t)) open_op = op.open(0, OPEN4_SHARE_ACCESS_BOTH , OPEN4_SHARE_DENY_NONE, owner, how, claim) fh_op = op.putrootfh() res = sess1.compound([fh_op, open_op, op.getfh()]) # OPEN print res check(res) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid stateid.seqid = 0 res = sess1.compound([op.putfh(fh), op.write(stateid, 5, FILE_SYNC4, "write test data")]) print res check(res) res = sess1.compound([op.putfh(fh), op.read(stateid, 0, 1000)]) print res check(res)
def testRepTooBig(t, env): """If requester sends a request for which the size of the reply would exceed ca_maxresponsesize, the replier will return NFS4ERR_REP_TOO_BIG FLAGS: create_session all CODE: CSESS26 """ name = env.testname(t) c1 = env.c1.new_client(name) # create session with a small ca_maxresponsesize chan_attrs = channel_attrs4(0,8192,500,8192,128,8,[]) sess1 = c1.create_session(fore_attrs=chan_attrs) sess1.compound([op.reclaim_complete(FALSE)]) owner = "owner_%s" % name path = sess1.c.homedir + [name] res = create_file(sess1, owner, path, access=OPEN4_SHARE_ACCESS_BOTH) check(res) # write some data to file fh = res.resarray[-1].object stateid = res.resarray[-2].stateid res = sess1.compound([op.putfh(fh), op.write(stateid, 5, FILE_SYNC4, "write test data " * 10)]) check(res) # read data rather than ca_maxresponsesize res = sess1.compound([op.putfh(fh), op.read(stateid, 0, 500)]) check(res, NFS4ERR_REP_TOO_BIG)
def testOPENClaimFH(t, env): """OPEN file with claim_type is CLAIM_FH FLAGS: open all CODE: OPEN7 """ sess1 = env.c1.new_client_session(env.testname(t)) res = create_file(sess1, env.testname(t)) check(res) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid res = close_file(sess1, fh, stateid=stateid) check(res) claim = open_claim4(CLAIM_FH) how = openflag4(OPEN4_NOCREATE) oowner = open_owner4(0, "My Open Owner 2") open_op = op.open(0, OPEN4_SHARE_ACCESS_BOTH, OPEN4_SHARE_DENY_NONE, oowner, how, claim) res = sess1.compound([op.putfh(fh), open_op]) check(res) stateid = res.resarray[-1].stateid stateid.seqid = 0 data = "write test data" res = sess1.compound([op.putfh(fh), op.write(stateid, 5, FILE_SYNC4, data)]) check(res) res = sess1.compound([op.putfh(fh), op.read(stateid, 0, 1000)]) check(res) if not res.resarray[-1].eof: fail("EOF not set on read") desired = "\0"*5 + data if res.resarray[-1].data != desired: fail("Expected %r, got %r" % (desired, res.resarray[-1].data))
def testReadWrite(t, env): """Do a simple READ and WRITE FLAGS: open all CODE: OPEN30 """ c1 = env.c1.new_client(env.testname(t)) sess1 = c1.create_session() owner = open_owner4(0, "My Open Owner") res = create_file(sess1, env.testname(t)) check(res) expect(res, seqid=1) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid stateid.seqid = 0 data = "write test data" res = sess1.compound( [op.putfh(fh), op.write(stateid, 5, FILE_SYNC4, data)]) check(res) res = sess1.compound([op.putfh(fh), op.read(stateid, 0, 1000)]) check(res) if not res.resarray[-1].eof: fail("EOF not set on read") desired = "\0" * 5 + data if res.resarray[-1].data != desired: fail("Expected %r, got %r" % (desired, res.resarray[-1].data))
def rename_obj(sess, oldpath, newpath): olddir = lookup_obj(sess, oldpath[:-1]) newdir = lookup_obj(sess, newpath[:-1]) ops = [op.putfh(olddir), op.savefh()] ops += [op.putfh(newdir)] ops += [op.rename(oldpath[-1], newpath[-1])] return sess.compound(ops)
def testStateid2(t, env): """Check for proper sequence handling in layout stateids. FLAGS: block CODE: BLOCK2 """ c1 = env.c1.new_client_session(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) # Create the file res = create_file(sess, env.testname(t)) check(res) # Get layout 1 fh = res.resarray[-1].object open_stateid = res.resarray[-2].stateid print open_stateid ops = [op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 0, 8192, 8192, open_stateid, 0xffff)] res = sess.compound(ops) check(res) # Get layout 2 lo_stateid1 = res.resarray[-1].logr_stateid print lo_stateid1 ops = [op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 8192, 8192, 8192, lo_stateid1, 0xffff)] res = sess.compound(ops) check(res) # Get layout 3 (merge of prior two) lo_stateid2 = res.resarray[-1].logr_stateid print lo_stateid2 ops = [op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 0, 2*8192, 2*8192, lo_stateid2, 0xffff)] res = sess.compound(ops) check(res) lo_stateid3 = res.resarray[-1].logr_stateid print lo_stateid3 # lo_stateid3.seqid = 3 # BUG - work around emc problem # Parse opaque to get info for commit # STUB not very general layout = res.resarray[-1].logr_layout[-1] p = BlockUnpacker(layout.loc_body) opaque = p.unpack_pnfs_block_layout4() p.done() extent = opaque.blo_extents[-1] extent.bex_state = PNFS_BLOCK_READWRITE_DATA p = BlockPacker() p.pack_pnfs_block_layoutupdate4(pnfs_block_layoutupdate4([extent])) time = newtime4(True, get_nfstime()) ops = [op.putfh(fh), op.layoutcommit(extent.bex_file_offset, extent.bex_length, False, lo_stateid3, newoffset4(True, 2 * 8192 - 1), time, layoutupdate4(LAYOUT4_BLOCK_VOLUME, p.get_buffer()))] res = sess.compound(ops) check(res)
def _testDeleg(t, env, openaccess, want, breakaccess, sec = None, sec2 = None): recall = threading.Event() def pre_hook(arg, env): recall.stateid = arg.stateid # NOTE this must be done before set() recall.cred = env.cred.raw_cred env.notify = recall.set # This is called after compound sent to queue def post_hook(arg, env, res): return res sess1 = env.c1.new_client_session("%s_1" % env.testname(t), sec = sec) sess1.client.cb_pre_hook(OP_CB_RECALL, pre_hook) sess1.client.cb_post_hook(OP_CB_RECALL, post_hook) if sec2: sess1.compound([op.backchannel_ctl(env.c1.prog, sec2)]) fh = _create_file_with_deleg(sess1, env.testname(t), openaccess | want) sess2 = env.c1.new_client_session("%s_2" % env.testname(t)) claim = open_claim4(CLAIM_NULL, env.testname(t)) owner = open_owner4(0, "My Open Owner 2") how = openflag4(OPEN4_NOCREATE) open_op = op.open(0, breakaccess, OPEN4_SHARE_DENY_NONE, owner, how, claim) slot = sess2.compound_async(env.home + [open_op]) # Wait for recall, and return delegation recall.wait() # STUB - deal with timeout # Getting here means CB_RECALL reply is in the send queue. # Give it a moment to actually be sent env.sleep(.1) res = sess1.compound([op.putfh(fh), op.delegreturn(recall.stateid)]) check(res) # Now get OPEN reply res = sess2.listen(slot) checklist(res, [NFS4_OK, NFS4ERR_DELAY]) return recall
def testLayout(t, env): """Verify layout handling FLAGS: layout all CODE: LAYOUT1 """ # Make sure E_ID returns MDS capabilities c1 = env.c1.new_client(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) if not c1.flags & EXCHGID4_FLAG_USE_PNFS_MDS: fail("Server can not be used as pnfs metadata server") sess = c1.create_session() # Test that fs handles block layouts ops = use_obj(env.opts.path) + [op.getattr(1 << FATTR4_FS_LAYOUT_TYPE)] res = sess.compound(ops) check(res) if FATTR4_FS_LAYOUT_TYPE not in res.resarray[-1].obj_attributes: fail("fs_layout_type not available") if LAYOUT4_BLOCK_VOLUME not in res.resarray[-1].obj_attributes[ FATTR4_FS_LAYOUT_TYPE]: fail("layout_type does not contain BLOCK") # Open the file owner = "owner for %s" % env.testname(t) # openres = open_file(sess, owner, env.opts.path + ["simple_extent"]) openres = open_file(sess, owner, env.opts.path + ["hole_between_extents"]) check(openres) # Get a layout fh = openres.resarray[-1].object ops = [ op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_READ, 0, 0xffffffff, 0, 0xffff) ] res = sess.compound(ops) check(res)
def ops(i): return [ op.putfh(fh), op.write(stateid, i * 1000, UNSTABLE4, chr(97 + i) * 100), op.getattr(42950721818L) ]
def open_file( sess, owner, path=None, access=OPEN4_SHARE_ACCESS_READ, deny=OPEN4_SHARE_DENY_NONE, claim_type=CLAIM_NULL, want_deleg=False, deleg_type=None, # Setting the following should induce server errors seqid=0, clientid=0): # Set defaults if path is None: dir = sess.c.homedir name = owner else: dir = path[:-1] name = path[-1] if not want_deleg and access & OPEN4_SHARE_ACCESS_WANT_DELEG_MASK == 0: access |= OPEN4_SHARE_ACCESS_WANT_NO_DELEG # Open the file if claim_type == CLAIM_NULL: fh_op = use_obj(dir) elif claim_type == CLAIM_PREVIOUS: fh_op = [op.putfh(path)] name = None if not want_deleg and access & OPEN4_SHARE_ACCESS_WANT_DELEG_MASK == 0: access |= OPEN4_SHARE_ACCESS_WANT_NO_DELEG open_op = op.open(seqid, access, deny, open_owner4(clientid, owner), openflag4(OPEN4_NOCREATE), open_claim4(claim_type, name, deleg_type)) return sess.compound(fh_op + [open_op, op.getfh()])
def testSupported2(t, env): """GETFH after do a SECINFO_NO_NAME or SECINFO result in a NOFILEHANDLE error, See rfc 5661 section 2.6.3.1.1.8 FLAGS: all CODE: SEC2 """ name = env.testname(t) c = env.c1.new_client(env.testname(t)) sess = c.create_session() # Create a tmpfile for testing owner = "owner_%s" % name path = sess.c.homedir + [name] res = create_file(sess, owner, path, access=OPEN4_SHARE_ACCESS_WRITE) check(res) # Get the filehandle of the tmpfile's parent dir res = sess.compound(use_obj(sess.c.homedir) + [op.getfh()]) check(res) fh = res.resarray[-1].object # GETFH after do a SECINFO should get error NFS4ERR_NOFILEHANDLE res = sess.compound([op.putfh(fh), op.secinfo(name), op.getfh()]) check(res, NFS4ERR_NOFILEHANDLE)
def testLockWriteLocku(t, env): """test current state id processing by having LOCK, WRITE and LOCKU in a single compound FLAGS: currentstateid all CODE: CSID4 """ sess1 = env.c1.new_client_session(env.testname(t)) res = create_file(sess1, env.testname(t)) check(res) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid data = "write test data" open_to_lock_owner = open_to_lock_owner4(0, stateid, 0, lock_owner4(0, "lock1")) lock_owner = locker4(open_owner=open_to_lock_owner, new_lock_owner=True) lock_ops = [ op.lock(WRITE_LT, False, 0, NFS4_UINT64_MAX, lock_owner), op.write(current_stateid, 5, FILE_SYNC4, data), op.locku(WRITE_LT, 0, current_stateid, 0, NFS4_UINT64_MAX), op.close(0, stateid) ] res = sess1.compound([op.putfh(fh)] + lock_ops) check(res, NFS4_OK)
def testLayoutReturnFsid(t, env): """ Return all of a filesystem's layouts FLAGS: layoutreturn all DEPEND: GETLAYOUT1 CODE: LAYOUTRET2 """ # Make sure E_ID returns MDS capabilities c1 = env.c1.new_client(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) if not c1.flags & EXCHGID4_FLAG_USE_PNFS_MDS: fail("Server can not be used as pnfs metadata server") sess = c1.create_session() print sess.c.homedir # Create the file res = create_file(sess, env.testname(t)) check(res) # Get layout fh = res.resarray[-1].object open_stateid = res.resarray[-2].stateid ops = [ op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_READ, 0, 0xffffffffffffffff, 0, open_stateid, 0xffff) ] res = sess.compound(ops) check(res) # Return layout ops = use_obj(env.opts.path) + \ [op.layoutreturn(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_ANY, layoutreturn4(LAYOUTRETURN4_FSID))] res = sess.compound(ops) check(res)
def xtestClientStateSeqid(t, env): """Verify server enforce that client stateid.seqid==0 See 8.1.3.1(draft-10): The client must...set the sequence value to zero. FLAGS: open all CODE: OPEN3 """ name = env.testname(t) c1 = env.c1.new_client(name) sess1 = c1.create_session() owner = "owner_%s" % name path = sess1.c.homedir + [name] res = create_file(sess1, owner, path, access=OPEN4_SHARE_ACCESS_WRITE) check(res) expect(res, seqid=1) # Now use returned stateid (w/o zeroing seqid) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid res = sess1.compound( [op.putfh(fh), op.write(stateid, 5, FILE_SYNC4, "write test data")]) check(res, NFS4ERR_BAD_STATEID, "Using an open_stateid w/o zeroing the seqid")
def _testDeleg(t, env, openaccess, want, breakaccess, sec=None, sec2=None): recall = threading.Event() def pre_hook(arg, env): recall.stateid = arg.stateid # NOTE this must be done before set() recall.cred = env.cred.raw_cred env.notify = recall.set # This is called after compound sent to queue def post_hook(arg, env, res): return res sess1 = env.c1.new_client_session("%s_1" % env.testname(t), sec=sec) sess1.client.cb_pre_hook(OP_CB_RECALL, pre_hook) sess1.client.cb_post_hook(OP_CB_RECALL, post_hook) if sec2: sess1.compound([op.backchannel_ctl(env.c1.prog, sec2)]) fh = _create_file_with_deleg(sess1, env.testname(t), openaccess | want) sess2 = env.c1.new_client_session("%s_2" % env.testname(t)) claim = open_claim4(CLAIM_NULL, env.testname(t)) owner = open_owner4(0, "My Open Owner 2") how = openflag4(OPEN4_NOCREATE) open_op = op.open(0, breakaccess, OPEN4_SHARE_DENY_NONE, owner, how, claim) slot = sess2.compound_async(env.home + [open_op]) # Wait for recall, and return delegation recall.wait() # STUB - deal with timeout # Getting here means CB_RECALL reply is in the send queue. # Give it a moment to actually be sent env.sleep(.1) res = sess1.compound([op.putfh(fh), op.delegreturn(recall.stateid)]) check(res) # Now get OPEN reply res = sess2.listen(slot) checklist(res, [NFS4_OK, NFS4ERR_DELAY]) return recall
def testLayout(t, env): """Verify layout handling FLAGS: layout all CODE: LAYOUT1 """ # Make sure E_ID returns MDS capabilities c1 = env.c1.new_client(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) if not c1.flags & EXCHGID4_FLAG_USE_PNFS_MDS: fail("Server can not be used as pnfs metadata server") sess = c1.create_session() # Test that fs handles block layouts ops = use_obj(env.opts.path) + [op.getattr(1<<FATTR4_FS_LAYOUT_TYPE)] res = sess.compound(ops) check(res) if FATTR4_FS_LAYOUT_TYPE not in res.resarray[-1].obj_attributes: fail("fs_layout_type not available") if LAYOUT4_BLOCK_VOLUME not in res.resarray[-1].obj_attributes[FATTR4_FS_LAYOUT_TYPE]: fail("layout_type does not contain BLOCK") # Open the file owner = "owner for %s" % env.testname(t) # openres = open_file(sess, owner, env.opts.path + ["simple_extent"]) openres = open_file(sess, owner, env.opts.path + ["hole_between_extents"]) check(openres) # Get a layout fh = openres.resarray[-1].object ops = [op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_READ, 0, 0xffffffff, 0, 0xffff)] res = sess.compound(ops) check(res)
def testSplitCommit(t, env): """Check for proper handling of disjoint LAYOUTCOMMIT.opaque FLAGS: block CODE: BLOCK4 """ sess = env.c1.new_client_session(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) # Create the file res = create_file(sess, env.testname(t)) check(res) # Get layout 1 fh = res.resarray[-1].object open_stateid = res.resarray[-2].stateid print open_stateid ops = [ op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 0, 2 * 8192, 2 * 8192, open_stateid, 0xffff) ] res = sess.compound(ops) check(res) lo_stateid1 = res.resarray[-1].logr_stateid print lo_stateid1 # Parse opaque to get info for commit # STUB not very general layout = res.resarray[-1].logr_layout[-1] p = BlockUnpacker(layout.loc_body) opaque = p.unpack_pnfs_block_layout4() p.done() dev = opaque.blo_extents[-1].bex_vol_id extent1 = pnfs_block_extent4(dev, 0, 8192, 0, PNFS_BLOCK_READWRITE_DATA) extent2 = pnfs_block_extent4(dev, 8192, 8192, 0, PNFS_BLOCK_READWRITE_DATA) p = BlockPacker() p.pack_pnfs_block_layoutupdate4( pnfs_block_layoutupdate4([extent1, extent2])) time = newtime4(True, get_nfstime()) ops = [ op.putfh(fh), op.layoutcommit(0, 2 * 8192, False, lo_stateid1, newoffset4(True, 2 * 8192 - 1), time, layoutupdate4(LAYOUT4_BLOCK_VOLUME, p.get_buffer())) ] res = sess.compound(ops) check(res)
def use_obj(file): """File is either None, a fh, or a list of path components""" if file is None or file == [None]: return [] elif type(file) is str: return [op.putfh(file)] else: return [op.putrootfh()] + [op.lookup(comp) for comp in file]
def close_file(self, mds_fh): """close the given file""" seqid=0 #FIXME: seqid must be !=0 fh, stateid = self.filehandles[mds_fh] ops = [op.putfh(fh)] + [op.close(seqid, stateid)] res = self.execute(ops) # ignoring return del self.filehandles[mds_fh]
def testStateid1(t, env): """Check for proper sequence handling in layout stateids. FLAGS: block CODE: BLOCK1 """ sess = env.c1.new_client_session(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) # Create the file res = create_file(sess, env.testname(t)) check(res) # Get layout 1 fh = res.resarray[-1].object open_stateid = res.resarray[-2].stateid print open_stateid ops = [ op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 0, 8192, 8192, open_stateid, 0xffff) ] res = sess.compound(ops) check(res) lo_stateid = res.resarray[-1].logr_stateid print lo_stateid if lo_stateid.seqid != 1: # From draft23 12.5.2 "The first successful LAYOUTGET processed by # the server using a non-layout stateid as an argument MUST have the # "seqid" field of the layout stateid in the response set to one." fail("Expected stateid.seqid==1, got %i" % lo_stateid.seqid) for i in range(6): # Get subsequent layouts ops = [ op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, (i + 1) * 8192, 8192, 8192, lo_stateid, 0xffff) ] res = sess.compound(ops) check(res) lo_stateid = res.resarray[-1].logr_stateid print lo_stateid if lo_stateid.seqid != i + 2: # From draft23 12.5.3 "After the layout stateid is established, # the server increments by one the value of the "seqid" in each # subsequent LAYOUTGET and LAYOUTRETURN response, fail("Expected stateid.seqid==%i, got %i" % (i + 2, lo_stateid.seqid))
def close_file(self, mds_fh): """close the given file""" seqid = 0 #FIXME: seqid must be !=0 fh, stateid = self.filehandles[mds_fh] ops = [op.putfh(fh)] + [op.close(seqid, stateid)] res = self.execute(ops) # ignoring return del self.filehandles[mds_fh]
def testSplitCommit(t, env): """Check for proper handling of disjoint LAYOUTCOMMIT.opaque FLAGS: block CODE: BLOCK4 """ sess = env.c1.new_client_session(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) # Create the file res = create_file(sess, env.testname(t)) check(res) # Get layout 1 fh = res.resarray[-1].object open_stateid = res.resarray[-2].stateid print open_stateid ops = [op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 0, 2*8192, 2*8192, open_stateid, 0xffff)] res = sess.compound(ops) check(res) lo_stateid1 = res.resarray[-1].logr_stateid print lo_stateid1 # Parse opaque to get info for commit # STUB not very general layout = res.resarray[-1].logr_layout[-1] p = BlockUnpacker(layout.loc_body) opaque = p.unpack_pnfs_block_layout4() p.done() dev = opaque.blo_extents[-1].bex_vol_id extent1 = pnfs_block_extent4(dev, 0, 8192, 0, PNFS_BLOCK_READWRITE_DATA) extent2 = pnfs_block_extent4(dev, 8192, 8192, 0, PNFS_BLOCK_READWRITE_DATA) p = BlockPacker() p.pack_pnfs_block_layoutupdate4(pnfs_block_layoutupdate4([extent1, extent2])) time = newtime4(True, get_nfstime()) ops = [op.putfh(fh), op.layoutcommit(0, 2*8192, False, lo_stateid1, newoffset4(True, 2 * 8192 - 1), time, layoutupdate4(LAYOUT4_BLOCK_VOLUME, p.get_buffer()))] res = sess.compound(ops) check(res)
def close_file(sess, fh, stateid, seqid=0): """close the given file""" if fh is None: ops = [] else: ops = [op.putfh(fh)] ops += [op.close(seqid, stateid)] res = sess.compound(ops) return res
def testBadHandle(t, env): """PUTFH with bad filehandle should return NFS4ERR_BADHANDLE FLAGS: putfh all CODE: PUTFH2 """ c = env.c1.new_client(env.testname(t)) sess = c.create_session() res = sess.compound([op.putfh('abc')]) check(res, NFS4ERR_BADHANDLE, "PUTFH with bad filehandle='abc'")
def _try_put(t, sess, path): # Get fh via LOOKUP res = sess.compound(use_obj(path) + [op.getfh()]) check(res) oldfh = res.resarray[-1].object # Now try PUTFH and GETFH, see if it agrees res = sess.compound([op.putfh(oldfh), op.getfh()]) check(res) newfh = res.resarray[-1].object if oldfh != newfh: t.fail("GETFH did not return input of PUTFH for /%s" % '/'.join(path))
def testStateid1(t, env): """Check for proper sequence handling in layout stateids. FLAGS: block CODE: BLOCK1 """ sess = env.c1.new_client_session(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) # Create the file res = create_file(sess, env.testname(t)) check(res) # Get layout 1 fh = res.resarray[-1].object open_stateid = res.resarray[-2].stateid print open_stateid ops = [op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 0, 8192, 8192, open_stateid, 0xffff)] res = sess.compound(ops) check(res) lo_stateid = res.resarray[-1].logr_stateid print lo_stateid if lo_stateid.seqid != 1: # From draft23 12.5.2 "The first successful LAYOUTGET processed by # the server using a non-layout stateid as an argument MUST have the # "seqid" field of the layout stateid in the response set to one." fail("Expected stateid.seqid==1, got %i" % lo_stateid.seqid) for i in range(6): # Get subsequent layouts ops = [op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, (i+1)*8192, 8192, 8192, lo_stateid, 0xffff)] res = sess.compound(ops) check(res) lo_stateid = res.resarray[-1].logr_stateid print lo_stateid if lo_stateid.seqid != i + 2: # From draft23 12.5.3 "After the layout stateid is established, # the server increments by one the value of the "seqid" in each # subsequent LAYOUTGET and LAYOUTRETURN response, fail("Expected stateid.seqid==%i, got %i" % (i+2, lo_stateid.seqid))
def testLookuppRoot(t, env): """Lookupp from root should return NFS4ERR_NOENT FLAGS: lookupp all CODE: LKPP2 """ c1 = env.c1.new_client(env.testname(t)) sess1 = c1.create_session() res = sess1.compound([op.putrootfh(), op.getfh()]) check(res) fh = res.resarray[-1].object res = sess1.compound([op.putfh(fh), op.lookupp()]) check(res, NFS4ERR_NOENT)
def testReadWrite(t, env): """Do a simple READ and WRITE FLAGS: open all CODE: OPEN30 """ sess1 = env.c1.new_client_session(env.testname(t)) owner = open_owner4(0, "My Open Owner") res = create_file(sess1, env.testname(t)) check(res) expect(res, seqid=1) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid stateid.seqid = 0 data = "write test data" res = sess1.compound([op.putfh(fh), op.write(stateid, 5, FILE_SYNC4, data)]) check(res) res = sess1.compound([op.putfh(fh), op.read(stateid, 0, 1000)]) check(res) if not res.resarray[-1].eof: fail("EOF not set on read") desired = "\0"*5 + data if res.resarray[-1].data != desired: fail("Expected %r, got %r" % (desired, res.resarray[-1].data))
def testOPENClaimFH(t, env): """OPEN file with claim_type is CLAIM_FH FLAGS: open all CODE: OPEN7 """ sess1 = env.c1.new_client_session(env.testname(t)) res = create_file(sess1, env.testname(t)) check(res) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid res = close_file(sess1, fh, stateid=stateid) check(res) claim = open_claim4(CLAIM_FH) how = openflag4(OPEN4_NOCREATE) oowner = open_owner4(0, "My Open Owner 2") open_op = op.open(0, OPEN4_SHARE_ACCESS_BOTH, OPEN4_SHARE_DENY_NONE, oowner, how, claim) res = sess1.compound([op.putfh(fh), open_op]) check(res) stateid = res.resarray[-1].stateid stateid.seqid = 0 data = "write test data" res = sess1.compound( [op.putfh(fh), op.write(stateid, 5, FILE_SYNC4, data)]) check(res) res = sess1.compound([op.putfh(fh), op.read(stateid, 0, 1000)]) check(res) if not res.resarray[-1].eof: fail("EOF not set on read") desired = "\0" * 5 + data if res.resarray[-1].data != desired: fail("Expected %r, got %r" % (desired, res.resarray[-1].data))
def open_create_file_op(sess, owner, path=None, attrs={FATTR4_MODE: 0644}, access=OPEN4_SHARE_ACCESS_BOTH, deny=OPEN4_SHARE_DENY_NONE, mode=GUARDED4, verifier=None, claim_type=CLAIM_NULL, want_deleg=False, deleg_type=None, open_create=OPEN4_NOCREATE, seqid=0, clientid=0): # Set defaults if path is None: dir = sess.c.homedir name = owner else: dir = path[:-1] name = path[-1] if ((mode == EXCLUSIVE4) or (mode == EXCLUSIVE4_1)) and (verifier == None): verifier = sess.c.verifier if not want_deleg and access & OPEN4_SHARE_ACCESS_WANT_DELEG_MASK == 0: access |= OPEN4_SHARE_ACCESS_WANT_NO_DELEG # Open the file if claim_type == CLAIM_NULL: fh_op = use_obj(dir) elif claim_type == CLAIM_PREVIOUS: fh_op = [op.putfh(path)] name = None if open_create == OPEN4_CREATE: openflag = openflag4( OPEN4_CREATE, createhow4(mode, attrs, verifier, creatverfattr(verifier, attrs))) openclaim = open_claim4(CLAIM_NULL, name) else: openflag = openflag4(OPEN4_NOCREATE) openclaim = open_claim4(claim_type, name, deleg_type) open_op = op.open(seqid, access, deny, open_owner4(clientid, owner), openflag, openclaim) return fh_op + [open_op, op.getfh()]
def testReadDeleg(t, env): """Test read delgation handout and return FLAGS: open all CODE: OPEN20 """ recall = threading.Event() def pre_hook(arg, env): recall.stateid = arg.stateid # NOTE this must be done before set() env.notify = recall.set # This is called after compound sent to queue def post_hook(arg, env, res): return res # c1 - OPEN - READ c1 = env.c1.new_client("%s_1" % env.testname(t)) c1.cb_pre_hook(OP_CB_RECALL, pre_hook) c1.cb_post_hook(OP_CB_RECALL, post_hook) sess1 = c1.create_session() res = create_file(sess1, env.testname(t), access=OPEN4_SHARE_ACCESS_READ | OPEN4_SHARE_ACCESS_WANT_READ_DELEG) check(res) fh = res.resarray[-1].object deleg = res.resarray[-2].delegation if deleg.delegation_type == OPEN_DELEGATE_NONE: fail("Could not get delegation") # c2 - OPEN - WRITE c2 = env.c1.new_client("%s_2" % env.testname(t)) sess2 = c2.create_session() claim = open_claim4(CLAIM_NULL, env.testname(t)) owner = open_owner4(0, "My Open Owner 2") how = openflag4(OPEN4_NOCREATE) open_op = op.open(0, OPEN4_SHARE_ACCESS_BOTH, OPEN4_SHARE_DENY_NONE, owner, how, claim) slot = sess2.compound_async(env.home + [open_op]) # Wait for recall, and return delegation recall.wait() # STUB - deal with timeout # Getting here means CB_RECALL reply is in the send queue. # Give it a moment to actually be sent env.sleep(1) res = sess1.compound([op.putfh(fh), op.delegreturn(recall.stateid)]) check(res) # Now get OPEN reply res = sess2.listen(slot) checklist(res, [NFS4_OK, NFS4ERR_DELAY])
def testCloseNoStateid(t, env): """test current state id processing by having CLOSE without operation which provides stateid FLAGS: currentstateid all CODE: CSID6 """ sess1 = env.c1.new_client_session(env.testname(t)) res = create_file(sess1, env.testname(t)) check(res) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid res = sess1.compound([op.putfh(fh), op.close(0, current_stateid)]) checklist(res, [NFS4ERR_STALE_STATEID, NFS4ERR_BAD_STATEID])
def testOpenSaveFHLookupRestoreFHClose(t, env): """test current state id processing by having OPEN, SAVEFH, LOOKUP, RESTOREFH and CLOSE in a single compound FLAGS: currentstateid all CODE: CSID10 """ sess1 = env.c1.new_client_session(env.testname(t)) fname = env.testname(t) open_op = open_create_file_op(sess1, fname, open_create=OPEN4_CREATE) lookup_op = env.home res = sess1.compound(lookup_op + [op.getfh()]) check(res) fh = res.resarray[-1].object res = sess1.compound(open_op + [op.savefh(), op.putfh(fh), op.restorefh(), op.close(0, current_stateid)]) check(res)
def testEMCGetLayout(t, env): """Verify layout handling Debugging test that looks for pre-existing file (server2fs1/dump.eth) so we don't have to worry about creating a file. FLAGS: CODE: GETLAYOUT100 """ # Make sure E_ID returns MDS capabilities c1 = env.c1.new_client(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) if not c1.flags & EXCHGID4_FLAG_USE_PNFS_MDS: fail("Server can not be used as pnfs metadata server") sess = c1.create_session() # Test that fs handles block layouts ops = use_obj(env.opts.path) + [op.getattr(1 << FATTR4_FS_LAYOUT_TYPE)] res = sess.compound(ops) check(res) if FATTR4_FS_LAYOUT_TYPE not in res.resarray[-1].obj_attributes: fail("fs_layout_type not available") if LAYOUT4_BLOCK_VOLUME not in res.resarray[-1].obj_attributes[ FATTR4_FS_LAYOUT_TYPE]: fail("layout_type does not contain BLOCK") # Create the file file = ["server2fs1", "dump.eth"] res = open_file(sess, env.testname(t), file) check(res) # Get layout fh = res.resarray[-1].object stateid = res.resarray[-2].stateid stateid.seqid = 0 ops = [ op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_READ, 0, 0xffffffffffffffff, 0, stateid, 0xffff) ] res = sess.compound(ops) check(res) # Parse opaque for layout in res.resarray[-1].logr_layout: if layout.loc_type == LAYOUT4_BLOCK_VOLUME: p = BlockUnpacker(layout.loc_body) opaque = p.unpack_pnfs_block_layout4() p.done() print opaque
def testWriteDeleg(t, env): """Test write delgation handout and return FLAGS: open deleg all CODE: DELEG2 """ recall = threading.Event() def pre_hook(arg, env): recall.stateid = arg.stateid # NOTE this must be done before set() env.notify = recall.set # This is called after compound sent to queue def post_hook(arg, env, res): return res # c1 - OPEN - WRITE c1 = env.c1.new_client("%s_1" % env.testname(t)) c1.cb_pre_hook(OP_CB_RECALL, pre_hook) c1.cb_post_hook(OP_CB_RECALL, post_hook) sess1 = c1.create_session() sess1.compound([op.reclaim_complete(FALSE)]) res = create_file(sess1, env.testname(t), access=OPEN4_SHARE_ACCESS_BOTH | OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG) check(res) fh = res.resarray[-1].object deleg = res.resarray[-2].delegation if deleg.delegation_type == OPEN_DELEGATE_NONE or deleg.delegation_type == OPEN_DELEGATE_NONE_EXT: fail("Could not get delegation") # c2 - OPEN - READ sess2 = env.c1.new_client_session("%s_2" % env.testname(t)) claim = open_claim4(CLAIM_NULL, env.testname(t)) owner = open_owner4(0, "My Open Owner 2") how = openflag4(OPEN4_NOCREATE) open_op = op.open(0, OPEN4_SHARE_ACCESS_READ, OPEN4_SHARE_DENY_NONE, owner, how, claim) slot = sess2.compound_async(env.home + [open_op]) # Wait for recall, and return delegation recall.wait() # STUB - deal with timeout # Getting here means CB_RECALL reply is in the send queue. # Give it a moment to actually be sent env.sleep(1) res = sess1.compound([op.putfh(fh), op.delegreturn(recall.stateid)]) check(res) # Now get OPEN reply res = sess2.listen(slot) checklist(res, [NFS4_OK, NFS4ERR_DELAY])
def _maketree(self, sess): """Make test tree""" # ensure /tmp (and path leading up) exists path = [] for comp in self.opts.home: path.append(comp) res = sess.compound(use_obj(path)) checklist(res, [NFS4_OK, NFS4ERR_NOENT], "LOOKUP /%s," % '/'.join(path)) if res.status == NFS4ERR_NOENT: res = create_obj(sess, path, NF4DIR) check(res, msg="Trying to create /%s," % '/'.join(path)) # ensure /tree exists and is empty tree = self.opts.path + ['tree'] res = sess.compound(use_obj(tree)) checklist(res, [NFS4_OK, NFS4ERR_NOENT]) if res.status == NFS4ERR_NOENT: res = create_obj(sess, tree, NF4DIR) check(res, msg="Trying to create /%s," % '/'.join(tree)) else: clean_dir(sess, tree) # make non-file objects in /tree d = { 'dir': NF4DIR, 'socket': NF4SOCK, 'fifo': NF4FIFO, 'link': createtype4(NF4LNK, linkdata=self.linkdata), 'block': createtype4(NF4BLK, devdata=specdata4(1, 2)), 'char': createtype4(NF4CHR, devdata=specdata4(1, 2)), } for name, kind in d.items(): path = tree + [name] res = create_obj(sess, path, kind) if res.status != NFS4_OK: log.warning("could not create /%s" % '/'.join(path)) # Make file-object in /tree fh, stateid = create_confirm(sess, 'maketree', tree + ['file']) stateid.seqid = 0 ops = [op.putfh(fh), op.write(stateid, 0, FILE_SYNC4, self.filedata)] res = sess.compound(ops) check(res, msg="Writing data to /%s/file" % '/'.join(tree)) res = close_file(sess, fh, stateid) check(res)
def _maketree(self, sess): """Make test tree""" # ensure /tmp (and path leading up) exists path = [] for comp in self.opts.home: path.append(comp) res = sess.compound(use_obj(path)) checklist(res, [NFS4_OK, NFS4ERR_NOENT], "LOOKUP /%s," % '/'.join(path)) if res.status == NFS4ERR_NOENT: res = create_obj(sess, path, NF4DIR) check(res, msg="Trying to create /%s," % '/'.join(path)) # ensure /tree exists and is empty tree = self.opts.path + ['tree'] res = sess.compound(use_obj(tree)) checklist(res, [NFS4_OK, NFS4ERR_NOENT]) if res.status == NFS4ERR_NOENT: res = create_obj(sess, tree, NF4DIR) check(res, msg="Trying to create /%s," % '/'.join(tree)) else: clean_dir(sess, tree) # make non-file objects in /tree d = {'dir': NF4DIR, 'socket': NF4SOCK, 'fifo': NF4FIFO, 'link': createtype4(NF4LNK, linkdata=self.linkdata), 'block': createtype4(NF4BLK, devdata=specdata4(1, 2)), 'char': createtype4(NF4CHR, devdata=specdata4(1, 2)), } for name, kind in d.items(): path = tree + [name] res = create_obj(sess, path, kind) if res.status != NFS4_OK: log.warning("could not create /%s" % '/'.join(path)) # Make file-object in /tree fh, stateid = create_confirm(sess, 'maketree', tree + ['file']) ops = [op.putfh(fh), op.write(stateid, 0, FILE_SYNC4, self.filedata)] res = sess.compound(ops) check(res, msg="Writing data to /%s/file" % '/'.join(tree)) res = close_file(sess, fh, stateid) check(res)
def testEMCGetLayout(t, env): """Verify layout handling Debugging test that looks for pre-existing file (server2fs1/dump.eth) so we don't have to worry about creating a file. FLAGS: CODE: GETLAYOUT100 """ # Make sure E_ID returns MDS capabilities c1 = env.c1.new_client(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) if not c1.flags & EXCHGID4_FLAG_USE_PNFS_MDS: fail("Server can not be used as pnfs metadata server") sess = c1.create_session() # Test that fs handles block layouts ops = use_obj(env.opts.path) + [op.getattr(1<<FATTR4_FS_LAYOUT_TYPE)] res = sess.compound(ops) check(res) if FATTR4_FS_LAYOUT_TYPE not in res.resarray[-1].obj_attributes: fail("fs_layout_type not available") if LAYOUT4_BLOCK_VOLUME not in res.resarray[-1].obj_attributes[FATTR4_FS_LAYOUT_TYPE]: fail("layout_type does not contain BLOCK") # Create the file file = ["server2fs1", "dump.eth"] res = open_file(sess, env.testname(t), file) check(res) # Get layout fh = res.resarray[-1].object stateid = res.resarray[-2].stateid stateid.seqid = 0 ops = [op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_READ, 0, 0xffffffffffffffff, 0, stateid, 0xffff)] res = sess.compound(ops) check(res) # Parse opaque for layout in res.resarray[-1].logr_layout: if layout.loc_type == LAYOUT4_BLOCK_VOLUME: p = BlockUnpacker(layout.loc_body) opaque = p.unpack_pnfs_block_layout4() p.done() print opaque
def open_create_file_op(sess, owner, path=None, attrs={FATTR4_MODE: 0644}, access=OPEN4_SHARE_ACCESS_BOTH, deny=OPEN4_SHARE_DENY_NONE, mode=GUARDED4, verifier=None, claim_type=CLAIM_NULL, want_deleg=False, deleg_type=None, open_create=OPEN4_NOCREATE, seqid=0, clientid=0): # Set defaults if path is None: dir = sess.c.homedir name = owner else: dir = path[:-1] name = path[-1] if ((mode==EXCLUSIVE4) or (mode==EXCLUSIVE4_1)) and (verifier==None): verifier = sess.c.verifier if not want_deleg and access & OPEN4_SHARE_ACCESS_WANT_DELEG_MASK == 0: access |= OPEN4_SHARE_ACCESS_WANT_NO_DELEG # Open the file if claim_type==CLAIM_NULL: fh_op = use_obj(dir) elif claim_type==CLAIM_PREVIOUS: fh_op = [op.putfh(path)] name = None if open_create==OPEN4_CREATE: openflag=openflag4(OPEN4_CREATE, createhow4(mode, attrs, verifier, creatverfattr(verifier, attrs))) openclaim=open_claim4(CLAIM_NULL, name) else: openflag=openflag4(OPEN4_NOCREATE) openclaim=open_claim4(claim_type, name, deleg_type) open_op = op.open(seqid, access, deny, open_owner4(clientid, owner), openflag, openclaim) return fh_op + [open_op, op.getfh()]
def testLockLockU(t, env): """test current state id processing by having LOCK and LOCKU in a single compound FLAGS: currentstateid all CODE: CSID2 """ sess1 = env.c1.new_client_session(env.testname(t)) res = create_file(sess1, env.testname(t)) check(res) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid open_to_lock_owner = open_to_lock_owner4( 0, stateid, 0, lock_owner4(0, "lock1")) lock_owner = locker4(open_owner=open_to_lock_owner, new_lock_owner=True) lock_ops = [ op.lock(WRITE_LT, False, 0, NFS4_UINT64_MAX, lock_owner), op.locku(WRITE_LT, 0, current_stateid, 0, NFS4_UINT64_MAX) ] res = sess1.compound([op.putfh(fh)] + lock_ops) check(res, NFS4_OK)
def xtestClientStateSeqid(t, env): """Verify server enforce that client stateid.seqid==0 See 8.1.3.1(draft-10): The client must...set the sequence value to zero. FLAGS: open all CODE: OPEN3 """ name = env.testname(t) sess1 = env.c1.new_client_session(name) owner = "owner_%s" % name path = sess1.c.homedir + [name] res = create_file(sess1, owner, path, access=OPEN4_SHARE_ACCESS_WRITE) check(res) expect(res, seqid=1) # Now use returned stateid (w/o zeroing seqid) fh = res.resarray[-1].object stateid = res.resarray[-2].stateid res = sess1.compound([op.putfh(fh), op.write(stateid, 5, FILE_SYNC4, "write test data")]) check(res, NFS4ERR_BAD_STATEID, "Using an open_stateid w/o zeroing the seqid")
def testSupported(t, env): """Do a simple SECINFO FLAGS: all CODE: SEC1 """ name = env.testname(t) sess = env.c1.new_client_session(env.testname(t)) # Create a tmpfile for testing owner = "owner_%s" % name path = sess.c.homedir + [name] res = create_file(sess, owner, path, access=OPEN4_SHARE_ACCESS_WRITE) check(res) # Get the filehandle of the tmpfile's parent dir res = sess.compound(use_obj(sess.c.homedir) + [op.getfh()]) check(res) fh = res.resarray[-1].object # Just do a simple SECINFO res = sess.compound([op.putfh(fh), op.secinfo(name)]) check(res)
def testSupported2(t, env): """GETFH after do a SECINFO_NO_NAME or SECINFO result in a NOFILEHANDLE error, See rfc 5661 section 2.6.3.1.1.8 FLAGS: all CODE: SEC2 """ name = env.testname(t) sess = env.c1.new_client_session(env.testname(t)) # Create a tmpfile for testing owner = "owner_%s" % name path = sess.c.homedir + [name] res = create_file(sess, owner, path, access=OPEN4_SHARE_ACCESS_WRITE) check(res) # Get the filehandle of the tmpfile's parent dir res = sess.compound(use_obj(sess.c.homedir) + [op.getfh()]) check(res) fh = res.resarray[-1].object # GETFH after do a SECINFO should get error NFS4ERR_NOFILEHANDLE res = sess.compound([op.putfh(fh), op.secinfo(name), op.getfh()]) check(res, NFS4ERR_NOFILEHANDLE)
def testStateid2(t, env): """Check for proper sequence handling in layout stateids. FLAGS: block CODE: BLOCK2 """ c1 = env.c1.new_client_session(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) # Create the file res = create_file(sess, env.testname(t)) check(res) # Get layout 1 fh = res.resarray[-1].object open_stateid = res.resarray[-2].stateid print open_stateid ops = [ op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 0, 8192, 8192, open_stateid, 0xffff) ] res = sess.compound(ops) check(res) # Get layout 2 lo_stateid1 = res.resarray[-1].logr_stateid print lo_stateid1 ops = [ op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 8192, 8192, 8192, lo_stateid1, 0xffff) ] res = sess.compound(ops) check(res) # Get layout 3 (merge of prior two) lo_stateid2 = res.resarray[-1].logr_stateid print lo_stateid2 ops = [ op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 0, 2 * 8192, 2 * 8192, lo_stateid2, 0xffff) ] res = sess.compound(ops) check(res) lo_stateid3 = res.resarray[-1].logr_stateid print lo_stateid3 # lo_stateid3.seqid = 3 # BUG - work around emc problem # Parse opaque to get info for commit # STUB not very general layout = res.resarray[-1].logr_layout[-1] p = BlockUnpacker(layout.loc_body) opaque = p.unpack_pnfs_block_layout4() p.done() extent = opaque.blo_extents[-1] extent.bex_state = PNFS_BLOCK_READWRITE_DATA p = BlockPacker() p.pack_pnfs_block_layoutupdate4(pnfs_block_layoutupdate4([extent])) time = newtime4(True, get_nfstime()) ops = [ op.putfh(fh), op.layoutcommit(extent.bex_file_offset, extent.bex_length, False, lo_stateid3, newoffset4(True, 2 * 8192 - 1), time, layoutupdate4(LAYOUT4_BLOCK_VOLUME, p.get_buffer())) ] res = sess.compound(ops) check(res)
def testLayoutCommit(t, env): """ Do some commits FLAGS: pnfs CODE: LAYOUTCOMMIT1 """ # Make sure E_ID returns MDS capabilities c1 = env.c1.new_client(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) if not c1.flags & EXCHGID4_FLAG_USE_PNFS_MDS: fail("Server can not be used as pnfs metadata server") sess = c1.create_session() # Test that fs handles block layouts ops = use_obj(env.opts.path) + [op.getattr(1<<FATTR4_FS_LAYOUT_TYPE | 1<<FATTR4_LAYOUT_BLKSIZE)] res = sess.compound(ops) check(res) attrdict = res.resarray[-1].obj_attributes if FATTR4_FS_LAYOUT_TYPE not in attrdict: fail("fs_layout_type not available") if LAYOUT4_BLOCK_VOLUME not in attrdict[FATTR4_FS_LAYOUT_TYPE]: fail("layout_type does not contain BLOCK") blocksize = attrdict[FATTR4_LAYOUT_BLKSIZE] # Create the file res = create_file(sess, env.testname(t)) check(res) # Get layout fh = res.resarray[-1].object open_stateid = res.resarray[-2].stateid ops = [op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 0, 4*blocksize, 4*blocksize, open_stateid, 0xffff)] res = sess.compound(ops) check(res) layout_stateid = res.resarray[-1].logr_stateid # Parse opaque for layout in res.resarray[-1].logr_layout: if layout.loc_type != LAYOUT4_BLOCK_VOLUME: fail("Did not get Block layout") p = BlockUnpacker(layout.loc_body) opaque = p.unpack_pnfs_block_layout4() p.done() print opaque final_extent = opaque.blo_extents[-1] print final_extent if final_extent.bex_state != PNFS_BLOCK_INVALID_DATA: fail("Expected INVALID_DATA in extent") # LAYOUTCOMMIT final_extent.bex_state = PNFS_BLOCK_READWRITE_DATA p = BlockPacker() p.pack_pnfs_block_layoutupdate4(pnfs_block_layoutupdate4([final_extent])) notime = newtime4(False) ops = [op.putfh(fh), op.layoutcommit(final_extent.bex_file_offset, final_extent.bex_length, False, layout_stateid, newoffset4(True, 4 * blocksize - 1), notime, layoutupdate4(LAYOUT4_BLOCK_VOLUME, p.get_buffer()))] res = sess.compound(ops) check(res) print res
def ops(i): return [op.putfh(fh), op.write(stateid, i*1000, UNSTABLE4, chr(97+i)*100), op.getattr(42950721818L) ]
def testLayoutCommit(t, env): """ Do some commits FLAGS: layoutcommit all CODE: LAYOUTCOMMIT1 """ # Make sure E_ID returns MDS capabilities c1 = env.c1.new_client(env.testname(t), flags=EXCHGID4_FLAG_USE_PNFS_MDS) if not c1.flags & EXCHGID4_FLAG_USE_PNFS_MDS: fail("Server can not be used as pnfs metadata server") sess = c1.create_session() # Test that fs handles block layouts ops = use_obj(env.opts.path) + [ op.getattr(1 << FATTR4_FS_LAYOUT_TYPE | 1 << FATTR4_LAYOUT_BLKSIZE) ] res = sess.compound(ops) check(res) attrdict = res.resarray[-1].obj_attributes if FATTR4_FS_LAYOUT_TYPE not in attrdict: fail("fs_layout_type not available") if LAYOUT4_BLOCK_VOLUME not in attrdict[FATTR4_FS_LAYOUT_TYPE]: fail("layout_type does not contain BLOCK") blocksize = attrdict[FATTR4_LAYOUT_BLKSIZE] # Create the file res = create_file(sess, env.testname(t)) check(res) # Get layout fh = res.resarray[-1].object open_stateid = res.resarray[-2].stateid ops = [ op.putfh(fh), op.layoutget(False, LAYOUT4_BLOCK_VOLUME, LAYOUTIOMODE4_RW, 0, 4 * blocksize, 4 * blocksize, open_stateid, 0xffff) ] res = sess.compound(ops) check(res) layout_stateid = res.resarray[-1].logr_stateid # Parse opaque for layout in res.resarray[-1].logr_layout: if layout.loc_type != LAYOUT4_BLOCK_VOLUME: fail("Did not get Block layout") p = BlockUnpacker(layout.loc_body) opaque = p.unpack_pnfs_block_layout4() p.done() print opaque final_extent = opaque.blo_extents[-1] print final_extent if final_extent.bex_state != PNFS_BLOCK_INVALID_DATA: fail("Expected INVALID_DATA in extent") # LAYOUTCOMMIT final_extent.bex_state = PNFS_BLOCK_READWRITE_DATA p = BlockPacker() p.pack_pnfs_block_layoutupdate4(pnfs_block_layoutupdate4([final_extent])) notime = newtime4(False) ops = [ op.putfh(fh), op.layoutcommit(final_extent.bex_file_offset, final_extent.bex_length, False, layout_stateid, newoffset4(True, 4 * blocksize - 1), notime, layoutupdate4(LAYOUT4_BLOCK_VOLUME, p.get_buffer())) ] res = sess.compound(ops) check(res) print res