blob: ae751163da8b9d9c2efc98827a239268f4d30d21 [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_time(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -070096{
97 timep->tv_sec = ntohl(*p++);
98 /* Convert microseconds into nanoseconds */
99 timep->tv_nsec = ntohl(*p++) * 1000;
100 return p;
101}
102
Al Viro9d787a72006-10-19 23:28:47 -0700103static __be32 *
104xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105{
Trond Myklebustbca79472009-03-11 14:10:26 -0400106 u32 rdev, type;
107 type = ntohl(*p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700108 fattr->mode = ntohl(*p++);
109 fattr->nlink = ntohl(*p++);
110 fattr->uid = ntohl(*p++);
111 fattr->gid = ntohl(*p++);
112 fattr->size = ntohl(*p++);
113 fattr->du.nfs2.blocksize = ntohl(*p++);
114 rdev = ntohl(*p++);
115 fattr->du.nfs2.blocks = ntohl(*p++);
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400116 fattr->fsid.major = ntohl(*p++);
117 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700118 fattr->fileid = ntohl(*p++);
119 p = xdr_decode_time(p, &fattr->atime);
120 p = xdr_decode_time(p, &fattr->mtime);
121 p = xdr_decode_time(p, &fattr->ctime);
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400122 fattr->valid |= NFS_ATTR_FATTR_V2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 fattr->rdev = new_decode_dev(rdev);
Trond Myklebustbca79472009-03-11 14:10:26 -0400124 if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
126 fattr->rdev = 0;
127 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 return p;
129}
130
Linus Torvalds1da177e2005-04-16 15:20:36 -0700131/*
Chuck Lever25a08662010-12-14 14:54:30 +0000132 * Encode/decode NFSv2 basic data types
133 *
134 * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
135 * "NFS: Network File System Protocol Specification".
136 *
137 * Not all basic data types have their own encoding and decoding
138 * functions. For run-time efficiency, some data types are encoded
139 * or decoded inline.
140 */
141
142/*
Chuck Leverf796f8b2010-12-14 14:55:10 +0000143 * typedef opaque nfsdata<>;
144 */
145static int decode_nfsdata(struct xdr_stream *xdr, struct nfs_readres *result)
146{
147 u32 recvd, count;
148 size_t hdrlen;
149 __be32 *p;
150
151 p = xdr_inline_decode(xdr, 4);
152 if (unlikely(p == NULL))
153 goto out_overflow;
154 count = be32_to_cpup(p);
155 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
156 recvd = xdr->buf->len - hdrlen;
157 if (unlikely(count > recvd))
158 goto out_cheating;
159out:
160 xdr_read_pages(xdr, count);
161 result->eof = 0; /* NFSv2 does not pass EOF flag on the wire. */
162 result->count = count;
163 return count;
164out_cheating:
165 dprintk("NFS: server cheating in read result: "
166 "count %u > recvd %u\n", count, recvd);
167 count = recvd;
168 goto out;
169out_overflow:
170 print_overflow_msg(__func__, xdr);
171 return -EIO;
172}
173
174/*
175 * enum stat {
176 * NFS_OK = 0,
177 * NFSERR_PERM = 1,
178 * NFSERR_NOENT = 2,
179 * NFSERR_IO = 5,
180 * NFSERR_NXIO = 6,
181 * NFSERR_ACCES = 13,
182 * NFSERR_EXIST = 17,
183 * NFSERR_NODEV = 19,
184 * NFSERR_NOTDIR = 20,
185 * NFSERR_ISDIR = 21,
186 * NFSERR_FBIG = 27,
187 * NFSERR_NOSPC = 28,
188 * NFSERR_ROFS = 30,
189 * NFSERR_NAMETOOLONG = 63,
190 * NFSERR_NOTEMPTY = 66,
191 * NFSERR_DQUOT = 69,
192 * NFSERR_STALE = 70,
193 * NFSERR_WFLUSH = 99
194 * };
195 */
196static int decode_stat(struct xdr_stream *xdr, enum nfs_stat *status)
197{
198 __be32 *p;
199
200 p = xdr_inline_decode(xdr, 4);
201 if (unlikely(p == NULL))
202 goto out_overflow;
203 *status = be32_to_cpup(p);
204 return 0;
205out_overflow:
206 print_overflow_msg(__func__, xdr);
207 return -EIO;
208}
209
210/*
Chuck Lever25a08662010-12-14 14:54:30 +0000211 * 2.3.3. fhandle
212 *
213 * typedef opaque fhandle[FHSIZE];
214 */
215static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
216{
217 __be32 *p;
218
219 BUG_ON(fh->size != NFS2_FHSIZE);
220 p = xdr_reserve_space(xdr, NFS2_FHSIZE);
221 memcpy(p, fh->data, NFS2_FHSIZE);
222}
223
Chuck Leverf796f8b2010-12-14 14:55:10 +0000224static int decode_fhandle(struct xdr_stream *xdr, struct nfs_fh *fh)
225{
226 __be32 *p;
227
228 p = xdr_inline_decode(xdr, NFS2_FHSIZE);
229 if (unlikely(p == NULL))
230 goto out_overflow;
231 fh->size = NFS2_FHSIZE;
232 memcpy(fh->data, p, NFS2_FHSIZE);
233 return 0;
234out_overflow:
235 print_overflow_msg(__func__, xdr);
236 return -EIO;
237}
238
Chuck Lever25a08662010-12-14 14:54:30 +0000239/*
Chuck Lever282ac2a2010-12-14 14:54:50 +0000240 * 2.3.4. timeval
241 *
242 * struct timeval {
243 * unsigned int seconds;
244 * unsigned int useconds;
245 * };
246 */
247static __be32 *xdr_encode_time(__be32 *p, const struct timespec *timep)
248{
249 *p++ = cpu_to_be32(timep->tv_sec);
250 if (timep->tv_nsec != 0)
251 *p++ = cpu_to_be32(timep->tv_nsec / NSEC_PER_USEC);
252 else
253 *p++ = cpu_to_be32(0);
254 return p;
255}
256
257/*
258 * Passing the invalid value useconds=1000000 is a Sun convention for
259 * "set to current server time". It's needed to make permissions checks
260 * for the "touch" program across v2 mounts to Solaris and Irix servers
261 * work correctly. See description of sattr in section 6.1 of "NFS
262 * Illustrated" by Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5.
263 */
264static __be32 *xdr_encode_current_server_time(__be32 *p,
265 const struct timespec *timep)
266{
267 *p++ = cpu_to_be32(timep->tv_sec);
268 *p++ = cpu_to_be32(1000000);
269 return p;
270}
271
272/*
Chuck Leverf796f8b2010-12-14 14:55:10 +0000273 * 2.3.5. fattr
274 *
275 * struct fattr {
276 * ftype type;
277 * unsigned int mode;
278 * unsigned int nlink;
279 * unsigned int uid;
280 * unsigned int gid;
281 * unsigned int size;
282 * unsigned int blocksize;
283 * unsigned int rdev;
284 * unsigned int blocks;
285 * unsigned int fsid;
286 * unsigned int fileid;
287 * timeval atime;
288 * timeval mtime;
289 * timeval ctime;
290 * };
291 *
292 */
293static int decode_fattr(struct xdr_stream *xdr, struct nfs_fattr *fattr)
294{
295 __be32 *p;
296
297 p = xdr_inline_decode(xdr, NFS_fattr_sz << 2);
298 if (unlikely(p == NULL))
299 goto out_overflow;
300 xdr_decode_fattr(p, fattr);
301 return 0;
302out_overflow:
303 print_overflow_msg(__func__, xdr);
304 return -EIO;
305}
306
307/*
Chuck Lever25a08662010-12-14 14:54:30 +0000308 * 2.3.6. sattr
309 *
310 * struct sattr {
311 * unsigned int mode;
312 * unsigned int uid;
313 * unsigned int gid;
314 * unsigned int size;
315 * timeval atime;
316 * timeval mtime;
317 * };
318 */
319
320#define NFS2_SATTR_NOT_SET (0xffffffff)
321
322static __be32 *xdr_time_not_set(__be32 *p)
323{
324 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
325 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
326 return p;
327}
328
329static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
330{
331 __be32 *p;
332
333 p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
334
335 if (attr->ia_valid & ATTR_MODE)
336 *p++ = cpu_to_be32(attr->ia_mode);
337 else
338 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
339 if (attr->ia_valid & ATTR_UID)
340 *p++ = cpu_to_be32(attr->ia_uid);
341 else
342 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
343 if (attr->ia_valid & ATTR_GID)
344 *p++ = cpu_to_be32(attr->ia_gid);
345 else
346 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
347 if (attr->ia_valid & ATTR_SIZE)
348 *p++ = cpu_to_be32((u32)attr->ia_size);
349 else
350 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
351
352 if (attr->ia_valid & ATTR_ATIME_SET)
353 p = xdr_encode_time(p, &attr->ia_atime);
354 else if (attr->ia_valid & ATTR_ATIME)
355 p = xdr_encode_current_server_time(p, &attr->ia_atime);
356 else
357 p = xdr_time_not_set(p);
358 if (attr->ia_valid & ATTR_MTIME_SET)
359 xdr_encode_time(p, &attr->ia_mtime);
360 else if (attr->ia_valid & ATTR_MTIME)
361 xdr_encode_current_server_time(p, &attr->ia_mtime);
362 else
363 xdr_time_not_set(p);
364}
365
366/*
367 * 2.3.7. filename
368 *
369 * typedef string filename<MAXNAMLEN>;
370 */
371static void encode_filename(struct xdr_stream *xdr,
372 const char *name, u32 length)
373{
374 __be32 *p;
375
376 BUG_ON(length > NFS2_MAXNAMLEN);
377 p = xdr_reserve_space(xdr, 4 + length);
378 xdr_encode_opaque(p, name, length);
379}
380
Chuck Leverf796f8b2010-12-14 14:55:10 +0000381static int decode_filename_inline(struct xdr_stream *xdr,
382 const char **name, u32 *length)
383{
384 __be32 *p;
385 u32 count;
386
387 p = xdr_inline_decode(xdr, 4);
388 if (unlikely(p == NULL))
389 goto out_overflow;
390 count = be32_to_cpup(p);
391 if (count > NFS3_MAXNAMLEN)
392 goto out_nametoolong;
393 p = xdr_inline_decode(xdr, count);
394 if (unlikely(p == NULL))
395 goto out_overflow;
396 *name = (const char *)p;
397 *length = count;
398 return 0;
399out_nametoolong:
400 dprintk("NFS: returned filename too long: %u\n", count);
401 return -ENAMETOOLONG;
402out_overflow:
403 print_overflow_msg(__func__, xdr);
404 return -EIO;
405}
406
Chuck Lever25a08662010-12-14 14:54:30 +0000407/*
408 * 2.3.8. path
409 *
410 * typedef string path<MAXPATHLEN>;
411 */
412static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
413{
414 __be32 *p;
415
416 BUG_ON(length > NFS2_MAXPATHLEN);
417 p = xdr_reserve_space(xdr, 4);
418 *p = cpu_to_be32(length);
419 xdr_write_pages(xdr, pages, 0, length);
420}
421
Chuck Leverf796f8b2010-12-14 14:55:10 +0000422static int decode_path(struct xdr_stream *xdr)
423{
424 u32 length, recvd;
425 size_t hdrlen;
426 __be32 *p;
427
428 p = xdr_inline_decode(xdr, 4);
429 if (unlikely(p == NULL))
430 goto out_overflow;
431 length = be32_to_cpup(p);
432 if (unlikely(length >= xdr->buf->page_len || length > NFS_MAXPATHLEN))
433 goto out_size;
434 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
435 recvd = xdr->buf->len - hdrlen;
436 if (unlikely(length > recvd))
437 goto out_cheating;
438
439 xdr_read_pages(xdr, length);
440 xdr_terminate_string(xdr->buf, length);
441 return 0;
442out_size:
443 dprintk("NFS: returned pathname too long: %u\n", length);
444 return -ENAMETOOLONG;
445out_cheating:
446 dprintk("NFS: server cheating in pathname result: "
447 "length %u > received %u\n", length, recvd);
448 return -EIO;
449out_overflow:
450 print_overflow_msg(__func__, xdr);
451 return -EIO;
452}
453
454/*
455 * 2.3.9. attrstat
456 *
457 * union attrstat switch (stat status) {
458 * case NFS_OK:
459 * fattr attributes;
460 * default:
461 * void;
462 * };
463 */
464static int decode_attrstat(struct xdr_stream *xdr, struct nfs_fattr *result)
465{
466 enum nfs_stat status;
467 int error;
468
469 error = decode_stat(xdr, &status);
470 if (unlikely(error))
471 goto out;
472 if (status != NFS_OK)
473 goto out_default;
474 error = decode_fattr(xdr, result);
475out:
476 return error;
477out_default:
478 return nfs_stat_to_errno(status);
479}
480
Chuck Lever25a08662010-12-14 14:54:30 +0000481/*
482 * 2.3.10. diropargs
483 *
484 * struct diropargs {
485 * fhandle dir;
486 * filename name;
487 * };
488 */
489static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
490 const char *name, u32 length)
491{
492 encode_fhandle(xdr, fh);
493 encode_filename(xdr, name, length);
494}
495
Chuck Leverf796f8b2010-12-14 14:55:10 +0000496/*
497 * 2.3.11. diropres
498 *
499 * union diropres switch (stat status) {
500 * case NFS_OK:
501 * struct {
502 * fhandle file;
503 * fattr attributes;
504 * } diropok;
505 * default:
506 * void;
507 * };
508 */
509static int decode_diropok(struct xdr_stream *xdr, struct nfs_diropok *result)
510{
511 int error;
512
513 error = decode_fhandle(xdr, result->fh);
514 if (unlikely(error))
515 goto out;
516 error = decode_fattr(xdr, result->fattr);
517out:
518 return error;
519}
520
521static int decode_diropres(struct xdr_stream *xdr, struct nfs_diropok *result)
522{
523 enum nfs_stat status;
524 int error;
525
526 error = decode_stat(xdr, &status);
527 if (unlikely(error))
528 goto out;
529 if (status != NFS_OK)
530 goto out_default;
531 error = decode_diropok(xdr, result);
532out:
533 return error;
534out_default:
535 return nfs_stat_to_errno(status);
536}
537
Chuck Lever25a08662010-12-14 14:54:30 +0000538
539/*
Chuck Lever2d70f532010-12-14 14:54:40 +0000540 * NFSv2 XDR encode functions
541 *
542 * NFSv2 argument types are defined in section 2.2 of RFC 1094:
543 * "NFS: Network File System Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700544 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545
Chuck Lever25a08662010-12-14 14:54:30 +0000546static int nfs2_xdr_enc_fhandle(struct rpc_rqst *req, __be32 *p,
547 const struct nfs_fh *fh)
548{
549 struct xdr_stream xdr;
550
551 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
552 encode_fhandle(&xdr, fh);
553 return 0;
554}
555
Linus Torvalds1da177e2005-04-16 15:20:36 -0700556/*
Chuck Lever25a08662010-12-14 14:54:30 +0000557 * 2.2.3. sattrargs
558 *
559 * struct sattrargs {
560 * fhandle file;
561 * sattr attributes;
562 * };
563 */
564static int nfs2_xdr_enc_sattrargs(struct rpc_rqst *req, __be32 *p,
565 const struct nfs_sattrargs *args)
566{
567 struct xdr_stream xdr;
568
569 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
570 encode_fhandle(&xdr, args->fh);
571 encode_sattr(&xdr, args->sattr);
572 return 0;
573}
574
Chuck Lever25a08662010-12-14 14:54:30 +0000575static int nfs2_xdr_enc_diropargs(struct rpc_rqst *req, __be32 *p,
576 const struct nfs_diropargs *args)
577{
578 struct xdr_stream xdr;
579
580 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
581 encode_diropargs(&xdr, args->fh, args->name, args->len);
582 return 0;
583}
584
Chuck Lever25a08662010-12-14 14:54:30 +0000585static int nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, __be32 *p,
586 const struct nfs_readlinkargs *args)
587{
588 struct xdr_stream xdr;
589
590 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
591 encode_fhandle(&xdr, args->fh);
592 prepare_reply_buffer(req, args->pages, args->pgbase,
593 args->pglen, NFS_readlinkres_sz);
594 return 0;
595}
596
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400597/*
Chuck Lever25a08662010-12-14 14:54:30 +0000598 * 2.2.7. readargs
599 *
600 * struct readargs {
601 * fhandle file;
602 * unsigned offset;
603 * unsigned count;
604 * unsigned totalcount;
605 * };
606 */
607static void encode_readargs(struct xdr_stream *xdr,
608 const struct nfs_readargs *args)
609{
610 u32 offset = args->offset;
611 u32 count = args->count;
612 __be32 *p;
613
614 encode_fhandle(xdr, args->fh);
615
616 p = xdr_reserve_space(xdr, 4 + 4 + 4);
617 *p++ = cpu_to_be32(offset);
618 *p++ = cpu_to_be32(count);
619 *p = cpu_to_be32(count);
620}
621
622static int nfs2_xdr_enc_readargs(struct rpc_rqst *req, __be32 *p,
623 const struct nfs_readargs *args)
624{
625 struct xdr_stream xdr;
626
627 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
628 encode_readargs(&xdr, args);
629 prepare_reply_buffer(req, args->pages, args->pgbase,
630 args->count, NFS_readres_sz);
631 req->rq_rcv_buf.flags |= XDRBUF_READ;
632 return 0;
633}
634
635/*
Chuck Lever25a08662010-12-14 14:54:30 +0000636 * 2.2.9. writeargs
637 *
638 * struct writeargs {
639 * fhandle file;
640 * unsigned beginoffset;
641 * unsigned offset;
642 * unsigned totalcount;
643 * nfsdata data;
644 * };
645 */
646static void encode_writeargs(struct xdr_stream *xdr,
647 const struct nfs_writeargs *args)
648{
649 u32 offset = args->offset;
650 u32 count = args->count;
651 __be32 *p;
652
653 encode_fhandle(xdr, args->fh);
654
655 p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
656 *p++ = cpu_to_be32(offset);
657 *p++ = cpu_to_be32(offset);
658 *p++ = cpu_to_be32(count);
659
660 /* nfsdata */
661 *p = cpu_to_be32(count);
662 xdr_write_pages(xdr, args->pages, args->pgbase, count);
663}
664
665static int nfs2_xdr_enc_writeargs(struct rpc_rqst *req, __be32 *p,
666 const struct nfs_writeargs *args)
667{
668 struct xdr_stream xdr;
669
670 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
671 encode_writeargs(&xdr, args);
672 xdr.buf->flags |= XDRBUF_WRITE;
673 return 0;
674}
675
676/*
Chuck Lever25a08662010-12-14 14:54:30 +0000677 * 2.2.10. createargs
678 *
679 * struct createargs {
680 * diropargs where;
681 * sattr attributes;
682 * };
683 */
684static int nfs2_xdr_enc_createargs(struct rpc_rqst *req, __be32 *p,
685 const struct nfs_createargs *args)
686{
687 struct xdr_stream xdr;
688
689 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
690 encode_diropargs(&xdr, args->fh, args->name, args->len);
691 encode_sattr(&xdr, args->sattr);
692 return 0;
693}
694
695static int nfs2_xdr_enc_removeargs(struct rpc_rqst *req, __be32 *p,
696 const struct nfs_removeargs *args)
697{
698 struct xdr_stream xdr;
699
700 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
701 encode_diropargs(&xdr, args->fh, args->name.name, args->name.len);
702 return 0;
703}
704
705/*
Chuck Lever25a08662010-12-14 14:54:30 +0000706 * 2.2.12. renameargs
707 *
708 * struct renameargs {
709 * diropargs from;
710 * diropargs to;
711 * };
712 */
713static int nfs2_xdr_enc_renameargs(struct rpc_rqst *req, __be32 *p,
714 const struct nfs_renameargs *args)
715{
716 const struct qstr *old = args->old_name;
717 const struct qstr *new = args->new_name;
718 struct xdr_stream xdr;
719
720 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
721 encode_diropargs(&xdr, args->old_dir, old->name, old->len);
722 encode_diropargs(&xdr, args->new_dir, new->name, new->len);
723 return 0;
724}
725
726/*
Chuck Lever25a08662010-12-14 14:54:30 +0000727 * 2.2.13. linkargs
728 *
729 * struct linkargs {
730 * fhandle from;
731 * diropargs to;
732 * };
733 */
734static int nfs2_xdr_enc_linkargs(struct rpc_rqst *req, __be32 *p,
735 const struct nfs_linkargs *args)
736{
737 struct xdr_stream xdr;
738
739 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
740 encode_fhandle(&xdr, args->fromfh);
741 encode_diropargs(&xdr, args->tofh, args->toname, args->tolen);
742 return 0;
743}
744
745/*
Chuck Lever25a08662010-12-14 14:54:30 +0000746 * 2.2.14. symlinkargs
747 *
748 * struct symlinkargs {
749 * diropargs from;
750 * path to;
751 * sattr attributes;
752 * };
753 */
754static int nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req, __be32 *p,
755 const struct nfs_symlinkargs *args)
756{
757 struct xdr_stream xdr;
758
759 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
760 encode_diropargs(&xdr, args->fromfh, args->fromname, args->fromlen);
761 encode_path(&xdr, args->pages, args->pathlen);
762 encode_sattr(&xdr, args->sattr);
763 return 0;
764}
765
766/*
Chuck Lever25a08662010-12-14 14:54:30 +0000767 * 2.2.17. readdirargs
768 *
769 * struct readdirargs {
770 * fhandle dir;
771 * nfscookie cookie;
772 * unsigned count;
773 * };
774 */
775static void encode_readdirargs(struct xdr_stream *xdr,
776 const struct nfs_readdirargs *args)
777{
778 __be32 *p;
779
780 encode_fhandle(xdr, args->fh);
781
782 p = xdr_reserve_space(xdr, 4 + 4);
783 *p++ = cpu_to_be32(args->cookie);
784 *p = cpu_to_be32(args->count);
785}
786
787static int nfs2_xdr_enc_readdirargs(struct rpc_rqst *req, __be32 *p,
788 const struct nfs_readdirargs *args)
789{
790 struct xdr_stream xdr;
791
792 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
793 encode_readdirargs(&xdr, args);
794 prepare_reply_buffer(req, args->pages, 0,
795 args->count, NFS_readdirres_sz);
796 return 0;
797}
798
799/*
Chuck Lever661ad422010-12-14 14:55:20 +0000800 * NFSv2 XDR decode functions
801 *
802 * NFSv2 result types are defined in section 2.2 of RFC 1094:
803 * "NFS: Network File System Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700805
Chuck Leverf796f8b2010-12-14 14:55:10 +0000806static int nfs2_xdr_dec_stat(struct rpc_rqst *req, __be32 *p,
807 void *__unused)
808{
809 struct xdr_stream xdr;
810 enum nfs_stat status;
811 int error;
812
813 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
814 error = decode_stat(&xdr, &status);
815 if (unlikely(error))
816 goto out;
817 if (status != NFS_OK)
818 goto out_default;
819out:
820 return error;
821out_default:
822 return nfs_stat_to_errno(status);
823}
824
Chuck Leverf796f8b2010-12-14 14:55:10 +0000825static int nfs2_xdr_dec_attrstat(struct rpc_rqst *req, __be32 *p,
826 struct nfs_fattr *result)
827{
828 struct xdr_stream xdr;
829
830 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
831 return decode_attrstat(&xdr, result);
832}
833
Chuck Leverf796f8b2010-12-14 14:55:10 +0000834static int nfs2_xdr_dec_diropres(struct rpc_rqst *req, __be32 *p,
835 struct nfs_diropok *result)
836{
837 struct xdr_stream xdr;
838
839 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
840 return decode_diropres(&xdr, result);
841}
842
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843/*
Chuck Leverf796f8b2010-12-14 14:55:10 +0000844 * 2.2.6. readlinkres
845 *
846 * union readlinkres switch (stat status) {
847 * case NFS_OK:
848 * path data;
849 * default:
850 * void;
851 * };
852 */
853static int nfs2_xdr_dec_readlinkres(struct rpc_rqst *req, __be32 *p,
854 void *__unused)
855{
856 struct xdr_stream xdr;
857 enum nfs_stat status;
858 int error;
859
860 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
861 error = decode_stat(&xdr, &status);
862 if (unlikely(error))
863 goto out;
864 if (status != NFS_OK)
865 goto out_default;
866 error = decode_path(&xdr);
867out:
868 return error;
869out_default:
870 return nfs_stat_to_errno(status);
871}
872
873/*
874 * 2.2.7. readres
875 *
876 * union readres switch (stat status) {
877 * case NFS_OK:
878 * fattr attributes;
879 * nfsdata data;
880 * default:
881 * void;
882 * };
883 */
884static int nfs2_xdr_dec_readres(struct rpc_rqst *req, __be32 *p,
885 struct nfs_readres *result)
886{
887 struct xdr_stream xdr;
888 enum nfs_stat status;
889 int error;
890
891 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
892 error = decode_stat(&xdr, &status);
893 if (unlikely(error))
894 goto out;
895 if (status != NFS_OK)
896 goto out_default;
897 error = decode_fattr(&xdr, result->fattr);
898 if (unlikely(error))
899 goto out;
900 error = decode_nfsdata(&xdr, result);
901out:
902 return error;
903out_default:
904 return nfs_stat_to_errno(status);
905}
906
Chuck Leverf796f8b2010-12-14 14:55:10 +0000907static int nfs2_xdr_dec_writeres(struct rpc_rqst *req, __be32 *p,
908 struct nfs_writeres *result)
909{
910 struct xdr_stream xdr;
911
912 /* All NFSv2 writes are "file sync" writes */
913 result->verf->committed = NFS_FILE_SYNC;
914
915 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
916 return decode_attrstat(&xdr, result->fattr);
917}
918
919/**
920 * nfs2_decode_dirent - Decode a single NFSv2 directory entry stored in
921 * the local page cache.
922 * @xdr: XDR stream where entry resides
923 * @entry: buffer to fill in with entry data
924 * @server: nfs_server data for this directory
925 * @plus: boolean indicating whether this should be a readdirplus entry
926 *
927 * Returns the position of the next item in the buffer, or an ERR_PTR.
928 *
929 * This function is not invoked during READDIR reply decoding, but
930 * rather whenever an application invokes the getdents(2) system call
931 * on a directory already in our cache.
932 *
933 * 2.2.17. entry
934 *
935 * struct entry {
936 * unsigned fileid;
937 * filename name;
938 * nfscookie cookie;
939 * entry *nextentry;
940 * };
941 */
942__be32 *nfs2_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry,
943 struct nfs_server *server, int plus)
944{
945 __be32 *p;
946 int error;
947
948 p = xdr_inline_decode(xdr, 4);
949 if (unlikely(p == NULL))
950 goto out_overflow;
951 if (*p++ == xdr_zero) {
952 p = xdr_inline_decode(xdr, 4);
953 if (unlikely(p == NULL))
954 goto out_overflow;
955 if (*p++ == xdr_zero)
956 return ERR_PTR(-EAGAIN);
957 entry->eof = 1;
958 return ERR_PTR(-EBADCOOKIE);
959 }
960
961 p = xdr_inline_decode(xdr, 4);
962 if (unlikely(p == NULL))
963 goto out_overflow;
964 entry->ino = be32_to_cpup(p);
965
966 error = decode_filename_inline(xdr, &entry->name, &entry->len);
967 if (unlikely(error))
968 return ERR_PTR(error);
969
970 /*
971 * The type (size and byte order) of nfscookie isn't defined in
972 * RFC 1094. This implementation assumes that it's an XDR uint32.
973 */
974 entry->prev_cookie = entry->cookie;
975 p = xdr_inline_decode(xdr, 4);
976 if (unlikely(p == NULL))
977 goto out_overflow;
978 entry->cookie = be32_to_cpup(p);
979
980 entry->d_type = DT_UNKNOWN;
981
982 /* Peek at the next entry to see if we're at EOD */
983 p = xdr_inline_peek(xdr, 4 + 4);
984 entry->eof = 0;
985 if (p != NULL)
986 entry->eof = (p[0] == xdr_zero) && (p[1] != xdr_zero);
987 return p;
988
989out_overflow:
990 print_overflow_msg(__func__, xdr);
991 return ERR_PTR(-EAGAIN);
992}
993
994/*
995 * 2.2.17. readdirres
996 *
997 * union readdirres switch (stat status) {
998 * case NFS_OK:
999 * struct {
1000 * entry *entries;
1001 * bool eof;
1002 * } readdirok;
1003 * default:
1004 * void;
1005 * };
1006 *
1007 * Read the directory contents into the page cache, but don't
1008 * touch them. The actual decoding is done by nfs2_decode_dirent()
1009 * during subsequent nfs_readdir() calls.
1010 */
1011static int decode_readdirok(struct xdr_stream *xdr)
1012{
1013 u32 recvd, pglen;
1014 size_t hdrlen;
1015
1016 pglen = xdr->buf->page_len;
1017 hdrlen = (u8 *)xdr->p - (u8 *)xdr->iov->iov_base;
1018 recvd = xdr->buf->len - hdrlen;
1019 if (unlikely(pglen > recvd))
1020 goto out_cheating;
1021out:
1022 xdr_read_pages(xdr, pglen);
1023 return pglen;
1024out_cheating:
1025 dprintk("NFS: server cheating in readdir result: "
1026 "pglen %u > recvd %u\n", pglen, recvd);
1027 pglen = recvd;
1028 goto out;
1029}
1030
1031static int nfs2_xdr_dec_readdirres(struct rpc_rqst *req, __be32 *p,
1032 void *__unused)
1033{
1034 struct xdr_stream xdr;
1035 enum nfs_stat status;
1036 int error;
1037
1038 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1039 error = decode_stat(&xdr, &status);
1040 if (unlikely(error))
1041 goto out;
1042 if (status != NFS_OK)
1043 goto out_default;
1044 error = decode_readdirok(&xdr);
1045out:
1046 return error;
1047out_default:
1048 return nfs_stat_to_errno(status);
1049}
1050
Linus Torvalds1da177e2005-04-16 15:20:36 -07001051/*
Chuck Leverf796f8b2010-12-14 14:55:10 +00001052 * 2.2.18. statfsres
1053 *
1054 * union statfsres (stat status) {
1055 * case NFS_OK:
1056 * struct {
1057 * unsigned tsize;
1058 * unsigned bsize;
1059 * unsigned blocks;
1060 * unsigned bfree;
1061 * unsigned bavail;
1062 * } info;
1063 * default:
1064 * void;
1065 * };
1066 */
1067static int decode_info(struct xdr_stream *xdr, struct nfs2_fsstat *result)
1068{
1069 __be32 *p;
1070
1071 p = xdr_inline_decode(xdr, NFS_info_sz << 2);
1072 if (unlikely(p == NULL))
1073 goto out_overflow;
1074 result->tsize = be32_to_cpup(p++);
1075 result->bsize = be32_to_cpup(p++);
1076 result->blocks = be32_to_cpup(p++);
1077 result->bfree = be32_to_cpup(p++);
1078 result->bavail = be32_to_cpup(p);
1079 return 0;
1080out_overflow:
1081 print_overflow_msg(__func__, xdr);
1082 return -EIO;
1083}
1084
1085static int nfs2_xdr_dec_statfsres(struct rpc_rqst *req, __be32 *p,
1086 struct nfs2_fsstat *result)
1087{
1088 struct xdr_stream xdr;
1089 enum nfs_stat status;
1090 int error;
1091
1092 xdr_init_decode(&xdr, &req->rq_rcv_buf, p);
1093 error = decode_stat(&xdr, &status);
1094 if (unlikely(error))
1095 goto out;
1096 if (status != NFS_OK)
1097 goto out_default;
1098 error = decode_info(&xdr, result);
1099out:
1100 return error;
1101out_default:
1102 return nfs_stat_to_errno(status);
1103}
1104
1105
1106/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001107 * We need to translate between nfs status return values and
1108 * the local errno values which may not be the same.
1109 */
Chuck Lever85828492010-12-14 14:55:00 +00001110static const struct {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001111 int stat;
1112 int errno;
1113} nfs_errtbl[] = {
1114 { NFS_OK, 0 },
Benny Halevy856dff32008-03-31 17:39:06 +03001115 { NFSERR_PERM, -EPERM },
1116 { NFSERR_NOENT, -ENOENT },
1117 { NFSERR_IO, -errno_NFSERR_IO},
1118 { NFSERR_NXIO, -ENXIO },
1119/* { NFSERR_EAGAIN, -EAGAIN }, */
1120 { NFSERR_ACCES, -EACCES },
1121 { NFSERR_EXIST, -EEXIST },
1122 { NFSERR_XDEV, -EXDEV },
1123 { NFSERR_NODEV, -ENODEV },
1124 { NFSERR_NOTDIR, -ENOTDIR },
1125 { NFSERR_ISDIR, -EISDIR },
1126 { NFSERR_INVAL, -EINVAL },
1127 { NFSERR_FBIG, -EFBIG },
1128 { NFSERR_NOSPC, -ENOSPC },
1129 { NFSERR_ROFS, -EROFS },
1130 { NFSERR_MLINK, -EMLINK },
1131 { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
1132 { NFSERR_NOTEMPTY, -ENOTEMPTY },
1133 { NFSERR_DQUOT, -EDQUOT },
1134 { NFSERR_STALE, -ESTALE },
1135 { NFSERR_REMOTE, -EREMOTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001136#ifdef EWFLUSH
Benny Halevy856dff32008-03-31 17:39:06 +03001137 { NFSERR_WFLUSH, -EWFLUSH },
Linus Torvalds1da177e2005-04-16 15:20:36 -07001138#endif
Benny Halevy856dff32008-03-31 17:39:06 +03001139 { NFSERR_BADHANDLE, -EBADHANDLE },
1140 { NFSERR_NOT_SYNC, -ENOTSYNC },
1141 { NFSERR_BAD_COOKIE, -EBADCOOKIE },
1142 { NFSERR_NOTSUPP, -ENOTSUPP },
1143 { NFSERR_TOOSMALL, -ETOOSMALL },
Trond Myklebustfdcb4572010-02-08 09:32:40 -05001144 { NFSERR_SERVERFAULT, -EREMOTEIO },
Benny Halevy856dff32008-03-31 17:39:06 +03001145 { NFSERR_BADTYPE, -EBADTYPE },
1146 { NFSERR_JUKEBOX, -EJUKEBOX },
1147 { -1, -EIO }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001148};
1149
Chuck Lever85828492010-12-14 14:55:00 +00001150/**
1151 * nfs_stat_to_errno - convert an NFS status code to a local errno
1152 * @status: NFS status code to convert
1153 *
1154 * Returns a local errno value, or -EIO if the NFS status code is
1155 * not recognized. This function is used jointly by NFSv2 and NFSv3.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001156 */
Chuck Lever85828492010-12-14 14:55:00 +00001157int nfs_stat_to_errno(enum nfs_stat status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158{
1159 int i;
1160
1161 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
Chuck Lever85828492010-12-14 14:55:00 +00001162 if (nfs_errtbl[i].stat == (int)status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163 return nfs_errtbl[i].errno;
1164 }
Chuck Lever85828492010-12-14 14:55:00 +00001165 dprintk("NFS: Unrecognized nfs status value: %u\n", status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166 return nfs_errtbl[i].errno;
1167}
1168
Linus Torvalds1da177e2005-04-16 15:20:36 -07001169#define PROC(proc, argtype, restype, timer) \
1170[NFSPROC_##proc] = { \
1171 .p_proc = NFSPROC_##proc, \
Chuck Lever25a08662010-12-14 14:54:30 +00001172 .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \
Chuck Leverf796f8b2010-12-14 14:55:10 +00001173 .p_decode = (kxdrproc_t)nfs2_xdr_dec_##restype, \
Chuck Lever2bea90d2007-03-29 16:47:53 -04001174 .p_arglen = NFS_##argtype##_sz, \
1175 .p_replen = NFS_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -05001176 .p_timer = timer, \
1177 .p_statidx = NFSPROC_##proc, \
1178 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001179 }
1180struct rpc_procinfo nfs_procedures[] = {
1181 PROC(GETATTR, fhandle, attrstat, 1),
1182 PROC(SETATTR, sattrargs, attrstat, 0),
1183 PROC(LOOKUP, diropargs, diropres, 2),
1184 PROC(READLINK, readlinkargs, readlinkres, 3),
1185 PROC(READ, readargs, readres, 3),
1186 PROC(WRITE, writeargs, writeres, 4),
1187 PROC(CREATE, createargs, diropres, 0),
Trond Myklebust4fdc17b2007-07-14 15:39:57 -04001188 PROC(REMOVE, removeargs, stat, 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189 PROC(RENAME, renameargs, stat, 0),
1190 PROC(LINK, linkargs, stat, 0),
1191 PROC(SYMLINK, symlinkargs, stat, 0),
1192 PROC(MKDIR, createargs, diropres, 0),
1193 PROC(RMDIR, diropargs, stat, 0),
1194 PROC(READDIR, readdirargs, readdirres, 3),
1195 PROC(STATFS, fhandle, statfsres, 0),
1196};
1197
1198struct rpc_version nfs_version2 = {
1199 .number = 2,
Tobias Klausere8c96f82006-03-24 03:15:34 -08001200 .nrprocs = ARRAY_SIZE(nfs_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001201 .procs = nfs_procedures
1202};