From b9b3b00e7601073818a06edd645f6570e02015fa Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Wed, 20 Jul 2011 13:46:36 -0400 Subject: [PATCH] recovery: support for CLAIM_DELEGATE_PREV, DELEGPURGE 10.2.1. Delegation Recovery (re: client restart/lease expiration) A server MAY support claim types of CLAIM_DELEGATE_PREV and CLAIM_DELEG_PREV_FH, and if it does, it MUST NOT remove delegations upon a CREATE_SESSION that confirm a client ID created by EXCHANGE_ID. Instead, the server MUST, for a period of time no less than that of the value of the lease_time attribute, maintain the client's delegations to allow time for the client to send CLAIM_DELEGATE_PREV and/or CLAIM_DELEG_PREV_FH requests. The server that supports CLAIM_DELEGATE_PREV and/or CLAIM_DELEG_PREV_FH MUST support the DELEGPURGE operation. if there's a delegation to reclaim, recover_open_no_grace() now tries CLAIM_DELEGATE_PREV (supported by emc server, but not linux) before falling back to CLAIM_NULL nfs41_client_delegation_recovery() sends DELEGPURGE to indicate that we're finished reclaiming delegations Signed-off-by: Casey Bodley --- daemon/delegation.c | 10 +++++++++- daemon/nfs41_ops.c | 29 +++++++++++++++++++++++++++++ daemon/nfs41_ops.h | 9 +++++++++ daemon/nfs41_xdr.c | 32 +++++++++++++++++++++++++++++++- daemon/recovery.c | 20 ++++++++++++++++++-- 5 files changed, 96 insertions(+), 4 deletions(-) diff --git a/daemon/delegation.c b/daemon/delegation.c index aef688d..c6e39bf 100644 --- a/daemon/delegation.c +++ b/daemon/delegation.c @@ -669,7 +669,15 @@ int nfs41_client_delegation_recovery( } if (status == NFS4ERR_BADSESSION) - break; + goto out; } + + /* use DELEGPURGE to indicate that we're done reclaiming delegations */ + status = nfs41_delegpurge(client->session); + + /* support for DELEGPURGE is optional; ignore any errors but BADSESSION */ + if (status != NFS4ERR_BADSESSION) + status = NFS4_OK; +out: return status; } diff --git a/daemon/nfs41_ops.c b/daemon/nfs41_ops.c index d22ed0a..f723c45 100644 --- a/daemon/nfs41_ops.c +++ b/daemon/nfs41_ops.c @@ -1527,6 +1527,35 @@ out: return status; } +int nfs41_delegpurge( + IN nfs41_session *session) +{ + int status; + nfs41_compound compound; + nfs_argop4 argops[2]; + nfs_resop4 resops[2]; + nfs41_sequence_args sequence_args; + nfs41_sequence_res sequence_res; + nfs41_delegpurge_res dp_res; + + compound_init(&compound, argops, resops, "delegpurge"); + + compound_add_op(&compound, OP_SEQUENCE, &sequence_args, &sequence_res); + status = nfs41_session_sequence(&sequence_args, session, 0); + if (status) + goto out; + + compound_add_op(&compound, OP_DELEGPURGE, NULL, &dp_res); + + status = compound_encode_send_decode(session, &compound, TRUE); + if (status) + goto out; + + compound_error(status = compound.res.status); +out: + return status; +} + int nfs41_delegreturn( IN nfs41_session *session, IN nfs41_path_fh *file, diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h index 16ccbb4..caf4f1d 100644 --- a/daemon/nfs41_ops.h +++ b/daemon/nfs41_ops.h @@ -373,6 +373,12 @@ typedef struct __nfs41_create_res { } nfs41_create_res; +/* OP_DELEGPURGE */ +typedef struct __nfs41_delegpurge_res { + uint32_t status; +} nfs41_delegpurge_res; + + /* OP_DELEGRETURN */ typedef struct __nfs41_delegreturn_args { stateid_arg *stateid; @@ -1152,6 +1158,9 @@ int nfs41_access( OUT uint32_t *supported OPTIONAL, OUT uint32_t *access OPTIONAL); +int nfs41_delegpurge( + IN nfs41_session *session); + int nfs41_delegreturn( IN nfs41_session *session, IN nfs41_path_fh *file, diff --git a/daemon/nfs41_xdr.c b/daemon/nfs41_xdr.c index 239c8ba..63934c2 100644 --- a/daemon/nfs41_xdr.c +++ b/daemon/nfs41_xdr.c @@ -1632,6 +1632,36 @@ static bool_t decode_op_locku( } +/* + * OP_DELEGPURGE + */ +static bool_t encode_op_delegpurge( + XDR *xdr, + nfs_argop4 *argop) +{ + uint64_t zero = 0; + + if (unexpected_op(argop->op, OP_DELEGPURGE)) + return FALSE; + + /* The client SHOULD set the client field to zero, + * and the server MUST ignore the clientid field. */ + return xdr_u_int64_t(xdr, &zero); +} + +static bool_t decode_op_delegpurge( + XDR *xdr, + nfs_resop4 *resop) +{ + nfs41_delegpurge_res *res = (nfs41_delegpurge_res*)resop->res; + + if (unexpected_op(resop->op, OP_DELEGPURGE)) + return FALSE; + + return xdr_u_int32_t(xdr, &res->status); +} + + /* * OP_DELEGRETURN */ @@ -3347,7 +3377,7 @@ static const op_table_entry g_op_table[] = { { encode_op_close, decode_op_close }, /* OP_CLOSE = 4 */ { encode_op_commit, decode_op_commit }, /* OP_COMMIT = 5 */ { encode_op_create, decode_op_create }, /* OP_CREATE = 6 */ - { NULL, NULL }, /* OP_DELEGPURGE = 7 */ + { encode_op_delegpurge, decode_op_delegpurge }, /* OP_DELEGPURGE = 7 */ { encode_op_delegreturn, decode_op_delegreturn }, /* OP_DELEGRETURN = 8 */ { encode_op_getattr, decode_op_getattr }, /* OP_GETATTR = 9 */ { encode_op_getfh, decode_op_getfh }, /* OP_GETFH = 10 */ diff --git a/daemon/recovery.c b/daemon/recovery.c index 467e3bb..3033849 100644 --- a/daemon/recovery.c +++ b/daemon/recovery.c @@ -101,8 +101,22 @@ static int recover_open_no_grace( OUT open_delegation4 *delegation) { open_claim4 claim; + int status; - /* TODO: try CLAIM_DELEGATE_PREV / CLAIM_DELEG_PREV_FH first */ + if (delegate_type != OPEN_DELEGATE_NONE) { + /* attempt out-of-grace recovery with CLAIM_DELEGATE_PREV */ + claim.claim = CLAIM_DELEGATE_PREV; + claim.u.deleg_prev.filename = &file->name; + + status = nfs41_open(session, parent, file, owner, + &claim, access, deny, OPEN4_NOCREATE, 0, 0, FALSE, + stateid, delegation, NULL); + if (status == NFS4_OK || status == NFS4ERR_BADSESSION) + goto out; + + /* server support for CLAIM_DELEGATE_PREV is optional; + * fall back to CLAIM_NULL on errors */ + } /* attempt out-of-grace recovery with CLAIM_NULL */ claim.claim = CLAIM_NULL; @@ -114,9 +128,11 @@ static int recover_open_no_grace( else if (delegate_type == OPEN_DELEGATE_WRITE) access |= OPEN4_SHARE_ACCESS_WANT_WRITE_DELEG; - return nfs41_open(session, parent, file, owner, + status = nfs41_open(session, parent, file, owner, &claim, access, deny, OPEN4_NOCREATE, 0, 0, FALSE, stateid, delegation, NULL); +out: + return status; } static int recover_open(