~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/nfsd/nfs3xdr.c

Version: ~ [ linux-5.13-rc2 ] ~ [ linux-5.12.4 ] ~ [ linux-5.11.21 ] ~ [ linux-5.10.37 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.119 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.190 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.232 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.268 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.268 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.18.140 ] ~ [ linux-3.16.85 ] ~ [ linux-3.14.79 ] ~ [ linux-3.12.74 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp