File: /usr/src/linux/fs/nfs/nfs3xdr.c
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/sched.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>
24
25 /* Uncomment this to support servers requiring longword lengths */
26 #define NFS_PAD_WRITES 1
27
28 #define NFSDBG_FACILITY NFSDBG_XDR
29
30 /* Mapping from NFS error code to "errno" error code. */
31 #define errno_NFSERR_IO EIO
32
33 extern int nfs_stat_to_errno(int);
34
35 /*
36 * Declare the space requirements for NFS arguments and replies as
37 * number of 32bit-words
38 */
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
53
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
69
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
86
87 /*
88 * Map file type to S_IFMT bits
89 */
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 }
103 };
104
105 /*
106 * Common NFS XDR functions as inlines
107 */
108 static inline u32 *
109 xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
110 {
111 *p++ = htonl(fh->size);
112 memcpy(p, fh->data, fh->size);
113 return p + XDR_QUADLEN(fh->size);
114 }
115
116 static inline u32 *
117 xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
118 {
119 /*
120 * Zero all nonused bytes
121 */
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);
126 }
127 return NULL;
128 }
129
130 /*
131 * Encode/decode time.
132 * Since the VFS doesn't care for fractional times, we ignore the
133 * nanosecond field.
134 */
135 static inline u32 *
136 xdr_encode_time(u32 *p, time_t time)
137 {
138 *p++ = htonl(time);
139 *p++ = 0;
140 return p;
141 }
142
143 static inline u32 *
144 xdr_decode_time3(u32 *p, u64 *timep)
145 {
146 u64 tmp = (u64)ntohl(*p++) << 32;
147 *timep = tmp + (u64)ntohl(*p++);
148 return p;
149 }
150
151 static inline u32 *
152 xdr_encode_time3(u32 *p, u64 time)
153 {
154 *p++ = htonl(time >> 32);
155 *p++ = htonl(time & 0xFFFFFFFF);
156 return p;
157 }
158
159 static inline u32 *
160 xdr_decode_string2(u32 *p, char **string, unsigned int *len,
161 unsigned int maxlen)
162 {
163 *len = ntohl(*p++);
164 if (*len > maxlen)
165 return NULL;
166 *string = (char *) p;
167 return p + XDR_QUADLEN(*len);
168 }
169
170 static inline u32 *
171 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
172 {
173 unsigned int type;
174 int fmode;
175
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);
195
196 /* Update the mode bits */
197 fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
198 return p;
199 }
200
201 static inline u32 *
202 xdr_encode_sattr(u32 *p, struct iattr *attr)
203 {
204 if (attr->ia_valid & ATTR_MODE) {
205 *p++ = xdr_one;
206 *p++ = htonl(attr->ia_mode);
207 } else {
208 *p++ = xdr_zero;
209 }
210 if (attr->ia_valid & ATTR_UID) {
211 *p++ = xdr_one;
212 *p++ = htonl(attr->ia_uid);
213 } else {
214 *p++ = xdr_zero;
215 }
216 if (attr->ia_valid & ATTR_GID) {
217 *p++ = xdr_one;
218 *p++ = htonl(attr->ia_gid);
219 } else {
220 *p++ = xdr_zero;
221 }
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;
227 }
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;
235 }
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;
243 }
244 return p;
245 }
246
247 static inline u32 *
248 xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
249 {
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;
255 }
256
257 static inline u32 *
258 xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
259 {
260 if (*p++)
261 p = xdr_decode_fattr(p, fattr);
262 return p;
263 }
264
265 static inline u32 *
266 xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
267 {
268 if (*p++)
269 return xdr_decode_wcc_attr(p, fattr);
270 return p;
271 }
272
273
274 static inline u32 *
275 xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
276 {
277 p = xdr_decode_pre_op_attr(p, fattr);
278 return xdr_decode_post_op_attr(p, fattr);
279 }
280
281 /*
282 * NFS encode functions
283 */
284 /*
285 * Encode void argument
286 */
287 static int
288 nfs3_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
289 {
290 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
291 return 0;
292 }
293
294 /*
295 * Encode file handle argument
296 */
297 static int
298 nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
299 {
300 p = xdr_encode_fhandle(p, fh);
301 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
302 return 0;
303 }
304
305 /*
306 * Encode SETATTR arguments
307 */
308 static int
309 nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
310 {
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;
318 }
319
320 /*
321 * Encode directory ops argument
322 */
323 static int
324 nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
325 {
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;
330 }
331
332 /*
333 * Encode access() argument
334 */
335 static int
336 nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
337 {
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;
342 }
343
344 /*
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.
348 */
349 static int
350 nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
351 {
352 struct rpc_auth *auth = req->rq_task->tk_auth;
353 int buflen, replen;
354 unsigned int nr;
355
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);
360
361 /* Get the number of buffers in the receive iovec */
362 nr = args->nriov;
363
364 if (nr+2 > MAX_IOVEC) {
365 printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
366 return -EINVAL;
367 }
368
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;
373
374 /* Copy the iovec */
375 memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
376
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;
381
382 return 0;
383 }
384
385 /*
386 * Write arguments. Splice the buffer to be written into the iovec.
387 */
388 static int
389 nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
390 {
391 unsigned int nr;
392 u32 count = args->count;
393
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);
400
401 /* Get the number of buffers in the send iovec */
402 nr = args->nriov;
403
404 if (nr+2 > MAX_IOVEC) {
405 printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs\n");
406 return -EINVAL;
407 }
408
409 /* Copy the iovec */
410 memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
411
412 #ifdef NFS_PAD_WRITES
413 /*
414 * Some old servers require that the message length
415 * be a multiple of 4, so we pad it here if needed.
416 */
417 if (count & 3) {
418 struct iovec *iov = req->rq_svec + nr + 1;
419 int pad = 4 - (count & 3);
420
421 iov->iov_base = (void *) "\0\0\0";
422 iov->iov_len = pad;
423 count += pad;
424 nr++;
425 }
426 #endif
427 req->rq_slen += count;
428 req->rq_snr += nr;
429
430 return 0;
431 }
432
433 /*
434 * Encode CREATE arguments
435 */
436 static int
437 nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
438 {
439 p = xdr_encode_fhandle(p, args->fh);
440 p = xdr_encode_array(p, args->name, args->len);
441
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);
448
449 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
450 return 0;
451 }
452
453 /*
454 * Encode MKDIR arguments
455 */
456 static int
457 nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
458 {
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;
464 }
465
466 /*
467 * Encode SYMLINK arguments
468 */
469 static int
470 nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
471 {
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;
478 }
479
480 /*
481 * Encode MKNOD arguments
482 */
483 static int
484 nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
485 {
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);
493 }
494
495 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
496 return 0;
497 }
498
499 /*
500 * Encode RENAME arguments
501 */
502 static int
503 nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
504 {
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;
511 }
512
513 /*
514 * Encode LINK arguments
515 */
516 static int
517 nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
518 {
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;
524 }
525
526 /*
527 * Encode arguments to readdir call
528 */
529 static int
530 nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
531 {
532 struct rpc_auth *auth = req->rq_task->tk_auth;
533 int buflen, replen;
534
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);
543 }
544 *p++ = htonl(args->bufsiz);
545 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
546
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;
557
558 return 0;
559 }
560
561 /*
562 * Decode the result of a readdir call.
563 * We just check for syntactical correctness.
564 */
565 static int
566 nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
567 {
568 struct iovec *iov = req->rq_rvec;
569 int hdrlen;
570 int status, nr;
571 unsigned int len;
572 u32 *entry, *end;
573
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;
585 }
586
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);
591 }
592
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;
604 }
605
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;
617 }
618 p += XDR_QUADLEN(len);
619 }
620 }
621
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;
628 }
629 }
630
631 return nr;
632 }
633
634 u32 *
635 nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
636 {
637 struct nfs_entry old = *entry;
638
639 if (!*p++) {
640 if (!*p)
641 return ERR_PTR(-EAGAIN);
642 entry->eof = 1;
643 return ERR_PTR(-EBADCOOKIE);
644 }
645
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);
652
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);
663 }
664 } else {
665 /* If we don't get a file handle, the attrs
666 * aren't worth a lot. */
667 entry->fattr.valid = 0;
668 }
669 }
670
671 entry->eof = !p[0] && p[1];
672 return p;
673 }
674
675 /*
676 * Encode COMMIT arguments
677 */
678 static int
679 nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
680 {
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;
686 }
687
688 /*
689 * NFS XDR decode functions
690 */
691 /*
692 * Decode void reply
693 */
694 static int
695 nfs3_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
696 {
697 return 0;
698 }
699
700 /*
701 * Decode attrstat reply.
702 */
703 static int
704 nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
705 {
706 int status;
707
708 if ((status = ntohl(*p++)))
709 return -nfs_stat_to_errno(status);
710 xdr_decode_fattr(p, fattr);
711 return 0;
712 }
713
714 /*
715 * Decode status+wcc_data reply
716 * SATTR, REMOVE, RMDIR
717 */
718 static int
719 nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
720 {
721 int status;
722
723 if ((status = ntohl(*p++)))
724 status = -nfs_stat_to_errno(status);
725 xdr_decode_wcc_data(p, fattr);
726 return status;
727 }
728
729 /*
730 * Decode LOOKUP reply
731 */
732 static int
733 nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
734 {
735 int status;
736
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);
743 }
744 xdr_decode_post_op_attr(p, res->dir_attr);
745 return status;
746 }
747
748 /*
749 * Decode ACCESS reply
750 */
751 static int
752 nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
753 {
754 int status = ntohl(*p++);
755
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;
761 }
762
763 static int
764 nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
765 {
766 struct rpc_task *task = req->rq_task;
767 struct rpc_auth *auth = task->tk_auth;
768 int buflen, replen;
769
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;
782 }
783
784 /*
785 * Decode READLINK reply
786 */
787 static int
788 nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkres *res)
789 {
790 struct iovec *iov = req->rq_rvec;
791 int hdrlen;
792 u32 *strlen;
793 char *string;
794 int status;
795 unsigned int len;
796
797 status = ntohl(*p++);
798 p = xdr_decode_post_op_attr(p, res->fattr);
799
800 if (status != 0)
801 return -nfs_stat_to_errno(status);
802
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);
807 }
808
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;
819 }
820
821 /*
822 * Decode READ reply
823 */
824 static int
825 nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
826 {
827 struct iovec *iov = req->rq_rvec;
828 int status, count, ocount, recvd, hdrlen;
829
830 status = ntohl(*p++);
831 p = xdr_decode_post_op_attr(p, res->fattr);
832
833 if (status != 0)
834 return -nfs_stat_to_errno(status);
835
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++);
842
843 if (ocount != count) {
844 printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
845 return -errno_NFSERR_IO;
846 }
847
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);
852 }
853
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;
859 }
860
861 if (count < res->count) {
862 xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
863 res->count = count;
864 }
865
866 return count;
867 }
868
869 /*
870 * Decode WRITE response
871 */
872 static int
873 nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
874 {
875 int status;
876
877 status = ntohl(*p++);
878 p = xdr_decode_wcc_data(p, res->fattr);
879
880 if (status != 0)
881 return -nfs_stat_to_errno(status);
882
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++;
887
888 return res->count;
889 }
890
891 /*
892 * Decode a CREATE response
893 */
894 static int
895 nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
896 {
897 int status;
898
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;
910 }
911 } else {
912 status = -nfs_stat_to_errno(status);
913 }
914 p = xdr_decode_wcc_data(p, res->dir_attr);
915 return status;
916 }
917
918 /*
919 * Decode RENAME reply
920 */
921 static int
922 nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
923 {
924 int status;
925
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;
931 }
932
933 /*
934 * Decode LINK reply
935 */
936 static int
937 nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
938 {
939 int status;
940
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;
946 }
947
948 /*
949 * Decode FSSTAT reply
950 */
951 static int
952 nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
953 {
954 struct nfs_fattr dummy;
955 int status;
956
957 status = ntohl(*p++);
958
959 p = xdr_decode_post_op_attr(p, &dummy);
960 if (status != 0)
961 return -nfs_stat_to_errno(status);
962
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);
969
970 /* ignore invarsec */
971 return 0;
972 }
973
974 /*
975 * Decode FSINFO reply
976 */
977 static int
978 nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
979 {
980 struct nfs_fattr dummy;
981 int status;
982
983 status = ntohl(*p++);
984
985 p = xdr_decode_post_op_attr(p, &dummy);
986 if (status != 0)
987 return -nfs_stat_to_errno(status);
988
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);
997
998 /* ignore time_delta and properties */
999 return 0;
1000 }
1001
1002 /*
1003 * Decode PATHCONF reply
1004 */
1005 static int
1006 nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
1007 {
1008 struct nfs_fattr dummy;
1009 int status;
1010
1011 status = ntohl(*p++);
1012
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++);
1018
1019 /* ignore remaining fields */
1020 return 0;
1021 }
1022
1023 /*
1024 * Decode COMMIT reply
1025 */
1026 static int
1027 nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
1028 {
1029 int status;
1030
1031 status = ntohl(*p++);
1032 p = xdr_decode_wcc_data(p, res->fattr);
1033 if (status != 0)
1034 return -nfs_stat_to_errno(status);
1035
1036 res->verf->verifier[0] = *p++;
1037 res->verf->verifier[1] = *p++;
1038 return 0;
1039 }
1040
1041 #ifndef MAX
1042 # define MAX(a, b) (((a) > (b))? (a) : (b))
1043 #endif
1044
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, \
1050 0 \
1051 }
1052
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),
1076 };
1077
1078 struct rpc_version nfs_version3 = {
1079 3,
1080 sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
1081 nfs3_procedures
1082 };
1083
1084