X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnfsd%2Fnfs4callback.c;h=f57655a7a2b66b9ae1b1567e9d5500b581a5c9ae;hb=refs%2Fheads%2Fvserver;hp=1fe7f53d7b8844b0ca05835bb328e05bff58ecd5;hpb=87fc8d1bb10cd459024a742c6a10961fefcef18f;p=linux-2.6.git diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c index 1fe7f53d7..f57655a7a 100644 --- a/fs/nfsd/nfs4callback.c +++ b/fs/nfsd/nfs4callback.c @@ -33,11 +33,11 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include #include #include +#include #include #include #include @@ -52,8 +52,7 @@ #define NFSPROC4_CB_COMPOUND 1 /* declarations */ -static void nfs4_cb_null(struct rpc_task *task); -extern spinlock_t recall_lock; +static const struct rpc_call_ops nfs4_cb_null_ops; /* Index of predefined Linux callback client operations */ @@ -86,8 +85,8 @@ enum nfs_cb_opnum4 { /* * Generic encode routines from fs/nfs/nfs4xdr.c */ -static inline u32 * -xdr_writemem(u32 *p, const void *ptr, int nbytes) +static inline __be32 * +xdr_writemem(__be32 *p, const void *ptr, int nbytes) { int tmp = XDR_QUADLEN(nbytes); if (!tmp) @@ -132,7 +131,7 @@ xdr_error: \ #define READ_BUF(nbytes) do { \ p = xdr_inline_decode(xdr, nbytes); \ if (!p) { \ - dprintk("NFSD: %s: reply buffer overflowed in line %d.", \ + dprintk("NFSD: %s: reply buffer overflowed in line %d.\n", \ __FUNCTION__, __LINE__); \ return -EIO; \ } \ @@ -206,7 +205,7 @@ nfs_cb_stat_to_errno(int stat) static int encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) { - u32 * p; + __be32 * p; RESERVE_SPACE(16); WRITE32(0); /* tag length is always 0 */ @@ -219,7 +218,7 @@ encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) static int encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) { - u32 *p; + __be32 *p; int len = cb_rec->cbr_fhlen; RESERVE_SPACE(12+sizeof(cb_rec->cbr_stateid) + len); @@ -232,7 +231,7 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_cb_recall *cb_rec) } static int -nfs4_xdr_enc_cb_null(struct rpc_rqst *req, u32 *p) +nfs4_xdr_enc_cb_null(struct rpc_rqst *req, __be32 *p) { struct xdr_stream xdrs, *xdr = &xdrs; @@ -242,10 +241,11 @@ nfs4_xdr_enc_cb_null(struct rpc_rqst *req, u32 *p) } static int -nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args) +nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p, struct nfs4_cb_recall *args) { struct xdr_stream xdr; struct nfs4_cb_compound_hdr hdr = { + .ident = args->cbr_ident, .nops = 1, }; @@ -257,7 +257,7 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, u32 *p, struct nfs4_cb_recall *args static int decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){ - u32 *p; + __be32 *p; READ_BUF(8); READ32(hdr->status); @@ -272,7 +272,7 @@ decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) static int decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) { - u32 *p; + __be32 *p; u32 op; int32_t nfserr; @@ -291,13 +291,13 @@ decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected) } static int -nfs4_xdr_dec_cb_null(struct rpc_rqst *req, u32 *p) +nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p) { return 0; } static int -nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p) +nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p) { struct xdr_stream xdr; struct nfs4_cb_compound_hdr hdr; @@ -308,7 +308,7 @@ nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, u32 *p) if (status) goto out; status = decode_cb_op_hdr(&xdr, OP_CB_RECALL); -out : +out: return status; } @@ -325,16 +325,18 @@ out : .p_encode = (kxdrproc_t) nfs4_xdr_##argtype, \ .p_decode = (kxdrproc_t) nfs4_xdr_##restype, \ .p_bufsiz = MAX(NFS4_##argtype##_sz,NFS4_##restype##_sz) << 2, \ + .p_statidx = NFSPROC4_CB_##call, \ + .p_name = #proc, \ } -struct rpc_procinfo nfs4_cb_procedures[] = { +static struct rpc_procinfo nfs4_cb_procedures[] = { PROC(CB_NULL, NULL, enc_cb_null, dec_cb_null), PROC(CB_RECALL, COMPOUND, enc_cb_recall, dec_cb_recall), }; -struct rpc_version nfs_cb_version4 = { +static struct rpc_version nfs_cb_version4 = { .number = 1, - .nrprocs = sizeof(nfs4_cb_procedures)/sizeof(nfs4_cb_procedures[0]), + .nrprocs = ARRAY_SIZE(nfs4_cb_procedures), .procs = nfs4_cb_procedures }; @@ -346,15 +348,13 @@ static struct rpc_version * nfs_cb_version[] = { /* * Use the SETCLIENTID credential */ -struct rpc_cred * +static struct rpc_cred * nfsd4_lookupcred(struct nfs4_client *clp, int taskflags) { struct auth_cred acred; struct rpc_clnt *clnt = clp->cl_callback.cb_client; - struct rpc_cred *ret = NULL; + struct rpc_cred *ret; - if (!clnt) - goto out; get_group_info(clp->cl_cred.cr_group_info); acred.uid = clp->cl_cred.cr_uid; acred.gid = clp->cl_cred.cr_gid; @@ -364,7 +364,6 @@ nfsd4_lookupcred(struct nfs4_client *clp, int taskflags) clnt->cl_auth->au_ops->au_name); ret = rpcauth_lookup_credcache(clnt->cl_auth, &acred, taskflags); put_group_info(clp->cl_cred.cr_group_info); -out: return ret; } @@ -376,21 +375,31 @@ nfsd4_probe_callback(struct nfs4_client *clp) { struct sockaddr_in addr; struct nfs4_callback *cb = &clp->cl_callback; - struct rpc_timeout timeparms; - struct rpc_xprt * xprt; + struct rpc_timeout timeparms = { + .to_initval = (NFSD_LEASE_TIME/4) * HZ, + .to_retries = 5, + .to_maxval = (NFSD_LEASE_TIME/2) * HZ, + .to_exponential = 1, + }; struct rpc_program * program = &cb->cb_program; - struct rpc_stat * stat = &cb->cb_stat; - struct rpc_clnt * clnt; + struct rpc_create_args args = { + .protocol = IPPROTO_TCP, + .address = (struct sockaddr *)&addr, + .addrsize = sizeof(addr), + .timeout = &timeparms, + .servername = clp->cl_name.data, + .program = program, + .version = nfs_cb_version[1]->number, + .authflavor = RPC_AUTH_UNIX, /* XXX: need AUTH_GSS... */ + .flags = (RPC_CLNT_CREATE_NOPING), + }; struct rpc_message msg = { .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_NULL], .rpc_argp = clp, }; - char hostname[32]; int status; - dprintk("NFSD: probe_callback. cb_parsed %d cb_set %d\n", - cb->cb_parsed, atomic_read(&cb->cb_set)); - if (!cb->cb_parsed || atomic_read(&cb->cb_set)) + if (atomic_read(&cb->cb_set)) return; /* Initialize address */ @@ -399,55 +408,36 @@ nfsd4_probe_callback(struct nfs4_client *clp) addr.sin_port = htons(cb->cb_port); addr.sin_addr.s_addr = htonl(cb->cb_addr); - /* Initialize timeout */ - timeparms.to_initval = (NFSD_LEASE_TIME/4) * HZ; - timeparms.to_retries = 5; - timeparms.to_maxval = (NFSD_LEASE_TIME/2) * HZ; - timeparms.to_exponential = 1; - - /* Create RPC transport */ - if (!(xprt = xprt_create_proto(IPPROTO_TCP, &addr, &timeparms))) { - dprintk("NFSD: couldn't create callback transport!\n"); - goto out_err; - } - /* Initialize rpc_program */ program->name = "nfs4_cb"; program->number = cb->cb_prog; - program->nrvers = sizeof(nfs_cb_version)/sizeof(nfs_cb_version[0]); + program->nrvers = ARRAY_SIZE(nfs_cb_version); program->version = nfs_cb_version; - program->stats = stat; + program->stats = &cb->cb_stat; /* Initialize rpc_stat */ - memset(stat, 0, sizeof(struct rpc_stat)); - stat->program = program; - - /* Create RPC client - * - * XXX AUTH_UNIX only - need AUTH_GSS.... - */ - sprintf(hostname, "%u.%u.%u.%u", NIPQUAD(addr.sin_addr.s_addr)); - if (!(clnt = rpc_create_client(xprt, hostname, program, 1, RPC_AUTH_UNIX))) { + memset(program->stats, 0, sizeof(cb->cb_stat)); + program->stats->program = program; + + /* Create RPC client */ + cb->cb_client = rpc_create(&args); + if (IS_ERR(cb->cb_client)) { dprintk("NFSD: couldn't create callback client\n"); - goto out_xprt; + goto out_err; } - clnt->cl_intr = 1; - clnt->cl_softrtry = 1; - clnt->cl_chatty = 1; - cb->cb_client = clnt; /* Kick rpciod, put the call on the wire. */ - - if (rpciod_up() != 0) { - dprintk("nfsd: couldn't start rpciod for callbacks!\n"); + if (rpciod_up() != 0) goto out_clnt; - } /* the task holds a reference to the nfs4_client struct */ atomic_inc(&clp->cl_count); msg.rpc_cred = nfsd4_lookupcred(clp,0); - status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, nfs4_cb_null, NULL); + if (IS_ERR(msg.rpc_cred)) + goto out_rpciod; + status = rpc_call_async(cb->cb_client, &msg, RPC_TASK_ASYNC, &nfs4_cb_null_ops, NULL); + put_rpccred(msg.rpc_cred); if (status != 0) { dprintk("NFSD: asynchronous NFSPROC4_CB_NULL failed!\n"); @@ -456,24 +446,22 @@ nfsd4_probe_callback(struct nfs4_client *clp) return; out_rpciod: + atomic_dec(&clp->cl_count); rpciod_down(); out_clnt: - rpc_shutdown_client(clnt); - goto out_err; -out_xprt: - xprt_destroy(xprt); + rpc_shutdown_client(cb->cb_client); out_err: + cb->cb_client = NULL; dprintk("NFSD: warning: no callback path to client %.*s\n", (int)clp->cl_name.len, clp->cl_name.data); - cb->cb_client = NULL; } static void -nfs4_cb_null(struct rpc_task *task) +nfs4_cb_null(struct rpc_task *task, void *dummy) { struct nfs4_client *clp = (struct nfs4_client *)task->tk_msg.rpc_argp; struct nfs4_callback *cb = &clp->cl_callback; - u32 addr = htonl(cb->cb_addr); + __be32 addr = htonl(cb->cb_addr); dprintk("NFSD: nfs4_cb_null task->tk_status %d\n", task->tk_status); @@ -488,96 +476,61 @@ out: put_nfs4_client(clp); } -/* - * Called with dp->dl_count incremented - */ -static void -nfs4_cb_recall_done(struct rpc_task *task) -{ - struct nfs4_cb_recall *cbr = (struct nfs4_cb_recall *)task->tk_calldata; - struct nfs4_delegation *dp = cbr->cbr_dp; - int status; - - /* all is well... */ - if (task->tk_status == 0) - goto out; - - /* network partition, retry nfsd4_cb_recall once. */ - if (task->tk_status == -EIO) { - if (atomic_read(&dp->dl_recall_cnt) == 0) - goto retry; - else - /* callback channel no longer available */ - atomic_set(&dp->dl_client->cl_callback.cb_set, 0); - } - - /* Race: a recall occurred miliseconds after a delegation was granted. - * Client may have received recall prior to delegation. retry recall - * once. - */ - if ((task->tk_status == -EBADHANDLE) || (task->tk_status == -NFS4ERR_BAD_STATEID)){ - if (atomic_read(&dp->dl_recall_cnt) == 0) - goto retry; - } - atomic_set(&dp->dl_state, NFS4_RECALL_COMPLETE); - -out: - if (atomic_dec_and_test(&dp->dl_count)) - atomic_set(&dp->dl_state, NFS4_REAP_DELEG); - BUG_ON(atomic_read(&dp->dl_count) < 0); - dprintk("NFSD: nfs4_cb_recall_done: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count)); - return; - -retry: - atomic_inc(&dp->dl_recall_cnt); - /* sleep 2 seconds before retrying recall */ - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(2*HZ); - status = nfsd4_cb_recall(dp); - dprintk("NFSD: nfs4_cb_recall_done: retry status: %d dp %p dl_flock %p\n",status,dp, dp->dl_flock); -} +static const struct rpc_call_ops nfs4_cb_null_ops = { + .rpc_call_done = nfs4_cb_null, +}; /* * called with dp->dl_count inc'ed. * nfs4_lock_state() may or may not have been called. */ -int +void nfsd4_cb_recall(struct nfs4_delegation *dp) { - struct nfs4_client *clp; - struct rpc_clnt *clnt; + struct nfs4_client *clp = dp->dl_client; + struct rpc_clnt *clnt = clp->cl_callback.cb_client; + struct nfs4_cb_recall *cbr = &dp->dl_recall; struct rpc_message msg = { .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], + .rpc_argp = cbr, }; - struct nfs4_cb_recall *cbr = &dp->dl_recall; - int status; - - dprintk("NFSD: nfsd4_cb_recall NFS4_enc_cb_recall_sz %d NFS4_dec_cb_recall_sz %d \n",NFS4_enc_cb_recall_sz,NFS4_dec_cb_recall_sz); + int retries = 1; + int status = 0; - clp = dp->dl_client; - clnt = clp->cl_callback.cb_client; - status = EIO; if ((!atomic_read(&clp->cl_callback.cb_set)) || !clnt) - goto out_free; + return; - msg.rpc_argp = cbr; - msg.rpc_resp = cbr; - msg.rpc_cred = nfsd4_lookupcred(clp,0); + msg.rpc_cred = nfsd4_lookupcred(clp, 0); + if (IS_ERR(msg.rpc_cred)) + goto out; cbr->cbr_trunc = 0; /* XXX need to implement truncate optimization */ cbr->cbr_dp = dp; - if ((status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, - nfs4_cb_recall_done, cbr ))) { - dprintk("NFSD: recall_delegation: rpc_call_async failed %d\n", - status); - goto out_fail; + status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); + while (retries--) { + switch (status) { + case -EIO: + /* Network partition? */ + case -EBADHANDLE: + case -NFS4ERR_BAD_STATEID: + /* Race: client probably got cb_recall + * before open reply granting delegation */ + break; + default: + goto out_put_cred; + } + ssleep(2); + status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFT); } +out_put_cred: + put_rpccred(msg.rpc_cred); out: - return status; -out_fail: - status = nfserrno(status); - out_free: - kfree(cbr); - goto out; + if (status == -EIO) + atomic_set(&clp->cl_callback.cb_set, 0); + /* Success or failure, now we're either waiting for lease expiration + * or deleg_return. */ + dprintk("NFSD: nfs4_cb_recall: dp %p dl_flock %p dl_count %d\n",dp, dp->dl_flock, atomic_read(&dp->dl_count)); + nfs4_put_delegation(dp); + return; }