NFSv4: Fix a bug in nfs4_validate_mount_data()
[linux-2.6-block.git] / fs / nfs / nfs3xdr.c
CommitLineData
1da177e4
LT
1/*
2 * linux/fs/nfs/nfs3xdr.c
3 *
4 * XDR functions to encode/decode NFSv3 RPC arguments and results.
5 *
6 * Copyright (C) 1996, 1997 Olaf Kirch
7 */
8
9#include <linux/param.h>
10#include <linux/time.h>
11#include <linux/mm.h>
12#include <linux/slab.h>
13#include <linux/utsname.h>
14#include <linux/errno.h>
15#include <linux/string.h>
16#include <linux/in.h>
17#include <linux/pagemap.h>
18#include <linux/proc_fs.h>
19#include <linux/kdev_t.h>
20#include <linux/sunrpc/clnt.h>
21#include <linux/nfs.h>
22#include <linux/nfs3.h>
23#include <linux/nfs_fs.h>
b7fa0554 24#include <linux/nfsacl.h>
f7b422b1 25#include "internal.h"
1da177e4
LT
26
27#define NFSDBG_FACILITY NFSDBG_XDR
28
29/* Mapping from NFS error code to "errno" error code. */
30#define errno_NFSERR_IO EIO
31
1da177e4
LT
32/*
33 * Declare the space requirements for NFS arguments and replies as
34 * number of 32bit-words
35 */
36#define NFS3_fhandle_sz (1+16)
37#define NFS3_fh_sz (NFS3_fhandle_sz) /* shorthand */
38#define NFS3_sattr_sz (15)
39#define NFS3_filename_sz (1+(NFS3_MAXNAMLEN>>2))
40#define NFS3_path_sz (1+(NFS3_MAXPATHLEN>>2))
41#define NFS3_fattr_sz (21)
42#define NFS3_wcc_attr_sz (6)
43#define NFS3_pre_op_attr_sz (1+NFS3_wcc_attr_sz)
44#define NFS3_post_op_attr_sz (1+NFS3_fattr_sz)
45#define NFS3_wcc_data_sz (NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz)
46#define NFS3_fsstat_sz
47#define NFS3_fsinfo_sz
48#define NFS3_pathconf_sz
49#define NFS3_entry_sz (NFS3_filename_sz+3)
50
51#define NFS3_sattrargs_sz (NFS3_fh_sz+NFS3_sattr_sz+3)
52#define NFS3_diropargs_sz (NFS3_fh_sz+NFS3_filename_sz)
4fdc17b2 53#define NFS3_removeargs_sz (NFS3_fh_sz+NFS3_filename_sz)
1da177e4
LT
54#define NFS3_accessargs_sz (NFS3_fh_sz+1)
55#define NFS3_readlinkargs_sz (NFS3_fh_sz)
56#define NFS3_readargs_sz (NFS3_fh_sz+3)
57#define NFS3_writeargs_sz (NFS3_fh_sz+5)
58#define NFS3_createargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
59#define NFS3_mkdirargs_sz (NFS3_diropargs_sz+NFS3_sattr_sz)
94a6d753 60#define NFS3_symlinkargs_sz (NFS3_diropargs_sz+1+NFS3_sattr_sz)
1da177e4
LT
61#define NFS3_mknodargs_sz (NFS3_diropargs_sz+2+NFS3_sattr_sz)
62#define NFS3_renameargs_sz (NFS3_diropargs_sz+NFS3_diropargs_sz)
63#define NFS3_linkargs_sz (NFS3_fh_sz+NFS3_diropargs_sz)
64#define NFS3_readdirargs_sz (NFS3_fh_sz+2)
65#define NFS3_commitargs_sz (NFS3_fh_sz+3)
66
67#define NFS3_attrstat_sz (1+NFS3_fattr_sz)
68#define NFS3_wccstat_sz (1+NFS3_wcc_data_sz)
4fdc17b2 69#define NFS3_removeres_sz (NFS3_wccstat_sz)
1da177e4
LT
70#define NFS3_lookupres_sz (1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz))
71#define NFS3_accessres_sz (1+NFS3_post_op_attr_sz+1)
72#define NFS3_readlinkres_sz (1+NFS3_post_op_attr_sz+1)
73#define NFS3_readres_sz (1+NFS3_post_op_attr_sz+3)
74#define NFS3_writeres_sz (1+NFS3_wcc_data_sz+4)
75#define NFS3_createres_sz (1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
76#define NFS3_renameres_sz (1+(2 * NFS3_wcc_data_sz))
77#define NFS3_linkres_sz (1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz)
78#define NFS3_readdirres_sz (1+NFS3_post_op_attr_sz+2)
79#define NFS3_fsstatres_sz (1+NFS3_post_op_attr_sz+13)
80#define NFS3_fsinfores_sz (1+NFS3_post_op_attr_sz+12)
81#define NFS3_pathconfres_sz (1+NFS3_post_op_attr_sz+6)
82#define NFS3_commitres_sz (1+NFS3_wcc_data_sz+2)
83
b7fa0554
AG
84#define ACL3_getaclargs_sz (NFS3_fh_sz+1)
85#define ACL3_setaclargs_sz (NFS3_fh_sz+1+2*(2+5*3))
86#define ACL3_getaclres_sz (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
87#define ACL3_setaclres_sz (1+NFS3_post_op_attr_sz)
88
1da177e4
LT
89/*
90 * Map file type to S_IFMT bits
91 */
92static struct {
93 unsigned int mode;
94 unsigned int nfs2type;
95} nfs_type2fmt[] = {
96 { 0, NFNON },
97 { S_IFREG, NFREG },
98 { S_IFDIR, NFDIR },
99 { S_IFBLK, NFBLK },
100 { S_IFCHR, NFCHR },
101 { S_IFLNK, NFLNK },
102 { S_IFSOCK, NFSOCK },
103 { S_IFIFO, NFFIFO },
104 { 0, NFBAD }
105};
106
107/*
108 * Common NFS XDR functions as inlines
109 */
d61005a6 110static inline __be32 *
4fdc17b2 111xdr_encode_fhandle(__be32 *p, const struct nfs_fh *fh)
1da177e4
LT
112{
113 return xdr_encode_array(p, fh->data, fh->size);
114}
115
d61005a6
AV
116static inline __be32 *
117xdr_decode_fhandle(__be32 *p, struct nfs_fh *fh)
1da177e4
LT
118{
119 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
120 memcpy(fh->data, p, fh->size);
121 return p + XDR_QUADLEN(fh->size);
122 }
123 return NULL;
124}
125
126/*
127 * Encode/decode time.
128 */
d61005a6
AV
129static inline __be32 *
130xdr_encode_time3(__be32 *p, struct timespec *timep)
1da177e4
LT
131{
132 *p++ = htonl(timep->tv_sec);
133 *p++ = htonl(timep->tv_nsec);
134 return p;
135}
136
d61005a6
AV
137static inline __be32 *
138xdr_decode_time3(__be32 *p, struct timespec *timep)
1da177e4
LT
139{
140 timep->tv_sec = ntohl(*p++);
141 timep->tv_nsec = ntohl(*p++);
142 return p;
143}
144
d61005a6
AV
145static __be32 *
146xdr_decode_fattr(__be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
147{
148 unsigned int type, major, minor;
149 int fmode;
150
151 type = ntohl(*p++);
152 if (type >= NF3BAD)
153 type = NF3BAD;
154 fmode = nfs_type2fmt[type].mode;
155 fattr->type = nfs_type2fmt[type].nfs2type;
156 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
157 fattr->nlink = ntohl(*p++);
158 fattr->uid = ntohl(*p++);
159 fattr->gid = ntohl(*p++);
160 p = xdr_decode_hyper(p, &fattr->size);
161 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
162
163 /* Turn remote device info into Linux-specific dev_t */
164 major = ntohl(*p++);
165 minor = ntohl(*p++);
166 fattr->rdev = MKDEV(major, minor);
167 if (MAJOR(fattr->rdev) != major || MINOR(fattr->rdev) != minor)
168 fattr->rdev = 0;
169
8b4bdcf8
TM
170 p = xdr_decode_hyper(p, &fattr->fsid.major);
171 fattr->fsid.minor = 0;
1da177e4
LT
172 p = xdr_decode_hyper(p, &fattr->fileid);
173 p = xdr_decode_time3(p, &fattr->atime);
174 p = xdr_decode_time3(p, &fattr->mtime);
175 p = xdr_decode_time3(p, &fattr->ctime);
176
177 /* Update the mode bits */
178 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
1da177e4
LT
179 return p;
180}
181
d61005a6
AV
182static inline __be32 *
183xdr_encode_sattr(__be32 *p, struct iattr *attr)
1da177e4
LT
184{
185 if (attr->ia_valid & ATTR_MODE) {
186 *p++ = xdr_one;
cf3fff54 187 *p++ = htonl(attr->ia_mode & S_IALLUGO);
1da177e4
LT
188 } else {
189 *p++ = xdr_zero;
190 }
191 if (attr->ia_valid & ATTR_UID) {
192 *p++ = xdr_one;
193 *p++ = htonl(attr->ia_uid);
194 } else {
195 *p++ = xdr_zero;
196 }
197 if (attr->ia_valid & ATTR_GID) {
198 *p++ = xdr_one;
199 *p++ = htonl(attr->ia_gid);
200 } else {
201 *p++ = xdr_zero;
202 }
203 if (attr->ia_valid & ATTR_SIZE) {
204 *p++ = xdr_one;
205 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
206 } else {
207 *p++ = xdr_zero;
208 }
209 if (attr->ia_valid & ATTR_ATIME_SET) {
210 *p++ = xdr_two;
211 p = xdr_encode_time3(p, &attr->ia_atime);
212 } else if (attr->ia_valid & ATTR_ATIME) {
213 *p++ = xdr_one;
214 } else {
215 *p++ = xdr_zero;
216 }
217 if (attr->ia_valid & ATTR_MTIME_SET) {
218 *p++ = xdr_two;
219 p = xdr_encode_time3(p, &attr->ia_mtime);
220 } else if (attr->ia_valid & ATTR_MTIME) {
221 *p++ = xdr_one;
222 } else {
223 *p++ = xdr_zero;
224 }
225 return p;
226}
227
d61005a6
AV
228static inline __be32 *
229xdr_decode_wcc_attr(__be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
230{
231 p = xdr_decode_hyper(p, &fattr->pre_size);
232 p = xdr_decode_time3(p, &fattr->pre_mtime);
233 p = xdr_decode_time3(p, &fattr->pre_ctime);
234 fattr->valid |= NFS_ATTR_WCC;
235 return p;
236}
237
d61005a6
AV
238static inline __be32 *
239xdr_decode_post_op_attr(__be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
240{
241 if (*p++)
242 p = xdr_decode_fattr(p, fattr);
243 return p;
244}
245
d61005a6
AV
246static inline __be32 *
247xdr_decode_pre_op_attr(__be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
248{
249 if (*p++)
250 return xdr_decode_wcc_attr(p, fattr);
251 return p;
252}
253
254
d61005a6
AV
255static inline __be32 *
256xdr_decode_wcc_data(__be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
257{
258 p = xdr_decode_pre_op_attr(p, fattr);
259 return xdr_decode_post_op_attr(p, fattr);
260}
261
262/*
263 * NFS encode functions
264 */
265
266/*
267 * Encode file handle argument
268 */
269static int
d61005a6 270nfs3_xdr_fhandle(struct rpc_rqst *req, __be32 *p, struct nfs_fh *fh)
1da177e4
LT
271{
272 p = xdr_encode_fhandle(p, fh);
273 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
274 return 0;
275}
276
277/*
278 * Encode SETATTR arguments
279 */
280static int
d61005a6 281nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *p, struct nfs3_sattrargs *args)
1da177e4
LT
282{
283 p = xdr_encode_fhandle(p, args->fh);
284 p = xdr_encode_sattr(p, args->sattr);
285 *p++ = htonl(args->guard);
286 if (args->guard)
287 p = xdr_encode_time3(p, &args->guardtime);
288 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
289 return 0;
290}
291
292/*
293 * Encode directory ops argument
294 */
295static int
d61005a6 296nfs3_xdr_diropargs(struct rpc_rqst *req, __be32 *p, struct nfs3_diropargs *args)
1da177e4
LT
297{
298 p = xdr_encode_fhandle(p, args->fh);
299 p = xdr_encode_array(p, args->name, args->len);
300 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
301 return 0;
302}
303
4fdc17b2
TM
304/*
305 * Encode REMOVE argument
306 */
307static int
308nfs3_xdr_removeargs(struct rpc_rqst *req, __be32 *p, const struct nfs_removeargs *args)
309{
310 p = xdr_encode_fhandle(p, args->fh);
311 p = xdr_encode_array(p, args->name.name, args->name.len);
312 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
313 return 0;
314}
315
1da177e4
LT
316/*
317 * Encode access() argument
318 */
319static int
d61005a6 320nfs3_xdr_accessargs(struct rpc_rqst *req, __be32 *p, struct nfs3_accessargs *args)
1da177e4
LT
321{
322 p = xdr_encode_fhandle(p, args->fh);
323 *p++ = htonl(args->access);
324 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
325 return 0;
326}
327
328/*
329 * Arguments to a READ call. Since we read data directly into the page
330 * cache, we also set up the reply iovec here so that iov[1] points
331 * exactly to the page we want to fetch.
332 */
333static int
d61005a6 334nfs3_xdr_readargs(struct rpc_rqst *req, __be32 *p, struct nfs_readargs *args)
1da177e4 335{
1be27f36 336 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
337 unsigned int replen;
338 u32 count = args->count;
339
340 p = xdr_encode_fhandle(p, args->fh);
341 p = xdr_encode_hyper(p, args->offset);
342 *p++ = htonl(count);
343 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
344
345 /* Inline the page array */
346 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
347 xdr_inline_pages(&req->rq_rcv_buf, replen,
348 args->pages, args->pgbase, count);
349 return 0;
350}
351
352/*
353 * Write arguments. Splice the buffer to be written into the iovec.
354 */
355static int
d61005a6 356nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
1da177e4
LT
357{
358 struct xdr_buf *sndbuf = &req->rq_snd_buf;
359 u32 count = args->count;
360
361 p = xdr_encode_fhandle(p, args->fh);
362 p = xdr_encode_hyper(p, args->offset);
363 *p++ = htonl(count);
364 *p++ = htonl(args->stable);
365 *p++ = htonl(count);
366 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
367
368 /* Copy the page array */
369 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
370 return 0;
371}
372
373/*
374 * Encode CREATE arguments
375 */
376static int
d61005a6 377nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
1da177e4
LT
378{
379 p = xdr_encode_fhandle(p, args->fh);
380 p = xdr_encode_array(p, args->name, args->len);
381
382 *p++ = htonl(args->createmode);
383 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
384 *p++ = args->verifier[0];
385 *p++ = args->verifier[1];
386 } else
387 p = xdr_encode_sattr(p, args->sattr);
388
389 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
390 return 0;
391}
392
393/*
394 * Encode MKDIR arguments
395 */
396static int
d61005a6 397nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
1da177e4
LT
398{
399 p = xdr_encode_fhandle(p, args->fh);
400 p = xdr_encode_array(p, args->name, args->len);
401 p = xdr_encode_sattr(p, args->sattr);
402 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
403 return 0;
404}
405
406/*
407 * Encode SYMLINK arguments
408 */
409static int
d61005a6 410nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
1da177e4
LT
411{
412 p = xdr_encode_fhandle(p, args->fromfh);
413 p = xdr_encode_array(p, args->fromname, args->fromlen);
414 p = xdr_encode_sattr(p, args->sattr);
94a6d753 415 *p++ = htonl(args->pathlen);
1da177e4 416 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
94a6d753
CL
417
418 /* Copy the page */
419 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
1da177e4
LT
420 return 0;
421}
422
423/*
424 * Encode MKNOD arguments
425 */
426static int
d61005a6 427nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
1da177e4
LT
428{
429 p = xdr_encode_fhandle(p, args->fh);
430 p = xdr_encode_array(p, args->name, args->len);
431 *p++ = htonl(args->type);
432 p = xdr_encode_sattr(p, args->sattr);
433 if (args->type == NF3CHR || args->type == NF3BLK) {
434 *p++ = htonl(MAJOR(args->rdev));
435 *p++ = htonl(MINOR(args->rdev));
436 }
437
438 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
439 return 0;
440}
441
442/*
443 * Encode RENAME arguments
444 */
445static int
d61005a6 446nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
1da177e4
LT
447{
448 p = xdr_encode_fhandle(p, args->fromfh);
449 p = xdr_encode_array(p, args->fromname, args->fromlen);
450 p = xdr_encode_fhandle(p, args->tofh);
451 p = xdr_encode_array(p, args->toname, args->tolen);
452 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
453 return 0;
454}
455
456/*
457 * Encode LINK arguments
458 */
459static int
d61005a6 460nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
1da177e4
LT
461{
462 p = xdr_encode_fhandle(p, args->fromfh);
463 p = xdr_encode_fhandle(p, args->tofh);
464 p = xdr_encode_array(p, args->toname, args->tolen);
465 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
466 return 0;
467}
468
469/*
470 * Encode arguments to readdir call
471 */
472static int
d61005a6 473nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
1da177e4 474{
1be27f36 475 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
476 unsigned int replen;
477 u32 count = args->count;
478
479 p = xdr_encode_fhandle(p, args->fh);
480 p = xdr_encode_hyper(p, args->cookie);
481 *p++ = args->verf[0];
482 *p++ = args->verf[1];
483 if (args->plus) {
484 /* readdirplus: need dircount + buffer size.
485 * We just make sure we make dircount big enough */
486 *p++ = htonl(count >> 3);
487 }
488 *p++ = htonl(count);
489 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
490
491 /* Inline the page array */
492 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
493 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
494 return 0;
495}
496
497/*
498 * Decode the result of a readdir call.
499 * We just check for syntactical correctness.
500 */
501static int
d61005a6 502nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
1da177e4
LT
503{
504 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
505 struct kvec *iov = rcvbuf->head;
506 struct page **page;
507 int hdrlen, recvd;
508 int status, nr;
509 unsigned int len, pglen;
d61005a6 510 __be32 *entry, *end, *kaddr;
1da177e4
LT
511
512 status = ntohl(*p++);
513 /* Decode post_op_attrs */
514 p = xdr_decode_post_op_attr(p, res->dir_attr);
515 if (status)
516 return -nfs_stat_to_errno(status);
517 /* Decode verifier cookie */
518 if (res->verf) {
519 res->verf[0] = *p++;
520 res->verf[1] = *p++;
521 } else {
522 p += 2;
523 }
524
525 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
526 if (iov->iov_len < hdrlen) {
fe82a183 527 dprintk("NFS: READDIR reply header overflowed:"
1da177e4
LT
528 "length %d > %Zu\n", hdrlen, iov->iov_len);
529 return -errno_NFSERR_IO;
530 } else if (iov->iov_len != hdrlen) {
531 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
532 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
533 }
534
535 pglen = rcvbuf->page_len;
536 recvd = rcvbuf->len - hdrlen;
537 if (pglen > recvd)
538 pglen = recvd;
539 page = rcvbuf->pages;
d61005a6
AV
540 kaddr = p = kmap_atomic(*page, KM_USER0);
541 end = (__be32 *)((char *)p + pglen);
1da177e4
LT
542 entry = p;
543 for (nr = 0; *p++; nr++) {
544 if (p + 3 > end)
545 goto short_pkt;
546 p += 2; /* inode # */
547 len = ntohl(*p++); /* string length */
548 p += XDR_QUADLEN(len) + 2; /* name + cookie */
549 if (len > NFS3_MAXNAMLEN) {
fe82a183 550 dprintk("NFS: giant filename in readdir (len %x)!\n",
1da177e4
LT
551 len);
552 goto err_unmap;
553 }
554
555 if (res->plus) {
556 /* post_op_attr */
557 if (p + 2 > end)
558 goto short_pkt;
559 if (*p++) {
560 p += 21;
561 if (p + 1 > end)
562 goto short_pkt;
563 }
564 /* post_op_fh3 */
565 if (*p++) {
566 if (p + 1 > end)
567 goto short_pkt;
568 len = ntohl(*p++);
569 if (len > NFS3_FHSIZE) {
fe82a183 570 dprintk("NFS: giant filehandle in "
1da177e4
LT
571 "readdir (len %x)!\n", len);
572 goto err_unmap;
573 }
574 p += XDR_QUADLEN(len);
575 }
576 }
577
578 if (p + 2 > end)
579 goto short_pkt;
580 entry = p;
581 }
582 if (!nr && (entry[0] != 0 || entry[1] == 0))
583 goto short_pkt;
584 out:
585 kunmap_atomic(kaddr, KM_USER0);
586 return nr;
587 short_pkt:
588 entry[0] = entry[1] = 0;
589 /* truncate listing ? */
590 if (!nr) {
fe82a183 591 dprintk("NFS: readdir reply truncated!\n");
1da177e4
LT
592 entry[1] = 1;
593 }
594 goto out;
595err_unmap:
596 nr = -errno_NFSERR_IO;
597 goto out;
598}
599
0dbb4c67
AV
600__be32 *
601nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
1da177e4
LT
602{
603 struct nfs_entry old = *entry;
604
605 if (!*p++) {
606 if (!*p)
607 return ERR_PTR(-EAGAIN);
608 entry->eof = 1;
609 return ERR_PTR(-EBADCOOKIE);
610 }
611
612 p = xdr_decode_hyper(p, &entry->ino);
613 entry->len = ntohl(*p++);
614 entry->name = (const char *) p;
615 p += XDR_QUADLEN(entry->len);
616 entry->prev_cookie = entry->cookie;
617 p = xdr_decode_hyper(p, &entry->cookie);
618
619 if (plus) {
620 entry->fattr->valid = 0;
621 p = xdr_decode_post_op_attr(p, entry->fattr);
622 /* In fact, a post_op_fh3: */
623 if (*p++) {
624 p = xdr_decode_fhandle(p, entry->fh);
625 /* Ugh -- server reply was truncated */
626 if (p == NULL) {
627 dprintk("NFS: FH truncated\n");
628 *entry = old;
629 return ERR_PTR(-EAGAIN);
630 }
631 } else
632 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
633 }
634
635 entry->eof = !p[0] && p[1];
636 return p;
637}
638
639/*
640 * Encode COMMIT arguments
641 */
642static int
d61005a6 643nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
1da177e4
LT
644{
645 p = xdr_encode_fhandle(p, args->fh);
646 p = xdr_encode_hyper(p, args->offset);
647 *p++ = htonl(args->count);
648 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
649 return 0;
650}
651
b7fa0554
AG
652#ifdef CONFIG_NFS_V3_ACL
653/*
654 * Encode GETACL arguments
655 */
656static int
d61005a6 657nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
b7fa0554
AG
658 struct nfs3_getaclargs *args)
659{
1be27f36 660 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
b7fa0554
AG
661 unsigned int replen;
662
663 p = xdr_encode_fhandle(p, args->fh);
664 *p++ = htonl(args->mask);
665 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
666
667 if (args->mask & (NFS_ACL | NFS_DFACL)) {
668 /* Inline the page array */
669 replen = (RPC_REPHDRSIZE + auth->au_rslack +
670 ACL3_getaclres_sz) << 2;
671 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
672 NFSACL_MAXPAGES << PAGE_SHIFT);
673 }
674 return 0;
675}
676
677/*
678 * Encode SETACL arguments
679 */
680static int
d61005a6 681nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
b7fa0554
AG
682 struct nfs3_setaclargs *args)
683{
684 struct xdr_buf *buf = &req->rq_snd_buf;
685 unsigned int base, len_in_head, len = nfsacl_size(
686 (args->mask & NFS_ACL) ? args->acl_access : NULL,
687 (args->mask & NFS_DFACL) ? args->acl_default : NULL);
688 int count, err;
689
690 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
691 *p++ = htonl(args->mask);
692 base = (char *)p - (char *)buf->head->iov_base;
693 /* put as much of the acls into head as possible. */
694 len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
695 len -= len_in_head;
21348425 696 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
b7fa0554
AG
697
698 for (count = 0; (count << PAGE_SHIFT) < len; count++) {
699 args->pages[count] = alloc_page(GFP_KERNEL);
700 if (!args->pages[count]) {
701 while (count)
702 __free_page(args->pages[--count]);
703 return -ENOMEM;
704 }
705 }
706 xdr_encode_pages(buf, args->pages, 0, len);
707
708 err = nfsacl_encode(buf, base, args->inode,
709 (args->mask & NFS_ACL) ?
710 args->acl_access : NULL, 1, 0);
711 if (err > 0)
712 err = nfsacl_encode(buf, base + err, args->inode,
713 (args->mask & NFS_DFACL) ?
714 args->acl_default : NULL, 1,
715 NFS_ACL_DEFAULT);
716 return (err > 0) ? 0 : err;
717}
718#endif /* CONFIG_NFS_V3_ACL */
719
1da177e4
LT
720/*
721 * NFS XDR decode functions
722 */
723
724/*
725 * Decode attrstat reply.
726 */
727static int
d61005a6 728nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
729{
730 int status;
731
732 if ((status = ntohl(*p++)))
733 return -nfs_stat_to_errno(status);
734 xdr_decode_fattr(p, fattr);
735 return 0;
736}
737
738/*
739 * Decode status+wcc_data reply
740 * SATTR, REMOVE, RMDIR
741 */
742static int
d61005a6 743nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
744{
745 int status;
746
747 if ((status = ntohl(*p++)))
748 status = -nfs_stat_to_errno(status);
749 xdr_decode_wcc_data(p, fattr);
750 return status;
751}
752
4fdc17b2
TM
753static int
754nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
755{
756 return nfs3_xdr_wccstat(req, p, &res->dir_attr);
757}
758
1da177e4
LT
759/*
760 * Decode LOOKUP reply
761 */
762static int
d61005a6 763nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
1da177e4
LT
764{
765 int status;
766
767 if ((status = ntohl(*p++))) {
768 status = -nfs_stat_to_errno(status);
769 } else {
770 if (!(p = xdr_decode_fhandle(p, res->fh)))
771 return -errno_NFSERR_IO;
772 p = xdr_decode_post_op_attr(p, res->fattr);
773 }
774 xdr_decode_post_op_attr(p, res->dir_attr);
775 return status;
776}
777
778/*
779 * Decode ACCESS reply
780 */
781static int
d61005a6 782nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
1da177e4
LT
783{
784 int status = ntohl(*p++);
785
786 p = xdr_decode_post_op_attr(p, res->fattr);
787 if (status)
788 return -nfs_stat_to_errno(status);
789 res->access = ntohl(*p++);
790 return 0;
791}
792
793static int
d61005a6 794nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
1da177e4 795{
1be27f36 796 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
797 unsigned int replen;
798
799 p = xdr_encode_fhandle(p, args->fh);
800 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
801
802 /* Inline the page array */
803 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
804 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
805 return 0;
806}
807
808/*
809 * Decode READLINK reply
810 */
811static int
d61005a6 812nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
813{
814 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
815 struct kvec *iov = rcvbuf->head;
816 int hdrlen, len, recvd;
817 char *kaddr;
818 int status;
819
820 status = ntohl(*p++);
821 p = xdr_decode_post_op_attr(p, fattr);
822
823 if (status != 0)
824 return -nfs_stat_to_errno(status);
825
826 /* Convert length of symlink */
827 len = ntohl(*p++);
828 if (len >= rcvbuf->page_len || len <= 0) {
fe82a183 829 dprintk("nfs: server returned giant symlink!\n");
1da177e4
LT
830 return -ENAMETOOLONG;
831 }
832
833 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
834 if (iov->iov_len < hdrlen) {
fe82a183 835 dprintk("NFS: READLINK reply header overflowed:"
1da177e4
LT
836 "length %d > %Zu\n", hdrlen, iov->iov_len);
837 return -errno_NFSERR_IO;
838 } else if (iov->iov_len != hdrlen) {
fe82a183
CL
839 dprintk("NFS: READLINK header is short. "
840 "iovec will be shifted.\n");
1da177e4
LT
841 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
842 }
843 recvd = req->rq_rcv_buf.len - hdrlen;
844 if (recvd < len) {
fe82a183 845 dprintk("NFS: server cheating in readlink reply: "
1da177e4
LT
846 "count %u > recvd %u\n", len, recvd);
847 return -EIO;
848 }
849
850 /* NULL terminate the string we got */
851 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
852 kaddr[len+rcvbuf->page_base] = '\0';
853 kunmap_atomic(kaddr, KM_USER0);
854 return 0;
855}
856
857/*
858 * Decode READ reply
859 */
860static int
d61005a6 861nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
1da177e4
LT
862{
863 struct kvec *iov = req->rq_rcv_buf.head;
864 int status, count, ocount, recvd, hdrlen;
865
866 status = ntohl(*p++);
867 p = xdr_decode_post_op_attr(p, res->fattr);
868
869 if (status != 0)
870 return -nfs_stat_to_errno(status);
871
872 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
873 * in that it puts the count both in the res struct and in the
874 * opaque data count. */
875 count = ntohl(*p++);
876 res->eof = ntohl(*p++);
877 ocount = ntohl(*p++);
878
879 if (ocount != count) {
fe82a183 880 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
1da177e4
LT
881 return -errno_NFSERR_IO;
882 }
883
884 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
885 if (iov->iov_len < hdrlen) {
fe82a183 886 dprintk("NFS: READ reply header overflowed:"
1da177e4
LT
887 "length %d > %Zu\n", hdrlen, iov->iov_len);
888 return -errno_NFSERR_IO;
889 } else if (iov->iov_len != hdrlen) {
890 dprintk("NFS: READ header is short. iovec will be shifted.\n");
891 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
892 }
893
894 recvd = req->rq_rcv_buf.len - hdrlen;
895 if (count > recvd) {
fe82a183 896 dprintk("NFS: server cheating in read reply: "
1da177e4
LT
897 "count %d > recvd %d\n", count, recvd);
898 count = recvd;
899 res->eof = 0;
900 }
901
902 if (count < res->count)
903 res->count = count;
904
905 return count;
906}
907
908/*
909 * Decode WRITE response
910 */
911static int
d61005a6 912nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1da177e4
LT
913{
914 int status;
915
916 status = ntohl(*p++);
917 p = xdr_decode_wcc_data(p, res->fattr);
918
919 if (status != 0)
920 return -nfs_stat_to_errno(status);
921
922 res->count = ntohl(*p++);
923 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
924 res->verf->verifier[0] = *p++;
925 res->verf->verifier[1] = *p++;
926
927 return res->count;
928}
929
930/*
931 * Decode a CREATE response
932 */
933static int
d61005a6 934nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
1da177e4
LT
935{
936 int status;
937
938 status = ntohl(*p++);
939 if (status == 0) {
940 if (*p++) {
941 if (!(p = xdr_decode_fhandle(p, res->fh)))
942 return -errno_NFSERR_IO;
943 p = xdr_decode_post_op_attr(p, res->fattr);
944 } else {
945 memset(res->fh, 0, sizeof(*res->fh));
946 /* Do decode post_op_attr but set it to NULL */
947 p = xdr_decode_post_op_attr(p, res->fattr);
948 res->fattr->valid = 0;
949 }
950 } else {
951 status = -nfs_stat_to_errno(status);
952 }
953 p = xdr_decode_wcc_data(p, res->dir_attr);
954 return status;
955}
956
957/*
958 * Decode RENAME reply
959 */
960static int
d61005a6 961nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
1da177e4
LT
962{
963 int status;
964
965 if ((status = ntohl(*p++)) != 0)
966 status = -nfs_stat_to_errno(status);
967 p = xdr_decode_wcc_data(p, res->fromattr);
968 p = xdr_decode_wcc_data(p, res->toattr);
969 return status;
970}
971
972/*
973 * Decode LINK reply
974 */
975static int
d61005a6 976nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
1da177e4
LT
977{
978 int status;
979
980 if ((status = ntohl(*p++)) != 0)
981 status = -nfs_stat_to_errno(status);
982 p = xdr_decode_post_op_attr(p, res->fattr);
983 p = xdr_decode_wcc_data(p, res->dir_attr);
984 return status;
985}
986
987/*
988 * Decode FSSTAT reply
989 */
990static int
d61005a6 991nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1da177e4
LT
992{
993 int status;
994
995 status = ntohl(*p++);
996
997 p = xdr_decode_post_op_attr(p, res->fattr);
998 if (status != 0)
999 return -nfs_stat_to_errno(status);
1000
1001 p = xdr_decode_hyper(p, &res->tbytes);
1002 p = xdr_decode_hyper(p, &res->fbytes);
1003 p = xdr_decode_hyper(p, &res->abytes);
1004 p = xdr_decode_hyper(p, &res->tfiles);
1005 p = xdr_decode_hyper(p, &res->ffiles);
1006 p = xdr_decode_hyper(p, &res->afiles);
1007
1008 /* ignore invarsec */
1009 return 0;
1010}
1011
1012/*
1013 * Decode FSINFO reply
1014 */
1015static int
d61005a6 1016nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1da177e4
LT
1017{
1018 int status;
1019
1020 status = ntohl(*p++);
1021
1022 p = xdr_decode_post_op_attr(p, res->fattr);
1023 if (status != 0)
1024 return -nfs_stat_to_errno(status);
1025
1026 res->rtmax = ntohl(*p++);
1027 res->rtpref = ntohl(*p++);
1028 res->rtmult = ntohl(*p++);
1029 res->wtmax = ntohl(*p++);
1030 res->wtpref = ntohl(*p++);
1031 res->wtmult = ntohl(*p++);
1032 res->dtpref = ntohl(*p++);
1033 p = xdr_decode_hyper(p, &res->maxfilesize);
1034
1035 /* ignore time_delta and properties */
1036 res->lease_time = 0;
1037 return 0;
1038}
1039
1040/*
1041 * Decode PATHCONF reply
1042 */
1043static int
d61005a6 1044nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1da177e4
LT
1045{
1046 int status;
1047
1048 status = ntohl(*p++);
1049
1050 p = xdr_decode_post_op_attr(p, res->fattr);
1051 if (status != 0)
1052 return -nfs_stat_to_errno(status);
1053 res->max_link = ntohl(*p++);
1054 res->max_namelen = ntohl(*p++);
1055
1056 /* ignore remaining fields */
1057 return 0;
1058}
1059
1060/*
1061 * Decode COMMIT reply
1062 */
1063static int
d61005a6 1064nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1da177e4
LT
1065{
1066 int status;
1067
1068 status = ntohl(*p++);
1069 p = xdr_decode_wcc_data(p, res->fattr);
1070 if (status != 0)
1071 return -nfs_stat_to_errno(status);
1072
1073 res->verf->verifier[0] = *p++;
1074 res->verf->verifier[1] = *p++;
1075 return 0;
1076}
1077
b7fa0554
AG
1078#ifdef CONFIG_NFS_V3_ACL
1079/*
1080 * Decode GETACL reply
1081 */
1082static int
d61005a6 1083nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
b7fa0554
AG
1084 struct nfs3_getaclres *res)
1085{
1086 struct xdr_buf *buf = &req->rq_rcv_buf;
1087 int status = ntohl(*p++);
1088 struct posix_acl **acl;
1089 unsigned int *aclcnt;
1090 int err, base;
1091
1092 if (status != 0)
1093 return -nfs_stat_to_errno(status);
1094 p = xdr_decode_post_op_attr(p, res->fattr);
1095 res->mask = ntohl(*p++);
1096 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1097 return -EINVAL;
1098 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1099
1100 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1101 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1102 err = nfsacl_decode(buf, base, aclcnt, acl);
1103
1104 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1105 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1106 if (err > 0)
1107 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1108 return (err > 0) ? 0 : err;
1109}
1110
1111/*
1112 * Decode setacl reply.
1113 */
1114static int
d61005a6 1115nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
b7fa0554
AG
1116{
1117 int status = ntohl(*p++);
1118
1119 if (status)
1120 return -nfs_stat_to_errno(status);
1121 xdr_decode_post_op_attr(p, fattr);
1122 return 0;
1123}
1124#endif /* CONFIG_NFS_V3_ACL */
1125
1da177e4
LT
1126#define PROC(proc, argtype, restype, timer) \
1127[NFS3PROC_##proc] = { \
1128 .p_proc = NFS3PROC_##proc, \
1129 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1130 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
2bea90d4
CL
1131 .p_arglen = NFS3_##argtype##_sz, \
1132 .p_replen = NFS3_##restype##_sz, \
cc0175c1
CL
1133 .p_timer = timer, \
1134 .p_statidx = NFS3PROC_##proc, \
1135 .p_name = #proc, \
1da177e4
LT
1136 }
1137
1138struct rpc_procinfo nfs3_procedures[] = {
1139 PROC(GETATTR, fhandle, attrstat, 1),
1140 PROC(SETATTR, sattrargs, wccstat, 0),
1141 PROC(LOOKUP, diropargs, lookupres, 2),
1142 PROC(ACCESS, accessargs, accessres, 1),
1143 PROC(READLINK, readlinkargs, readlinkres, 3),
1144 PROC(READ, readargs, readres, 3),
1145 PROC(WRITE, writeargs, writeres, 4),
1146 PROC(CREATE, createargs, createres, 0),
1147 PROC(MKDIR, mkdirargs, createres, 0),
1148 PROC(SYMLINK, symlinkargs, createres, 0),
1149 PROC(MKNOD, mknodargs, createres, 0),
4fdc17b2 1150 PROC(REMOVE, removeargs, removeres, 0),
1da177e4
LT
1151 PROC(RMDIR, diropargs, wccstat, 0),
1152 PROC(RENAME, renameargs, renameres, 0),
1153 PROC(LINK, linkargs, linkres, 0),
1154 PROC(READDIR, readdirargs, readdirres, 3),
1155 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1156 PROC(FSSTAT, fhandle, fsstatres, 0),
1157 PROC(FSINFO, fhandle, fsinfores, 0),
1158 PROC(PATHCONF, fhandle, pathconfres, 0),
1159 PROC(COMMIT, commitargs, commitres, 5),
1160};
1161
1162struct rpc_version nfs_version3 = {
1163 .number = 3,
e8c96f8c 1164 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1da177e4
LT
1165 .procs = nfs3_procedures
1166};
1167
b7fa0554
AG
1168#ifdef CONFIG_NFS_V3_ACL
1169static struct rpc_procinfo nfs3_acl_procedures[] = {
1170 [ACLPROC3_GETACL] = {
1171 .p_proc = ACLPROC3_GETACL,
1172 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1173 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
2bea90d4
CL
1174 .p_arglen = ACL3_getaclargs_sz,
1175 .p_replen = ACL3_getaclres_sz,
b7fa0554 1176 .p_timer = 1,
cc0175c1 1177 .p_name = "GETACL",
b7fa0554
AG
1178 },
1179 [ACLPROC3_SETACL] = {
1180 .p_proc = ACLPROC3_SETACL,
1181 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1182 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
2bea90d4
CL
1183 .p_arglen = ACL3_setaclargs_sz,
1184 .p_replen = ACL3_setaclres_sz,
b7fa0554 1185 .p_timer = 0,
cc0175c1 1186 .p_name = "SETACL",
b7fa0554
AG
1187 },
1188};
1189
1190struct rpc_version nfsacl_version3 = {
1191 .number = 3,
1192 .nrprocs = sizeof(nfs3_acl_procedures)/
1193 sizeof(nfs3_acl_procedures[0]),
1194 .procs = nfs3_acl_procedures,
1195};
1196#endif /* CONFIG_NFS_V3_ACL */