[XFS] Don't allow silent errors in xfs_inactive().
[deliverable/linux.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);
4f22ccc3 349 req->rq_rcv_buf.flags |= XDRBUF_READ;
1da177e4
LT
350 return 0;
351}
352
353/*
354 * Write arguments. Splice the buffer to be written into the iovec.
355 */
356static int
d61005a6 357nfs3_xdr_writeargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
1da177e4
LT
358{
359 struct xdr_buf *sndbuf = &req->rq_snd_buf;
360 u32 count = args->count;
361
362 p = xdr_encode_fhandle(p, args->fh);
363 p = xdr_encode_hyper(p, args->offset);
364 *p++ = htonl(count);
365 *p++ = htonl(args->stable);
366 *p++ = htonl(count);
367 sndbuf->len = xdr_adjust_iovec(sndbuf->head, p);
368
369 /* Copy the page array */
370 xdr_encode_pages(sndbuf, args->pages, args->pgbase, count);
4f22ccc3 371 sndbuf->flags |= XDRBUF_WRITE;
1da177e4
LT
372 return 0;
373}
374
375/*
376 * Encode CREATE arguments
377 */
378static int
d61005a6 379nfs3_xdr_createargs(struct rpc_rqst *req, __be32 *p, struct nfs3_createargs *args)
1da177e4
LT
380{
381 p = xdr_encode_fhandle(p, args->fh);
382 p = xdr_encode_array(p, args->name, args->len);
383
384 *p++ = htonl(args->createmode);
385 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
386 *p++ = args->verifier[0];
387 *p++ = args->verifier[1];
388 } else
389 p = xdr_encode_sattr(p, args->sattr);
390
391 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
392 return 0;
393}
394
395/*
396 * Encode MKDIR arguments
397 */
398static int
d61005a6 399nfs3_xdr_mkdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mkdirargs *args)
1da177e4
LT
400{
401 p = xdr_encode_fhandle(p, args->fh);
402 p = xdr_encode_array(p, args->name, args->len);
403 p = xdr_encode_sattr(p, args->sattr);
404 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
405 return 0;
406}
407
408/*
409 * Encode SYMLINK arguments
410 */
411static int
d61005a6 412nfs3_xdr_symlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_symlinkargs *args)
1da177e4
LT
413{
414 p = xdr_encode_fhandle(p, args->fromfh);
415 p = xdr_encode_array(p, args->fromname, args->fromlen);
416 p = xdr_encode_sattr(p, args->sattr);
94a6d753 417 *p++ = htonl(args->pathlen);
1da177e4 418 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
94a6d753
CL
419
420 /* Copy the page */
421 xdr_encode_pages(&req->rq_snd_buf, args->pages, 0, args->pathlen);
1da177e4
LT
422 return 0;
423}
424
425/*
426 * Encode MKNOD arguments
427 */
428static int
d61005a6 429nfs3_xdr_mknodargs(struct rpc_rqst *req, __be32 *p, struct nfs3_mknodargs *args)
1da177e4
LT
430{
431 p = xdr_encode_fhandle(p, args->fh);
432 p = xdr_encode_array(p, args->name, args->len);
433 *p++ = htonl(args->type);
434 p = xdr_encode_sattr(p, args->sattr);
435 if (args->type == NF3CHR || args->type == NF3BLK) {
436 *p++ = htonl(MAJOR(args->rdev));
437 *p++ = htonl(MINOR(args->rdev));
438 }
439
440 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
441 return 0;
442}
443
444/*
445 * Encode RENAME arguments
446 */
447static int
d61005a6 448nfs3_xdr_renameargs(struct rpc_rqst *req, __be32 *p, struct nfs3_renameargs *args)
1da177e4
LT
449{
450 p = xdr_encode_fhandle(p, args->fromfh);
451 p = xdr_encode_array(p, args->fromname, args->fromlen);
452 p = xdr_encode_fhandle(p, args->tofh);
453 p = xdr_encode_array(p, args->toname, args->tolen);
454 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
455 return 0;
456}
457
458/*
459 * Encode LINK arguments
460 */
461static int
d61005a6 462nfs3_xdr_linkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_linkargs *args)
1da177e4
LT
463{
464 p = xdr_encode_fhandle(p, args->fromfh);
465 p = xdr_encode_fhandle(p, args->tofh);
466 p = xdr_encode_array(p, args->toname, args->tolen);
467 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
468 return 0;
469}
470
471/*
472 * Encode arguments to readdir call
473 */
474static int
d61005a6 475nfs3_xdr_readdirargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirargs *args)
1da177e4 476{
1be27f36 477 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
478 unsigned int replen;
479 u32 count = args->count;
480
481 p = xdr_encode_fhandle(p, args->fh);
482 p = xdr_encode_hyper(p, args->cookie);
483 *p++ = args->verf[0];
484 *p++ = args->verf[1];
485 if (args->plus) {
486 /* readdirplus: need dircount + buffer size.
487 * We just make sure we make dircount big enough */
488 *p++ = htonl(count >> 3);
489 }
490 *p++ = htonl(count);
491 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
492
493 /* Inline the page array */
494 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
495 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0, count);
496 return 0;
497}
498
499/*
500 * Decode the result of a readdir call.
501 * We just check for syntactical correctness.
502 */
503static int
d61005a6 504nfs3_xdr_readdirres(struct rpc_rqst *req, __be32 *p, struct nfs3_readdirres *res)
1da177e4
LT
505{
506 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
507 struct kvec *iov = rcvbuf->head;
508 struct page **page;
c957c526
CL
509 size_t hdrlen;
510 u32 len, recvd, pglen;
1da177e4 511 int status, nr;
d61005a6 512 __be32 *entry, *end, *kaddr;
1da177e4
LT
513
514 status = ntohl(*p++);
515 /* Decode post_op_attrs */
516 p = xdr_decode_post_op_attr(p, res->dir_attr);
517 if (status)
518 return -nfs_stat_to_errno(status);
519 /* Decode verifier cookie */
520 if (res->verf) {
521 res->verf[0] = *p++;
522 res->verf[1] = *p++;
523 } else {
524 p += 2;
525 }
526
527 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
528 if (iov->iov_len < hdrlen) {
fe82a183 529 dprintk("NFS: READDIR reply header overflowed:"
c957c526 530 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
531 return -errno_NFSERR_IO;
532 } else if (iov->iov_len != hdrlen) {
533 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
534 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
535 }
536
537 pglen = rcvbuf->page_len;
538 recvd = rcvbuf->len - hdrlen;
539 if (pglen > recvd)
540 pglen = recvd;
541 page = rcvbuf->pages;
d61005a6
AV
542 kaddr = p = kmap_atomic(*page, KM_USER0);
543 end = (__be32 *)((char *)p + pglen);
1da177e4
LT
544 entry = p;
545 for (nr = 0; *p++; nr++) {
546 if (p + 3 > end)
547 goto short_pkt;
548 p += 2; /* inode # */
549 len = ntohl(*p++); /* string length */
550 p += XDR_QUADLEN(len) + 2; /* name + cookie */
551 if (len > NFS3_MAXNAMLEN) {
c957c526 552 dprintk("NFS: giant filename in readdir (len 0x%x)!\n",
1da177e4
LT
553 len);
554 goto err_unmap;
555 }
556
557 if (res->plus) {
558 /* post_op_attr */
559 if (p + 2 > end)
560 goto short_pkt;
561 if (*p++) {
562 p += 21;
563 if (p + 1 > end)
564 goto short_pkt;
565 }
566 /* post_op_fh3 */
567 if (*p++) {
568 if (p + 1 > end)
569 goto short_pkt;
570 len = ntohl(*p++);
571 if (len > NFS3_FHSIZE) {
fe82a183 572 dprintk("NFS: giant filehandle in "
c957c526 573 "readdir (len 0x%x)!\n", len);
1da177e4
LT
574 goto err_unmap;
575 }
576 p += XDR_QUADLEN(len);
577 }
578 }
579
580 if (p + 2 > end)
581 goto short_pkt;
582 entry = p;
583 }
584 if (!nr && (entry[0] != 0 || entry[1] == 0))
585 goto short_pkt;
586 out:
587 kunmap_atomic(kaddr, KM_USER0);
588 return nr;
589 short_pkt:
590 entry[0] = entry[1] = 0;
591 /* truncate listing ? */
592 if (!nr) {
fe82a183 593 dprintk("NFS: readdir reply truncated!\n");
1da177e4
LT
594 entry[1] = 1;
595 }
596 goto out;
597err_unmap:
598 nr = -errno_NFSERR_IO;
599 goto out;
600}
601
0dbb4c67
AV
602__be32 *
603nfs3_decode_dirent(__be32 *p, struct nfs_entry *entry, int plus)
1da177e4
LT
604{
605 struct nfs_entry old = *entry;
606
607 if (!*p++) {
608 if (!*p)
609 return ERR_PTR(-EAGAIN);
610 entry->eof = 1;
611 return ERR_PTR(-EBADCOOKIE);
612 }
613
614 p = xdr_decode_hyper(p, &entry->ino);
615 entry->len = ntohl(*p++);
616 entry->name = (const char *) p;
617 p += XDR_QUADLEN(entry->len);
618 entry->prev_cookie = entry->cookie;
619 p = xdr_decode_hyper(p, &entry->cookie);
620
621 if (plus) {
622 entry->fattr->valid = 0;
623 p = xdr_decode_post_op_attr(p, entry->fattr);
624 /* In fact, a post_op_fh3: */
625 if (*p++) {
626 p = xdr_decode_fhandle(p, entry->fh);
627 /* Ugh -- server reply was truncated */
628 if (p == NULL) {
629 dprintk("NFS: FH truncated\n");
630 *entry = old;
631 return ERR_PTR(-EAGAIN);
632 }
633 } else
634 memset((u8*)(entry->fh), 0, sizeof(*entry->fh));
635 }
636
637 entry->eof = !p[0] && p[1];
638 return p;
639}
640
641/*
642 * Encode COMMIT arguments
643 */
644static int
d61005a6 645nfs3_xdr_commitargs(struct rpc_rqst *req, __be32 *p, struct nfs_writeargs *args)
1da177e4
LT
646{
647 p = xdr_encode_fhandle(p, args->fh);
648 p = xdr_encode_hyper(p, args->offset);
649 *p++ = htonl(args->count);
650 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
651 return 0;
652}
653
b7fa0554
AG
654#ifdef CONFIG_NFS_V3_ACL
655/*
656 * Encode GETACL arguments
657 */
658static int
d61005a6 659nfs3_xdr_getaclargs(struct rpc_rqst *req, __be32 *p,
b7fa0554
AG
660 struct nfs3_getaclargs *args)
661{
1be27f36 662 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
b7fa0554
AG
663 unsigned int replen;
664
665 p = xdr_encode_fhandle(p, args->fh);
666 *p++ = htonl(args->mask);
667 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
668
669 if (args->mask & (NFS_ACL | NFS_DFACL)) {
670 /* Inline the page array */
671 replen = (RPC_REPHDRSIZE + auth->au_rslack +
672 ACL3_getaclres_sz) << 2;
673 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, 0,
674 NFSACL_MAXPAGES << PAGE_SHIFT);
675 }
676 return 0;
677}
678
679/*
680 * Encode SETACL arguments
681 */
682static int
d61005a6 683nfs3_xdr_setaclargs(struct rpc_rqst *req, __be32 *p,
b7fa0554
AG
684 struct nfs3_setaclargs *args)
685{
686 struct xdr_buf *buf = &req->rq_snd_buf;
687 unsigned int base, len_in_head, len = nfsacl_size(
688 (args->mask & NFS_ACL) ? args->acl_access : NULL,
689 (args->mask & NFS_DFACL) ? args->acl_default : NULL);
690 int count, err;
691
692 p = xdr_encode_fhandle(p, NFS_FH(args->inode));
693 *p++ = htonl(args->mask);
694 base = (char *)p - (char *)buf->head->iov_base;
695 /* put as much of the acls into head as possible. */
696 len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
697 len -= len_in_head;
21348425 698 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
b7fa0554
AG
699
700 for (count = 0; (count << PAGE_SHIFT) < len; count++) {
701 args->pages[count] = alloc_page(GFP_KERNEL);
702 if (!args->pages[count]) {
703 while (count)
704 __free_page(args->pages[--count]);
705 return -ENOMEM;
706 }
707 }
708 xdr_encode_pages(buf, args->pages, 0, len);
709
710 err = nfsacl_encode(buf, base, args->inode,
711 (args->mask & NFS_ACL) ?
712 args->acl_access : NULL, 1, 0);
713 if (err > 0)
714 err = nfsacl_encode(buf, base + err, args->inode,
715 (args->mask & NFS_DFACL) ?
716 args->acl_default : NULL, 1,
717 NFS_ACL_DEFAULT);
718 return (err > 0) ? 0 : err;
719}
720#endif /* CONFIG_NFS_V3_ACL */
721
1da177e4
LT
722/*
723 * NFS XDR decode functions
724 */
725
726/*
727 * Decode attrstat reply.
728 */
729static int
d61005a6 730nfs3_xdr_attrstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
731{
732 int status;
733
734 if ((status = ntohl(*p++)))
735 return -nfs_stat_to_errno(status);
736 xdr_decode_fattr(p, fattr);
737 return 0;
738}
739
740/*
741 * Decode status+wcc_data reply
742 * SATTR, REMOVE, RMDIR
743 */
744static int
d61005a6 745nfs3_xdr_wccstat(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
746{
747 int status;
748
749 if ((status = ntohl(*p++)))
750 status = -nfs_stat_to_errno(status);
751 xdr_decode_wcc_data(p, fattr);
752 return status;
753}
754
4fdc17b2
TM
755static int
756nfs3_xdr_removeres(struct rpc_rqst *req, __be32 *p, struct nfs_removeres *res)
757{
758 return nfs3_xdr_wccstat(req, p, &res->dir_attr);
759}
760
1da177e4
LT
761/*
762 * Decode LOOKUP reply
763 */
764static int
d61005a6 765nfs3_xdr_lookupres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
1da177e4
LT
766{
767 int status;
768
769 if ((status = ntohl(*p++))) {
770 status = -nfs_stat_to_errno(status);
771 } else {
772 if (!(p = xdr_decode_fhandle(p, res->fh)))
773 return -errno_NFSERR_IO;
774 p = xdr_decode_post_op_attr(p, res->fattr);
775 }
776 xdr_decode_post_op_attr(p, res->dir_attr);
777 return status;
778}
779
780/*
781 * Decode ACCESS reply
782 */
783static int
d61005a6 784nfs3_xdr_accessres(struct rpc_rqst *req, __be32 *p, struct nfs3_accessres *res)
1da177e4
LT
785{
786 int status = ntohl(*p++);
787
788 p = xdr_decode_post_op_attr(p, res->fattr);
789 if (status)
790 return -nfs_stat_to_errno(status);
791 res->access = ntohl(*p++);
792 return 0;
793}
794
795static int
d61005a6 796nfs3_xdr_readlinkargs(struct rpc_rqst *req, __be32 *p, struct nfs3_readlinkargs *args)
1da177e4 797{
1be27f36 798 struct rpc_auth *auth = req->rq_task->tk_msg.rpc_cred->cr_auth;
1da177e4
LT
799 unsigned int replen;
800
801 p = xdr_encode_fhandle(p, args->fh);
802 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
803
804 /* Inline the page array */
805 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
806 xdr_inline_pages(&req->rq_rcv_buf, replen, args->pages, args->pgbase, args->pglen);
807 return 0;
808}
809
810/*
811 * Decode READLINK reply
812 */
813static int
d61005a6 814nfs3_xdr_readlinkres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
1da177e4
LT
815{
816 struct xdr_buf *rcvbuf = &req->rq_rcv_buf;
817 struct kvec *iov = rcvbuf->head;
c957c526
CL
818 size_t hdrlen;
819 u32 len, recvd;
1da177e4
LT
820 char *kaddr;
821 int status;
822
823 status = ntohl(*p++);
824 p = xdr_decode_post_op_attr(p, fattr);
825
826 if (status != 0)
827 return -nfs_stat_to_errno(status);
828
829 /* Convert length of symlink */
830 len = ntohl(*p++);
c957c526 831 if (len >= rcvbuf->page_len) {
fe82a183 832 dprintk("nfs: server returned giant symlink!\n");
1da177e4
LT
833 return -ENAMETOOLONG;
834 }
835
836 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
837 if (iov->iov_len < hdrlen) {
fe82a183 838 dprintk("NFS: READLINK reply header overflowed:"
c957c526 839 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
840 return -errno_NFSERR_IO;
841 } else if (iov->iov_len != hdrlen) {
fe82a183
CL
842 dprintk("NFS: READLINK header is short. "
843 "iovec will be shifted.\n");
1da177e4
LT
844 xdr_shift_buf(rcvbuf, iov->iov_len - hdrlen);
845 }
846 recvd = req->rq_rcv_buf.len - hdrlen;
847 if (recvd < len) {
fe82a183 848 dprintk("NFS: server cheating in readlink reply: "
1da177e4
LT
849 "count %u > recvd %u\n", len, recvd);
850 return -EIO;
851 }
852
853 /* NULL terminate the string we got */
854 kaddr = (char*)kmap_atomic(rcvbuf->pages[0], KM_USER0);
855 kaddr[len+rcvbuf->page_base] = '\0';
856 kunmap_atomic(kaddr, KM_USER0);
857 return 0;
858}
859
860/*
861 * Decode READ reply
862 */
863static int
d61005a6 864nfs3_xdr_readres(struct rpc_rqst *req, __be32 *p, struct nfs_readres *res)
1da177e4
LT
865{
866 struct kvec *iov = req->rq_rcv_buf.head;
c957c526
CL
867 size_t hdrlen;
868 u32 count, ocount, recvd;
869 int status;
1da177e4
LT
870
871 status = ntohl(*p++);
872 p = xdr_decode_post_op_attr(p, res->fattr);
873
874 if (status != 0)
875 return -nfs_stat_to_errno(status);
876
c957c526 877 /* Decode reply count and EOF flag. NFSv3 is somewhat redundant
1da177e4
LT
878 * in that it puts the count both in the res struct and in the
879 * opaque data count. */
880 count = ntohl(*p++);
881 res->eof = ntohl(*p++);
882 ocount = ntohl(*p++);
883
884 if (ocount != count) {
fe82a183 885 dprintk("NFS: READ count doesn't match RPC opaque count.\n");
1da177e4
LT
886 return -errno_NFSERR_IO;
887 }
888
889 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
890 if (iov->iov_len < hdrlen) {
fe82a183 891 dprintk("NFS: READ reply header overflowed:"
c957c526 892 "length %Zu > %Zu\n", hdrlen, iov->iov_len);
1da177e4
LT
893 return -errno_NFSERR_IO;
894 } else if (iov->iov_len != hdrlen) {
895 dprintk("NFS: READ header is short. iovec will be shifted.\n");
896 xdr_shift_buf(&req->rq_rcv_buf, iov->iov_len - hdrlen);
897 }
898
899 recvd = req->rq_rcv_buf.len - hdrlen;
900 if (count > recvd) {
fe82a183 901 dprintk("NFS: server cheating in read reply: "
c957c526 902 "count %u > recvd %u\n", count, recvd);
1da177e4
LT
903 count = recvd;
904 res->eof = 0;
905 }
906
907 if (count < res->count)
908 res->count = count;
909
910 return count;
911}
912
913/*
914 * Decode WRITE response
915 */
916static int
d61005a6 917nfs3_xdr_writeres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1da177e4
LT
918{
919 int status;
920
921 status = ntohl(*p++);
922 p = xdr_decode_wcc_data(p, res->fattr);
923
924 if (status != 0)
925 return -nfs_stat_to_errno(status);
926
927 res->count = ntohl(*p++);
928 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
929 res->verf->verifier[0] = *p++;
930 res->verf->verifier[1] = *p++;
931
932 return res->count;
933}
934
935/*
936 * Decode a CREATE response
937 */
938static int
d61005a6 939nfs3_xdr_createres(struct rpc_rqst *req, __be32 *p, struct nfs3_diropres *res)
1da177e4
LT
940{
941 int status;
942
943 status = ntohl(*p++);
944 if (status == 0) {
945 if (*p++) {
946 if (!(p = xdr_decode_fhandle(p, res->fh)))
947 return -errno_NFSERR_IO;
948 p = xdr_decode_post_op_attr(p, res->fattr);
949 } else {
950 memset(res->fh, 0, sizeof(*res->fh));
951 /* Do decode post_op_attr but set it to NULL */
952 p = xdr_decode_post_op_attr(p, res->fattr);
953 res->fattr->valid = 0;
954 }
955 } else {
956 status = -nfs_stat_to_errno(status);
957 }
958 p = xdr_decode_wcc_data(p, res->dir_attr);
959 return status;
960}
961
962/*
963 * Decode RENAME reply
964 */
965static int
d61005a6 966nfs3_xdr_renameres(struct rpc_rqst *req, __be32 *p, struct nfs3_renameres *res)
1da177e4
LT
967{
968 int status;
969
970 if ((status = ntohl(*p++)) != 0)
971 status = -nfs_stat_to_errno(status);
972 p = xdr_decode_wcc_data(p, res->fromattr);
973 p = xdr_decode_wcc_data(p, res->toattr);
974 return status;
975}
976
977/*
978 * Decode LINK reply
979 */
980static int
d61005a6 981nfs3_xdr_linkres(struct rpc_rqst *req, __be32 *p, struct nfs3_linkres *res)
1da177e4
LT
982{
983 int status;
984
985 if ((status = ntohl(*p++)) != 0)
986 status = -nfs_stat_to_errno(status);
987 p = xdr_decode_post_op_attr(p, res->fattr);
988 p = xdr_decode_wcc_data(p, res->dir_attr);
989 return status;
990}
991
992/*
993 * Decode FSSTAT reply
994 */
995static int
d61005a6 996nfs3_xdr_fsstatres(struct rpc_rqst *req, __be32 *p, struct nfs_fsstat *res)
1da177e4
LT
997{
998 int status;
999
1000 status = ntohl(*p++);
1001
1002 p = xdr_decode_post_op_attr(p, res->fattr);
1003 if (status != 0)
1004 return -nfs_stat_to_errno(status);
1005
1006 p = xdr_decode_hyper(p, &res->tbytes);
1007 p = xdr_decode_hyper(p, &res->fbytes);
1008 p = xdr_decode_hyper(p, &res->abytes);
1009 p = xdr_decode_hyper(p, &res->tfiles);
1010 p = xdr_decode_hyper(p, &res->ffiles);
1011 p = xdr_decode_hyper(p, &res->afiles);
1012
1013 /* ignore invarsec */
1014 return 0;
1015}
1016
1017/*
1018 * Decode FSINFO reply
1019 */
1020static int
d61005a6 1021nfs3_xdr_fsinfores(struct rpc_rqst *req, __be32 *p, struct nfs_fsinfo *res)
1da177e4
LT
1022{
1023 int status;
1024
1025 status = ntohl(*p++);
1026
1027 p = xdr_decode_post_op_attr(p, res->fattr);
1028 if (status != 0)
1029 return -nfs_stat_to_errno(status);
1030
1031 res->rtmax = ntohl(*p++);
1032 res->rtpref = ntohl(*p++);
1033 res->rtmult = ntohl(*p++);
1034 res->wtmax = ntohl(*p++);
1035 res->wtpref = ntohl(*p++);
1036 res->wtmult = ntohl(*p++);
1037 res->dtpref = ntohl(*p++);
1038 p = xdr_decode_hyper(p, &res->maxfilesize);
1039
1040 /* ignore time_delta and properties */
1041 res->lease_time = 0;
1042 return 0;
1043}
1044
1045/*
1046 * Decode PATHCONF reply
1047 */
1048static int
d61005a6 1049nfs3_xdr_pathconfres(struct rpc_rqst *req, __be32 *p, struct nfs_pathconf *res)
1da177e4
LT
1050{
1051 int status;
1052
1053 status = ntohl(*p++);
1054
1055 p = xdr_decode_post_op_attr(p, res->fattr);
1056 if (status != 0)
1057 return -nfs_stat_to_errno(status);
1058 res->max_link = ntohl(*p++);
1059 res->max_namelen = ntohl(*p++);
1060
1061 /* ignore remaining fields */
1062 return 0;
1063}
1064
1065/*
1066 * Decode COMMIT reply
1067 */
1068static int
d61005a6 1069nfs3_xdr_commitres(struct rpc_rqst *req, __be32 *p, struct nfs_writeres *res)
1da177e4
LT
1070{
1071 int status;
1072
1073 status = ntohl(*p++);
1074 p = xdr_decode_wcc_data(p, res->fattr);
1075 if (status != 0)
1076 return -nfs_stat_to_errno(status);
1077
1078 res->verf->verifier[0] = *p++;
1079 res->verf->verifier[1] = *p++;
1080 return 0;
1081}
1082
b7fa0554
AG
1083#ifdef CONFIG_NFS_V3_ACL
1084/*
1085 * Decode GETACL reply
1086 */
1087static int
d61005a6 1088nfs3_xdr_getaclres(struct rpc_rqst *req, __be32 *p,
b7fa0554
AG
1089 struct nfs3_getaclres *res)
1090{
1091 struct xdr_buf *buf = &req->rq_rcv_buf;
1092 int status = ntohl(*p++);
1093 struct posix_acl **acl;
1094 unsigned int *aclcnt;
1095 int err, base;
1096
1097 if (status != 0)
1098 return -nfs_stat_to_errno(status);
1099 p = xdr_decode_post_op_attr(p, res->fattr);
1100 res->mask = ntohl(*p++);
1101 if (res->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
1102 return -EINVAL;
1103 base = (char *)p - (char *)req->rq_rcv_buf.head->iov_base;
1104
1105 acl = (res->mask & NFS_ACL) ? &res->acl_access : NULL;
1106 aclcnt = (res->mask & NFS_ACLCNT) ? &res->acl_access_count : NULL;
1107 err = nfsacl_decode(buf, base, aclcnt, acl);
1108
1109 acl = (res->mask & NFS_DFACL) ? &res->acl_default : NULL;
1110 aclcnt = (res->mask & NFS_DFACLCNT) ? &res->acl_default_count : NULL;
1111 if (err > 0)
1112 err = nfsacl_decode(buf, base + err, aclcnt, acl);
1113 return (err > 0) ? 0 : err;
1114}
1115
1116/*
1117 * Decode setacl reply.
1118 */
1119static int
d61005a6 1120nfs3_xdr_setaclres(struct rpc_rqst *req, __be32 *p, struct nfs_fattr *fattr)
b7fa0554
AG
1121{
1122 int status = ntohl(*p++);
1123
1124 if (status)
1125 return -nfs_stat_to_errno(status);
1126 xdr_decode_post_op_attr(p, fattr);
1127 return 0;
1128}
1129#endif /* CONFIG_NFS_V3_ACL */
1130
1da177e4
LT
1131#define PROC(proc, argtype, restype, timer) \
1132[NFS3PROC_##proc] = { \
1133 .p_proc = NFS3PROC_##proc, \
1134 .p_encode = (kxdrproc_t) nfs3_xdr_##argtype, \
1135 .p_decode = (kxdrproc_t) nfs3_xdr_##restype, \
2bea90d4
CL
1136 .p_arglen = NFS3_##argtype##_sz, \
1137 .p_replen = NFS3_##restype##_sz, \
cc0175c1
CL
1138 .p_timer = timer, \
1139 .p_statidx = NFS3PROC_##proc, \
1140 .p_name = #proc, \
1da177e4
LT
1141 }
1142
1143struct rpc_procinfo nfs3_procedures[] = {
1144 PROC(GETATTR, fhandle, attrstat, 1),
1145 PROC(SETATTR, sattrargs, wccstat, 0),
1146 PROC(LOOKUP, diropargs, lookupres, 2),
1147 PROC(ACCESS, accessargs, accessres, 1),
1148 PROC(READLINK, readlinkargs, readlinkres, 3),
1149 PROC(READ, readargs, readres, 3),
1150 PROC(WRITE, writeargs, writeres, 4),
1151 PROC(CREATE, createargs, createres, 0),
1152 PROC(MKDIR, mkdirargs, createres, 0),
1153 PROC(SYMLINK, symlinkargs, createres, 0),
1154 PROC(MKNOD, mknodargs, createres, 0),
4fdc17b2 1155 PROC(REMOVE, removeargs, removeres, 0),
1da177e4
LT
1156 PROC(RMDIR, diropargs, wccstat, 0),
1157 PROC(RENAME, renameargs, renameres, 0),
1158 PROC(LINK, linkargs, linkres, 0),
1159 PROC(READDIR, readdirargs, readdirres, 3),
1160 PROC(READDIRPLUS, readdirargs, readdirres, 3),
1161 PROC(FSSTAT, fhandle, fsstatres, 0),
1162 PROC(FSINFO, fhandle, fsinfores, 0),
1163 PROC(PATHCONF, fhandle, pathconfres, 0),
1164 PROC(COMMIT, commitargs, commitres, 5),
1165};
1166
1167struct rpc_version nfs_version3 = {
1168 .number = 3,
e8c96f8c 1169 .nrprocs = ARRAY_SIZE(nfs3_procedures),
1da177e4
LT
1170 .procs = nfs3_procedures
1171};
1172
b7fa0554
AG
1173#ifdef CONFIG_NFS_V3_ACL
1174static struct rpc_procinfo nfs3_acl_procedures[] = {
1175 [ACLPROC3_GETACL] = {
1176 .p_proc = ACLPROC3_GETACL,
1177 .p_encode = (kxdrproc_t) nfs3_xdr_getaclargs,
1178 .p_decode = (kxdrproc_t) nfs3_xdr_getaclres,
2bea90d4
CL
1179 .p_arglen = ACL3_getaclargs_sz,
1180 .p_replen = ACL3_getaclres_sz,
b7fa0554 1181 .p_timer = 1,
cc0175c1 1182 .p_name = "GETACL",
b7fa0554
AG
1183 },
1184 [ACLPROC3_SETACL] = {
1185 .p_proc = ACLPROC3_SETACL,
1186 .p_encode = (kxdrproc_t) nfs3_xdr_setaclargs,
1187 .p_decode = (kxdrproc_t) nfs3_xdr_setaclres,
2bea90d4
CL
1188 .p_arglen = ACL3_setaclargs_sz,
1189 .p_replen = ACL3_setaclres_sz,
b7fa0554 1190 .p_timer = 0,
cc0175c1 1191 .p_name = "SETACL",
b7fa0554
AG
1192 },
1193};
1194
1195struct rpc_version nfsacl_version3 = {
1196 .number = 3,
1197 .nrprocs = sizeof(nfs3_acl_procedures)/
1198 sizeof(nfs3_acl_procedures[0]),
1199 .procs = nfs3_acl_procedures,
1200};
1201#endif /* CONFIG_NFS_V3_ACL */
This page took 0.369729 seconds and 5 git commands to generate.