Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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