Commit 20b7f4e2 authored by Tigran Mkrtchyan's avatar Tigran Mkrtchyan
Browse files

nfsv41: fix expired client session recovery

observed with RHEL 6.2

at some point client sends late SEQUENCE.
Server reply with NFS4ERR_EXPIRED. Client
attempts to establish a new session, but uses
old client id. Due to a bug in recovery procedure
This ends up with EXPIRED as well.
parent 21a41b0c
......@@ -210,8 +210,8 @@ public class NFS4Client {
_isConfirmed = true;
}
public long leaseTime() {
return _cl_time;
public boolean isLeaseValid() {
return (System.currentTimeMillis() - _cl_time) > _leaseTime;
}
/**
......
......@@ -190,22 +190,23 @@ public class OperationEXCHANGE_ID extends AbstractNFSv4Operation {
if (client.isConfirmed()) {
if (client.verifierEquals(verifier) && principal.equals(client.principal())) {
_log.debug("Case 2: Non-Update on Existing Client ID");
if (!client.hasState()) {
client.refreshLeaseTime();
}
} else if (principal.equals(client.principal())) {
_log.debug("case 5: Client Restart");
context.getStateHandler().removeClient(client);
client = context.getStateHandler().createClient(
remoteSocketAddress, localSocketAddress,
clientOwner, _args.opexchange_id.eia_clientowner.co_verifier, principal);
} else {
if ((!client.hasState()) || (System.currentTimeMillis() - client.leaseTime()) > (NFSv4Defaults.NFS4_LEASE_TIME * 1000)) {
_log.debug("case 3a: Client Collision is equivalent to case 1 (the new Owner ID)");
_log.debug("Case 3b: Client Collision");
if ((!client.hasState()) || !client.isLeaseValid()) {
context.getStateHandler().removeClient(client);
client = context.getStateHandler().createClient(
remoteSocketAddress, localSocketAddress,
clientOwner, _args.opexchange_id.eia_clientowner.co_verifier, principal);
} else {
_log.debug("Case 3b: Client Collision");
throw new ChimeraNFSException(nfsstat.NFSERR_CLID_INUSE, "Principal Missmatch");
}
}
......
......@@ -17,9 +17,11 @@
package org.dcache.chimera.nfs.v4;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import org.dcache.chimera.nfs.nfsstat;
import org.dcache.chimera.nfs.v4.client.CreateSessionStub;
import org.dcache.chimera.nfs.v4.client.ExchangeIDStub;
import org.dcache.chimera.nfs.v4.client.SequenceStub;
import org.dcache.chimera.nfs.v4.xdr.*;
import org.junit.Before;
import org.junit.Test;
......@@ -33,7 +35,7 @@ public class OperationEXCHANGE_IDTest {
@Before
public void setUp() {
stateHandler = new NFSv4StateHandler();
stateHandler = new NFSv4StateHandler(2000);
clientId = UUID.randomUUID().toString();
}
......@@ -136,4 +138,46 @@ public class OperationEXCHANGE_IDTest {
result = nfs_resop4.resopFor(nfs_opnum4.OP_EXCHANGE_ID);
AssertNFS.assertNFS(EXCHANGE_ID, context, result, nfsstat.NFS_OK);
}
@Test
public void testResendConfirmedLate() throws Exception {
CompoundContext context;
nfs_resop4 result;
nfs_argop4 exchangeid_args = ExchangeIDStub.normal(domain, name, clientId, 0, state_protect_how4.SP4_NONE);
OperationEXCHANGE_ID EXCHANGE_ID = new OperationEXCHANGE_ID(exchangeid_args, 0);
result = nfs_resop4.resopFor(nfs_opnum4.OP_EXCHANGE_ID);
context = new CompoundContextBuilder()
.withStateHandler(stateHandler)
.withOpCount(1)
.build();
AssertNFS.assertNFS(EXCHANGE_ID, context, result, nfsstat.NFS_OK);
nfs_argop4 cretaesession_args = CreateSessionStub.standard(
result.opexchange_id.eir_resok4.eir_clientid, result.opexchange_id.eir_resok4.eir_sequenceid);
OperationCREATE_SESSION CREATE_SESSION = new OperationCREATE_SESSION(cretaesession_args);
result = nfs_resop4.resopFor(nfs_opnum4.OP_CREATE_SESSION);
context = new CompoundContextBuilder()
.withStateHandler(stateHandler)
.withOpCount(1)
.build();
AssertNFS.assertNFS(CREATE_SESSION, context, result, nfsstat.NFS_OK);
TimeUnit.SECONDS.sleep(3);
nfs_argop4 sequence_args = SequenceStub.generateRequest(false,
result.opcreate_session.csr_resok4.csr_sessionid.value, 0, 0, 0);
OperationSEQUENCE SEQUENCE = new OperationSEQUENCE(sequence_args);
result = nfs_resop4.resopFor(nfs_opnum4.OP_SEQUENCE);
AssertNFS.assertNFS(SEQUENCE, context, result, nfsstat.NFSERR_EXPIRED);
EXCHANGE_ID = new OperationEXCHANGE_ID(exchangeid_args, 0);
result = nfs_resop4.resopFor(nfs_opnum4.OP_EXCHANGE_ID);
AssertNFS.assertNFS(EXCHANGE_ID, context, result, nfsstat.NFS_OK);
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment