aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd/nfs4callback.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd/nfs4callback.c')
-rw-r--r--fs/nfsd/nfs4callback.c57
1 files changed, 32 insertions, 25 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index eb78e7e22077..988cbb3a19b6 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -143,8 +143,6 @@ struct nfs4_cb_compound_hdr {
143 u32 minorversion; 143 u32 minorversion;
144 /* res */ 144 /* res */
145 int status; 145 int status;
146 u32 taglen;
147 char *tag;
148}; 146};
149 147
150static struct { 148static struct {
@@ -205,6 +203,16 @@ nfs_cb_stat_to_errno(int stat)
205 */ 203 */
206 204
207static void 205static void
206encode_stateid(struct xdr_stream *xdr, stateid_t *sid)
207{
208 __be32 *p;
209
210 RESERVE_SPACE(sizeof(stateid_t));
211 WRITE32(sid->si_generation);
212 WRITEMEM(&sid->si_opaque, sizeof(stateid_opaque_t));
213}
214
215static void
208encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr) 216encode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr)
209{ 217{
210 __be32 * p; 218 __be32 * p;
@@ -229,10 +237,10 @@ encode_cb_recall(struct xdr_stream *xdr, struct nfs4_delegation *dp,
229 __be32 *p; 237 __be32 *p;
230 int len = dp->dl_fh.fh_size; 238 int len = dp->dl_fh.fh_size;
231 239
232 RESERVE_SPACE(12+sizeof(dp->dl_stateid) + len); 240 RESERVE_SPACE(4);
233 WRITE32(OP_CB_RECALL); 241 WRITE32(OP_CB_RECALL);
234 WRITE32(dp->dl_stateid.si_generation); 242 encode_stateid(xdr, &dp->dl_stateid);
235 WRITEMEM(&dp->dl_stateid.si_opaque, sizeof(stateid_opaque_t)); 243 RESERVE_SPACE(8 + (XDR_QUADLEN(len) << 2));
236 WRITE32(0); /* truncate optimization not implemented */ 244 WRITE32(0); /* truncate optimization not implemented */
237 WRITE32(len); 245 WRITE32(len);
238 WRITEMEM(&dp->dl_fh.fh_base, len); 246 WRITEMEM(&dp->dl_fh.fh_base, len);
@@ -293,13 +301,14 @@ nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p,
293static int 301static int
294decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){ 302decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
295 __be32 *p; 303 __be32 *p;
304 u32 taglen;
296 305
297 READ_BUF(8); 306 READ_BUF(8);
298 READ32(hdr->status); 307 READ32(hdr->status);
299 READ32(hdr->taglen); 308 /* We've got no use for the tag; ignore it: */
300 READ_BUF(hdr->taglen + 4); 309 READ32(taglen);
301 hdr->tag = (char *)p; 310 READ_BUF(taglen + 4);
302 p += XDR_QUADLEN(hdr->taglen); 311 p += XDR_QUADLEN(taglen);
303 READ32(hdr->nops); 312 READ32(hdr->nops);
304 return 0; 313 return 0;
305} 314}
@@ -667,28 +676,28 @@ static void nfsd4_cb_recall_done(struct rpc_task *task, void *calldata)
667 } 676 }
668 677
669 switch (task->tk_status) { 678 switch (task->tk_status) {
670 case -EIO: 679 case 0:
680 return;
681 case -EBADHANDLE:
682 case -NFS4ERR_BAD_STATEID:
683 /* Race: client probably got cb_recall
684 * before open reply granting delegation */
685 break;
686 default:
671 /* Network partition? */ 687 /* Network partition? */
672 atomic_set(&clp->cl_cb_set, 0); 688 atomic_set(&clp->cl_cb_set, 0);
673 warn_no_callback_path(clp, task->tk_status); 689 warn_no_callback_path(clp, task->tk_status);
674 if (current_rpc_client != task->tk_client) { 690 if (current_rpc_client != task->tk_client) {
675 /* queue a callback on the new connection: */ 691 /* queue a callback on the new connection: */
692 atomic_inc(&dp->dl_count);
676 nfsd4_cb_recall(dp); 693 nfsd4_cb_recall(dp);
677 return; 694 return;
678 } 695 }
679 case -EBADHANDLE:
680 case -NFS4ERR_BAD_STATEID:
681 /* Race: client probably got cb_recall
682 * before open reply granting delegation */
683 break;
684 default:
685 /* success, or error we can't handle */
686 return;
687 } 696 }
688 if (dp->dl_retries--) { 697 if (dp->dl_retries--) {
689 rpc_delay(task, 2*HZ); 698 rpc_delay(task, 2*HZ);
690 task->tk_status = 0; 699 task->tk_status = 0;
691 rpc_restart_call(task); 700 rpc_restart_call_prepare(task);
692 return; 701 return;
693 } else { 702 } else {
694 atomic_set(&clp->cl_cb_set, 0); 703 atomic_set(&clp->cl_cb_set, 0);
@@ -752,18 +761,16 @@ static void _nfsd4_cb_recall(struct nfs4_delegation *dp)
752 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL], 761 .rpc_proc = &nfs4_cb_procedures[NFSPROC4_CLNT_CB_RECALL],
753 .rpc_cred = callback_cred 762 .rpc_cred = callback_cred
754 }; 763 };
755 int status;
756 764
757 if (clnt == NULL) 765 if (clnt == NULL) {
766 nfs4_put_delegation(dp);
758 return; /* Client is shutting down; give up. */ 767 return; /* Client is shutting down; give up. */
768 }
759 769
760 args->args_op = dp; 770 args->args_op = dp;
761 msg.rpc_argp = args; 771 msg.rpc_argp = args;
762 dp->dl_retries = 1; 772 dp->dl_retries = 1;
763 status = rpc_call_async(clnt, &msg, RPC_TASK_SOFT, 773 rpc_call_async(clnt, &msg, RPC_TASK_SOFT, &nfsd4_cb_recall_ops, dp);
764 &nfsd4_cb_recall_ops, dp);
765 if (status)
766 nfs4_put_delegation(dp);
767} 774}
768 775
769void nfsd4_do_callback_rpc(struct work_struct *w) 776void nfsd4_do_callback_rpc(struct work_struct *w)