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