From: Benny Halevy Subject: [RFC 05/10] nfsd41: callback infrastructure Date: Fri, 1 May 2009 02:06:08 +0300 Message-ID: <1241132768-32526-1-git-send-email-bhalevy@panasas.com> References: <49FA2D86.8060402@panasas.com> Cc: Ricardo Labiaga , pnfs@linux-nfs.org, linux-nfs@vger.kernel.org, Andy Adamson , Benny Halevy To: " J. Bruce Fields" Return-path: Received: from gw-ca.panasas.com ([209.116.51.66]:24469 "EHLO laguna.int.panasas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1758513AbZD3XGU (ORCPT ); Thu, 30 Apr 2009 19:06:20 -0400 In-Reply-To: <49FA2D86.8060402@panasas.com> Sender: linux-nfs-owner@vger.kernel.org List-ID: From: Andy Adamson Keep the xprt used for create_session in cl_cb_xprt. Mark cl_callback.cb_minorversion = 1 and remember the client provided cl_callback.cb_prog rpc program number. Use it to probe the callback path. Define xdr sizes and code nfs4_cb_compound header to be able to send a null callback rpc. Signed-off-by: Andy Adamson Signed-off-by: Benny Halevy [get callback minorversion from fore channel's] Signed-off-by: Benny Halevy --- fs/nfsd/nfs4callback.c | 33 ++++++++++++++++++++++++++++++--- fs/nfsd/nfs4state.c | 10 ++++++++++ include/linux/nfsd/state.h | 3 +++ 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 5823b9a..6f1ca49 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include #include @@ -52,16 +53,19 @@ #define NFSPROC4_CB_NULL 0 #define NFSPROC4_CB_COMPOUND 1 +#define NFS4_STATEID_SIZE 16 /* Index of predefined Linux callback client operations */ enum { - NFSPROC4_CLNT_CB_NULL = 0, + NFSPROC4_CLNT_CB_NULL = 0, NFSPROC4_CLNT_CB_RECALL, + NFSPROC4_CLNT_CB_SEQUENCE, }; enum nfs_cb_opnum4 { OP_CB_RECALL = 4, + OP_CB_SEQUENCE = 11, }; #define NFS4_MAXTAGLEN 20 @@ -70,15 +74,22 @@ enum nfs_cb_opnum4 { #define NFS4_dec_cb_null_sz 0 #define cb_compound_enc_hdr_sz 4 #define cb_compound_dec_hdr_sz (3 + (NFS4_MAXTAGLEN >> 2)) +#define sessionid_sz (NFS4_MAX_SESSIONID_LEN >> 2) +#define cb_sequence_enc_sz (sessionid_sz + 4 + \ + 1 /* no referring calls list yet */) +#define cb_sequence_dec_sz (op_dec_sz + sessionid_sz + 4) + #define op_enc_sz 1 #define op_dec_sz 2 #define enc_nfs4_fh_sz (1 + (NFS4_FHSIZE >> 2)) #define enc_stateid_sz (NFS4_STATEID_SIZE >> 2) #define NFS4_enc_cb_recall_sz (cb_compound_enc_hdr_sz + \ + cb_sequence_enc_sz + \ 1 + enc_stateid_sz + \ enc_nfs4_fh_sz) #define NFS4_dec_cb_recall_sz (cb_compound_dec_hdr_sz + \ + cb_sequence_dec_sz + \ op_dec_sz) /* @@ -135,13 +146,19 @@ xdr_error: \ return -EIO; \ } \ } while (0) +#define COPYMEM(x, nbytes) do { \ + memcpy((x), p, nbytes); \ + p += XDR_QUADLEN(nbytes); \ +} while (0) struct nfs4_cb_compound_hdr { - int status; - u32 ident; + /* args */ + u32 ident; /* minorversion 0 only */ u32 nops; __be32 *nops_p; u32 minorversion; + /* res */ + int status; u32 taglen; char *tag; }; @@ -402,6 +419,15 @@ static struct rpc_clnt *setup_callback_client(struct nfs4_client *clp) addr.sin_family = AF_INET; addr.sin_port = htons(cb->cb_port); addr.sin_addr.s_addr = htonl(cb->cb_addr); + if (cb->cb_minorversion) { + BUG_ON(cb->cb_minorversion != 1); + args.bc_sock = container_of(clp->cl_cb_xprt, struct svc_sock, + sk_xprt); + } + + dprintk("%s: program %s 0x%x nrvers %u version %u minorversion %u\n", + __func__, args.program->name, args.prognumber, + args.program->nrvers, args.version, cb->cb_minorversion); /* Create RPC client */ client = rpc_create(&args); @@ -441,6 +467,7 @@ static int do_probe_callback(void *data) put_nfs4_client(clp); return 0; out_release_client: + dprintk("NFSD: synchronous CB_NULL failed. status=%d\n", status); rpc_shutdown_client(client); out_err: dprintk("NFSD: warning: no callback path to client %.*s: error %d\n", diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index ad30039..61d5c66 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -651,6 +651,8 @@ static inline void free_client(struct nfs4_client *clp) { shutdown_callback_client(clp); + if (clp->cl_cb_xprt) + svc_xprt_put(clp->cl_cb_xprt); nfsd4_release_respages(clp->cl_slot.sl_cache_entry.ce_respages, clp->cl_slot.sl_cache_entry.ce_resused); if (clp->cl_cred.cr_group_info) @@ -1391,6 +1393,14 @@ nfsd4_create_session(struct svc_rqst *rqstp, cr_ses->flags &= ~SESSION4_PERSIST; cr_ses->flags &= ~SESSION4_RDMA; + if (cr_ses->flags & SESSION4_BACK_CHAN) { + unconf->cl_cb_xprt = rqstp->rq_xprt; + svc_xprt_get(unconf->cl_cb_xprt); + unconf->cl_callback.cb_minorversion = + cstate->minorversion; + unconf->cl_callback.cb_prog = cr_ses->callback_prog; + nfsd4_probe_callback(unconf); + } conf = unconf; } else { status = nfserr_stale_clientid; diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 8762843..6bdf0d5 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h @@ -203,6 +203,9 @@ struct nfs4_client { struct nfsd4_slot cl_slot; /* create_session slot */ u32 cl_exchange_flags; struct nfs4_sessionid cl_sessionid; + + /* for nfs41 callbacks */ + struct svc_xprt *cl_cb_xprt; /* 4.1 callback transport */ }; /* struct nfs4_client_reset -- 1.6.2.1