blob: f5ea9dcf08d63f6f95bebff7e0cd96499a5748a1 [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
80
Linus Torvalds1da177e2005-04-16 15:20:36 -070081/*
82 * Common NFS XDR functions as inlines
83 */
Al Viro9d787a72006-10-19 23:28:47 -070084static inline __be32 *
Al Viro9d787a72006-10-19 23:28:47 -070085xdr_decode_fhandle(__be32 *p, struct nfs_fh *fhandle)
Linus Torvalds1da177e2005-04-16 15:20:36 -070086{
87 /* NFSv2 handles have a fixed length */
88 fhandle->size = NFS2_FHSIZE;
89 memcpy(fhandle->data, p, NFS2_FHSIZE);
90 return p + XDR_QUADLEN(NFS2_FHSIZE);
91}
92
Al Viro9d787a72006-10-19 23:28:47 -070093static inline __be32*
Chuck Lever25a08662010-12-14 14:54:30 +000094xdr_encode_time(__be32 *p, const struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -070095{
96 *p++ = htonl(timep->tv_sec);
97 /* Convert nanoseconds into microseconds */
98 *p++ = htonl(timep->tv_nsec ? timep->tv_nsec / 1000 : 0);
99 return p;
100}
101
Al Viro9d787a72006-10-19 23:28:47 -0700102static inline __be32*
Chuck Lever25a08662010-12-14 14:54:30 +0000103xdr_encode_current_server_time(__be32 *p, const struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104{
105 /*
106 * Passing the invalid value useconds=1000000 is a
107 * Sun convention for "set to current server time".
108 * It's needed to make permissions checks for the
109 * "touch" program across v2 mounts to Solaris and
110 * Irix boxes work correctly. See description of
111 * sattr in section 6.1 of "NFS Illustrated" by
112 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
113 */
114 *p++ = htonl(timep->tv_sec);
115 *p++ = htonl(1000000);
116 return p;
117}
118
Al Viro9d787a72006-10-19 23:28:47 -0700119static inline __be32*
120xdr_decode_time(__be32 *p, struct timespec *timep)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121{
122 timep->tv_sec = ntohl(*p++);
123 /* Convert microseconds into nanoseconds */
124 timep->tv_nsec = ntohl(*p++) * 1000;
125 return p;
126}
127
Al Viro9d787a72006-10-19 23:28:47 -0700128static __be32 *
129xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700130{
Trond Myklebustbca79472009-03-11 14:10:26 -0400131 u32 rdev, type;
132 type = ntohl(*p++);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700133 fattr->mode = ntohl(*p++);
134 fattr->nlink = ntohl(*p++);
135 fattr->uid = ntohl(*p++);
136 fattr->gid = ntohl(*p++);
137 fattr->size = ntohl(*p++);
138 fattr->du.nfs2.blocksize = ntohl(*p++);
139 rdev = ntohl(*p++);
140 fattr->du.nfs2.blocks = ntohl(*p++);
Trond Myklebust8b4bdcf2006-06-09 09:34:19 -0400141 fattr->fsid.major = ntohl(*p++);
142 fattr->fsid.minor = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 fattr->fileid = ntohl(*p++);
144 p = xdr_decode_time(p, &fattr->atime);
145 p = xdr_decode_time(p, &fattr->mtime);
146 p = xdr_decode_time(p, &fattr->ctime);
Trond Myklebust9e6e70f2009-03-11 14:10:24 -0400147 fattr->valid |= NFS_ATTR_FATTR_V2;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148 fattr->rdev = new_decode_dev(rdev);
Trond Myklebustbca79472009-03-11 14:10:26 -0400149 if (type == NFCHR && rdev == NFS2_FIFO_DEV) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150 fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
151 fattr->rdev = 0;
152 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 return p;
154}
155
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156/*
Chuck Lever25a08662010-12-14 14:54:30 +0000157 * Encode/decode NFSv2 basic data types
158 *
159 * Basic NFSv2 data types are defined in section 2.3 of RFC 1094:
160 * "NFS: Network File System Protocol Specification".
161 *
162 * Not all basic data types have their own encoding and decoding
163 * functions. For run-time efficiency, some data types are encoded
164 * or decoded inline.
165 */
166
167/*
168 * 2.3.3. fhandle
169 *
170 * typedef opaque fhandle[FHSIZE];
171 */
172static void encode_fhandle(struct xdr_stream *xdr, const struct nfs_fh *fh)
173{
174 __be32 *p;
175
176 BUG_ON(fh->size != NFS2_FHSIZE);
177 p = xdr_reserve_space(xdr, NFS2_FHSIZE);
178 memcpy(p, fh->data, NFS2_FHSIZE);
179}
180
181/*
182 * 2.3.6. sattr
183 *
184 * struct sattr {
185 * unsigned int mode;
186 * unsigned int uid;
187 * unsigned int gid;
188 * unsigned int size;
189 * timeval atime;
190 * timeval mtime;
191 * };
192 */
193
194#define NFS2_SATTR_NOT_SET (0xffffffff)
195
196static __be32 *xdr_time_not_set(__be32 *p)
197{
198 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
199 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
200 return p;
201}
202
203static void encode_sattr(struct xdr_stream *xdr, const struct iattr *attr)
204{
205 __be32 *p;
206
207 p = xdr_reserve_space(xdr, NFS_sattr_sz << 2);
208
209 if (attr->ia_valid & ATTR_MODE)
210 *p++ = cpu_to_be32(attr->ia_mode);
211 else
212 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
213 if (attr->ia_valid & ATTR_UID)
214 *p++ = cpu_to_be32(attr->ia_uid);
215 else
216 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
217 if (attr->ia_valid & ATTR_GID)
218 *p++ = cpu_to_be32(attr->ia_gid);
219 else
220 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
221 if (attr->ia_valid & ATTR_SIZE)
222 *p++ = cpu_to_be32((u32)attr->ia_size);
223 else
224 *p++ = cpu_to_be32(NFS2_SATTR_NOT_SET);
225
226 if (attr->ia_valid & ATTR_ATIME_SET)
227 p = xdr_encode_time(p, &attr->ia_atime);
228 else if (attr->ia_valid & ATTR_ATIME)
229 p = xdr_encode_current_server_time(p, &attr->ia_atime);
230 else
231 p = xdr_time_not_set(p);
232 if (attr->ia_valid & ATTR_MTIME_SET)
233 xdr_encode_time(p, &attr->ia_mtime);
234 else if (attr->ia_valid & ATTR_MTIME)
235 xdr_encode_current_server_time(p, &attr->ia_mtime);
236 else
237 xdr_time_not_set(p);
238}
239
240/*
241 * 2.3.7. filename
242 *
243 * typedef string filename<MAXNAMLEN>;
244 */
245static void encode_filename(struct xdr_stream *xdr,
246 const char *name, u32 length)
247{
248 __be32 *p;
249
250 BUG_ON(length > NFS2_MAXNAMLEN);
251 p = xdr_reserve_space(xdr, 4 + length);
252 xdr_encode_opaque(p, name, length);
253}
254
255/*
256 * 2.3.8. path
257 *
258 * typedef string path<MAXPATHLEN>;
259 */
260static void encode_path(struct xdr_stream *xdr, struct page **pages, u32 length)
261{
262 __be32 *p;
263
264 BUG_ON(length > NFS2_MAXPATHLEN);
265 p = xdr_reserve_space(xdr, 4);
266 *p = cpu_to_be32(length);
267 xdr_write_pages(xdr, pages, 0, length);
268}
269
270/*
271 * 2.3.10. diropargs
272 *
273 * struct diropargs {
274 * fhandle dir;
275 * filename name;
276 * };
277 */
278static void encode_diropargs(struct xdr_stream *xdr, const struct nfs_fh *fh,
279 const char *name, u32 length)
280{
281 encode_fhandle(xdr, fh);
282 encode_filename(xdr, name, length);
283}
284
285
286/*
Chuck Lever2d70f532010-12-14 14:54:40 +0000287 * NFSv2 XDR encode functions
288 *
289 * NFSv2 argument types are defined in section 2.2 of RFC 1094:
290 * "NFS: Network File System Protocol Specification".
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700292
Chuck Lever25a08662010-12-14 14:54:30 +0000293static int nfs2_xdr_enc_fhandle(struct rpc_rqst *req, __be32 *p,
294 const struct nfs_fh *fh)
295{
296 struct xdr_stream xdr;
297
298 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
299 encode_fhandle(&xdr, fh);
300 return 0;
301}
302
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303/*
Chuck Lever25a08662010-12-14 14:54:30 +0000304 * 2.2.3. sattrargs
305 *
306 * struct sattrargs {
307 * fhandle file;
308 * sattr attributes;
309 * };
310 */
311static int nfs2_xdr_enc_sattrargs(struct rpc_rqst *req, __be32 *p,
312 const struct nfs_sattrargs *args)
313{
314 struct xdr_stream xdr;
315
316 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
317 encode_fhandle(&xdr, args->fh);
318 encode_sattr(&xdr, args->sattr);
319 return 0;
320}
321
Chuck Lever25a08662010-12-14 14:54:30 +0000322static int nfs2_xdr_enc_diropargs(struct rpc_rqst *req, __be32 *p,
323 const struct nfs_diropargs *args)
324{
325 struct xdr_stream xdr;
326
327 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
328 encode_diropargs(&xdr, args->fh, args->name, args->len);
329 return 0;
330}
331
Chuck Lever25a08662010-12-14 14:54:30 +0000332static int nfs2_xdr_enc_readlinkargs(struct rpc_rqst *req, __be32 *p,
333 const struct nfs_readlinkargs *args)
334{
335 struct xdr_stream xdr;
336
337 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
338 encode_fhandle(&xdr, args->fh);
339 prepare_reply_buffer(req, args->pages, args->pgbase,
340 args->pglen, NFS_readlinkres_sz);
341 return 0;
342}
343
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400344/*
Chuck Lever25a08662010-12-14 14:54:30 +0000345 * 2.2.7. readargs
346 *
347 * struct readargs {
348 * fhandle file;
349 * unsigned offset;
350 * unsigned count;
351 * unsigned totalcount;
352 * };
353 */
354static void encode_readargs(struct xdr_stream *xdr,
355 const struct nfs_readargs *args)
356{
357 u32 offset = args->offset;
358 u32 count = args->count;
359 __be32 *p;
360
361 encode_fhandle(xdr, args->fh);
362
363 p = xdr_reserve_space(xdr, 4 + 4 + 4);
364 *p++ = cpu_to_be32(offset);
365 *p++ = cpu_to_be32(count);
366 *p = cpu_to_be32(count);
367}
368
369static int nfs2_xdr_enc_readargs(struct rpc_rqst *req, __be32 *p,
370 const struct nfs_readargs *args)
371{
372 struct xdr_stream xdr;
373
374 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
375 encode_readargs(&xdr, args);
376 prepare_reply_buffer(req, args->pages, args->pgbase,
377 args->count, NFS_readres_sz);
378 req->rq_rcv_buf.flags |= XDRBUF_READ;
379 return 0;
380}
381
382/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700383 * Decode READ reply
384 */
385static int
Al Viro9d787a72006-10-19 23:28:47 -0700386nfs_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700387{
388 struct kvec *iov = req->rq_rcv_buf.head;
Chuck Lever6232dbb2007-10-26 13:31:52 -0400389 size_t hdrlen;
390 u32 count, recvd;
391 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700392
393 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300394 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 p = xdr_decode_fattr(p, res->fattr);
396
397 count = ntohl(*p++);
398 res->eof = 0;
399 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
400 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400401 dprintk("NFS: READ reply header overflowed:"
Chuck Lever6232dbb2007-10-26 13:31:52 -0400402 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 return -errno_NFSERR_IO;
404 } else if (iov->iov_len != hdrlen) {
405 dprintk("NFS: READ header is short. iovec will be shifted.\n");
406 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
407 }
408
409 recvd = req->rq_rcv_buf.len - hdrlen;
410 if (count > recvd) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400411 dprintk("NFS: server cheating in read reply: "
Chuck Lever6232dbb2007-10-26 13:31:52 -0400412 "count %u > recvd %u\n", count, recvd);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700413 count = recvd;
414 }
415
Chuck Lever6232dbb2007-10-26 13:31:52 -0400416 dprintk("RPC: readres OK count %u\n", count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 if (count < res->count)
418 res->count = count;
419
420 return count;
421}
422
423
424/*
Chuck Lever25a08662010-12-14 14:54:30 +0000425 * 2.2.9. writeargs
426 *
427 * struct writeargs {
428 * fhandle file;
429 * unsigned beginoffset;
430 * unsigned offset;
431 * unsigned totalcount;
432 * nfsdata data;
433 * };
434 */
435static void encode_writeargs(struct xdr_stream *xdr,
436 const struct nfs_writeargs *args)
437{
438 u32 offset = args->offset;
439 u32 count = args->count;
440 __be32 *p;
441
442 encode_fhandle(xdr, args->fh);
443
444 p = xdr_reserve_space(xdr, 4 + 4 + 4 + 4);
445 *p++ = cpu_to_be32(offset);
446 *p++ = cpu_to_be32(offset);
447 *p++ = cpu_to_be32(count);
448
449 /* nfsdata */
450 *p = cpu_to_be32(count);
451 xdr_write_pages(xdr, args->pages, args->pgbase, count);
452}
453
454static int nfs2_xdr_enc_writeargs(struct rpc_rqst *req, __be32 *p,
455 const struct nfs_writeargs *args)
456{
457 struct xdr_stream xdr;
458
459 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
460 encode_writeargs(&xdr, args);
461 xdr.buf->flags |= XDRBUF_WRITE;
462 return 0;
463}
464
465/*
Chuck Lever25a08662010-12-14 14:54:30 +0000466 * 2.2.10. createargs
467 *
468 * struct createargs {
469 * diropargs where;
470 * sattr attributes;
471 * };
472 */
473static int nfs2_xdr_enc_createargs(struct rpc_rqst *req, __be32 *p,
474 const struct nfs_createargs *args)
475{
476 struct xdr_stream xdr;
477
478 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
479 encode_diropargs(&xdr, args->fh, args->name, args->len);
480 encode_sattr(&xdr, args->sattr);
481 return 0;
482}
483
484static int nfs2_xdr_enc_removeargs(struct rpc_rqst *req, __be32 *p,
485 const struct nfs_removeargs *args)
486{
487 struct xdr_stream xdr;
488
489 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
490 encode_diropargs(&xdr, args->fh, args->name.name, args->name.len);
491 return 0;
492}
493
494/*
Chuck Lever25a08662010-12-14 14:54:30 +0000495 * 2.2.12. renameargs
496 *
497 * struct renameargs {
498 * diropargs from;
499 * diropargs to;
500 * };
501 */
502static int nfs2_xdr_enc_renameargs(struct rpc_rqst *req, __be32 *p,
503 const struct nfs_renameargs *args)
504{
505 const struct qstr *old = args->old_name;
506 const struct qstr *new = args->new_name;
507 struct xdr_stream xdr;
508
509 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
510 encode_diropargs(&xdr, args->old_dir, old->name, old->len);
511 encode_diropargs(&xdr, args->new_dir, new->name, new->len);
512 return 0;
513}
514
515/*
Chuck Lever25a08662010-12-14 14:54:30 +0000516 * 2.2.13. linkargs
517 *
518 * struct linkargs {
519 * fhandle from;
520 * diropargs to;
521 * };
522 */
523static int nfs2_xdr_enc_linkargs(struct rpc_rqst *req, __be32 *p,
524 const struct nfs_linkargs *args)
525{
526 struct xdr_stream xdr;
527
528 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
529 encode_fhandle(&xdr, args->fromfh);
530 encode_diropargs(&xdr, args->tofh, args->toname, args->tolen);
531 return 0;
532}
533
534/*
Chuck Lever25a08662010-12-14 14:54:30 +0000535 * 2.2.14. symlinkargs
536 *
537 * struct symlinkargs {
538 * diropargs from;
539 * path to;
540 * sattr attributes;
541 * };
542 */
543static int nfs2_xdr_enc_symlinkargs(struct rpc_rqst *req, __be32 *p,
544 const struct nfs_symlinkargs *args)
545{
546 struct xdr_stream xdr;
547
548 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
549 encode_diropargs(&xdr, args->fromfh, args->fromname, args->fromlen);
550 encode_path(&xdr, args->pages, args->pathlen);
551 encode_sattr(&xdr, args->sattr);
552 return 0;
553}
554
555/*
Chuck Lever25a08662010-12-14 14:54:30 +0000556 * 2.2.17. readdirargs
557 *
558 * struct readdirargs {
559 * fhandle dir;
560 * nfscookie cookie;
561 * unsigned count;
562 * };
563 */
564static void encode_readdirargs(struct xdr_stream *xdr,
565 const struct nfs_readdirargs *args)
566{
567 __be32 *p;
568
569 encode_fhandle(xdr, args->fh);
570
571 p = xdr_reserve_space(xdr, 4 + 4);
572 *p++ = cpu_to_be32(args->cookie);
573 *p = cpu_to_be32(args->count);
574}
575
576static int nfs2_xdr_enc_readdirargs(struct rpc_rqst *req, __be32 *p,
577 const struct nfs_readdirargs *args)
578{
579 struct xdr_stream xdr;
580
581 xdr_init_encode(&xdr, &req->rq_snd_buf, p);
582 encode_readdirargs(&xdr, args);
583 prepare_reply_buffer(req, args->pages, 0,
584 args->count, NFS_readdirres_sz);
585 return 0;
586}
587
588/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 * Decode the result of a readdir call.
590 * We're not really decoding anymore, we just leave the buffer untouched
591 * and only check that it is syntactically correct.
592 * The real decoding happens in nfs_decode_entry below, called directly
593 * from nfs_readdir for each entry.
594 */
595static int
Al Viro9d787a72006-10-19 23:28:47 -0700596nfs_xdr_readdirres(struct rpc_rqst *req, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597{
598 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
599 struct kvec *iov = rcvbuf->head;
600 struct page **page;
Chuck Lever6232dbb2007-10-26 13:31:52 -0400601 size_t hdrlen;
602 unsigned int pglen, recvd;
Trond Myklebustac396122010-11-15 20:26:22 -0500603 int status;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
605 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300606 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607
608 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
609 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400610 dprintk("NFS: READDIR reply header overflowed:"
Chuck Lever6232dbb2007-10-26 13:31:52 -0400611 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 return -errno_NFSERR_IO;
613 } else if (iov->iov_len != hdrlen) {
614 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
615 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
616 }
617
618 pglen = rcvbuf->page_len;
619 recvd = rcvbuf->len - hdrlen;
620 if (pglen > recvd)
621 pglen = recvd;
622 page = rcvbuf->pages;
Trond Myklebustac396122010-11-15 20:26:22 -0500623 return pglen;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700624}
625
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400626static void print_overflow_msg(const char *func, const struct xdr_stream *xdr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700627{
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400628 dprintk("nfs: %s: prematurely hit end of receive buffer. "
629 "Remaining buffer length is %tu words.\n",
630 func, xdr->end - xdr->p);
631}
632
633__be32 *
Bryan Schumaker82f2e542010-10-21 16:33:18 -0400634nfs_decode_dirent(struct xdr_stream *xdr, struct nfs_entry *entry, struct nfs_server *server, int plus)
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400635{
636 __be32 *p;
637 p = xdr_inline_decode(xdr, 4);
638 if (unlikely(!p))
639 goto out_overflow;
640 if (!ntohl(*p++)) {
641 p = xdr_inline_decode(xdr, 4);
642 if (unlikely(!p))
643 goto out_overflow;
644 if (!ntohl(*p++))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 return ERR_PTR(-EAGAIN);
646 entry->eof = 1;
647 return ERR_PTR(-EBADCOOKIE);
648 }
649
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400650 p = xdr_inline_decode(xdr, 8);
651 if (unlikely(!p))
652 goto out_overflow;
653
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 entry->ino = ntohl(*p++);
655 entry->len = ntohl(*p++);
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400656
657 p = xdr_inline_decode(xdr, entry->len + 4);
658 if (unlikely(!p))
659 goto out_overflow;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 entry->name = (const char *) p;
661 p += XDR_QUADLEN(entry->len);
662 entry->prev_cookie = entry->cookie;
663 entry->cookie = ntohl(*p++);
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400664
Trond Myklebust0b26a0b2010-11-20 14:26:44 -0500665 entry->d_type = DT_UNKNOWN;
666
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400667 p = xdr_inline_peek(xdr, 8);
668 if (p != NULL)
669 entry->eof = !p[0] && p[1];
670 else
671 entry->eof = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672
673 return p;
Bryan Schumakerbabddc72010-10-20 15:44:29 -0400674
675out_overflow:
676 print_overflow_msg(__func__, xdr);
Trond Myklebust463a3762010-11-20 12:22:20 -0500677 return ERR_PTR(-EAGAIN);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678}
679
680/*
681 * NFS XDR decode functions
682 */
683/*
684 * Decode simple status reply
685 */
686static int
Al Viro9d787a72006-10-19 23:28:47 -0700687nfs_xdr_stat(struct rpc_rqst *req, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700688{
689 int status;
690
691 if ((status = ntohl(*p++)) != 0)
Benny Halevy856dff32008-03-31 17:39:06 +0300692 status = nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 return status;
694}
695
696/*
697 * Decode attrstat reply
698 * GETATTR, SETATTR, WRITE
699 */
700static int
Al Viro9d787a72006-10-19 23:28:47 -0700701nfs_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702{
703 int status;
704
705 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300706 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707 xdr_decode_fattr(p, fattr);
708 return 0;
709}
710
711/*
712 * Decode diropres reply
713 * LOOKUP, CREATE, MKDIR
714 */
715static int
Al Viro9d787a72006-10-19 23:28:47 -0700716nfs_xdr_diropres(struct rpc_rqst *req, __be32 *p, struct nfs_diropok *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717{
718 int status;
719
720 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300721 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 p = xdr_decode_fhandle(p, res->fh);
723 xdr_decode_fattr(p, res->fattr);
724 return 0;
725}
726
727/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728 * Decode READLINK reply
729 */
730static int
Al Viro9d787a72006-10-19 23:28:47 -0700731nfs_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, void *dummy)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732{
733 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
734 struct kvec *iov = rcvbuf->head;
Chuck Lever6232dbb2007-10-26 13:31:52 -0400735 size_t hdrlen;
736 u32 len, recvd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737 int status;
738
739 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300740 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 /* Convert length of symlink */
742 len = ntohl(*p++);
Chuck Lever6232dbb2007-10-26 13:31:52 -0400743 if (len >= rcvbuf->page_len) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400744 dprintk("nfs: server returned giant symlink!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 return -ENAMETOOLONG;
746 }
747 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
748 if (iov->iov_len < hdrlen) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400749 dprintk("NFS: READLINK reply header overflowed:"
Chuck Lever6232dbb2007-10-26 13:31:52 -0400750 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 return -errno_NFSERR_IO;
752 } else if (iov->iov_len != hdrlen) {
753 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
754 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
755 }
756 recvd = req->rq_rcv_buf.len - hdrlen;
757 if (recvd < len) {
Chuck Leverfe82a182007-09-11 18:01:10 -0400758 dprintk("NFS: server cheating in readlink reply: "
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 "count %u > recvd %u\n", len, recvd);
760 return -EIO;
761 }
762
Chuck Leverb4687da2010-09-21 16:55:48 -0400763 xdr_terminate_string(rcvbuf, len);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764 return 0;
765}
766
767/*
768 * Decode WRITE reply
769 */
770static int
Al Viro9d787a72006-10-19 23:28:47 -0700771nfs_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772{
773 res->verf->committed = NFS_FILE_SYNC;
774 return nfs_xdr_attrstat(req, p, res->fattr);
775}
776
777/*
778 * Decode STATFS reply
779 */
780static int
Al Viro9d787a72006-10-19 23:28:47 -0700781nfs_xdr_statfsres(struct rpc_rqst *req, __be32 *p, struct nfs2_fsstat *res)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782{
783 int status;
784
785 if ((status = ntohl(*p++)))
Benny Halevy856dff32008-03-31 17:39:06 +0300786 return nfs_stat_to_errno(status);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700787
788 res->tsize = ntohl(*p++);
789 res->bsize = ntohl(*p++);
790 res->blocks = ntohl(*p++);
791 res->bfree = ntohl(*p++);
792 res->bavail = ntohl(*p++);
793 return 0;
794}
795
796/*
797 * We need to translate between nfs status return values and
798 * the local errno values which may not be the same.
799 */
800static struct {
801 int stat;
802 int errno;
803} nfs_errtbl[] = {
804 { NFS_OK, 0 },
Benny Halevy856dff32008-03-31 17:39:06 +0300805 { NFSERR_PERM, -EPERM },
806 { NFSERR_NOENT, -ENOENT },
807 { NFSERR_IO, -errno_NFSERR_IO},
808 { NFSERR_NXIO, -ENXIO },
809/* { NFSERR_EAGAIN, -EAGAIN }, */
810 { NFSERR_ACCES, -EACCES },
811 { NFSERR_EXIST, -EEXIST },
812 { NFSERR_XDEV, -EXDEV },
813 { NFSERR_NODEV, -ENODEV },
814 { NFSERR_NOTDIR, -ENOTDIR },
815 { NFSERR_ISDIR, -EISDIR },
816 { NFSERR_INVAL, -EINVAL },
817 { NFSERR_FBIG, -EFBIG },
818 { NFSERR_NOSPC, -ENOSPC },
819 { NFSERR_ROFS, -EROFS },
820 { NFSERR_MLINK, -EMLINK },
821 { NFSERR_NAMETOOLONG, -ENAMETOOLONG },
822 { NFSERR_NOTEMPTY, -ENOTEMPTY },
823 { NFSERR_DQUOT, -EDQUOT },
824 { NFSERR_STALE, -ESTALE },
825 { NFSERR_REMOTE, -EREMOTE },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826#ifdef EWFLUSH
Benny Halevy856dff32008-03-31 17:39:06 +0300827 { NFSERR_WFLUSH, -EWFLUSH },
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828#endif
Benny Halevy856dff32008-03-31 17:39:06 +0300829 { NFSERR_BADHANDLE, -EBADHANDLE },
830 { NFSERR_NOT_SYNC, -ENOTSYNC },
831 { NFSERR_BAD_COOKIE, -EBADCOOKIE },
832 { NFSERR_NOTSUPP, -ENOTSUPP },
833 { NFSERR_TOOSMALL, -ETOOSMALL },
Trond Myklebustfdcb4572010-02-08 09:32:40 -0500834 { NFSERR_SERVERFAULT, -EREMOTEIO },
Benny Halevy856dff32008-03-31 17:39:06 +0300835 { NFSERR_BADTYPE, -EBADTYPE },
836 { NFSERR_JUKEBOX, -EJUKEBOX },
837 { -1, -EIO }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700838};
839
840/*
841 * Convert an NFS error code to a local one.
842 * This one is used jointly by NFSv2 and NFSv3.
843 */
844int
845nfs_stat_to_errno(int stat)
846{
847 int i;
848
849 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
850 if (nfs_errtbl[i].stat == stat)
851 return nfs_errtbl[i].errno;
852 }
Chuck Leverfe82a182007-09-11 18:01:10 -0400853 dprintk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854 return nfs_errtbl[i].errno;
855}
856
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857#define PROC(proc, argtype, restype, timer) \
858[NFSPROC_##proc] = { \
859 .p_proc = NFSPROC_##proc, \
Chuck Lever25a08662010-12-14 14:54:30 +0000860 .p_encode = (kxdrproc_t)nfs2_xdr_enc_##argtype, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700861 .p_decode = (kxdrproc_t) nfs_xdr_##restype, \
Chuck Lever2bea90d2007-03-29 16:47:53 -0400862 .p_arglen = NFS_##argtype##_sz, \
863 .p_replen = NFS_##restype##_sz, \
Chuck Levercc0175c2006-03-20 13:44:22 -0500864 .p_timer = timer, \
865 .p_statidx = NFSPROC_##proc, \
866 .p_name = #proc, \
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867 }
868struct rpc_procinfo nfs_procedures[] = {
869 PROC(GETATTR, fhandle, attrstat, 1),
870 PROC(SETATTR, sattrargs, attrstat, 0),
871 PROC(LOOKUP, diropargs, diropres, 2),
872 PROC(READLINK, readlinkargs, readlinkres, 3),
873 PROC(READ, readargs, readres, 3),
874 PROC(WRITE, writeargs, writeres, 4),
875 PROC(CREATE, createargs, diropres, 0),
Trond Myklebust4fdc17b2007-07-14 15:39:57 -0400876 PROC(REMOVE, removeargs, stat, 0),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700877 PROC(RENAME, renameargs, stat, 0),
878 PROC(LINK, linkargs, stat, 0),
879 PROC(SYMLINK, symlinkargs, stat, 0),
880 PROC(MKDIR, createargs, diropres, 0),
881 PROC(RMDIR, diropargs, stat, 0),
882 PROC(READDIR, readdirargs, readdirres, 3),
883 PROC(STATFS, fhandle, statfsres, 0),
884};
885
886struct rpc_version nfs_version2 = {
887 .number = 2,
Tobias Klausere8c96f82006-03-24 03:15:34 -0800888 .nrprocs = ARRAY_SIZE(nfs_procedures),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 .procs = nfs_procedures
890};