Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
nfs3xdr.c
Go to the documentation of this file.
1 /*
2  * XDR support for nfsd/protocol version 3.
3  *
4  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <[email protected]>
5  *
6  * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()!
7  */
8 
9 #include <linux/namei.h>
10 #include "xdr3.h"
11 #include "auth.h"
12 
13 #define NFSDDBG_FACILITY NFSDDBG_XDR
14 
15 
16 /*
17  * Mapping of S_IF* types to NFS file types
18  */
19 static u32 nfs3_ftypes[] = {
24 };
25 
26 /*
27  * XDR functions for basic NFS types
28  */
29 static __be32 *
30 encode_time3(__be32 *p, struct timespec *time)
31 {
32  *p++ = htonl((u32) time->tv_sec); *p++ = htonl(time->tv_nsec);
33  return p;
34 }
35 
36 static __be32 *
37 decode_time3(__be32 *p, struct timespec *time)
38 {
39  time->tv_sec = ntohl(*p++);
40  time->tv_nsec = ntohl(*p++);
41  return p;
42 }
43 
44 static __be32 *
45 decode_fh(__be32 *p, struct svc_fh *fhp)
46 {
47  unsigned int size;
48  fh_init(fhp, NFS3_FHSIZE);
49  size = ntohl(*p++);
50  if (size > NFS3_FHSIZE)
51  return NULL;
52 
53  memcpy(&fhp->fh_handle.fh_base, p, size);
54  fhp->fh_handle.fh_size = size;
55  return p + XDR_QUADLEN(size);
56 }
57 
58 /* Helper function for NFSv3 ACL code */
60 {
61  return decode_fh(p, fhp);
62 }
63 
64 static __be32 *
65 encode_fh(__be32 *p, struct svc_fh *fhp)
66 {
67  unsigned int size = fhp->fh_handle.fh_size;
68  *p++ = htonl(size);
69  if (size) p[XDR_QUADLEN(size)-1]=0;
70  memcpy(p, &fhp->fh_handle.fh_base, size);
71  return p + XDR_QUADLEN(size);
72 }
73 
74 /*
75  * Decode a file name and make sure that the path contains
76  * no slashes or null bytes.
77  */
78 static __be32 *
79 decode_filename(__be32 *p, char **namp, unsigned int *lenp)
80 {
81  char *name;
82  unsigned int i;
83 
84  if ((p = xdr_decode_string_inplace(p, namp, lenp, NFS3_MAXNAMLEN)) != NULL) {
85  for (i = 0, name = *namp; i < *lenp; i++, name++) {
86  if (*name == '\0' || *name == '/')
87  return NULL;
88  }
89  }
90 
91  return p;
92 }
93 
94 static __be32 *
95 decode_sattr3(__be32 *p, struct iattr *iap)
96 {
97  u32 tmp;
98 
99  iap->ia_valid = 0;
100 
101  if (*p++) {
102  iap->ia_valid |= ATTR_MODE;
103  iap->ia_mode = ntohl(*p++);
104  }
105  if (*p++) {
106  iap->ia_valid |= ATTR_UID;
107  iap->ia_uid = ntohl(*p++);
108  }
109  if (*p++) {
110  iap->ia_valid |= ATTR_GID;
111  iap->ia_gid = ntohl(*p++);
112  }
113  if (*p++) {
114  u64 newsize;
115 
116  iap->ia_valid |= ATTR_SIZE;
117  p = xdr_decode_hyper(p, &newsize);
118  if (newsize <= NFS_OFFSET_MAX)
119  iap->ia_size = newsize;
120  else
121  iap->ia_size = NFS_OFFSET_MAX;
122  }
123  if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
124  iap->ia_valid |= ATTR_ATIME;
125  } else if (tmp == 2) { /* set to client time */
127  iap->ia_atime.tv_sec = ntohl(*p++);
128  iap->ia_atime.tv_nsec = ntohl(*p++);
129  }
130  if ((tmp = ntohl(*p++)) == 1) { /* set to server time */
131  iap->ia_valid |= ATTR_MTIME;
132  } else if (tmp == 2) { /* set to client time */
134  iap->ia_mtime.tv_sec = ntohl(*p++);
135  iap->ia_mtime.tv_nsec = ntohl(*p++);
136  }
137  return p;
138 }
139 
140 static __be32 *encode_fsid(__be32 *p, struct svc_fh *fhp)
141 {
142  u64 f;
143  switch(fsid_source(fhp)) {
144  default:
145  case FSIDSOURCE_DEV:
146  p = xdr_encode_hyper(p, (u64)huge_encode_dev
147  (fhp->fh_dentry->d_inode->i_sb->s_dev));
148  break;
149  case FSIDSOURCE_FSID:
150  p = xdr_encode_hyper(p, (u64) fhp->fh_export->ex_fsid);
151  break;
152  case FSIDSOURCE_UUID:
153  f = ((u64*)fhp->fh_export->ex_uuid)[0];
154  f ^= ((u64*)fhp->fh_export->ex_uuid)[1];
155  p = xdr_encode_hyper(p, f);
156  break;
157  }
158  return p;
159 }
160 
161 static __be32 *
162 encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
163  struct kstat *stat)
164 {
165  *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
166  *p++ = htonl((u32) stat->mode);
167  *p++ = htonl((u32) stat->nlink);
168  *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid));
169  *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid));
170  if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) {
171  p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN);
172  } else {
173  p = xdr_encode_hyper(p, (u64) stat->size);
174  }
175  p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
176  *p++ = htonl((u32) MAJOR(stat->rdev));
177  *p++ = htonl((u32) MINOR(stat->rdev));
178  p = encode_fsid(p, fhp);
179  p = xdr_encode_hyper(p, stat->ino);
180  p = encode_time3(p, &stat->atime);
181  p = encode_time3(p, &stat->mtime);
182  p = encode_time3(p, &stat->ctime);
183 
184  return p;
185 }
186 
187 static __be32 *
188 encode_saved_post_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
189 {
190  /* Attributes to follow */
191  *p++ = xdr_one;
192  return encode_fattr3(rqstp, p, fhp, &fhp->fh_post_attr);
193 }
194 
195 /*
196  * Encode post-operation attributes.
197  * The inode may be NULL if the call failed because of a stale file
198  * handle. In this case, no attributes are returned.
199  */
200 static __be32 *
201 encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
202 {
203  struct dentry *dentry = fhp->fh_dentry;
204  if (dentry && dentry->d_inode) {
205  int err;
206  struct kstat stat;
207 
208  err = vfs_getattr(fhp->fh_export->ex_path.mnt, dentry, &stat);
209  if (!err) {
210  *p++ = xdr_one; /* attributes follow */
211  lease_get_mtime(dentry->d_inode, &stat.mtime);
212  return encode_fattr3(rqstp, p, fhp, &stat);
213  }
214  }
215  *p++ = xdr_zero;
216  return p;
217 }
218 
219 /* Helper for NFSv3 ACLs */
220 __be32 *
221 nfs3svc_encode_post_op_attr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
222 {
223  return encode_post_op_attr(rqstp, p, fhp);
224 }
225 
226 /*
227  * Enocde weak cache consistency data
228  */
229 static __be32 *
230 encode_wcc_data(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp)
231 {
232  struct dentry *dentry = fhp->fh_dentry;
233 
234  if (dentry && dentry->d_inode && fhp->fh_post_saved) {
235  if (fhp->fh_pre_saved) {
236  *p++ = xdr_one;
237  p = xdr_encode_hyper(p, (u64) fhp->fh_pre_size);
238  p = encode_time3(p, &fhp->fh_pre_mtime);
239  p = encode_time3(p, &fhp->fh_pre_ctime);
240  } else {
241  *p++ = xdr_zero;
242  }
243  return encode_saved_post_attr(rqstp, p, fhp);
244  }
245  /* no pre- or post-attrs */
246  *p++ = xdr_zero;
247  return encode_post_op_attr(rqstp, p, fhp);
248 }
249 
250 /*
251  * Fill in the post_op attr for the wcc data
252  */
253 void fill_post_wcc(struct svc_fh *fhp)
254 {
255  int err;
256 
257  if (fhp->fh_post_saved)
258  printk("nfsd: inode locked twice during operation.\n");
259 
260  err = vfs_getattr(fhp->fh_export->ex_path.mnt, fhp->fh_dentry,
261  &fhp->fh_post_attr);
262  fhp->fh_post_change = fhp->fh_dentry->d_inode->i_version;
263  if (err) {
264  fhp->fh_post_saved = 0;
265  /* Grab the ctime anyway - set_change_info might use it */
266  fhp->fh_post_attr.ctime = fhp->fh_dentry->d_inode->i_ctime;
267  } else
268  fhp->fh_post_saved = 1;
269 }
270 
271 /*
272  * XDR decode functions
273  */
274 int
275 nfs3svc_decode_fhandle(struct svc_rqst *rqstp, __be32 *p, struct nfsd_fhandle *args)
276 {
277  if (!(p = decode_fh(p, &args->fh)))
278  return 0;
279  return xdr_argsize_check(rqstp, p);
280 }
281 
282 int
284  struct nfsd3_sattrargs *args)
285 {
286  if (!(p = decode_fh(p, &args->fh)))
287  return 0;
288  p = decode_sattr3(p, &args->attrs);
289 
290  if ((args->check_guard = ntohl(*p++)) != 0) {
291  struct timespec time;
292  p = decode_time3(p, &time);
293  args->guardtime = time.tv_sec;
294  }
295 
296  return xdr_argsize_check(rqstp, p);
297 }
298 
299 int
301  struct nfsd3_diropargs *args)
302 {
303  if (!(p = decode_fh(p, &args->fh))
304  || !(p = decode_filename(p, &args->name, &args->len)))
305  return 0;
306 
307  return xdr_argsize_check(rqstp, p);
308 }
309 
310 int
312  struct nfsd3_accessargs *args)
313 {
314  if (!(p = decode_fh(p, &args->fh)))
315  return 0;
316  args->access = ntohl(*p++);
317 
318  return xdr_argsize_check(rqstp, p);
319 }
320 
321 int
323  struct nfsd3_readargs *args)
324 {
325  unsigned int len;
326  int v,pn;
327  u32 max_blocksize = svc_max_payload(rqstp);
328 
329  if (!(p = decode_fh(p, &args->fh)))
330  return 0;
331  p = xdr_decode_hyper(p, &args->offset);
332 
333  len = args->count = ntohl(*p++);
334 
335  if (len > max_blocksize)
336  len = max_blocksize;
337 
338  /* set up the kvec */
339  v=0;
340  while (len > 0) {
341  pn = rqstp->rq_resused++;
342  rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_respages[pn]);
343  rqstp->rq_vec[v].iov_len = len < PAGE_SIZE? len : PAGE_SIZE;
344  len -= rqstp->rq_vec[v].iov_len;
345  v++;
346  }
347  args->vlen = v;
348  return xdr_argsize_check(rqstp, p);
349 }
350 
351 int
353  struct nfsd3_writeargs *args)
354 {
355  unsigned int len, v, hdr, dlen;
356  u32 max_blocksize = svc_max_payload(rqstp);
357 
358  if (!(p = decode_fh(p, &args->fh)))
359  return 0;
360  p = xdr_decode_hyper(p, &args->offset);
361 
362  args->count = ntohl(*p++);
363  args->stable = ntohl(*p++);
364  len = args->len = ntohl(*p++);
365  /*
366  * The count must equal the amount of data passed.
367  */
368  if (args->count != args->len)
369  return 0;
370 
371  /*
372  * Check to make sure that we got the right number of
373  * bytes.
374  */
375  hdr = (void*)p - rqstp->rq_arg.head[0].iov_base;
376  dlen = rqstp->rq_arg.head[0].iov_len + rqstp->rq_arg.page_len
377  - hdr;
378  /*
379  * Round the length of the data which was specified up to
380  * the next multiple of XDR units and then compare that
381  * against the length which was actually received.
382  * Note that when RPCSEC/GSS (for example) is used, the
383  * data buffer can be padded so dlen might be larger
384  * than required. It must never be smaller.
385  */
386  if (dlen < XDR_QUADLEN(len)*4)
387  return 0;
388 
389  if (args->count > max_blocksize) {
390  args->count = max_blocksize;
391  len = args->len = max_blocksize;
392  }
393  rqstp->rq_vec[0].iov_base = (void*)p;
394  rqstp->rq_vec[0].iov_len = rqstp->rq_arg.head[0].iov_len - hdr;
395  v = 0;
396  while (len > rqstp->rq_vec[v].iov_len) {
397  len -= rqstp->rq_vec[v].iov_len;
398  v++;
399  rqstp->rq_vec[v].iov_base = page_address(rqstp->rq_pages[v]);
400  rqstp->rq_vec[v].iov_len = PAGE_SIZE;
401  }
402  rqstp->rq_vec[v].iov_len = len;
403  args->vlen = v + 1;
404  return 1;
405 }
406 
407 int
409  struct nfsd3_createargs *args)
410 {
411  if (!(p = decode_fh(p, &args->fh))
412  || !(p = decode_filename(p, &args->name, &args->len)))
413  return 0;
414 
415  switch (args->createmode = ntohl(*p++)) {
417  case NFS3_CREATE_GUARDED:
418  p = decode_sattr3(p, &args->attrs);
419  break;
421  args->verf = p;
422  p += 2;
423  break;
424  default:
425  return 0;
426  }
427 
428  return xdr_argsize_check(rqstp, p);
429 }
430 int
432  struct nfsd3_createargs *args)
433 {
434  if (!(p = decode_fh(p, &args->fh)) ||
435  !(p = decode_filename(p, &args->name, &args->len)))
436  return 0;
437  p = decode_sattr3(p, &args->attrs);
438 
439  return xdr_argsize_check(rqstp, p);
440 }
441 
442 int
444  struct nfsd3_symlinkargs *args)
445 {
446  unsigned int len, avail;
447  char *old, *new;
448  struct kvec *vec;
449 
450  if (!(p = decode_fh(p, &args->ffh)) ||
451  !(p = decode_filename(p, &args->fname, &args->flen))
452  )
453  return 0;
454  p = decode_sattr3(p, &args->attrs);
455 
456  /* now decode the pathname, which might be larger than the first page.
457  * As we have to check for nul's anyway, we copy it into a new page
458  * This page appears in the rq_res.pages list, but as pages_len is always
459  * 0, it won't get in the way
460  */
461  len = ntohl(*p++);
462  if (len == 0 || len > NFS3_MAXPATHLEN || len >= PAGE_SIZE)
463  return 0;
464  args->tname = new =
465  page_address(rqstp->rq_respages[rqstp->rq_resused++]);
466  args->tlen = len;
467  /* first copy and check from the first page */
468  old = (char*)p;
469  vec = &rqstp->rq_arg.head[0];
470  avail = vec->iov_len - (old - (char*)vec->iov_base);
471  while (len && avail && *old) {
472  *new++ = *old++;
473  len--;
474  avail--;
475  }
476  /* now copy next page if there is one */
477  if (len && !avail && rqstp->rq_arg.page_len) {
478  avail = rqstp->rq_arg.page_len;
479  if (avail > PAGE_SIZE)
480  avail = PAGE_SIZE;
481  old = page_address(rqstp->rq_arg.pages[0]);
482  }
483  while (len && avail && *old) {
484  *new++ = *old++;
485  len--;
486  avail--;
487  }
488  *new = '\0';
489  if (len)
490  return 0;
491 
492  return 1;
493 }
494 
495 int
497  struct nfsd3_mknodargs *args)
498 {
499  if (!(p = decode_fh(p, &args->fh))
500  || !(p = decode_filename(p, &args->name, &args->len)))
501  return 0;
502 
503  args->ftype = ntohl(*p++);
504 
505  if (args->ftype == NF3BLK || args->ftype == NF3CHR
506  || args->ftype == NF3SOCK || args->ftype == NF3FIFO)
507  p = decode_sattr3(p, &args->attrs);
508 
509  if (args->ftype == NF3BLK || args->ftype == NF3CHR) {
510  args->major = ntohl(*p++);
511  args->minor = ntohl(*p++);
512  }
513 
514  return xdr_argsize_check(rqstp, p);
515 }
516 
517 int
519  struct nfsd3_renameargs *args)
520 {
521  if (!(p = decode_fh(p, &args->ffh))
522  || !(p = decode_filename(p, &args->fname, &args->flen))
523  || !(p = decode_fh(p, &args->tfh))
524  || !(p = decode_filename(p, &args->tname, &args->tlen)))
525  return 0;
526 
527  return xdr_argsize_check(rqstp, p);
528 }
529 
530 int
532  struct nfsd3_readlinkargs *args)
533 {
534  if (!(p = decode_fh(p, &args->fh)))
535  return 0;
536  args->buffer =
537  page_address(rqstp->rq_respages[rqstp->rq_resused++]);
538 
539  return xdr_argsize_check(rqstp, p);
540 }
541 
542 int
544  struct nfsd3_linkargs *args)
545 {
546  if (!(p = decode_fh(p, &args->ffh))
547  || !(p = decode_fh(p, &args->tfh))
548  || !(p = decode_filename(p, &args->tname, &args->tlen)))
549  return 0;
550 
551  return xdr_argsize_check(rqstp, p);
552 }
553 
554 int
556  struct nfsd3_readdirargs *args)
557 {
558  if (!(p = decode_fh(p, &args->fh)))
559  return 0;
560  p = xdr_decode_hyper(p, &args->cookie);
561  args->verf = p; p += 2;
562  args->dircount = ~0;
563  args->count = ntohl(*p++);
564 
565  if (args->count > PAGE_SIZE)
566  args->count = PAGE_SIZE;
567 
568  args->buffer =
569  page_address(rqstp->rq_respages[rqstp->rq_resused++]);
570 
571  return xdr_argsize_check(rqstp, p);
572 }
573 
574 int
576  struct nfsd3_readdirargs *args)
577 {
578  int len, pn;
579  u32 max_blocksize = svc_max_payload(rqstp);
580 
581  if (!(p = decode_fh(p, &args->fh)))
582  return 0;
583  p = xdr_decode_hyper(p, &args->cookie);
584  args->verf = p; p += 2;
585  args->dircount = ntohl(*p++);
586  args->count = ntohl(*p++);
587 
588  len = (args->count > max_blocksize) ? max_blocksize :
589  args->count;
590  args->count = len;
591 
592  while (len > 0) {
593  pn = rqstp->rq_resused++;
594  if (!args->buffer)
595  args->buffer = page_address(rqstp->rq_respages[pn]);
596  len -= PAGE_SIZE;
597  }
598 
599  return xdr_argsize_check(rqstp, p);
600 }
601 
602 int
604  struct nfsd3_commitargs *args)
605 {
606  if (!(p = decode_fh(p, &args->fh)))
607  return 0;
608  p = xdr_decode_hyper(p, &args->offset);
609  args->count = ntohl(*p++);
610 
611  return xdr_argsize_check(rqstp, p);
612 }
613 
614 /*
615  * XDR encode functions
616  */
617 /*
618  * There must be an encoding function for void results so svc_process
619  * will work properly.
620  */
621 int
622 nfs3svc_encode_voidres(struct svc_rqst *rqstp, __be32 *p, void *dummy)
623 {
624  return xdr_ressize_check(rqstp, p);
625 }
626 
627 /* GETATTR */
628 int
630  struct nfsd3_attrstat *resp)
631 {
632  if (resp->status == 0) {
633  lease_get_mtime(resp->fh.fh_dentry->d_inode,
634  &resp->stat.mtime);
635  p = encode_fattr3(rqstp, p, &resp->fh, &resp->stat);
636  }
637  return xdr_ressize_check(rqstp, p);
638 }
639 
640 /* SETATTR, REMOVE, RMDIR */
641 int
643  struct nfsd3_attrstat *resp)
644 {
645  p = encode_wcc_data(rqstp, p, &resp->fh);
646  return xdr_ressize_check(rqstp, p);
647 }
648 
649 /* LOOKUP */
650 int
652  struct nfsd3_diropres *resp)
653 {
654  if (resp->status == 0) {
655  p = encode_fh(p, &resp->fh);
656  p = encode_post_op_attr(rqstp, p, &resp->fh);
657  }
658  p = encode_post_op_attr(rqstp, p, &resp->dirfh);
659  return xdr_ressize_check(rqstp, p);
660 }
661 
662 /* ACCESS */
663 int
665  struct nfsd3_accessres *resp)
666 {
667  p = encode_post_op_attr(rqstp, p, &resp->fh);
668  if (resp->status == 0)
669  *p++ = htonl(resp->access);
670  return xdr_ressize_check(rqstp, p);
671 }
672 
673 /* READLINK */
674 int
676  struct nfsd3_readlinkres *resp)
677 {
678  p = encode_post_op_attr(rqstp, p, &resp->fh);
679  if (resp->status == 0) {
680  *p++ = htonl(resp->len);
681  xdr_ressize_check(rqstp, p);
682  rqstp->rq_res.page_len = resp->len;
683  if (resp->len & 3) {
684  /* need to pad the tail */
685  rqstp->rq_res.tail[0].iov_base = p;
686  *p = 0;
687  rqstp->rq_res.tail[0].iov_len = 4 - (resp->len&3);
688  }
689  return 1;
690  } else
691  return xdr_ressize_check(rqstp, p);
692 }
693 
694 /* READ */
695 int
697  struct nfsd3_readres *resp)
698 {
699  p = encode_post_op_attr(rqstp, p, &resp->fh);
700  if (resp->status == 0) {
701  *p++ = htonl(resp->count);
702  *p++ = htonl(resp->eof);
703  *p++ = htonl(resp->count); /* xdr opaque count */
704  xdr_ressize_check(rqstp, p);
705  /* now update rqstp->rq_res to reflect data as well */
706  rqstp->rq_res.page_len = resp->count;
707  if (resp->count & 3) {
708  /* need to pad the tail */
709  rqstp->rq_res.tail[0].iov_base = p;
710  *p = 0;
711  rqstp->rq_res.tail[0].iov_len = 4 - (resp->count & 3);
712  }
713  return 1;
714  } else
715  return xdr_ressize_check(rqstp, p);
716 }
717 
718 /* WRITE */
719 int
721  struct nfsd3_writeres *resp)
722 {
723  p = encode_wcc_data(rqstp, p, &resp->fh);
724  if (resp->status == 0) {
725  *p++ = htonl(resp->count);
726  *p++ = htonl(resp->committed);
727  *p++ = htonl(nfssvc_boot.tv_sec);
728  *p++ = htonl(nfssvc_boot.tv_usec);
729  }
730  return xdr_ressize_check(rqstp, p);
731 }
732 
733 /* CREATE, MKDIR, SYMLINK, MKNOD */
734 int
736  struct nfsd3_diropres *resp)
737 {
738  if (resp->status == 0) {
739  *p++ = xdr_one;
740  p = encode_fh(p, &resp->fh);
741  p = encode_post_op_attr(rqstp, p, &resp->fh);
742  }
743  p = encode_wcc_data(rqstp, p, &resp->dirfh);
744  return xdr_ressize_check(rqstp, p);
745 }
746 
747 /* RENAME */
748 int
750  struct nfsd3_renameres *resp)
751 {
752  p = encode_wcc_data(rqstp, p, &resp->ffh);
753  p = encode_wcc_data(rqstp, p, &resp->tfh);
754  return xdr_ressize_check(rqstp, p);
755 }
756 
757 /* LINK */
758 int
760  struct nfsd3_linkres *resp)
761 {
762  p = encode_post_op_attr(rqstp, p, &resp->fh);
763  p = encode_wcc_data(rqstp, p, &resp->tfh);
764  return xdr_ressize_check(rqstp, p);
765 }
766 
767 /* READDIR */
768 int
770  struct nfsd3_readdirres *resp)
771 {
772  p = encode_post_op_attr(rqstp, p, &resp->fh);
773 
774  if (resp->status == 0) {
775  /* stupid readdir cookie */
776  memcpy(p, resp->verf, 8); p += 2;
777  xdr_ressize_check(rqstp, p);
778  if (rqstp->rq_res.head[0].iov_len + (2<<2) > PAGE_SIZE)
779  return 1; /*No room for trailer */
780  rqstp->rq_res.page_len = (resp->count) << 2;
781 
782  /* add the 'tail' to the end of the 'head' page - page 0. */
783  rqstp->rq_res.tail[0].iov_base = p;
784  *p++ = 0; /* no more entries */
785  *p++ = htonl(resp->common.err == nfserr_eof);
786  rqstp->rq_res.tail[0].iov_len = 2<<2;
787  return 1;
788  } else
789  return xdr_ressize_check(rqstp, p);
790 }
791 
792 static __be32 *
793 encode_entry_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name,
794  int namlen, u64 ino)
795 {
796  *p++ = xdr_one; /* mark entry present */
797  p = xdr_encode_hyper(p, ino); /* file id */
798  p = xdr_encode_array(p, name, namlen);/* name length & name */
799 
800  cd->offset = p; /* remember pointer */
801  p = xdr_encode_hyper(p, NFS_OFFSET_MAX);/* offset of next entry */
802 
803  return p;
804 }
805 
806 static __be32
807 compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
808  const char *name, int namlen)
809 {
810  struct svc_export *exp;
811  struct dentry *dparent, *dchild;
812  __be32 rv = nfserr_noent;
813 
814  dparent = cd->fh.fh_dentry;
815  exp = cd->fh.fh_export;
816 
817  if (isdotent(name, namlen)) {
818  if (namlen == 2) {
819  dchild = dget_parent(dparent);
820  /* filesystem root - cannot return filehandle for ".." */
821  if (dchild == dparent)
822  goto out;
823  } else
824  dchild = dget(dparent);
825  } else
826  dchild = lookup_one_len(name, dparent, namlen);
827  if (IS_ERR(dchild))
828  return rv;
829  if (d_mountpoint(dchild))
830  goto out;
831  if (!dchild->d_inode)
832  goto out;
833  rv = fh_compose(fhp, exp, dchild, &cd->fh);
834 out:
835  dput(dchild);
836  return rv;
837 }
838 
839 static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen)
840 {
841  struct svc_fh fh;
842  __be32 err;
843 
844  fh_init(&fh, NFS3_FHSIZE);
845  err = compose_entry_fh(cd, &fh, name, namlen);
846  if (err) {
847  *p++ = 0;
848  *p++ = 0;
849  goto out;
850  }
851  p = encode_post_op_attr(cd->rqstp, p, &fh);
852  *p++ = xdr_one; /* yes, a file handle follows */
853  p = encode_fh(p, &fh);
854 out:
855  fh_put(&fh);
856  return p;
857 }
858 
859 /*
860  * Encode a directory entry. This one works for both normal readdir
861  * and readdirplus.
862  * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
863  * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
864  *
865  * The readdirplus baggage is 1+21 words for post_op_attr, plus the
866  * file handle.
867  */
868 
869 #define NFS3_ENTRY_BAGGAGE (2 + 1 + 2 + 1)
870 #define NFS3_ENTRYPLUS_BAGGAGE (1 + 21 + 1 + (NFS3_FHSIZE >> 2))
871 static int
872 encode_entry(struct readdir_cd *ccd, const char *name, int namlen,
873  loff_t offset, u64 ino, unsigned int d_type, int plus)
874 {
875  struct nfsd3_readdirres *cd = container_of(ccd, struct nfsd3_readdirres,
876  common);
877  __be32 *p = cd->buffer;
878  caddr_t curr_page_addr = NULL;
879  int pn; /* current page number */
880  int slen; /* string (name) length */
881  int elen; /* estimated entry length in words */
882  int num_entry_words = 0; /* actual number of words */
883 
884  if (cd->offset) {
885  u64 offset64 = offset;
886 
887  if (unlikely(cd->offset1)) {
888  /* we ended up with offset on a page boundary */
889  *cd->offset = htonl(offset64 >> 32);
890  *cd->offset1 = htonl(offset64 & 0xffffffff);
891  cd->offset1 = NULL;
892  } else {
893  xdr_encode_hyper(cd->offset, offset64);
894  }
895  }
896 
897  /*
898  dprintk("encode_entry(%.*s @%ld%s)\n",
899  namlen, name, (long) offset, plus? " plus" : "");
900  */
901 
902  /* truncate filename if too long */
903  if (namlen > NFS3_MAXNAMLEN)
904  namlen = NFS3_MAXNAMLEN;
905 
906  slen = XDR_QUADLEN(namlen);
907  elen = slen + NFS3_ENTRY_BAGGAGE
908  + (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
909 
910  if (cd->buflen < elen) {
911  cd->common.err = nfserr_toosmall;
912  return -EINVAL;
913  }
914 
915  /* determine which page in rq_respages[] we are currently filling */
916  for (pn=1; pn < cd->rqstp->rq_resused; pn++) {
917  curr_page_addr = page_address(cd->rqstp->rq_respages[pn]);
918 
919  if (((caddr_t)cd->buffer >= curr_page_addr) &&
920  ((caddr_t)cd->buffer < curr_page_addr + PAGE_SIZE))
921  break;
922  }
923 
924  if ((caddr_t)(cd->buffer + elen) < (curr_page_addr + PAGE_SIZE)) {
925  /* encode entry in current page */
926 
927  p = encode_entry_baggage(cd, p, name, namlen, ino);
928 
929  if (plus)
930  p = encode_entryplus_baggage(cd, p, name, namlen);
931  num_entry_words = p - cd->buffer;
932  } else if (cd->rqstp->rq_respages[pn+1] != NULL) {
933  /* temporarily encode entry into next page, then move back to
934  * current and next page in rq_respages[] */
935  __be32 *p1, *tmp;
936  int len1, len2;
937 
938  /* grab next page for temporary storage of entry */
939  p1 = tmp = page_address(cd->rqstp->rq_respages[pn+1]);
940 
941  p1 = encode_entry_baggage(cd, p1, name, namlen, ino);
942 
943  if (plus)
944  p1 = encode_entryplus_baggage(cd, p1, name, namlen);
945 
946  /* determine entry word length and lengths to go in pages */
947  num_entry_words = p1 - tmp;
948  len1 = curr_page_addr + PAGE_SIZE - (caddr_t)cd->buffer;
949  if ((num_entry_words << 2) < len1) {
950  /* the actual number of words in the entry is less
951  * than elen and can still fit in the current page
952  */
953  memmove(p, tmp, num_entry_words << 2);
954  p += num_entry_words;
955 
956  /* update offset */
957  cd->offset = cd->buffer + (cd->offset - tmp);
958  } else {
959  unsigned int offset_r = (cd->offset - tmp) << 2;
960 
961  /* update pointer to offset location.
962  * This is a 64bit quantity, so we need to
963  * deal with 3 cases:
964  * - entirely in first page
965  * - entirely in second page
966  * - 4 bytes in each page
967  */
968  if (offset_r + 8 <= len1) {
969  cd->offset = p + (cd->offset - tmp);
970  } else if (offset_r >= len1) {
971  cd->offset -= len1 >> 2;
972  } else {
973  /* sitting on the fence */
974  BUG_ON(offset_r != len1 - 4);
975  cd->offset = p + (cd->offset - tmp);
976  cd->offset1 = tmp;
977  }
978 
979  len2 = (num_entry_words << 2) - len1;
980 
981  /* move from temp page to current and next pages */
982  memmove(p, tmp, len1);
983  memmove(tmp, (caddr_t)tmp+len1, len2);
984 
985  p = tmp + (len2 >> 2);
986  }
987  }
988  else {
989  cd->common.err = nfserr_toosmall;
990  return -EINVAL;
991  }
992 
993  cd->buflen -= num_entry_words;
994  cd->buffer = p;
995  cd->common.err = nfs_ok;
996  return 0;
997 
998 }
999 
1000 int
1001 nfs3svc_encode_entry(void *cd, const char *name,
1002  int namlen, loff_t offset, u64 ino, unsigned int d_type)
1003 {
1004  return encode_entry(cd, name, namlen, offset, ino, d_type, 0);
1005 }
1006 
1007 int
1008 nfs3svc_encode_entry_plus(void *cd, const char *name,
1009  int namlen, loff_t offset, u64 ino,
1010  unsigned int d_type)
1011 {
1012  return encode_entry(cd, name, namlen, offset, ino, d_type, 1);
1013 }
1014 
1015 /* FSSTAT */
1016 int
1018  struct nfsd3_fsstatres *resp)
1019 {
1020  struct kstatfs *s = &resp->stats;
1021  u64 bs = s->f_bsize;
1022 
1023  *p++ = xdr_zero; /* no post_op_attr */
1024 
1025  if (resp->status == 0) {
1026  p = xdr_encode_hyper(p, bs * s->f_blocks); /* total bytes */
1027  p = xdr_encode_hyper(p, bs * s->f_bfree); /* free bytes */
1028  p = xdr_encode_hyper(p, bs * s->f_bavail); /* user available bytes */
1029  p = xdr_encode_hyper(p, s->f_files); /* total inodes */
1030  p = xdr_encode_hyper(p, s->f_ffree); /* free inodes */
1031  p = xdr_encode_hyper(p, s->f_ffree); /* user available inodes */
1032  *p++ = htonl(resp->invarsec); /* mean unchanged time */
1033  }
1034  return xdr_ressize_check(rqstp, p);
1035 }
1036 
1037 /* FSINFO */
1038 int
1040  struct nfsd3_fsinfores *resp)
1041 {
1042  *p++ = xdr_zero; /* no post_op_attr */
1043 
1044  if (resp->status == 0) {
1045  *p++ = htonl(resp->f_rtmax);
1046  *p++ = htonl(resp->f_rtpref);
1047  *p++ = htonl(resp->f_rtmult);
1048  *p++ = htonl(resp->f_wtmax);
1049  *p++ = htonl(resp->f_wtpref);
1050  *p++ = htonl(resp->f_wtmult);
1051  *p++ = htonl(resp->f_dtpref);
1052  p = xdr_encode_hyper(p, resp->f_maxfilesize);
1053  *p++ = xdr_one;
1054  *p++ = xdr_zero;
1055  *p++ = htonl(resp->f_properties);
1056  }
1057 
1058  return xdr_ressize_check(rqstp, p);
1059 }
1060 
1061 /* PATHCONF */
1062 int
1064  struct nfsd3_pathconfres *resp)
1065 {
1066  *p++ = xdr_zero; /* no post_op_attr */
1067 
1068  if (resp->status == 0) {
1069  *p++ = htonl(resp->p_link_max);
1070  *p++ = htonl(resp->p_name_max);
1071  *p++ = htonl(resp->p_no_trunc);
1072  *p++ = htonl(resp->p_chown_restricted);
1073  *p++ = htonl(resp->p_case_insensitive);
1074  *p++ = htonl(resp->p_case_preserving);
1075  }
1076 
1077  return xdr_ressize_check(rqstp, p);
1078 }
1079 
1080 /* COMMIT */
1081 int
1083  struct nfsd3_commitres *resp)
1084 {
1085  p = encode_wcc_data(rqstp, p, &resp->fh);
1086  /* Write verifier */
1087  if (resp->status == 0) {
1088  *p++ = htonl(nfssvc_boot.tv_sec);
1089  *p++ = htonl(nfssvc_boot.tv_usec);
1090  }
1091  return xdr_ressize_check(rqstp, p);
1092 }
1093 
1094 /*
1095  * XDR release functions
1096  */
1097 int
1099  struct nfsd3_attrstat *resp)
1100 {
1101  fh_put(&resp->fh);
1102  return 1;
1103 }
1104 
1105 int
1107  struct nfsd3_fhandle_pair *resp)
1108 {
1109  fh_put(&resp->fh1);
1110  fh_put(&resp->fh2);
1111  return 1;
1112 }