blob: 827d1b8ad55b52ccf618ed51acc5c59e530545ea [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/fs/nfs/nfs2xdr.c
3 *
4 * XDR functions to encode/decode NFS RPC arguments and results.
5 *
6 * Copyright (C) 1992, 1993, 1994 Rick Sladkey
7 * Copyright (C) 1996 Olaf Kirch
8 * 04 Aug 1998 Ion Badulescu <ionut@cs.columbia.edu>
9 * FIFO's need special handling in NFSv2
10 */
11
12#include <linux/param.h>
13#include <linux/time.h>
14#include <linux/mm.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#include <linux/errno.h>
16#include <linux/string.h>
17#include <linux/in.h>
18#include <linux/pagemap.h>
19#include <linux/proc_fs.h>
20#include <linux/sunrpc/clnt.h>
21#include <linux/nfs.h>
22#include <linux/nfs2.h>
23#include <linux/nfs_fs.h>
Trond Myklebust816724e2006-06-24 08:41:41 -040024#include "internal.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070025
26#define NFSDBG_FACILITY NFSDBG_XDR
Linus Torvalds1da177e2005-04-16 15:20:36 -070027
Linus Torvalds1da177e2005-04-16 15:20:36 -070028/* Mapping from NFS error code to "errno" error code. */
29#define errno_NFSERR_IO EIO
30
31/*
32 * Declare the space requirements for NFS arguments and replies as
33 * number of 32bit-words
34 */
35#define NFS_fhandle_sz (8)
36#define NFS_sattr_sz (8)
37#define NFS_filename_sz (1+(NFS2_MAXNAMLEN>>2))
38#define NFS_path_sz (1+(NFS2_MAXPATHLEN>>2))
39#define NFS_fattr_sz (17)
40#define NFS_info_sz (5)
41#define NFS_entry_sz (NFS_filename_sz+3)
42
43#define NFS_diropargs_sz (NFS_fhandle_sz+NFS_filename_sz)
Trond Myklebust4fdc17b2007-07-14 15:39:57 -040044#define NFS_removeargs_sz (NFS_fhandle_sz+NFS_filename_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070045#define NFS_sattrargs_sz (NFS_fhandle_sz+NFS_sattr_sz)
46#define NFS_readlinkargs_sz (NFS_fhandle_sz)
47#define NFS_readargs_sz (NFS_fhandle_sz+3)
48#define NFS_writeargs_sz (NFS_fhandle_sz+4)
49#define NFS_createargs_sz (NFS_diropargs_sz+NFS_sattr_sz)
50#define NFS_renameargs_sz (NFS_diropargs_sz+NFS_diropargs_sz)
51#define NFS_linkargs_sz (NFS_fhandle_sz+NFS_diropargs_sz)
Chuck Lever94a6d752006-08-22 20:06:23 -040052#define NFS_symlinkargs_sz (NFS_diropargs_sz+1+NFS_sattr_sz)
Linus Torvalds1da177e2005-04-16 15:20:36 -070053#define NFS_readdirargs_sz (NFS_fhandle_sz+2)
54
55#define NFS_attrstat_sz (1+NFS_fattr_sz)
56#define NFS_diropres_sz (1+NFS_fhandle_sz+NFS_fattr_sz)
57#define NFS_readlinkres_sz (2)
58#define NFS_readres_sz (1+NFS_fattr_sz+1)
59#define NFS_writeres_sz (NFS_attrstat_sz)
60#define NFS_stat_sz (1)
61#define NFS_readdirres_sz (1)
62#define NFS_statfsres_sz (1+NFS_info_sz)
63
Chuck Lever25a08662010-12-14 14:54:30 +000064
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
Chuck Leverf796f8b2010-12-14 14:55:10 +000080/*
81 * Handle decode buffer overflows out-of-line.
82 */
83static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
84{
85 dprintk("NFS: %s prematurely hit the end of our receive buffer. "
86 "Remaining buffer length is %tu words.\n",
87 func, xdr->end - xdr->p);
88}
89
Chuck Lever25a08662010-12-14 14:54:30 +000090
Linus Torvalds1da177e2005-04-16 15:20:36 -070091/*
92 * Common NFS XDR functions as inlines
93 */
Al Viro9d787a72006-10-19 23:28:47 -070094static inline __be32 *
Al Viro9d787a72006-10-19 23:28:47 -070095xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
97 /* NFSv2 handles have a fixed length */
98 fhandle->size = NFS2_FHSIZE;
99 memcpy(fhandle->data, p, NFS2_FHSIZE);
100 return p + XDR_QUADLEN(NFS2_FHSIZE);
101}
102
Al Viro9d787a72006-10-19 23:28:47 -0700103static inline __be32*
Al Viro9d787a72006-10-19 23:28:47 -0700104xdr_decode_time(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105{
106 timep->tv_sec = ntohl(*p++);
107 /* Convert microseconds into nanoseconds */
108 timep->tv_nsec = ntohl(*p++) * 1000;
109 return p;
110}
111
Al Viro9d787a72006-10-19 23:28:47 -0700112static __be32 *
113xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
Trond Myklebustbca79472009-03-11 14:10:26 -0400115 u32 rdev, type;
116 type = ntohl(*p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700117 fattr->mode = ntohl(*p++);
118 fattr->nlink = ntohl(*p++);
119 fattr->uid = ntohl(*p++);
120 fattr->gid = ntohl(*p++);
121 fattr->size = ntohl(*p++);
122 fattr->du.nfs2.blocksize = ntohl(*p++);
123 rdev = ntohl(*p++);
124 fattr->du.nfs2.blocks = ntohl(*p++);
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400125 fattr->fsid.major = ntohl(*p++);
126 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 fattr->fileid = ntohl(*p++);
128 p = xdr_decode_time(p, &fattr->atime);
129 p = xdr_decode_time(p, &fattr->mtime);
130 p = xdr_decode_time(p, &fattr->ctime);
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400131 fattr->valid |= NFS_ATTR_FATTR_V2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 fattr->rdev = new_decode_dev(rdev);
Trond Myklebustbca79472009-03-11 14:10:26 -0400133 if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700134 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
135 fattr->rdev = 0;
136 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 return p;
138}
139
Linus Torvalds1da177e2005-04-16 15:20:36 -0700140/*
Chuck Lever25a08662010-12-14 14:54:30 +0000141 * Encode/decode NFSv2 basic data types
142 *
143 * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
144 * "NFS: Network File System Protocol Specification".
145 *
146 * Not all basic data types have their own encoding and decoding
147 * functions. For run-time efficiency, some data types are encoded
148 * or decoded inline.
149 */
150
151/*
Chuck Leverf796f8b2010-12-14 14:55:10 +0000152 * typedef opaque nfsdata<>;
153 */
154static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result)
155{
156 u32 recvd, count;
157 size_t hdrlen;
158 __be32 *p;
159
160 p = xdr_inline_decode(xdr, 4);
161 if (unlikely(p == NULL))
162 goto out_overflow;
163 count = be32_to_cpup(p);
164 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
165 recvd = xdr->buf->len - hdrlen;
166 if (unlikely(count > recvd))
167 goto out_cheating;
168out:
169 xdr_read_pages(xdr, count);
170 result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */
171 result->count = count;
172 return count;
173out_cheating:
174 dprintk("NFS: server cheating in read result: "
175 "count %u > recvd %u\n", count, recvd);
176 count = recvd;
177 goto out;
178out_overflow:
179 print_overflow_msg(__func__, xdr);
180 return -EIO;
181}
182
183/*
184 * enum stat {
185 * NFS_OK = 0,
186 * NFSERR_PERM = 1,
187 * NFSERR_NOENT = 2,
188 * NFSERR_IO = 5,
189 * NFSERR_NXIO = 6,
190 * NFSERR_ACCES = 13,
191 * NFSERR_EXIST = 17,
192 * NFSERR_NODEV = 19,
193 * NFSERR_NOTDIR = 20,
194 * NFSERR_ISDIR = 21,
195 * NFSERR_FBIG = 27,
196 * NFSERR_NOSPC = 28,
197 * NFSERR_ROFS = 30,
198 * NFSERR_NAMETOOLONG = 63,
199 * NFSERR_NOTEMPTY = 66,
200 * NFSERR_DQUOT = 69,
201 * NFSERR_STALE = 70,
202 * NFSERR_WFLUSH = 99
203 * };
204 */
205static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
206{
207 __be32 *p;
208
209 p = xdr_inline_decode(xdr, 4);
210 if (unlikely(p == NULL))
211 goto out_overflow;
212 *status = be32_to_cpup(p);
213 return 0;
214out_overflow:
215 print_overflow_msg(__func__, xdr);
216 return -EIO;
217}
218
219/*
Chuck Lever25a08662010-12-14 14:54:30 +0000220 * 2.3.3. fhandle
221 *
222 * typedef opaque fhandle[FHSIZE];
223 */
224static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
225{
226 __be32 *p;
227
228 BUG_ON(fh->size != NFS2_FHSIZE);
229 p = xdr_reserve_space(xdr, NFS2_FHSIZE);
230 memcpy(p, fh->data, NFS2_FHSIZE);
231}
232
Chuck Leverf796f8b2010-12-14 14:55:10 +0000233static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
234{
235 __be32 *p;
236
237 p = xdr_inline_decode(xdr, NFS2_FHSIZE);
238 if (unlikely(p == NULL))
239 goto out_overflow;
240 fh->size = NFS2_FHSIZE;
241 memcpy(fh->data, p, NFS2_FHSIZE);
242 return 0;
243out_overflow:
244 print_overflow_msg(__func__, xdr);
245 return -EIO;
246}
247
Chuck Lever25a08662010-12-14 14:54:30 +0000248/*
Chuck Lever282ac2a2010-12-14 14:54:50 +0000249 * 2.3.4. timeval
250 *
251 * struct timeval {
252 * unsigned int seconds;
253 * unsigned int useconds;
254 * };
255 */
256static __be32 *xdr_encode_time(__be32 *p, const struct timespec *timep)
257{
258 *p++ = cpu_to_be32(timep->tv_sec);
259 if (timep->tv_nsec != 0)
260 *p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC);
261 else
262 *p++ = cpu_to_be32(0);
263 return p;
264}
265
266/*
267 * Passing the invalid value useconds=1000000 is a Sun convention for
268 * "set to current server time". It's needed to make permissions checks
269 * for the "touch" program across v2 mounts to Solaris and Irix servers
270 * work correctly. See description of sattr in section 6.1 of "NFS
271 * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5.
272 */
273static __be32 *xdr_encode_current_server_time(__be32 *p,
274 const struct timespec *timep)
275{
276 *p++ = cpu_to_be32(timep->tv_sec);
277 *p++ = cpu_to_be32(1000000);
278 return p;
279}
280
281/*
Chuck Leverf796f8b2010-12-14 14:55:10 +0000282 * 2.3.5. fattr
283 *
284 * struct fattr {
285 * ftype type;
286 * unsigned int mode;
287 * unsigned int nlink;
288 * unsigned int uid;
289 * unsigned int gid;
290 * unsigned int size;
291 * unsigned int blocksize;
292 * unsigned int rdev;
293 * unsigned int blocks;
294 * unsigned int fsid;
295 * unsigned int fileid;
296 * timeval atime;
297 * timeval mtime;
298 * timeval ctime;
299 * };
300 *
301 */
302static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
303{
304 __be32 *p;
305
306 p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
307 if (unlikely(p == NULL))
308 goto out_overflow;
309 xdr_decode_fattr(p, fattr);
310 return 0;
311out_overflow:
312 print_overflow_msg(__func__, xdr);
313 return -EIO;
314}
315
316/*
Chuck Lever25a08662010-12-14 14:54:30 +0000317 * 2.3.6. sattr
318 *
319 * struct sattr {
320 * unsigned int mode;
321 * unsigned int uid;
322 * unsigned int gid;
323 * unsigned int size;
324 * timeval atime;
325 * timeval mtime;
326 * };
327 */
328
329#define NFS2_SATTR_NOT_SET (0xffffffff)
330
331static __be32 *xdr_time_not_set(__be32 *p)
332{
333 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
334 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
335 return p;
336}
337
338static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
339{
340 __be32 *p;
341
342 p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
343
344 if (attr->ia_valid & ATTR_MODE)
345 *p++ = cpu_to_be32(attr->ia_mode);
346 else
347 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
348 if (attr->ia_valid & ATTR_UID)
349 *p++ = cpu_to_be32(attr->ia_uid);
350 else
351 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
352 if (attr->ia_valid & ATTR_GID)
353 *p++ = cpu_to_be32(attr->ia_gid);
354 else
355 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
356 if (attr->ia_valid & ATTR_SIZE)
357 *p++ = cpu_to_be32((u32)attr->ia_size);
358 else
359 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
360
361 if (attr->ia_valid & ATTR_ATIME_SET)
362 p = xdr_encode_time(p, &attr->ia_atime);
363 else if (attr->ia_valid & ATTR_ATIME)
364 p = xdr_encode_current_server_time(p, &attr->ia_atime);
365 else
366 p = xdr_time_not_set(p);
367 if (attr->ia_valid & ATTR_MTIME_SET)
368 xdr_encode_time(p, &attr->ia_mtime);
369 else if (attr->ia_valid & ATTR_MTIME)
370 xdr_encode_current_server_time(p, &attr->ia_mtime);
371 else
372 xdr_time_not_set(p);
373}
374
375/*
376 * 2.3.7. filename
377 *
378 * typedef string filename<MAXNAMLEN>;
379 */
380static void encode_filename(struct xdr_stream *xdr,
381 const char *name, u32 length)
382{
383 __be32 *p;
384
385 BUG_ON(length > NFS2_MAXNAMLEN);
386 p = xdr_reserve_space(xdr, 4 + length);
387 xdr_encode_opaque(p, name, length);
388}
389
Chuck Leverf796f8b2010-12-14 14:55:10 +0000390static int decode_filename_inline(struct xdr_stream *xdr,
391 const char **name, u32 *length)
392{
393 __be32 *p;
394 u32 count;
395
396 p = xdr_inline_decode(xdr, 4);
397 if (unlikely(p == NULL))
398 goto out_overflow;
399 count = be32_to_cpup(p);
400 if (count > NFS3_MAXNAMLEN)
401 goto out_nametoolong;
402 p = xdr_inline_decode(xdr, count);
403 if (unlikely(p == NULL))
404 goto out_overflow;
405 *name = (const char *)p;
406 *length = count;
407 return 0;
408out_nametoolong:
409 dprintk("NFS: returned filename too long: %u\n", count);
410 return -ENAMETOOLONG;
411out_overflow:
412 print_overflow_msg(__func__, xdr);
413 return -EIO;
414}
415
Chuck Lever25a08662010-12-14 14:54:30 +0000416/*
417 * 2.3.8. path
418 *
419 * typedef string path<MAXPATHLEN>;
420 */
421static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
422{
423 __be32 *p;
424
425 BUG_ON(length > NFS2_MAXPATHLEN);
426 p = xdr_reserve_space(xdr, 4);
427 *p = cpu_to_be32(length);
428 xdr_write_pages(xdr, pages, 0, length);
429}
430
Chuck Leverf796f8b2010-12-14 14:55:10 +0000431static int decode_path(struct xdr_stream *xdr)
432{
433 u32 length, recvd;
434 size_t hdrlen;
435 __be32 *p;
436
437 p = xdr_inline_decode(xdr, 4);
438 if (unlikely(p == NULL))
439 goto out_overflow;
440 length = be32_to_cpup(p);
441 if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
442 goto out_size;
443 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
444 recvd = xdr->buf->len - hdrlen;
445 if (unlikely(length > recvd))
446 goto out_cheating;
447
448 xdr_read_pages(xdr, length);
449 xdr_terminate_string(xdr->buf, length);
450 return 0;
451out_size:
452 dprintk("NFS: returned pathname too long: %u\n", length);
453 return -ENAMETOOLONG;
454out_cheating:
455 dprintk("NFS: server cheating in pathname result: "
456 "length %u > received %u\n", length, recvd);
457 return -EIO;
458out_overflow:
459 print_overflow_msg(__func__, xdr);
460 return -EIO;
461}
462
463/*
464 * 2.3.9. attrstat
465 *
466 * union attrstat switch (stat status) {
467 * case NFS_OK:
468 * fattr attributes;
469 * default:
470 * void;
471 * };
472 */
473static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result)
474{
475 enum nfs_stat status;
476 int error;
477
478 error = decode_stat(xdr, &status);
479 if (unlikely(error))
480 goto out;
481 if (status != NFS_OK)
482 goto out_default;
483 error = decode_fattr(xdr, result);
484out:
485 return error;
486out_default:
487 return nfs_stat_to_errno(status);
488}
489
Chuck Lever25a08662010-12-14 14:54:30 +0000490/*
491 * 2.3.10. diropargs
492 *
493 * struct diropargs {
494 * fhandle dir;
495 * filename name;
496 * };
497 */
498static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
499 const char *name, u32 length)
500{
501 encode_fhandle(xdr, fh);
502 encode_filename(xdr, name, length);
503}
504
Chuck Leverf796f8b2010-12-14 14:55:10 +0000505/*
506 * 2.3.11. diropres
507 *
508 * union diropres switch (stat status) {
509 * case NFS_OK:
510 * struct {
511 * fhandle file;
512 * fattr attributes;
513 * } diropok;
514 * default:
515 * void;
516 * };
517 */
518static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result)
519{
520 int error;
521
522 error = decode_fhandle(xdr, result->fh);
523 if (unlikely(error))
524 goto out;
525 error = decode_fattr(xdr, result->fattr);
526out:
527 return error;
528}
529
530static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result)
531{
532 enum nfs_stat status;
533 int error;
534
535 error = decode_stat(xdr, &status);
536 if (unlikely(error))
537 goto out;
538 if (status != NFS_OK)
539 goto out_default;
540 error = decode_diropok(xdr, result);
541out:
542 return error;
543out_default:
544 return nfs_stat_to_errno(status);
545}
546
Chuck Lever25a08662010-12-14 14:54:30 +0000547
548/*
Chuck Lever2d70f532010-12-14 14:54:40 +0000549 * NFSv2 XDR encode functions
550 *
551 * NFSv2 argument types are defined in section 2.2 of RFC 1094:
552 * "NFS: Network File System Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Chuck Lever25a08662010-12-14 14:54:30 +0000555static int nfs2_xdr_enc_fhandle(struct rpc_rqst *req, __be32 *p,
556 const struct nfs_fh *fh)
557{
558 struct xdr_stream xdr;
559
560 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
561 encode_fhandle(&xdr, fh);
562 return 0;
563}
564
Linus Torvalds1da177e2005-04-16 15:20:36 -0700565/*
Chuck Lever25a08662010-12-14 14:54:30 +0000566 * 2.2.3. sattrargs
567 *
568 * struct sattrargs {
569 * fhandle file;
570 * sattr attributes;
571 * };
572 */
573static int nfs2_xdr_enc_sattrargs(struct rpc_rqst *req, __be32 *p,
574 const struct nfs_sattrargs *args)
575{
576 struct xdr_stream xdr;
577
578 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
579 encode_fhandle(&xdr, args->fh);
580 encode_sattr(&xdr, args->sattr);
581 return 0;
582}
583
Chuck Lever25a08662010-12-14 14:54:30 +0000584static int nfs2_xdr_enc_diropargs(struct rpc_rqst *req, __be32 *p,
585 const struct nfs_diropargs *args)
586{
587 struct xdr_stream xdr;
588
589 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
590 encode_diropargs(&xdr, args->fh, args->name, args->len);
591 return 0;
592}
593
Chuck Lever25a08662010-12-14 14:54:30 +0000594static int nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, __be32 *p,
595 const struct nfs_readlinkargs *args)
596{
597 struct xdr_stream xdr;
598
599 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
600 encode_fhandle(&xdr, args->fh);
601 prepare_reply_buffer(req, args->pages, args->pgbase,
602 args->pglen, NFS_readlinkres_sz);
603 return 0;
604}
605
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400606/*
Chuck Lever25a08662010-12-14 14:54:30 +0000607 * 2.2.7. readargs
608 *
609 * struct readargs {
610 * fhandle file;
611 * unsigned offset;
612 * unsigned count;
613 * unsigned totalcount;
614 * };
615 */
616static void encode_readargs(struct xdr_stream *xdr,
617 const struct nfs_readargs *args)
618{
619 u32 offset = args->offset;
620 u32 count = args->count;
621 __be32 *p;
622
623 encode_fhandle(xdr, args->fh);
624
625 p = xdr_reserve_space(xdr, 4 + 4 + 4);
626 *p++ = cpu_to_be32(offset);
627 *p++ = cpu_to_be32(count);
628 *p = cpu_to_be32(count);
629}
630
631static int nfs2_xdr_enc_readargs(struct rpc_rqst *req, __be32 *p,
632 const struct nfs_readargs *args)
633{
634 struct xdr_stream xdr;
635
636 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
637 encode_readargs(&xdr, args);
638 prepare_reply_buffer(req, args->pages, args->pgbase,
639 args->count, NFS_readres_sz);
640 req->rq_rcv_buf.flags |= XDRBUF_READ;
641 return 0;
642}
643
644/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 * Decode READ reply
646 */
647static int
Al Viro9d787a72006-10-19 23:28:47 -0700648nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649{
650 struct kvec *iov = req->rq_rcv_buf.head;
Chuck Lever6232dbb2007-10-26 13:31:52 -0400651 size_t hdrlen;
652 u32 count, recvd;
653 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654
655 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300656 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700657 p = xdr_decode_fattr(p, res->fattr);
658
659 count = ntohl(*p++);
660 res->eof = 0;
661 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
662 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400663 dprintk("NFS: READ reply header overflowed:"
Chuck Lever6232dbb2007-10-26 13:31:52 -0400664 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return -errno_NFSERR_IO;
666 } else if (iov->iov_len != hdrlen) {
667 dprintk("NFS: READ header is short. iovec will be shifted.\n");
668 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
669 }
670
671 recvd = req->rq_rcv_buf.len - hdrlen;
672 if (count > recvd) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400673 dprintk("NFS: server cheating in read reply: "
Chuck Lever6232dbb2007-10-26 13:31:52 -0400674 "count %u > recvd %u\n", count, recvd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700675 count = recvd;
676 }
677
Chuck Lever6232dbb2007-10-26 13:31:52 -0400678 dprintk("RPC: readres OK count %u\n", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 if (count < res->count)
680 res->count = count;
681
682 return count;
683}
684
685
686/*
Chuck Lever25a08662010-12-14 14:54:30 +0000687 * 2.2.9. writeargs
688 *
689 * struct writeargs {
690 * fhandle file;
691 * unsigned beginoffset;
692 * unsigned offset;
693 * unsigned totalcount;
694 * nfsdata data;
695 * };
696 */
697static void encode_writeargs(struct xdr_stream *xdr,
698 const struct nfs_writeargs *args)
699{
700 u32 offset = args->offset;
701 u32 count = args->count;
702 __be32 *p;
703
704 encode_fhandle(xdr, args->fh);
705
706 p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
707 *p++ = cpu_to_be32(offset);
708 *p++ = cpu_to_be32(offset);
709 *p++ = cpu_to_be32(count);
710
711 /* nfsdata */
712 *p = cpu_to_be32(count);
713 xdr_write_pages(xdr, args->pages, args->pgbase, count);
714}
715
716static int nfs2_xdr_enc_writeargs(struct rpc_rqst *req, __be32 *p,
717 const struct nfs_writeargs *args)
718{
719 struct xdr_stream xdr;
720
721 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
722 encode_writeargs(&xdr, args);
723 xdr.buf->flags |= XDRBUF_WRITE;
724 return 0;
725}
726
727/*
Chuck Lever25a08662010-12-14 14:54:30 +0000728 * 2.2.10. createargs
729 *
730 * struct createargs {
731 * diropargs where;
732 * sattr attributes;
733 * };
734 */
735static int nfs2_xdr_enc_createargs(struct rpc_rqst *req, __be32 *p,
736 const struct nfs_createargs *args)
737{
738 struct xdr_stream xdr;
739
740 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
741 encode_diropargs(&xdr, args->fh, args->name, args->len);
742 encode_sattr(&xdr, args->sattr);
743 return 0;
744}
745
746static int nfs2_xdr_enc_removeargs(struct rpc_rqst *req, __be32 *p,
747 const struct nfs_removeargs *args)
748{
749 struct xdr_stream xdr;
750
751 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
752 encode_diropargs(&xdr, args->fh, args->name.name, args->name.len);
753 return 0;
754}
755
756/*
Chuck Lever25a08662010-12-14 14:54:30 +0000757 * 2.2.12. renameargs
758 *
759 * struct renameargs {
760 * diropargs from;
761 * diropargs to;
762 * };
763 */
764static int nfs2_xdr_enc_renameargs(struct rpc_rqst *req, __be32 *p,
765 const struct nfs_renameargs *args)
766{
767 const struct qstr *old = args->old_name;
768 const struct qstr *new = args->new_name;
769 struct xdr_stream xdr;
770
771 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
772 encode_diropargs(&xdr, args->old_dir, old->name, old->len);
773 encode_diropargs(&xdr, args->new_dir, new->name, new->len);
774 return 0;
775}
776
777/*
Chuck Lever25a08662010-12-14 14:54:30 +0000778 * 2.2.13. linkargs
779 *
780 * struct linkargs {
781 * fhandle from;
782 * diropargs to;
783 * };
784 */
785static int nfs2_xdr_enc_linkargs(struct rpc_rqst *req, __be32 *p,
786 const struct nfs_linkargs *args)
787{
788 struct xdr_stream xdr;
789
790 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
791 encode_fhandle(&xdr, args->fromfh);
792 encode_diropargs(&xdr, args->tofh, args->toname, args->tolen);
793 return 0;
794}
795
796/*
Chuck Lever25a08662010-12-14 14:54:30 +0000797 * 2.2.14. symlinkargs
798 *
799 * struct symlinkargs {
800 * diropargs from;
801 * path to;
802 * sattr attributes;
803 * };
804 */
805static int nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req, __be32 *p,
806 const struct nfs_symlinkargs *args)
807{
808 struct xdr_stream xdr;
809
810 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
811 encode_diropargs(&xdr, args->fromfh, args->fromname, args->fromlen);
812 encode_path(&xdr, args->pages, args->pathlen);
813 encode_sattr(&xdr, args->sattr);
814 return 0;
815}
816
817/*
Chuck Lever25a08662010-12-14 14:54:30 +0000818 * 2.2.17. readdirargs
819 *
820 * struct readdirargs {
821 * fhandle dir;
822 * nfscookie cookie;
823 * unsigned count;
824 * };
825 */
826static void encode_readdirargs(struct xdr_stream *xdr,
827 const struct nfs_readdirargs *args)
828{
829 __be32 *p;
830
831 encode_fhandle(xdr, args->fh);
832
833 p = xdr_reserve_space(xdr, 4 + 4);
834 *p++ = cpu_to_be32(args->cookie);
835 *p = cpu_to_be32(args->count);
836}
837
838static int nfs2_xdr_enc_readdirargs(struct rpc_rqst *req, __be32 *p,
839 const struct nfs_readdirargs *args)
840{
841 struct xdr_stream xdr;
842
843 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
844 encode_readdirargs(&xdr, args);
845 prepare_reply_buffer(req, args->pages, 0,
846 args->count, NFS_readdirres_sz);
847 return 0;
848}
849
850/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851 * Decode the result of a readdir call.
852 * We're not really decoding anymore, we just leave the buffer untouched
853 * and only check that it is syntactically correct.
854 * The real decoding happens in nfs_decode_entry below, called directly
855 * from nfs_readdir for each entry.
856 */
857static int
Al Viro9d787a72006-10-19 23:28:47 -0700858nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859{
860 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
861 struct kvec *iov = rcvbuf->head;
862 struct page **page;
Chuck Lever6232dbb2007-10-26 13:31:52 -0400863 size_t hdrlen;
864 unsigned int pglen, recvd;
Trond Myklebustac396122010-11-15 20:26:22 -0500865 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700866
867 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300868 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869
870 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
871 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400872 dprintk("NFS: READDIR reply header overflowed:"
Chuck Lever6232dbb2007-10-26 13:31:52 -0400873 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 return -errno_NFSERR_IO;
875 } else if (iov->iov_len != hdrlen) {
876 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
877 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
878 }
879
880 pglen = rcvbuf->page_len;
881 recvd = rcvbuf->len - hdrlen;
882 if (pglen > recvd)
883 pglen = recvd;
884 page = rcvbuf->pages;
Trond Myklebustac396122010-11-15 20:26:22 -0500885 return pglen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700886}
887
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400888__be32 *
Bryan Schumaker82f2e542010-10-21 16:33:18 -0400889nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400890{
891 __be32 *p;
892 p = xdr_inline_decode(xdr, 4);
893 if (unlikely(!p))
894 goto out_overflow;
895 if (!ntohl(*p++)) {
896 p = xdr_inline_decode(xdr, 4);
897 if (unlikely(!p))
898 goto out_overflow;
899 if (!ntohl(*p++))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 return ERR_PTR(-EAGAIN);
901 entry->eof = 1;
902 return ERR_PTR(-EBADCOOKIE);
903 }
904
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400905 p = xdr_inline_decode(xdr, 8);
906 if (unlikely(!p))
907 goto out_overflow;
908
Linus Torvalds1da177e2005-04-16 15:20:36 -0700909 entry->ino = ntohl(*p++);
910 entry->len = ntohl(*p++);
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400911
912 p = xdr_inline_decode(xdr, entry->len + 4);
913 if (unlikely(!p))
914 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915 entry->name = (const char *) p;
916 p += XDR_QUADLEN(entry->len);
917 entry->prev_cookie = entry->cookie;
918 entry->cookie = ntohl(*p++);
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400919
Trond Myklebust0b26a0b2010-11-20 14:26:44 -0500920 entry->d_type = DT_UNKNOWN;
921
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400922 p = xdr_inline_peek(xdr, 8);
923 if (p != NULL)
924 entry->eof = !p[0] && p[1];
925 else
926 entry->eof = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927
928 return p;
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400929
930out_overflow:
931 print_overflow_msg(__func__, xdr);
Trond Myklebust463a3762010-11-20 12:22:20 -0500932 return ERR_PTR(-EAGAIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700933}
934
935/*
936 * NFS XDR decode functions
937 */
938/*
939 * Decode simple status reply
940 */
941static int
Al Viro9d787a72006-10-19 23:28:47 -0700942nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700943{
944 int status;
945
946 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +0300947 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948 return status;
949}
950
Chuck Leverf796f8b2010-12-14 14:55:10 +0000951static int nfs2_xdr_dec_stat(struct rpc_rqst *req, __be32 *p,
952 void *__unused)
953{
954 struct xdr_stream xdr;
955 enum nfs_stat status;
956 int error;
957
958 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
959 error = decode_stat(&xdr, &status);
960 if (unlikely(error))
961 goto out;
962 if (status != NFS_OK)
963 goto out_default;
964out:
965 return error;
966out_default:
967 return nfs_stat_to_errno(status);
968}
969
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970/*
971 * Decode attrstat reply
972 * GETATTR, SETATTR, WRITE
973 */
974static int
Al Viro9d787a72006-10-19 23:28:47 -0700975nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700976{
977 int status;
978
979 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300980 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700981 xdr_decode_fattr(p, fattr);
982 return 0;
983}
984
Chuck Leverf796f8b2010-12-14 14:55:10 +0000985static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, __be32 *p,
986 struct nfs_fattr *result)
987{
988 struct xdr_stream xdr;
989
990 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
991 return decode_attrstat(&xdr, result);
992}
993
Linus Torvalds1da177e2005-04-16 15:20:36 -0700994/*
995 * Decode diropres reply
996 * LOOKUP, CREATE, MKDIR
997 */
998static int
Al Viro9d787a72006-10-19 23:28:47 -0700999nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001000{
1001 int status;
1002
1003 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001004 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 p = xdr_decode_fhandle(p, res->fh);
1006 xdr_decode_fattr(p, res->fattr);
1007 return 0;
1008}
1009
Chuck Leverf796f8b2010-12-14 14:55:10 +00001010static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, __be32 *p,
1011 struct nfs_diropok *result)
1012{
1013 struct xdr_stream xdr;
1014
1015 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1016 return decode_diropres(&xdr, result);
1017}
1018
Linus Torvalds1da177e2005-04-16 15:20:36 -07001019/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001020 * Decode READLINK reply
1021 */
1022static int
Al Viro9d787a72006-10-19 23:28:47 -07001023nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001024{
1025 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
1026 struct kvec *iov = rcvbuf->head;
Chuck Lever6232dbb2007-10-26 13:31:52 -04001027 size_t hdrlen;
1028 u32 len, recvd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001029 int status;
1030
1031 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001032 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001033 /* Convert length of symlink */
1034 len = ntohl(*p++);
Chuck Lever6232dbb2007-10-26 13:31:52 -04001035 if (len >= rcvbuf->page_len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001036 dprintk("nfs: server returned giant symlink!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001037 return -ENAMETOOLONG;
1038 }
1039 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
1040 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001041 dprintk("NFS: READLINK reply header overflowed:"
Chuck Lever6232dbb2007-10-26 13:31:52 -04001042 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001043 return -errno_NFSERR_IO;
1044 } else if (iov->iov_len != hdrlen) {
1045 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
1046 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
1047 }
1048 recvd = req->rq_rcv_buf.len - hdrlen;
1049 if (recvd < len) {
Chuck Leverfe82a182007-09-11 18:01:10 -04001050 dprintk("NFS: server cheating in readlink reply: "
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051 "count %u > recvd %u\n", len, recvd);
1052 return -EIO;
1053 }
1054
Chuck Leverb4687da2010-09-21 16:55:48 -04001055 xdr_terminate_string(rcvbuf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001056 return 0;
1057}
1058
1059/*
Chuck Leverf796f8b2010-12-14 14:55:10 +00001060 * 2.2.6. readlinkres
1061 *
1062 * union readlinkres switch (stat status) {
1063 * case NFS_OK:
1064 * path data;
1065 * default:
1066 * void;
1067 * };
1068 */
1069static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req, __be32 *p,
1070 void *__unused)
1071{
1072 struct xdr_stream xdr;
1073 enum nfs_stat status;
1074 int error;
1075
1076 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1077 error = decode_stat(&xdr, &status);
1078 if (unlikely(error))
1079 goto out;
1080 if (status != NFS_OK)
1081 goto out_default;
1082 error = decode_path(&xdr);
1083out:
1084 return error;
1085out_default:
1086 return nfs_stat_to_errno(status);
1087}
1088
1089/*
1090 * 2.2.7. readres
1091 *
1092 * union readres switch (stat status) {
1093 * case NFS_OK:
1094 * fattr attributes;
1095 * nfsdata data;
1096 * default:
1097 * void;
1098 * };
1099 */
1100static int nfs2_xdr_dec_readres(struct rpc_rqst *req, __be32 *p,
1101 struct nfs_readres *result)
1102{
1103 struct xdr_stream xdr;
1104 enum nfs_stat status;
1105 int error;
1106
1107 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1108 error = decode_stat(&xdr, &status);
1109 if (unlikely(error))
1110 goto out;
1111 if (status != NFS_OK)
1112 goto out_default;
1113 error = decode_fattr(&xdr, result->fattr);
1114 if (unlikely(error))
1115 goto out;
1116 error = decode_nfsdata(&xdr, result);
1117out:
1118 return error;
1119out_default:
1120 return nfs_stat_to_errno(status);
1121}
1122
1123/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001124 * Decode WRITE reply
1125 */
1126static int
Al Viro9d787a72006-10-19 23:28:47 -07001127nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128{
1129 res->verf->committed = NFS_FILE_SYNC;
1130 return nfs_xdr_attrstat(req, p, res->fattr);
1131}
1132
Chuck Leverf796f8b2010-12-14 14:55:10 +00001133static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, __be32 *p,
1134 struct nfs_writeres *result)
1135{
1136 struct xdr_stream xdr;
1137
1138 /* All NFSv2 writes are "file sync" writes */
1139 result->verf->committed = NFS_FILE_SYNC;
1140
1141 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1142 return decode_attrstat(&xdr, result->fattr);
1143}
1144
1145/**
1146 * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
1147 * the local page cache.
1148 * @xdr: XDR stream where entry resides
1149 * @entry: buffer to fill in with entry data
1150 * @server: nfs_server data for this directory
1151 * @plus: boolean indicating whether this should be a readdirplus entry
1152 *
1153 * Returns the position of the next item in the buffer, or an ERR_PTR.
1154 *
1155 * This function is not invoked during READDIR reply decoding, but
1156 * rather whenever an application invokes the getdents(2) system call
1157 * on a directory already in our cache.
1158 *
1159 * 2.2.17. entry
1160 *
1161 * struct entry {
1162 * unsigned fileid;
1163 * filename name;
1164 * nfscookie cookie;
1165 * entry *nextentry;
1166 * };
1167 */
1168__be32 *nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
1169 struct nfs_server *server, int plus)
1170{
1171 __be32 *p;
1172 int error;
1173
1174 p = xdr_inline_decode(xdr, 4);
1175 if (unlikely(p == NULL))
1176 goto out_overflow;
1177 if (*p++ == xdr_zero) {
1178 p = xdr_inline_decode(xdr, 4);
1179 if (unlikely(p == NULL))
1180 goto out_overflow;
1181 if (*p++ == xdr_zero)
1182 return ERR_PTR(-EAGAIN);
1183 entry->eof = 1;
1184 return ERR_PTR(-EBADCOOKIE);
1185 }
1186
1187 p = xdr_inline_decode(xdr, 4);
1188 if (unlikely(p == NULL))
1189 goto out_overflow;
1190 entry->ino = be32_to_cpup(p);
1191
1192 error = decode_filename_inline(xdr, &entry->name, &entry->len);
1193 if (unlikely(error))
1194 return ERR_PTR(error);
1195
1196 /*
1197 * The type (size and byte order) of nfscookie isn't defined in
1198 * RFC 1094. This implementation assumes that it's an XDR uint32.
1199 */
1200 entry->prev_cookie = entry->cookie;
1201 p = xdr_inline_decode(xdr, 4);
1202 if (unlikely(p == NULL))
1203 goto out_overflow;
1204 entry->cookie = be32_to_cpup(p);
1205
1206 entry->d_type = DT_UNKNOWN;
1207
1208 /* Peek at the next entry to see if we're at EOD */
1209 p = xdr_inline_peek(xdr, 4 + 4);
1210 entry->eof = 0;
1211 if (p != NULL)
1212 entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
1213 return p;
1214
1215out_overflow:
1216 print_overflow_msg(__func__, xdr);
1217 return ERR_PTR(-EAGAIN);
1218}
1219
1220/*
1221 * 2.2.17. readdirres
1222 *
1223 * union readdirres switch (stat status) {
1224 * case NFS_OK:
1225 * struct {
1226 * entry *entries;
1227 * bool eof;
1228 * } readdirok;
1229 * default:
1230 * void;
1231 * };
1232 *
1233 * Read the directory contents into the page cache, but don't
1234 * touch them. The actual decoding is done by nfs2_decode_dirent()
1235 * during subsequent nfs_readdir() calls.
1236 */
1237static int decode_readdirok(struct xdr_stream *xdr)
1238{
1239 u32 recvd, pglen;
1240 size_t hdrlen;
1241
1242 pglen = xdr->buf->page_len;
1243 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
1244 recvd = xdr->buf->len - hdrlen;
1245 if (unlikely(pglen > recvd))
1246 goto out_cheating;
1247out:
1248 xdr_read_pages(xdr, pglen);
1249 return pglen;
1250out_cheating:
1251 dprintk("NFS: server cheating in readdir result: "
1252 "pglen %u > recvd %u\n", pglen, recvd);
1253 pglen = recvd;
1254 goto out;
1255}
1256
1257static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, __be32 *p,
1258 void *__unused)
1259{
1260 struct xdr_stream xdr;
1261 enum nfs_stat status;
1262 int error;
1263
1264 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1265 error = decode_stat(&xdr, &status);
1266 if (unlikely(error))
1267 goto out;
1268 if (status != NFS_OK)
1269 goto out_default;
1270 error = decode_readdirok(&xdr);
1271out:
1272 return error;
1273out_default:
1274 return nfs_stat_to_errno(status);
1275}
1276
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277/*
1278 * Decode STATFS reply
1279 */
1280static int
Al Viro9d787a72006-10-19 23:28:47 -07001281nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001282{
1283 int status;
1284
1285 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +03001286 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001287
1288 res->tsize = ntohl(*p++);
1289 res->bsize = ntohl(*p++);
1290 res->blocks = ntohl(*p++);
1291 res->bfree = ntohl(*p++);
1292 res->bavail = ntohl(*p++);
1293 return 0;
1294}
1295
1296/*
Chuck Leverf796f8b2010-12-14 14:55:10 +00001297 * 2.2.18. statfsres
1298 *
1299 * union statfsres (stat status) {
1300 * case NFS_OK:
1301 * struct {
1302 * unsigned tsize;
1303 * unsigned bsize;
1304 * unsigned blocks;
1305 * unsigned bfree;
1306 * unsigned bavail;
1307 * } info;
1308 * default:
1309 * void;
1310 * };
1311 */
1312static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
1313{
1314 __be32 *p;
1315
1316 p = xdr_inline_decode(xdr, NFS_info_sz << 2);
1317 if (unlikely(p == NULL))
1318 goto out_overflow;
1319 result->tsize = be32_to_cpup(p++);
1320 result->bsize = be32_to_cpup(p++);
1321 result->blocks = be32_to_cpup(p++);
1322 result->bfree = be32_to_cpup(p++);
1323 result->bavail = be32_to_cpup(p);
1324 return 0;
1325out_overflow:
1326 print_overflow_msg(__func__, xdr);
1327 return -EIO;
1328}
1329
1330static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, __be32 *p,
1331 struct nfs2_fsstat *result)
1332{
1333 struct xdr_stream xdr;
1334 enum nfs_stat status;
1335 int error;
1336
1337 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1338 error = decode_stat(&xdr, &status);
1339 if (unlikely(error))
1340 goto out;
1341 if (status != NFS_OK)
1342 goto out_default;
1343 error = decode_info(&xdr, result);
1344out:
1345 return error;
1346out_default:
1347 return nfs_stat_to_errno(status);
1348}
1349
1350
1351/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001352 * We need to translate between nfs status return values and
1353 * the local errno values which may not be the same.
1354 */
Chuck Lever85828492010-12-14 14:55:00 +00001355static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 int stat;
1357 int errno;
1358} nfs_errtbl[] = {
1359 { NFS_OK, 0 },
Benny Halevy856dff32008-03-31 17:39:06 +03001360 { NFSERR_PERM, -EPERM },
1361 { NFSERR_NOENT, -ENOENT },
1362 { NFSERR_IO, -errno_NFSERR_IO},
1363 { NFSERR_NXIO, -ENXIO },
1364/* { NFSERR_EAGAIN, -EAGAIN }, */
1365 { NFSERR_ACCES, -EACCES },
1366 { NFSERR_EXIST, -EEXIST },
1367 { NFSERR_XDEV, -EXDEV },
1368 { NFSERR_NODEV, -ENODEV },
1369 { NFSERR_NOTDIR, -ENOTDIR },
1370 { NFSERR_ISDIR, -EISDIR },
1371 { NFSERR_INVAL, -EINVAL },
1372 { NFSERR_FBIG, -EFBIG },
1373 { NFSERR_NOSPC, -ENOSPC },
1374 { NFSERR_ROFS, -EROFS },
1375 { NFSERR_MLINK, -EMLINK },
1376 { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
1377 { NFSERR_NOTEMPTY, -ENOTEMPTY },
1378 { NFSERR_DQUOT, -EDQUOT },
1379 { NFSERR_STALE, -ESTALE },
1380 { NFSERR_REMOTE, -EREMOTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001381#ifdef EWFLUSH
Benny Halevy856dff32008-03-31 17:39:06 +03001382 { NFSERR_WFLUSH, -EWFLUSH },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001383#endif
Benny Halevy856dff32008-03-31 17:39:06 +03001384 { NFSERR_BADHANDLE, -EBADHANDLE },
1385 { NFSERR_NOT_SYNC, -ENOTSYNC },
1386 { NFSERR_BAD_COOKIE, -EBADCOOKIE },
1387 { NFSERR_NOTSUPP, -ENOTSUPP },
1388 { NFSERR_TOOSMALL, -ETOOSMALL },
Trond Myklebustfdcb4572010-02-08 09:32:40 -05001389 { NFSERR_SERVERFAULT, -EREMOTEIO },
Benny Halevy856dff32008-03-31 17:39:06 +03001390 { NFSERR_BADTYPE, -EBADTYPE },
1391 { NFSERR_JUKEBOX, -EJUKEBOX },
1392 { -1, -EIO }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393};
1394
Chuck Lever85828492010-12-14 14:55:00 +00001395/**
1396 * nfs_stat_to_errno - convert an NFS status code to a local errno
1397 * @status: NFS status code to convert
1398 *
1399 * Returns a local errno value, or -EIO if the NFS status code is
1400 * not recognized. This function is used jointly by NFSv2 and NFSv3.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001401 */
Chuck Lever85828492010-12-14 14:55:00 +00001402int nfs_stat_to_errno(enum nfs_stat status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001403{
1404 int i;
1405
1406 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
Chuck Lever85828492010-12-14 14:55:00 +00001407 if (nfs_errtbl[i].stat == (int)status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408 return nfs_errtbl[i].errno;
1409 }
Chuck Lever85828492010-12-14 14:55:00 +00001410 dprintk("NFS: Unrecognized nfs status value: %u\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 return nfs_errtbl[i].errno;
1412}
1413
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414#define PROC(proc, argtype, restype, timer) \
1415[NFSPROC_##proc] = { \
1416 .p_proc = NFSPROC_##proc, \
Chuck Lever25a08662010-12-14 14:54:30 +00001417 .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \
Chuck Leverf796f8b2010-12-14 14:55:10 +00001418 .p_decode = (kxdrproc_t)nfs2_xdr_dec_##restype, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04001419 .p_arglen = NFS_##argtype##_sz, \
1420 .p_replen = NFS_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05001421 .p_timer = timer, \
1422 .p_statidx = NFSPROC_##proc, \
1423 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 }
1425struct rpc_procinfo nfs_procedures[] = {
1426 PROC(GETATTR, fhandle, attrstat, 1),
1427 PROC(SETATTR, sattrargs, attrstat, 0),
1428 PROC(LOOKUP, diropargs, diropres, 2),
1429 PROC(READLINK, readlinkargs, readlinkres, 3),
1430 PROC(READ, readargs, readres, 3),
1431 PROC(WRITE, writeargs, writeres, 4),
1432 PROC(CREATE, createargs, diropres, 0),
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001433 PROC(REMOVE, removeargs, stat, 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001434 PROC(RENAME, renameargs, stat, 0),
1435 PROC(LINK, linkargs, stat, 0),
1436 PROC(SYMLINK, symlinkargs, stat, 0),
1437 PROC(MKDIR, createargs, diropres, 0),
1438 PROC(RMDIR, diropargs, stat, 0),
1439 PROC(READDIR, readdirargs, readdirres, 3),
1440 PROC(STATFS, fhandle, statfsres, 0),
1441};
1442
1443struct rpc_version nfs_version2 = {
1444 .number = 2,
Tobias Klausere8c96f82006-03-24 03:15:34 -08001445 .nrprocs = ARRAY_SIZE(nfs_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001446 .procs = nfs_procedures
1447};