- Linus: drop support for old-style Makefiles entirely. Big.
[davej-history.git] / fs / nfs / nfs3xdr.c
blobf6260a55205961f7060b27f473441c0e296f81e9
1 /*
2 * linux/fs/nfs/nfs3xdr.c
4 * XDR functions to encode/decode NFSv3 RPC arguments and results.
6 * Copyright (C) 1996, 1997 Olaf Kirch
7 */
9 #include <linux/param.h>
10 #include <linux/sched.h>
11 #include <linux/mm.h>
12 #include <linux/malloc.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>
25 /* Uncomment this to support servers requiring longword lengths */
26 #define NFS_PAD_WRITES 1
28 #define NFSDBG_FACILITY NFSDBG_XDR
30 /* Mapping from NFS error code to "errno" error code. */
31 #define errno_NFSERR_IO EIO
33 extern int nfs_stat_to_errno(int);
36 * Declare the space requirements for NFS arguments and replies as
37 * number of 32bit-words
39 #define NFS3_fhandle_sz 1+16
40 #define NFS3_fh_sz NFS3_fhandle_sz /* shorthand */
41 #define NFS3_sattr_sz 15
42 #define NFS3_filename_sz 1+(NFS3_MAXNAMLEN>>2)
43 #define NFS3_path_sz 1+(NFS3_MAXPATHLEN>>2)
44 #define NFS3_fattr_sz 21
45 #define NFS3_wcc_attr_sz 6
46 #define NFS3_pre_op_attr_sz 1+NFS3_wcc_attr_sz
47 #define NFS3_post_op_attr_sz 1+NFS3_fattr_sz
48 #define NFS3_wcc_data_sz NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
49 #define NFS3_fsstat_sz
50 #define NFS3_fsinfo_sz
51 #define NFS3_pathconf_sz
52 #define NFS3_entry_sz NFS3_filename_sz+3
54 #define NFS3_enc_void_sz 0
55 #define NFS3_sattrargs_sz NFS3_fh_sz+NFS3_sattr_sz+3
56 #define NFS3_diropargs_sz NFS3_fh_sz+NFS3_filename_sz
57 #define NFS3_accessargs_sz NFS3_fh_sz+1
58 #define NFS3_readlinkargs_sz NFS3_fh_sz
59 #define NFS3_readargs_sz NFS3_fh_sz+3
60 #define NFS3_writeargs_sz NFS3_fh_sz+5
61 #define NFS3_createargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
62 #define NFS3_mkdirargs_sz NFS3_diropargs_sz+NFS3_sattr_sz
63 #define NFS3_symlinkargs_sz NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
64 #define NFS3_mknodargs_sz NFS3_diropargs_sz+2+NFS3_sattr_sz
65 #define NFS3_renameargs_sz NFS3_diropargs_sz+NFS3_diropargs_sz
66 #define NFS3_linkargs_sz NFS3_fh_sz+NFS3_diropargs_sz
67 #define NFS3_readdirargs_sz NFS3_fh_sz+2
68 #define NFS3_commitargs_sz NFS3_fh_sz+3
70 #define NFS3_dec_void_sz 0
71 #define NFS3_attrstat_sz 1+NFS3_fattr_sz
72 #define NFS3_wccstat_sz 1+NFS3_wcc_data_sz
73 #define NFS3_lookupres_sz 1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
74 #define NFS3_accessres_sz 1+NFS3_post_op_attr_sz+1
75 #define NFS3_readlinkres_sz 1+NFS3_post_op_attr_sz
76 #define NFS3_readres_sz 1+NFS3_post_op_attr_sz+3
77 #define NFS3_writeres_sz 1+NFS3_wcc_data_sz+4
78 #define NFS3_createres_sz 1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
79 #define NFS3_renameres_sz 1+(2 * NFS3_wcc_data_sz)
80 #define NFS3_linkres_sz 1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
81 #define NFS3_readdirres_sz 1+NFS3_post_op_attr_sz+2
82 #define NFS3_fsstatres_sz 1+NFS3_post_op_attr_sz+13
83 #define NFS3_fsinfores_sz 1+NFS3_post_op_attr_sz+12
84 #define NFS3_pathconfres_sz 1+NFS3_post_op_attr_sz+6
85 #define NFS3_commitres_sz 1+NFS3_wcc_data_sz+2
88 * Map file type to S_IFMT bits
90 static struct {
91 unsigned int mode;
92 unsigned int nfs2type;
93 } nfs_type2fmt[] = {
94 { 0, NFNON },
95 { S_IFREG, NFREG },
96 { S_IFDIR, NFDIR },
97 { S_IFBLK, NFBLK },
98 { S_IFCHR, NFCHR },
99 { S_IFLNK, NFLNK },
100 { S_IFSOCK, NFSOCK },
101 { S_IFIFO, NFFIFO },
102 { 0, NFBAD }
106 * Common NFS XDR functions as inlines
108 static inline u32 *
109 xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
111 *p++ = htonl(fh->size);
112 memcpy(p, fh->data, fh->size);
113 return p + XDR_QUADLEN(fh->size);
116 static inline u32 *
117 xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
120 * Zero all nonused bytes
122 memset((u8 *)fh, 0, sizeof(*fh));
123 if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
124 memcpy(fh->data, p, fh->size);
125 return p + XDR_QUADLEN(fh->size);
127 return NULL;
131 * Encode/decode time.
132 * Since the VFS doesn't care for fractional times, we ignore the
133 * nanosecond field.
135 static inline u32 *
136 xdr_encode_time(u32 *p, time_t time)
138 *p++ = htonl(time);
139 *p++ = 0;
140 return p;
143 static inline u32 *
144 xdr_decode_time3(u32 *p, u64 *timep)
146 u64 tmp = (u64)ntohl(*p++) << 32;
147 *timep = tmp + (u64)ntohl(*p++);
148 return p;
151 static inline u32 *
152 xdr_encode_time3(u32 *p, u64 time)
154 *p++ = htonl(time >> 32);
155 *p++ = htonl(time & 0xFFFFFFFF);
156 return p;
159 static inline u32 *
160 xdr_decode_string2(u32 *p, char **string, unsigned int *len,
161 unsigned int maxlen)
163 *len = ntohl(*p++);
164 if (*len > maxlen)
165 return NULL;
166 *string = (char *) p;
167 return p + XDR_QUADLEN(*len);
170 static inline u32 *
171 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
173 unsigned int type;
174 int fmode;
176 type = ntohl(*p++);
177 if (type >= NF3BAD)
178 type = NF3BAD;
179 fmode = nfs_type2fmt[type].mode;
180 fattr->type = nfs_type2fmt[type].nfs2type;
181 fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
182 fattr->nlink = ntohl(*p++);
183 fattr->uid = ntohl(*p++);
184 fattr->gid = ntohl(*p++);
185 p = xdr_decode_hyper(p, &fattr->size);
186 p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
187 /* Turn remote device info into Linux-specific dev_t */
188 fattr->rdev = ntohl(*p++) << MINORBITS;
189 fattr->rdev |= ntohl(*p++) & MINORMASK;
190 p = xdr_decode_hyper(p, &fattr->fsid);
191 p = xdr_decode_hyper(p, &fattr->fileid);
192 p = xdr_decode_time3(p, &fattr->atime);
193 p = xdr_decode_time3(p, &fattr->mtime);
194 p = xdr_decode_time3(p, &fattr->ctime);
196 /* Update the mode bits */
197 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
198 return p;
201 static inline u32 *
202 xdr_encode_sattr(u32 *p, struct iattr *attr)
204 if (attr->ia_valid & ATTR_MODE) {
205 *p++ = xdr_one;
206 *p++ = htonl(attr->ia_mode);
207 } else {
208 *p++ = xdr_zero;
210 if (attr->ia_valid & ATTR_UID) {
211 *p++ = xdr_one;
212 *p++ = htonl(attr->ia_uid);
213 } else {
214 *p++ = xdr_zero;
216 if (attr->ia_valid & ATTR_GID) {
217 *p++ = xdr_one;
218 *p++ = htonl(attr->ia_gid);
219 } else {
220 *p++ = xdr_zero;
222 if (attr->ia_valid & ATTR_SIZE) {
223 *p++ = xdr_one;
224 p = xdr_encode_hyper(p, (__u64) attr->ia_size);
225 } else {
226 *p++ = xdr_zero;
228 if (attr->ia_valid & ATTR_ATIME_SET) {
229 *p++ = xdr_two;
230 p = xdr_encode_time(p, attr->ia_atime);
231 } else if (attr->ia_valid & ATTR_ATIME) {
232 *p++ = xdr_one;
233 } else {
234 *p++ = xdr_zero;
236 if (attr->ia_valid & ATTR_MTIME_SET) {
237 *p++ = xdr_two;
238 p = xdr_encode_time(p, attr->ia_mtime);
239 } else if (attr->ia_valid & ATTR_MTIME) {
240 *p++ = xdr_one;
241 } else {
242 *p++ = xdr_zero;
244 return p;
247 static inline u32 *
248 xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
250 p = xdr_decode_hyper(p, &fattr->pre_size);
251 p = xdr_decode_time3(p, &fattr->pre_mtime);
252 p = xdr_decode_time3(p, &fattr->pre_ctime);
253 fattr->valid |= NFS_ATTR_WCC;
254 return p;
257 static inline u32 *
258 xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
260 if (*p++)
261 p = xdr_decode_fattr(p, fattr);
262 return p;
265 static inline u32 *
266 xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
268 if (*p++)
269 return xdr_decode_wcc_attr(p, fattr);
270 return p;
274 static inline u32 *
275 xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
277 p = xdr_decode_pre_op_attr(p, fattr);
278 return xdr_decode_post_op_attr(p, fattr);
282 * NFS encode functions
285 * Encode void argument
287 static int
288 nfs3_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
290 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
291 return 0;
295 * Encode file handle argument
297 static int
298 nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
300 p = xdr_encode_fhandle(p, fh);
301 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
302 return 0;
306 * Encode SETATTR arguments
308 static int
309 nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
311 p = xdr_encode_fhandle(p, args->fh);
312 p = xdr_encode_sattr(p, args->sattr);
313 *p++ = htonl(args->guard);
314 if (args->guard)
315 p = xdr_encode_time3(p, args->guardtime);
316 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
317 return 0;
321 * Encode directory ops argument
323 static int
324 nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
326 p = xdr_encode_fhandle(p, args->fh);
327 p = xdr_encode_array(p, args->name, args->len);
328 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
329 return 0;
333 * Encode access() argument
335 static int
336 nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
338 p = xdr_encode_fhandle(p, args->fh);
339 *p++ = htonl(args->access);
340 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
341 return 0;
345 * Arguments to a READ call. Since we read data directly into the page
346 * cache, we also set up the reply iovec here so that iov[1] points
347 * exactly to the page we want to fetch.
349 static int
350 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
352 struct rpc_auth *auth = req->rq_task->tk_auth;
353 int buflen, replen;
354 unsigned int nr;
356 p = xdr_encode_fhandle(p, args->fh);
357 p = xdr_encode_hyper(p, args->offset);
358 *p++ = htonl(args->count);
359 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
361 /* Get the number of buffers in the receive iovec */
362 nr = args->nriov;
364 if (nr+2 > MAX_IOVEC) {
365 printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
366 return -EINVAL;
369 /* set up reply iovec */
370 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
371 buflen = req->rq_rvec[0].iov_len;
372 req->rq_rvec[0].iov_len = replen;
374 /* Copy the iovec */
375 memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
377 req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
378 req->rq_rvec[nr+1].iov_len = buflen - replen;
379 req->rq_rlen = args->count + buflen;
380 req->rq_rnr += nr+1;
382 return 0;
386 * Write arguments. Splice the buffer to be written into the iovec.
388 static int
389 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
391 unsigned int nr;
392 u32 count = args->count;
394 p = xdr_encode_fhandle(p, args->fh);
395 p = xdr_encode_hyper(p, args->offset);
396 *p++ = htonl(count);
397 *p++ = htonl(args->stable);
398 *p++ = htonl(count);
399 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
401 /* Get the number of buffers in the send iovec */
402 nr = args->nriov;
404 if (nr+2 > MAX_IOVEC) {
405 printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs\n");
406 return -EINVAL;
409 /* Copy the iovec */
410 memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
412 #ifdef NFS_PAD_WRITES
414 * Some old servers require that the message length
415 * be a multiple of 4, so we pad it here if needed.
417 if (count & 3) {
418 struct iovec *iov = req->rq_svec + nr + 1;
419 int pad = 4 - (count & 3);
421 iov->iov_base = (void *) "\0\0\0";
422 iov->iov_len = pad;
423 count += pad;
424 nr++;
426 #endif
427 req->rq_slen += count;
428 req->rq_snr += nr;
430 return 0;
434 * Encode CREATE arguments
436 static int
437 nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
439 p = xdr_encode_fhandle(p, args->fh);
440 p = xdr_encode_array(p, args->name, args->len);
442 *p++ = htonl(args->createmode);
443 if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
444 *p++ = args->verifier[0];
445 *p++ = args->verifier[1];
446 } else
447 p = xdr_encode_sattr(p, args->sattr);
449 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
450 return 0;
454 * Encode MKDIR arguments
456 static int
457 nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
459 p = xdr_encode_fhandle(p, args->fh);
460 p = xdr_encode_array(p, args->name, args->len);
461 p = xdr_encode_sattr(p, args->sattr);
462 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
463 return 0;
467 * Encode SYMLINK arguments
469 static int
470 nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
472 p = xdr_encode_fhandle(p, args->fromfh);
473 p = xdr_encode_array(p, args->fromname, args->fromlen);
474 p = xdr_encode_sattr(p, args->sattr);
475 p = xdr_encode_array(p, args->topath, args->tolen);
476 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
477 return 0;
481 * Encode MKNOD arguments
483 static int
484 nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
486 p = xdr_encode_fhandle(p, args->fh);
487 p = xdr_encode_array(p, args->name, args->len);
488 *p++ = htonl(args->type);
489 p = xdr_encode_sattr(p, args->sattr);
490 if (args->type == NF3CHR || args->type == NF3BLK) {
491 *p++ = htonl(args->rdev >> MINORBITS);
492 *p++ = htonl(args->rdev & MINORMASK);
495 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
496 return 0;
500 * Encode RENAME arguments
502 static int
503 nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
505 p = xdr_encode_fhandle(p, args->fromfh);
506 p = xdr_encode_array(p, args->fromname, args->fromlen);
507 p = xdr_encode_fhandle(p, args->tofh);
508 p = xdr_encode_array(p, args->toname, args->tolen);
509 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
510 return 0;
514 * Encode LINK arguments
516 static int
517 nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
519 p = xdr_encode_fhandle(p, args->fromfh);
520 p = xdr_encode_fhandle(p, args->tofh);
521 p = xdr_encode_array(p, args->toname, args->tolen);
522 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
523 return 0;
527 * Encode arguments to readdir call
529 static int
530 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
532 struct rpc_auth *auth = req->rq_task->tk_auth;
533 int buflen, replen;
535 p = xdr_encode_fhandle(p, args->fh);
536 p = xdr_encode_hyper(p, args->cookie);
537 *p++ = args->verf[0];
538 *p++ = args->verf[1];
539 if (args->plus) {
540 /* readdirplus: need dircount + buffer size.
541 * We just make sure we make dircount big enough */
542 *p++ = htonl(args->bufsiz >> 3);
544 *p++ = htonl(args->bufsiz);
545 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
547 /* set up reply iovec */
548 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
549 buflen = req->rq_rvec[0].iov_len;
550 req->rq_rvec[0].iov_len = replen;
551 req->rq_rvec[1].iov_base = args->buffer;
552 req->rq_rvec[1].iov_len = args->bufsiz;
553 req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
554 req->rq_rvec[2].iov_len = buflen - replen;
555 req->rq_rlen = buflen + args->bufsiz;
556 req->rq_rnr += 2;
558 return 0;
562 * Decode the result of a readdir call.
563 * We just check for syntactical correctness.
565 static int
566 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
568 struct iovec *iov = req->rq_rvec;
569 int hdrlen;
570 int status, nr;
571 unsigned int len;
572 u32 *entry, *end;
574 status = ntohl(*p++);
575 /* Decode post_op_attrs */
576 p = xdr_decode_post_op_attr(p, res->dir_attr);
577 if (status)
578 return -nfs_stat_to_errno(status);
579 /* Decode verifier cookie */
580 if (res->verf) {
581 res->verf[0] = *p++;
582 res->verf[1] = *p++;
583 } else {
584 p += 2;
587 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
588 if (iov->iov_len > hdrlen) {
589 dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
590 xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
593 p = (u32 *) iov[1].iov_base;
594 end = (u32 *) ((u8 *) p + iov[1].iov_len);
595 for (nr = 0; *p++; nr++) {
596 entry = p - 1;
597 p += 2; /* inode # */
598 len = ntohl(*p++); /* string length */
599 p += XDR_QUADLEN(len) + 2; /* name + cookie */
600 if (len > NFS3_MAXNAMLEN) {
601 printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
602 len);
603 return -errno_NFSERR_IO;
606 if (res->plus) {
607 /* post_op_attr */
608 if (*p++)
609 p += 21;
610 /* post_op_fh3 */
611 if (*p++) {
612 len = ntohl(*p++);
613 if (len > NFS3_FHSIZE) {
614 printk(KERN_WARNING "NFS: giant filehandle in "
615 "readdir (len %x)!\n", len);
616 return -errno_NFSERR_IO;
618 p += XDR_QUADLEN(len);
622 if (p + 2 > end) {
623 printk(KERN_NOTICE
624 "NFS: short packet in readdir reply!\n");
625 /* truncate listing */
626 entry[0] = entry[1] = 0;
627 break;
631 return nr;
634 u32 *
635 nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
637 struct nfs_entry old = *entry;
639 if (!*p++) {
640 if (!*p)
641 return ERR_PTR(-EAGAIN);
642 entry->eof = 1;
643 return ERR_PTR(-EBADCOOKIE);
646 p = xdr_decode_hyper(p, &entry->ino);
647 entry->len = ntohl(*p++);
648 entry->name = (const char *) p;
649 p += XDR_QUADLEN(entry->len);
650 entry->prev_cookie = entry->cookie;
651 p = xdr_decode_hyper(p, &entry->cookie);
653 if (plus) {
654 p = xdr_decode_post_op_attr(p, &entry->fattr);
655 /* In fact, a post_op_fh3: */
656 if (*p++) {
657 p = xdr_decode_fhandle(p, &entry->fh);
658 /* Ugh -- server reply was truncated */
659 if (p == NULL) {
660 dprintk("NFS: FH truncated\n");
661 *entry = old;
662 return ERR_PTR(-EAGAIN);
664 } else {
665 /* If we don't get a file handle, the attrs
666 * aren't worth a lot. */
667 entry->fattr.valid = 0;
671 entry->eof = !p[0] && p[1];
672 return p;
676 * Encode COMMIT arguments
678 static int
679 nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
681 p = xdr_encode_fhandle(p, args->fh);
682 p = xdr_encode_hyper(p, args->offset);
683 *p++ = htonl(args->count);
684 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
685 return 0;
689 * NFS XDR decode functions
692 * Decode void reply
694 static int
695 nfs3_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
697 return 0;
701 * Decode attrstat reply.
703 static int
704 nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
706 int status;
708 if ((status = ntohl(*p++)))
709 return -nfs_stat_to_errno(status);
710 xdr_decode_fattr(p, fattr);
711 return 0;
715 * Decode status+wcc_data reply
716 * SATTR, REMOVE, RMDIR
718 static int
719 nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
721 int status;
723 if ((status = ntohl(*p++)))
724 status = -nfs_stat_to_errno(status);
725 xdr_decode_wcc_data(p, fattr);
726 return status;
730 * Decode LOOKUP reply
732 static int
733 nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
735 int status;
737 if ((status = ntohl(*p++))) {
738 status = -nfs_stat_to_errno(status);
739 } else {
740 if (!(p = xdr_decode_fhandle(p, res->fh)))
741 return -errno_NFSERR_IO;
742 p = xdr_decode_post_op_attr(p, res->fattr);
744 xdr_decode_post_op_attr(p, res->dir_attr);
745 return status;
749 * Decode ACCESS reply
751 static int
752 nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
754 int status = ntohl(*p++);
756 p = xdr_decode_post_op_attr(p, res->fattr);
757 if (status)
758 return -nfs_stat_to_errno(status);
759 res->access = ntohl(*p++);
760 return 0;
763 static int
764 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
766 struct rpc_task *task = req->rq_task;
767 struct rpc_auth *auth = task->tk_auth;
768 int buflen, replen;
770 p = xdr_encode_fhandle(p, args->fh);
771 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
772 replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
773 buflen = req->rq_rvec[0].iov_len;
774 req->rq_rvec[0].iov_len = replen;
775 req->rq_rvec[1].iov_base = args->buffer;
776 req->rq_rvec[1].iov_len = args->bufsiz;
777 req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
778 req->rq_rvec[2].iov_len = buflen - replen;
779 req->rq_rlen = buflen + args->bufsiz;
780 req->rq_rnr += 2;
781 return 0;
785 * Decode READLINK reply
787 static int
788 nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkres *res)
790 struct iovec *iov = req->rq_rvec;
791 int hdrlen;
792 u32 *strlen;
793 char *string;
794 int status;
795 unsigned int len;
797 status = ntohl(*p++);
798 p = xdr_decode_post_op_attr(p, res->fattr);
800 if (status != 0)
801 return -nfs_stat_to_errno(status);
803 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
804 if (iov->iov_len > hdrlen) {
805 dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
806 xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
809 strlen = (u32*)res->buffer;
810 /* Convert length of symlink */
811 len = ntohl(*strlen);
812 if (len > res->bufsiz - 5)
813 len = res->bufsiz - 5;
814 *strlen = len;
815 /* NULL terminate the string we got */
816 string = (char *)(strlen + 1);
817 string[len] = 0;
818 return 0;
822 * Decode READ reply
824 static int
825 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
827 struct iovec *iov = req->rq_rvec;
828 int status, count, ocount, recvd, hdrlen;
830 status = ntohl(*p++);
831 p = xdr_decode_post_op_attr(p, res->fattr);
833 if (status != 0)
834 return -nfs_stat_to_errno(status);
836 /* Decode reply could and EOF flag. NFSv3 is somewhat redundant
837 * in that it puts the count both in the res struct and in the
838 * opaque data count. */
839 count = ntohl(*p++);
840 res->eof = ntohl(*p++);
841 ocount = ntohl(*p++);
843 if (ocount != count) {
844 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
845 return -errno_NFSERR_IO;
848 hdrlen = (u8 *) p - (u8 *) iov->iov_base;
849 if (iov->iov_len > hdrlen) {
850 dprintk("NFS: READ header is short. iovec will be shifted.\n");
851 xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
854 recvd = req->rq_rlen - hdrlen;
855 if (count > recvd) {
856 printk(KERN_WARNING "NFS: server cheating in read reply: "
857 "count %d > recvd %d\n", count, recvd);
858 count = recvd;
861 if (count < res->count) {
862 xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
863 res->count = count;
866 return count;
870 * Decode WRITE response
872 static int
873 nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
875 int status;
877 status = ntohl(*p++);
878 p = xdr_decode_wcc_data(p, res->fattr);
880 if (status != 0)
881 return -nfs_stat_to_errno(status);
883 res->count = ntohl(*p++);
884 res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
885 res->verf->verifier[0] = *p++;
886 res->verf->verifier[1] = *p++;
888 return res->count;
892 * Decode a CREATE response
894 static int
895 nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
897 int status;
899 status = ntohl(*p++);
900 if (status == 0) {
901 if (*p++) {
902 if (!(p = xdr_decode_fhandle(p, res->fh)))
903 return -errno_NFSERR_IO;
904 p = xdr_decode_post_op_attr(p, res->fattr);
905 } else {
906 memset(res->fh, 0, sizeof(*res->fh));
907 /* Do decode post_op_attr but set it to NULL */
908 p = xdr_decode_post_op_attr(p, res->fattr);
909 res->fattr->valid = 0;
911 } else {
912 status = -nfs_stat_to_errno(status);
914 p = xdr_decode_wcc_data(p, res->dir_attr);
915 return status;
919 * Decode RENAME reply
921 static int
922 nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
924 int status;
926 if ((status = ntohl(*p++)) != 0)
927 status = -nfs_stat_to_errno(status);
928 p = xdr_decode_wcc_data(p, res->fromattr);
929 p = xdr_decode_wcc_data(p, res->toattr);
930 return status;
934 * Decode LINK reply
936 static int
937 nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
939 int status;
941 if ((status = ntohl(*p++)) != 0)
942 status = -nfs_stat_to_errno(status);
943 p = xdr_decode_post_op_attr(p, res->fattr);
944 p = xdr_decode_wcc_data(p, res->dir_attr);
945 return status;
949 * Decode FSSTAT reply
951 static int
952 nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
954 struct nfs_fattr dummy;
955 int status;
957 status = ntohl(*p++);
959 p = xdr_decode_post_op_attr(p, &dummy);
960 if (status != 0)
961 return -nfs_stat_to_errno(status);
963 p = xdr_decode_hyper(p, &res->tbytes);
964 p = xdr_decode_hyper(p, &res->fbytes);
965 p = xdr_decode_hyper(p, &res->abytes);
966 p = xdr_decode_hyper(p, &res->tfiles);
967 p = xdr_decode_hyper(p, &res->ffiles);
968 p = xdr_decode_hyper(p, &res->afiles);
970 /* ignore invarsec */
971 return 0;
975 * Decode FSINFO reply
977 static int
978 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
980 struct nfs_fattr dummy;
981 int status;
983 status = ntohl(*p++);
985 p = xdr_decode_post_op_attr(p, &dummy);
986 if (status != 0)
987 return -nfs_stat_to_errno(status);
989 res->rtmax = ntohl(*p++);
990 res->rtpref = ntohl(*p++);
991 res->rtmult = ntohl(*p++);
992 res->wtmax = ntohl(*p++);
993 res->wtpref = ntohl(*p++);
994 res->wtmult = ntohl(*p++);
995 res->dtpref = ntohl(*p++);
996 p = xdr_decode_hyper(p, &res->maxfilesize);
998 /* ignore time_delta and properties */
999 return 0;
1003 * Decode PATHCONF reply
1005 static int
1006 nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
1008 struct nfs_fattr dummy;
1009 int status;
1011 status = ntohl(*p++);
1013 p = xdr_decode_post_op_attr(p, &dummy);
1014 if (status != 0)
1015 return -nfs_stat_to_errno(status);
1016 res->linkmax = ntohl(*p++);
1017 res->namelen = ntohl(*p++);
1019 /* ignore remaining fields */
1020 return 0;
1024 * Decode COMMIT reply
1026 static int
1027 nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
1029 int status;
1031 status = ntohl(*p++);
1032 p = xdr_decode_wcc_data(p, res->fattr);
1033 if (status != 0)
1034 return -nfs_stat_to_errno(status);
1036 res->verf->verifier[0] = *p++;
1037 res->verf->verifier[1] = *p++;
1038 return 0;
1041 #ifndef MAX
1042 # define MAX(a, b) (((a) > (b))? (a) : (b))
1043 #endif
1045 #define PROC(proc, argtype, restype) \
1046 { "nfs3_" #proc, \
1047 (kxdrproc_t) nfs3_xdr_##argtype, \
1048 (kxdrproc_t) nfs3_xdr_##restype, \
1049 MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2, \
1053 static struct rpc_procinfo nfs3_procedures[22] = {
1054 PROC(null, enc_void, dec_void),
1055 PROC(getattr, fhandle, attrstat),
1056 PROC(setattr, sattrargs, wccstat),
1057 PROC(lookup, diropargs, lookupres),
1058 PROC(access, accessargs, accessres),
1059 PROC(readlink, readlinkargs, readlinkres),
1060 PROC(read, readargs, readres),
1061 PROC(write, writeargs, writeres),
1062 PROC(create, createargs, createres),
1063 PROC(mkdir, mkdirargs, createres),
1064 PROC(symlink, symlinkargs, createres),
1065 PROC(mknod, mknodargs, createres),
1066 PROC(remove, diropargs, wccstat),
1067 PROC(rmdir, diropargs, wccstat),
1068 PROC(rename, renameargs, renameres),
1069 PROC(link, linkargs, linkres),
1070 PROC(readdir, readdirargs, readdirres),
1071 PROC(readdirplus, readdirargs, readdirres),
1072 PROC(fsstat, fhandle, fsstatres),
1073 PROC(fsinfo, fhandle, fsinfores),
1074 PROC(pathconf, fhandle, pathconfres),
1075 PROC(commit, commitargs, commitres),
1078 struct rpc_version nfs_version3 = {
1080 sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
1081 nfs3_procedures