aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2010-12-14 09:57:32 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-12-16 12:37:24 -0500
commit85a56480191ca9f08fc775c129b9eb5c8c1f2c05 (patch)
treeaf91e03abcb7344662d25ad24e036f6de1af0c02 /fs
parenta033db487eec09afde00a3562842982a8053c887 (diff)
NFSD: Update XDR decoders in NFSv4 callback client
Clean up. Remove old-style NFSv4 XDR macros in favor of the style now used in fs/nfs/nfs4xdr.c. These were forgotten during the recent nfs4xdr.c rewrite. Additional whitespace cleanup adds to the size of this patch. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Tested-by: J. Bruce Fields <bfields@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4callback.c415
1 files changed, 239 insertions, 176 deletions
diff --git a/fs/nfsd/nfs4callback.c b/fs/nfsd/nfs4callback.c
index d8148cc461e..c3c6a903144 100644
--- a/fs/nfsd/nfs4callback.c
+++ b/fs/nfsd/nfs4callback.c
@@ -74,37 +74,6 @@ enum {
74 cb_sequence_dec_sz + \ 74 cb_sequence_dec_sz + \
75 op_dec_sz) 75 op_dec_sz)
76 76
77/*
78 * Generic decode routines from fs/nfs/nfs4xdr.c
79 */
80#define DECODE_TAIL \
81 status = 0; \
82out: \
83 return status; \
84xdr_error: \
85 dprintk("NFSD: xdr error! (%s:%d)\n", __FILE__, __LINE__); \
86 status = -EIO; \
87 goto out
88
89#define READ32(x) (x) = ntohl(*p++)
90#define READ64(x) do { \
91 (x) = (u64)ntohl(*p++) << 32; \
92 (x) |= ntohl(*p++); \
93} while (0)
94#define READTIME(x) do { \
95 p++; \
96 (x.tv_sec) = ntohl(*p++); \
97 (x.tv_nsec) = ntohl(*p++); \
98} while (0)
99#define READ_BUF(nbytes) do { \
100 p = xdr_inline_decode(xdr, nbytes); \
101 if (!p) { \
102 dprintk("NFSD: %s: reply buffer overflowed in line %d.\n", \
103 __func__, __LINE__); \
104 return -EIO; \
105 } \
106} while (0)
107
108struct nfs4_cb_compound_hdr { 77struct nfs4_cb_compound_hdr {
109 /* args */ 78 /* args */
110 u32 ident; /* minorversion 0 only */ 79 u32 ident; /* minorversion 0 only */
@@ -115,57 +84,14 @@ struct nfs4_cb_compound_hdr {
115 int status; 84 int status;
116}; 85};
117 86
118static struct { 87/*
119int stat; 88 * Handle decode buffer overflows out-of-line.
120int errno; 89 */
121} nfs_cb_errtbl[] = { 90static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
122 { NFS4_OK, 0 },
123 { NFS4ERR_PERM, EPERM },
124 { NFS4ERR_NOENT, ENOENT },
125 { NFS4ERR_IO, EIO },
126 { NFS4ERR_NXIO, ENXIO },
127 { NFS4ERR_ACCESS, EACCES },
128 { NFS4ERR_EXIST, EEXIST },
129 { NFS4ERR_XDEV, EXDEV },
130 { NFS4ERR_NOTDIR, ENOTDIR },
131 { NFS4ERR_ISDIR, EISDIR },
132 { NFS4ERR_INVAL, EINVAL },
133 { NFS4ERR_FBIG, EFBIG },
134 { NFS4ERR_NOSPC, ENOSPC },
135 { NFS4ERR_ROFS, EROFS },
136 { NFS4ERR_MLINK, EMLINK },
137 { NFS4ERR_NAMETOOLONG, ENAMETOOLONG },
138 { NFS4ERR_NOTEMPTY, ENOTEMPTY },
139 { NFS4ERR_DQUOT, EDQUOT },
140 { NFS4ERR_STALE, ESTALE },
141 { NFS4ERR_BADHANDLE, EBADHANDLE },
142 { NFS4ERR_BAD_COOKIE, EBADCOOKIE },
143 { NFS4ERR_NOTSUPP, ENOTSUPP },
144 { NFS4ERR_TOOSMALL, ETOOSMALL },
145 { NFS4ERR_SERVERFAULT, ESERVERFAULT },
146 { NFS4ERR_BADTYPE, EBADTYPE },
147 { NFS4ERR_LOCKED, EAGAIN },
148 { NFS4ERR_RESOURCE, EREMOTEIO },
149 { NFS4ERR_SYMLINK, ELOOP },
150 { NFS4ERR_OP_ILLEGAL, EOPNOTSUPP },
151 { NFS4ERR_DEADLOCK, EDEADLK },
152 { -1, EIO }
153};
154
155static int
156nfs_cb_stat_to_errno(int stat)
157{ 91{
158 int i; 92 dprintk("NFS: %s prematurely hit the end of our receive buffer. "
159 for (i = 0; nfs_cb_errtbl[i].stat != -1; i++) { 93 "Remaining buffer length is %tu words.\n",
160 if (nfs_cb_errtbl[i].stat == stat) 94 func, xdr->end - xdr->p);
161 return nfs_cb_errtbl[i].errno;
162 }
163 /* If we cannot translate the error, the recovery routines should
164 * handle it.
165 * Note: remaining NFSv4 error codes have values > 10000, so should
166 * not conflict with native Linux error codes.
167 */
168 return stat;
169} 95}
170 96
171static __be32 *xdr_encode_empty_array(__be32 *p) 97static __be32 *xdr_encode_empty_array(__be32 *p)
@@ -263,6 +189,89 @@ static void encode_sessionid4(struct xdr_stream *xdr,
263} 189}
264 190
265/* 191/*
192 * nfsstat4
193 */
194static const struct {
195 int stat;
196 int errno;
197} nfs_cb_errtbl[] = {
198 { NFS4_OK, 0 },
199 { NFS4ERR_PERM, -EPERM },
200 { NFS4ERR_NOENT, -ENOENT },
201 { NFS4ERR_IO, -EIO },
202 { NFS4ERR_NXIO, -ENXIO },
203 { NFS4ERR_ACCESS, -EACCES },
204 { NFS4ERR_EXIST, -EEXIST },
205 { NFS4ERR_XDEV, -EXDEV },
206 { NFS4ERR_NOTDIR, -ENOTDIR },
207 { NFS4ERR_ISDIR, -EISDIR },
208 { NFS4ERR_INVAL, -EINVAL },
209 { NFS4ERR_FBIG, -EFBIG },
210 { NFS4ERR_NOSPC, -ENOSPC },
211 { NFS4ERR_ROFS, -EROFS },
212 { NFS4ERR_MLINK, -EMLINK },
213 { NFS4ERR_NAMETOOLONG, -ENAMETOOLONG },
214 { NFS4ERR_NOTEMPTY, -ENOTEMPTY },
215 { NFS4ERR_DQUOT, -EDQUOT },
216 { NFS4ERR_STALE, -ESTALE },
217 { NFS4ERR_BADHANDLE, -EBADHANDLE },
218 { NFS4ERR_BAD_COOKIE, -EBADCOOKIE },
219 { NFS4ERR_NOTSUPP, -ENOTSUPP },
220 { NFS4ERR_TOOSMALL, -ETOOSMALL },
221 { NFS4ERR_SERVERFAULT, -ESERVERFAULT },
222 { NFS4ERR_BADTYPE, -EBADTYPE },
223 { NFS4ERR_LOCKED, -EAGAIN },
224 { NFS4ERR_RESOURCE, -EREMOTEIO },
225 { NFS4ERR_SYMLINK, -ELOOP },
226 { NFS4ERR_OP_ILLEGAL, -EOPNOTSUPP },
227 { NFS4ERR_DEADLOCK, -EDEADLK },
228 { -1, -EIO }
229};
230
231/*
232 * If we cannot translate the error, the recovery routines should
233 * handle it.
234 *
235 * Note: remaining NFSv4 error codes have values > 10000, so should
236 * not conflict with native Linux error codes.
237 */
238static int nfs_cb_stat_to_errno(int status)
239{
240 int i;
241
242 for (i = 0; nfs_cb_errtbl[i].stat != -1; i++) {
243 if (nfs_cb_errtbl[i].stat == status)
244 return nfs_cb_errtbl[i].errno;
245 }
246
247 dprintk("NFSD: Unrecognized NFS CB status value: %u\n", status);
248 return -status;
249}
250
251static int decode_cb_op_status(struct xdr_stream *xdr, enum nfs_opnum4 expected,
252 enum nfsstat4 *status)
253{
254 __be32 *p;
255 u32 op;
256
257 p = xdr_inline_decode(xdr, 4 + 4);
258 if (unlikely(p == NULL))
259 goto out_overflow;
260 op = be32_to_cpup(p++);
261 if (unlikely(op != expected))
262 goto out_unexpected;
263 *status = be32_to_cpup(p);
264 return 0;
265out_overflow:
266 print_overflow_msg(__func__, xdr);
267 return -EIO;
268out_unexpected:
269 dprintk("NFSD: Callback server returned operation %d but "
270 "we issued a request for %d\n", op, expected);
271 return -EIO;
272}
273
274/*
266 * CB_COMPOUND4args 275 * CB_COMPOUND4args
267 * 276 *
268 * struct CB_COMPOUND4args { 277 * struct CB_COMPOUND4args {
@@ -296,6 +305,37 @@ static void encode_cb_nops(struct nfs4_cb_compound_hdr *hdr)
296} 305}
297 306
298/* 307/*
308 * CB_COMPOUND4res
309 *
310 * struct CB_COMPOUND4res {
311 * nfsstat4 status;
312 * utf8str_cs tag;
313 * nfs_cb_resop4 resarray<>;
314 * };
315 */
316static int decode_cb_compound4res(struct xdr_stream *xdr,
317 struct nfs4_cb_compound_hdr *hdr)
318{
319 u32 length;
320 __be32 *p;
321
322 p = xdr_inline_decode(xdr, 4 + 4);
323 if (unlikely(p == NULL))
324 goto out_overflow;
325 hdr->status = be32_to_cpup(p++);
326 /* Ignore the tag */
327 length = be32_to_cpup(p++);
328 p = xdr_inline_decode(xdr, length + 4);
329 if (unlikely(p == NULL))
330 goto out_overflow;
331 hdr->nops = be32_to_cpup(p);
332 return 0;
333out_overflow:
334 print_overflow_msg(__func__, xdr);
335 return -EIO;
336}
337
338/*
299 * CB_RECALL4args 339 * CB_RECALL4args
300 * 340 *
301 * struct CB_RECALL4args { 341 * struct CB_RECALL4args {
@@ -357,6 +397,97 @@ static void encode_cb_sequence4args(struct xdr_stream *xdr,
357} 397}
358 398
359/* 399/*
400 * CB_SEQUENCE4resok
401 *
402 * struct CB_SEQUENCE4resok {
403 * sessionid4 csr_sessionid;
404 * sequenceid4 csr_sequenceid;
405 * slotid4 csr_slotid;
406 * slotid4 csr_highest_slotid;
407 * slotid4 csr_target_highest_slotid;
408 * };
409 *
410 * union CB_SEQUENCE4res switch (nfsstat4 csr_status) {
411 * case NFS4_OK:
412 * CB_SEQUENCE4resok csr_resok4;
413 * default:
414 * void;
415 * };
416 *
417 * Our current back channel implmentation supports a single backchannel
418 * with a single slot.
419 */
420static int decode_cb_sequence4resok(struct xdr_stream *xdr,
421 struct nfsd4_callback *cb)
422{
423 struct nfsd4_session *session = cb->cb_clp->cl_cb_session;
424 struct nfs4_sessionid id;
425 int status;
426 __be32 *p;
427 u32 dummy;
428
429 status = -ESERVERFAULT;
430
431 /*
432 * If the server returns different values for sessionID, slotID or
433 * sequence number, the server is looney tunes.
434 */
435 p = xdr_inline_decode(xdr, NFS4_MAX_SESSIONID_LEN + 4 + 4);
436 if (unlikely(p == NULL))
437 goto out_overflow;
438 memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN);
439 if (memcmp(id.data, session->se_sessionid.data,
440 NFS4_MAX_SESSIONID_LEN) != 0) {
441 dprintk("NFS: %s Invalid session id\n", __func__);
442 goto out;
443 }
444 p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN);
445
446 dummy = be32_to_cpup(p++);
447 if (dummy != session->se_cb_seq_nr) {
448 dprintk("NFS: %s Invalid sequence number\n", __func__);
449 goto out;
450 }
451
452 dummy = be32_to_cpup(p++);
453 if (dummy != 0) {
454 dprintk("NFS: %s Invalid slotid\n", __func__);
455 goto out;
456 }
457
458 /*
459 * FIXME: process highest slotid and target highest slotid
460 */
461 status = 0;
462out:
463 return status;
464out_overflow:
465 print_overflow_msg(__func__, xdr);
466 return -EIO;
467}
468
469static int decode_cb_sequence4res(struct xdr_stream *xdr,
470 struct nfsd4_callback *cb)
471{
472 enum nfsstat4 nfserr;
473 int status;
474
475 if (cb->cb_minorversion == 0)
476 return 0;
477
478 status = decode_cb_op_status(xdr, OP_CB_SEQUENCE, &nfserr);
479 if (unlikely(status))
480 goto out;
481 if (unlikely(nfserr != NFS4_OK))
482 goto out_default;
483 status = decode_cb_sequence4resok(xdr, cb);
484out:
485 return status;
486out_default:
487 return nfs_cb_stat_to_errno(status);
488}
489
490/*
360 * NFSv4.0 and NFSv4.1 XDR encode functions 491 * NFSv4.0 and NFSv4.1 XDR encode functions
361 * 492 *
362 * NFSv4.0 callback argument types are defined in section 15 of RFC 493 * NFSv4.0 callback argument types are defined in section 15 of RFC
@@ -399,119 +530,51 @@ static int nfs4_xdr_enc_cb_recall(struct rpc_rqst *req, __be32 *p,
399} 530}
400 531
401 532
402static int
403decode_cb_compound_hdr(struct xdr_stream *xdr, struct nfs4_cb_compound_hdr *hdr){
404 __be32 *p;
405 u32 taglen;
406
407 READ_BUF(8);
408 READ32(hdr->status);
409 /* We've got no use for the tag; ignore it: */
410 READ32(taglen);
411 READ_BUF(taglen + 4);
412 p += XDR_QUADLEN(taglen);
413 READ32(hdr->nops);
414 return 0;
415}
416
417static int
418decode_cb_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
419{
420 __be32 *p;
421 u32 op;
422 int32_t nfserr;
423
424 READ_BUF(8);
425 READ32(op);
426 if (op != expected) {
427 dprintk("NFSD: decode_cb_op_hdr: Callback server returned "
428 " operation %d but we issued a request for %d\n",
429 op, expected);
430 return -EIO;
431 }
432 READ32(nfserr);
433 if (nfserr != NFS_OK)
434 return -nfs_cb_stat_to_errno(nfserr);
435 return 0;
436}
437
438/* 533/*
439 * Our current back channel implmentation supports a single backchannel 534 * NFSv4.0 and NFSv4.1 XDR decode functions
440 * with a single slot. 535 *
536 * NFSv4.0 callback result types are defined in section 15 of RFC
537 * 3530: "Network File System (NFS) version 4 Protocol" and section 20
538 * of RFC 5661: "Network File System (NFS) Version 4 Minor Version 1
539 * Protocol".
441 */ 540 */
442static int
443decode_cb_sequence(struct xdr_stream *xdr, struct nfsd4_callback *cb,
444 struct rpc_rqst *rqstp)
445{
446 struct nfsd4_session *ses = cb->cb_clp->cl_cb_session;
447 struct nfs4_sessionid id;
448 int status;
449 u32 dummy;
450 __be32 *p;
451
452 if (cb->cb_minorversion == 0)
453 return 0;
454
455 status = decode_cb_op_hdr(xdr, OP_CB_SEQUENCE);
456 if (status)
457 return status;
458
459 /*
460 * If the server returns different values for sessionID, slotID or
461 * sequence number, the server is looney tunes.
462 */
463 status = -ESERVERFAULT;
464
465 READ_BUF(NFS4_MAX_SESSIONID_LEN + 16);
466 memcpy(id.data, p, NFS4_MAX_SESSIONID_LEN);
467 p += XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN);
468 if (memcmp(id.data, ses->se_sessionid.data, NFS4_MAX_SESSIONID_LEN)) {
469 dprintk("%s Invalid session id\n", __func__);
470 goto out;
471 }
472 READ32(dummy);
473 if (dummy != ses->se_cb_seq_nr) {
474 dprintk("%s Invalid sequence number\n", __func__);
475 goto out;
476 }
477 READ32(dummy); /* slotid must be 0 */
478 if (dummy != 0) {
479 dprintk("%s Invalid slotid\n", __func__);
480 goto out;
481 }
482 /* FIXME: process highest slotid and target highest slotid */
483 status = 0;
484out:
485 return status;
486}
487
488 541
489static int 542static int nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p, void *__unused)
490nfs4_xdr_dec_cb_null(struct rpc_rqst *req, __be32 *p)
491{ 543{
492 return 0; 544 return 0;
493} 545}
494 546
495static int 547/*
496nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p, 548 * 20.2. Operation 4: CB_RECALL - Recall a Delegation
497 struct nfsd4_callback *cb) 549 */
550static int nfs4_xdr_dec_cb_recall(struct rpc_rqst *rqstp, __be32 *p,
551 struct nfsd4_callback *cb)
498{ 552{
499 struct xdr_stream xdr; 553 struct xdr_stream xdr;
500 struct nfs4_cb_compound_hdr hdr; 554 struct nfs4_cb_compound_hdr hdr;
555 enum nfsstat4 nfserr;
501 int status; 556 int status;
502 557
503 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); 558 xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
504 status = decode_cb_compound_hdr(&xdr, &hdr); 559 status = decode_cb_compound4res(&xdr, &hdr);
505 if (status) 560 if (unlikely(status))
506 goto out; 561 goto out;
507 if (cb) { 562
508 status = decode_cb_sequence(&xdr, cb, rqstp); 563 if (cb != NULL) {
509 if (status) 564 status = decode_cb_sequence4res(&xdr, cb);
565 if (unlikely(status))
510 goto out; 566 goto out;
511 } 567 }
512 status = decode_cb_op_hdr(&xdr, OP_CB_RECALL); 568
569 status = decode_cb_op_status(&xdr, OP_CB_RECALL, &nfserr);
570 if (unlikely(status))
571 goto out;
572 if (unlikely(nfserr != NFS4_OK))
573 goto out_default;
513out: 574out:
514 return status; 575 return status;
576out_default:
577 return nfs_cb_stat_to_errno(status);
515} 578}
516 579
517/* 580/*