aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/nfs2xdr.c
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2010-12-14 09:54:30 -0500
committerTrond Myklebust <Trond.Myklebust@netapp.com>2010-12-16 12:37:20 -0500
commit25a0866cc63281b480cc0c11ddeaccb2ffc57dc9 (patch)
tree97c44600812b98f05f13f0e7a0b8c192ad07dd67 /fs/nfs/nfs2xdr.c
parentb3444d164be8f977f4133ef0c6f4a18f2741373f (diff)
NFS: Introduce new-style XDR encoding functions for NFSv2
We're interested in taking advantage of the safety benefits of xdr_streams. These data structures allow more careful checking for buffer overflow while encoding. More careful type checking is also introduced in the new functions. For efficiency, we also eventually want to be able to pass xdr_streams from call_encode() to all XDR encoding functions, rather than building an xdr_stream in every XDR encoding function in the kernel. To do this means all encoders must be ready to handle a passed-in xdr_stream. The new encoders follow the modern paradigm for XDR encoders: BUG on any error, and always return a zero status code. Static helper functions are left without the "inline" directive. This allows the compiler to choose automatically how to optimize these for size or speed. 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/nfs/nfs2xdr.c')
-rw-r--r--fs/nfs/nfs2xdr.c406
1 files changed, 403 insertions, 3 deletions
diff --git a/fs/nfs/nfs2xdr.c b/fs/nfs/nfs2xdr.c
index 5914a1911c95..869e2151a2b1 100644
--- a/fs/nfs/nfs2xdr.c
+++ b/fs/nfs/nfs2xdr.c
@@ -61,6 +61,23 @@
61#define NFS_readdirres_sz (1) 61#define NFS_readdirres_sz (1)
62#define NFS_statfsres_sz (1+NFS_info_sz) 62#define NFS_statfsres_sz (1+NFS_info_sz)
63 63
64
65/*
66 * While encoding arguments, set up the reply buffer in advance to
67 * receive reply data directly into the page cache.
68 */
69static void prepare_reply_buffer(struct rpc_rqst *req, struct page **pages,
70 unsigned int base, unsigned int len,
71 unsigned int bufsize)
72{
73 struct rpc_auth *auth = req->rq_cred->cr_auth;
74 unsigned int replen;
75
76 replen = RPC_REPHDRSIZE + auth->au_rslack + bufsize;
77 xdr_inline_pages(&req->rq_rcv_buf, replen << 2, pages, base, len);
78}
79
80
64/* 81/*
65 * Common NFS XDR functions as inlines 82 * Common NFS XDR functions as inlines
66 */ 83 */
@@ -81,7 +98,7 @@ xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
81} 98}
82 99
83static inline __be32* 100static inline __be32*
84xdr_encode_time(__be32 *p, struct timespec *timep) 101xdr_encode_time(__be32 *p, const struct timespec *timep)
85{ 102{
86 *p++ = htonl(timep->tv_sec); 103 *p++ = htonl(timep->tv_sec);
87 /* Convert nanoseconds into microseconds */ 104 /* Convert nanoseconds into microseconds */
@@ -90,7 +107,7 @@ xdr_encode_time(__be32 *p, struct timespec *timep)
90} 107}
91 108
92static inline __be32* 109static inline __be32*
93xdr_encode_current_server_time(__be32 *p, struct timespec *timep) 110xdr_encode_current_server_time(__be32 *p, const struct timespec *timep)
94{ 111{
95 /* 112 /*
96 * Passing the invalid value useconds=1000000 is a 113 * Passing the invalid value useconds=1000000 is a
@@ -174,6 +191,136 @@ xdr_encode_sattr(__be32 *p, struct iattr *attr)
174} 191}
175 192
176/* 193/*
194 * Encode/decode NFSv2 basic data types
195 *
196 * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
197 * "NFS: Network File System Protocol Specification".
198 *
199 * Not all basic data types have their own encoding and decoding
200 * functions. For run-time efficiency, some data types are encoded
201 * or decoded inline.
202 */
203
204/*
205 * 2.3.3. fhandle
206 *
207 * typedef opaque fhandle[FHSIZE];
208 */
209static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
210{
211 __be32 *p;
212
213 BUG_ON(fh->size != NFS2_FHSIZE);
214 p = xdr_reserve_space(xdr, NFS2_FHSIZE);
215 memcpy(p, fh->data, NFS2_FHSIZE);
216}
217
218/*
219 * 2.3.6. sattr
220 *
221 * struct sattr {
222 * unsigned int mode;
223 * unsigned int uid;
224 * unsigned int gid;
225 * unsigned int size;
226 * timeval atime;
227 * timeval mtime;
228 * };
229 */
230
231#define NFS2_SATTR_NOT_SET (0xffffffff)
232
233static __be32 *xdr_time_not_set(__be32 *p)
234{
235 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
236 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
237 return p;
238}
239
240static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
241{
242 __be32 *p;
243
244 p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
245
246 if (attr->ia_valid & ATTR_MODE)
247 *p++ = cpu_to_be32(attr->ia_mode);
248 else
249 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
250 if (attr->ia_valid & ATTR_UID)
251 *p++ = cpu_to_be32(attr->ia_uid);
252 else
253 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
254 if (attr->ia_valid & ATTR_GID)
255 *p++ = cpu_to_be32(attr->ia_gid);
256 else
257 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
258 if (attr->ia_valid & ATTR_SIZE)
259 *p++ = cpu_to_be32((u32)attr->ia_size);
260 else
261 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
262
263 if (attr->ia_valid & ATTR_ATIME_SET)
264 p = xdr_encode_time(p, &attr->ia_atime);
265 else if (attr->ia_valid & ATTR_ATIME)
266 p = xdr_encode_current_server_time(p, &attr->ia_atime);
267 else
268 p = xdr_time_not_set(p);
269 if (attr->ia_valid & ATTR_MTIME_SET)
270 xdr_encode_time(p, &attr->ia_mtime);
271 else if (attr->ia_valid & ATTR_MTIME)
272 xdr_encode_current_server_time(p, &attr->ia_mtime);
273 else
274 xdr_time_not_set(p);
275}
276
277/*
278 * 2.3.7. filename
279 *
280 * typedef string filename<MAXNAMLEN>;
281 */
282static void encode_filename(struct xdr_stream *xdr,
283 const char *name, u32 length)
284{
285 __be32 *p;
286
287 BUG_ON(length > NFS2_MAXNAMLEN);
288 p = xdr_reserve_space(xdr, 4 + length);
289 xdr_encode_opaque(p, name, length);
290}
291
292/*
293 * 2.3.8. path
294 *
295 * typedef string path<MAXPATHLEN>;
296 */
297static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
298{
299 __be32 *p;
300
301 BUG_ON(length > NFS2_MAXPATHLEN);
302 p = xdr_reserve_space(xdr, 4);
303 *p = cpu_to_be32(length);
304 xdr_write_pages(xdr, pages, 0, length);
305}
306
307/*
308 * 2.3.10. diropargs
309 *
310 * struct diropargs {
311 * fhandle dir;
312 * filename name;
313 * };
314 */
315static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
316 const char *name, u32 length)
317{
318 encode_fhandle(xdr, fh);
319 encode_filename(xdr, name, length);
320}
321
322
323/*
177 * NFS encode functions 324 * NFS encode functions
178 */ 325 */
179/* 326/*
@@ -188,6 +335,16 @@ nfs_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
188 return 0; 335 return 0;
189} 336}
190 337
338static int nfs2_xdr_enc_fhandle(struct rpc_rqst *req, __be32 *p,
339 const struct nfs_fh *fh)
340{
341 struct xdr_stream xdr;
342
343 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
344 encode_fhandle(&xdr, fh);
345 return 0;
346}
347
191/* 348/*
192 * Encode SETATTR arguments 349 * Encode SETATTR arguments
193 */ 350 */
@@ -201,6 +358,25 @@ nfs_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs_sattrargs *args)
201} 358}
202 359
203/* 360/*
361 * 2.2.3. sattrargs
362 *
363 * struct sattrargs {
364 * fhandle file;
365 * sattr attributes;
366 * };
367 */
368static int nfs2_xdr_enc_sattrargs(struct rpc_rqst *req, __be32 *p,
369 const struct nfs_sattrargs *args)
370{
371 struct xdr_stream xdr;
372
373 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
374 encode_fhandle(&xdr, args->fh);
375 encode_sattr(&xdr, args->sattr);
376 return 0;
377}
378
379/*
204 * Encode directory ops argument 380 * Encode directory ops argument
205 * LOOKUP, RMDIR 381 * LOOKUP, RMDIR
206 */ 382 */
@@ -213,6 +389,16 @@ nfs_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs_diropargs *args)
213 return 0; 389 return 0;
214} 390}
215 391
392static int nfs2_xdr_enc_diropargs(struct rpc_rqst *req, __be32 *p,
393 const struct nfs_diropargs *args)
394{
395 struct xdr_stream xdr;
396
397 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
398 encode_diropargs(&xdr, args->fh, args->name, args->len);
399 return 0;
400}
401
216/* 402/*
217 * Encode REMOVE argument 403 * Encode REMOVE argument
218 */ 404 */
@@ -225,6 +411,18 @@ nfs_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs
225 return 0; 411 return 0;
226} 412}
227 413
414static int nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, __be32 *p,
415 const struct nfs_readlinkargs *args)
416{
417 struct xdr_stream xdr;
418
419 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
420 encode_fhandle(&xdr, args->fh);
421 prepare_reply_buffer(req, args->pages, args->pgbase,
422 args->pglen, NFS_readlinkres_sz);
423 return 0;
424}
425
228/* 426/*
229 * Arguments to a READ call. Since we read data directly into the page 427 * Arguments to a READ call. Since we read data directly into the page
230 * cache, we also set up the reply iovec here so that iov[1] points 428 * cache, we also set up the reply iovec here so that iov[1] points
@@ -253,6 +451,44 @@ nfs_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
253} 451}
254 452
255/* 453/*
454 * 2.2.7. readargs
455 *
456 * struct readargs {
457 * fhandle file;
458 * unsigned offset;
459 * unsigned count;
460 * unsigned totalcount;
461 * };
462 */
463static void encode_readargs(struct xdr_stream *xdr,
464 const struct nfs_readargs *args)
465{
466 u32 offset = args->offset;
467 u32 count = args->count;
468 __be32 *p;
469
470 encode_fhandle(xdr, args->fh);
471
472 p = xdr_reserve_space(xdr, 4 + 4 + 4);
473 *p++ = cpu_to_be32(offset);
474 *p++ = cpu_to_be32(count);
475 *p = cpu_to_be32(count);
476}
477
478static int nfs2_xdr_enc_readargs(struct rpc_rqst *req, __be32 *p,
479 const struct nfs_readargs *args)
480{
481 struct xdr_stream xdr;
482
483 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
484 encode_readargs(&xdr, args);
485 prepare_reply_buffer(req, args->pages, args->pgbase,
486 args->count, NFS_readres_sz);
487 req->rq_rcv_buf.flags |= XDRBUF_READ;
488 return 0;
489}
490
491/*
256 * Decode READ reply 492 * Decode READ reply
257 */ 493 */
258static int 494static int
@@ -318,6 +554,47 @@ nfs_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
318} 554}
319 555
320/* 556/*
557 * 2.2.9. writeargs
558 *
559 * struct writeargs {
560 * fhandle file;
561 * unsigned beginoffset;
562 * unsigned offset;
563 * unsigned totalcount;
564 * nfsdata data;
565 * };
566 */
567static void encode_writeargs(struct xdr_stream *xdr,
568 const struct nfs_writeargs *args)
569{
570 u32 offset = args->offset;
571 u32 count = args->count;
572 __be32 *p;
573
574 encode_fhandle(xdr, args->fh);
575
576 p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
577 *p++ = cpu_to_be32(offset);
578 *p++ = cpu_to_be32(offset);
579 *p++ = cpu_to_be32(count);
580
581 /* nfsdata */
582 *p = cpu_to_be32(count);
583 xdr_write_pages(xdr, args->pages, args->pgbase, count);
584}
585
586static int nfs2_xdr_enc_writeargs(struct rpc_rqst *req, __be32 *p,
587 const struct nfs_writeargs *args)
588{
589 struct xdr_stream xdr;
590
591 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
592 encode_writeargs(&xdr, args);
593 xdr.buf->flags |= XDRBUF_WRITE;
594 return 0;
595}
596
597/*
321 * Encode create arguments 598 * Encode create arguments
322 * CREATE, MKDIR 599 * CREATE, MKDIR
323 */ 600 */
@@ -332,6 +609,35 @@ nfs_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs_createargs *args)
332} 609}
333 610
334/* 611/*
612 * 2.2.10. createargs
613 *
614 * struct createargs {
615 * diropargs where;
616 * sattr attributes;
617 * };
618 */
619static int nfs2_xdr_enc_createargs(struct rpc_rqst *req, __be32 *p,
620 const struct nfs_createargs *args)
621{
622 struct xdr_stream xdr;
623
624 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
625 encode_diropargs(&xdr, args->fh, args->name, args->len);
626 encode_sattr(&xdr, args->sattr);
627 return 0;
628}
629
630static int nfs2_xdr_enc_removeargs(struct rpc_rqst *req, __be32 *p,
631 const struct nfs_removeargs *args)
632{
633 struct xdr_stream xdr;
634
635 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
636 encode_diropargs(&xdr, args->fh, args->name.name, args->name.len);
637 return 0;
638}
639
640/*
335 * Encode RENAME arguments 641 * Encode RENAME arguments
336 */ 642 */
337static int 643static int
@@ -346,6 +652,27 @@ nfs_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs_renameargs *args)
346} 652}
347 653
348/* 654/*
655 * 2.2.12. renameargs
656 *
657 * struct renameargs {
658 * diropargs from;
659 * diropargs to;
660 * };
661 */
662static int nfs2_xdr_enc_renameargs(struct rpc_rqst *req, __be32 *p,
663 const struct nfs_renameargs *args)
664{
665 const struct qstr *old = args->old_name;
666 const struct qstr *new = args->new_name;
667 struct xdr_stream xdr;
668
669 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
670 encode_diropargs(&xdr, args->old_dir, old->name, old->len);
671 encode_diropargs(&xdr, args->new_dir, new->name, new->len);
672 return 0;
673}
674
675/*
349 * Encode LINK arguments 676 * Encode LINK arguments
350 */ 677 */
351static int 678static int
@@ -359,6 +686,25 @@ nfs_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs_linkargs *args)
359} 686}
360 687
361/* 688/*
689 * 2.2.13. linkargs
690 *
691 * struct linkargs {
692 * fhandle from;
693 * diropargs to;
694 * };
695 */
696static int nfs2_xdr_enc_linkargs(struct rpc_rqst *req, __be32 *p,
697 const struct nfs_linkargs *args)
698{
699 struct xdr_stream xdr;
700
701 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
702 encode_fhandle(&xdr, args->fromfh);
703 encode_diropargs(&xdr, args->tofh, args->toname, args->tolen);
704 return 0;
705}
706
707/*
362 * Encode SYMLINK arguments 708 * Encode SYMLINK arguments
363 */ 709 */
364static int 710static int
@@ -388,6 +734,27 @@ nfs_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs_symlinkargs *arg
388} 734}
389 735
390/* 736/*
737 * 2.2.14. symlinkargs
738 *
739 * struct symlinkargs {
740 * diropargs from;
741 * path to;
742 * sattr attributes;
743 * };
744 */
745static int nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req, __be32 *p,
746 const struct nfs_symlinkargs *args)
747{
748 struct xdr_stream xdr;
749
750 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
751 encode_diropargs(&xdr, args->fromfh, args->fromname, args->fromlen);
752 encode_path(&xdr, args->pages, args->pathlen);
753 encode_sattr(&xdr, args->sattr);
754 return 0;
755}
756
757/*
391 * Encode arguments to readdir call 758 * Encode arguments to readdir call
392 */ 759 */
393static int 760static int
@@ -409,6 +776,39 @@ nfs_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs_readdirargs *arg
409} 776}
410 777
411/* 778/*
779 * 2.2.17. readdirargs
780 *
781 * struct readdirargs {
782 * fhandle dir;
783 * nfscookie cookie;
784 * unsigned count;
785 * };
786 */
787static void encode_readdirargs(struct xdr_stream *xdr,
788 const struct nfs_readdirargs *args)
789{
790 __be32 *p;
791
792 encode_fhandle(xdr, args->fh);
793
794 p = xdr_reserve_space(xdr, 4 + 4);
795 *p++ = cpu_to_be32(args->cookie);
796 *p = cpu_to_be32(args->count);
797}
798
799static int nfs2_xdr_enc_readdirargs(struct rpc_rqst *req, __be32 *p,
800 const struct nfs_readdirargs *args)
801{
802 struct xdr_stream xdr;
803
804 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
805 encode_readdirargs(&xdr, args);
806 prepare_reply_buffer(req, args->pages, 0,
807 args->count, NFS_readdirres_sz);
808 return 0;
809}
810
811/*
412 * Decode the result of a readdir call. 812 * Decode the result of a readdir call.
413 * We're not really decoding anymore, we just leave the buffer untouched 813 * We're not really decoding anymore, we just leave the buffer untouched
414 * and only check that it is syntactically correct. 814 * and only check that it is syntactically correct.
@@ -698,7 +1098,7 @@ nfs_stat_to_errno(int stat)
698#define PROC(proc, argtype, restype, timer) \ 1098#define PROC(proc, argtype, restype, timer) \
699[NFSPROC_##proc] = { \ 1099[NFSPROC_##proc] = { \
700 .p_proc = NFSPROC_##proc, \ 1100 .p_proc = NFSPROC_##proc, \
701 .p_encode = (kxdrproc_t) nfs_xdr_##argtype, \ 1101 .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \
702 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \ 1102 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
703 .p_arglen = NFS_##argtype##_sz, \ 1103 .p_arglen = NFS_##argtype##_sz, \
704 .p_replen = NFS_##restype##_sz, \ 1104 .p_replen = NFS_##restype##_sz, \