Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * XDR support for nfsd/protocol version 3.
0004  *
0005  * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
0006  *
0007  * 2003-08-09 Jamie Lokier: Use htonl() for nanoseconds, not htons()!
0008  */
0009 
0010 #include <linux/namei.h>
0011 #include <linux/sunrpc/svc_xprt.h>
0012 #include "xdr3.h"
0013 #include "auth.h"
0014 #include "netns.h"
0015 #include "vfs.h"
0016 
0017 /*
0018  * Force construction of an empty post-op attr
0019  */
0020 static const struct svc_fh nfs3svc_null_fh = {
0021     .fh_no_wcc  = true,
0022 };
0023 
0024 /*
0025  * time_delta. {1, 0} means the server is accurate only
0026  * to the nearest second.
0027  */
0028 static const struct timespec64 nfs3svc_time_delta = {
0029     .tv_sec     = 1,
0030     .tv_nsec    = 0,
0031 };
0032 
0033 /*
0034  * Mapping of S_IF* types to NFS file types
0035  */
0036 static const u32 nfs3_ftypes[] = {
0037     NF3NON,  NF3FIFO, NF3CHR, NF3BAD,
0038     NF3DIR,  NF3BAD,  NF3BLK, NF3BAD,
0039     NF3REG,  NF3BAD,  NF3LNK, NF3BAD,
0040     NF3SOCK, NF3BAD,  NF3LNK, NF3BAD,
0041 };
0042 
0043 
0044 /*
0045  * Basic NFSv3 data types (RFC 1813 Sections 2.5 and 2.6)
0046  */
0047 
0048 static __be32 *
0049 encode_nfstime3(__be32 *p, const struct timespec64 *time)
0050 {
0051     *p++ = cpu_to_be32((u32)time->tv_sec);
0052     *p++ = cpu_to_be32(time->tv_nsec);
0053 
0054     return p;
0055 }
0056 
0057 static bool
0058 svcxdr_decode_nfstime3(struct xdr_stream *xdr, struct timespec64 *timep)
0059 {
0060     __be32 *p;
0061 
0062     p = xdr_inline_decode(xdr, XDR_UNIT * 2);
0063     if (!p)
0064         return false;
0065     timep->tv_sec = be32_to_cpup(p++);
0066     timep->tv_nsec = be32_to_cpup(p);
0067 
0068     return true;
0069 }
0070 
0071 /**
0072  * svcxdr_decode_nfs_fh3 - Decode an NFSv3 file handle
0073  * @xdr: XDR stream positioned at an undecoded NFSv3 FH
0074  * @fhp: OUT: filled-in server file handle
0075  *
0076  * Return values:
0077  *  %false: The encoded file handle was not valid
0078  *  %true: @fhp has been initialized
0079  */
0080 bool
0081 svcxdr_decode_nfs_fh3(struct xdr_stream *xdr, struct svc_fh *fhp)
0082 {
0083     __be32 *p;
0084     u32 size;
0085 
0086     if (xdr_stream_decode_u32(xdr, &size) < 0)
0087         return false;
0088     if (size == 0 || size > NFS3_FHSIZE)
0089         return false;
0090     p = xdr_inline_decode(xdr, size);
0091     if (!p)
0092         return false;
0093     fh_init(fhp, NFS3_FHSIZE);
0094     fhp->fh_handle.fh_size = size;
0095     memcpy(&fhp->fh_handle.fh_raw, p, size);
0096 
0097     return true;
0098 }
0099 
0100 /**
0101  * svcxdr_encode_nfsstat3 - Encode an NFSv3 status code
0102  * @xdr: XDR stream
0103  * @status: status value to encode
0104  *
0105  * Return values:
0106  *   %false: Send buffer space was exhausted
0107  *   %true: Success
0108  */
0109 bool
0110 svcxdr_encode_nfsstat3(struct xdr_stream *xdr, __be32 status)
0111 {
0112     __be32 *p;
0113 
0114     p = xdr_reserve_space(xdr, sizeof(status));
0115     if (!p)
0116         return false;
0117     *p = status;
0118 
0119     return true;
0120 }
0121 
0122 static bool
0123 svcxdr_encode_nfs_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp)
0124 {
0125     u32 size = fhp->fh_handle.fh_size;
0126     __be32 *p;
0127 
0128     p = xdr_reserve_space(xdr, XDR_UNIT + size);
0129     if (!p)
0130         return false;
0131     *p++ = cpu_to_be32(size);
0132     if (size)
0133         p[XDR_QUADLEN(size) - 1] = 0;
0134     memcpy(p, &fhp->fh_handle.fh_raw, size);
0135 
0136     return true;
0137 }
0138 
0139 static bool
0140 svcxdr_encode_post_op_fh3(struct xdr_stream *xdr, const struct svc_fh *fhp)
0141 {
0142     if (xdr_stream_encode_item_present(xdr) < 0)
0143         return false;
0144     if (!svcxdr_encode_nfs_fh3(xdr, fhp))
0145         return false;
0146 
0147     return true;
0148 }
0149 
0150 static bool
0151 svcxdr_encode_cookieverf3(struct xdr_stream *xdr, const __be32 *verf)
0152 {
0153     __be32 *p;
0154 
0155     p = xdr_reserve_space(xdr, NFS3_COOKIEVERFSIZE);
0156     if (!p)
0157         return false;
0158     memcpy(p, verf, NFS3_COOKIEVERFSIZE);
0159 
0160     return true;
0161 }
0162 
0163 static bool
0164 svcxdr_encode_writeverf3(struct xdr_stream *xdr, const __be32 *verf)
0165 {
0166     __be32 *p;
0167 
0168     p = xdr_reserve_space(xdr, NFS3_WRITEVERFSIZE);
0169     if (!p)
0170         return false;
0171     memcpy(p, verf, NFS3_WRITEVERFSIZE);
0172 
0173     return true;
0174 }
0175 
0176 static bool
0177 svcxdr_decode_filename3(struct xdr_stream *xdr, char **name, unsigned int *len)
0178 {
0179     u32 size, i;
0180     __be32 *p;
0181     char *c;
0182 
0183     if (xdr_stream_decode_u32(xdr, &size) < 0)
0184         return false;
0185     if (size == 0 || size > NFS3_MAXNAMLEN)
0186         return false;
0187     p = xdr_inline_decode(xdr, size);
0188     if (!p)
0189         return false;
0190 
0191     *len = size;
0192     *name = (char *)p;
0193     for (i = 0, c = *name; i < size; i++, c++) {
0194         if (*c == '\0' || *c == '/')
0195             return false;
0196     }
0197 
0198     return true;
0199 }
0200 
0201 static bool
0202 svcxdr_decode_diropargs3(struct xdr_stream *xdr, struct svc_fh *fhp,
0203              char **name, unsigned int *len)
0204 {
0205     return svcxdr_decode_nfs_fh3(xdr, fhp) &&
0206         svcxdr_decode_filename3(xdr, name, len);
0207 }
0208 
0209 static bool
0210 svcxdr_decode_sattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
0211              struct iattr *iap)
0212 {
0213     u32 set_it;
0214 
0215     iap->ia_valid = 0;
0216 
0217     if (xdr_stream_decode_bool(xdr, &set_it) < 0)
0218         return false;
0219     if (set_it) {
0220         u32 mode;
0221 
0222         if (xdr_stream_decode_u32(xdr, &mode) < 0)
0223             return false;
0224         iap->ia_valid |= ATTR_MODE;
0225         iap->ia_mode = mode;
0226     }
0227     if (xdr_stream_decode_bool(xdr, &set_it) < 0)
0228         return false;
0229     if (set_it) {
0230         u32 uid;
0231 
0232         if (xdr_stream_decode_u32(xdr, &uid) < 0)
0233             return false;
0234         iap->ia_uid = make_kuid(nfsd_user_namespace(rqstp), uid);
0235         if (uid_valid(iap->ia_uid))
0236             iap->ia_valid |= ATTR_UID;
0237     }
0238     if (xdr_stream_decode_bool(xdr, &set_it) < 0)
0239         return false;
0240     if (set_it) {
0241         u32 gid;
0242 
0243         if (xdr_stream_decode_u32(xdr, &gid) < 0)
0244             return false;
0245         iap->ia_gid = make_kgid(nfsd_user_namespace(rqstp), gid);
0246         if (gid_valid(iap->ia_gid))
0247             iap->ia_valid |= ATTR_GID;
0248     }
0249     if (xdr_stream_decode_bool(xdr, &set_it) < 0)
0250         return false;
0251     if (set_it) {
0252         u64 newsize;
0253 
0254         if (xdr_stream_decode_u64(xdr, &newsize) < 0)
0255             return false;
0256         iap->ia_valid |= ATTR_SIZE;
0257         iap->ia_size = newsize;
0258     }
0259     if (xdr_stream_decode_u32(xdr, &set_it) < 0)
0260         return false;
0261     switch (set_it) {
0262     case DONT_CHANGE:
0263         break;
0264     case SET_TO_SERVER_TIME:
0265         iap->ia_valid |= ATTR_ATIME;
0266         break;
0267     case SET_TO_CLIENT_TIME:
0268         if (!svcxdr_decode_nfstime3(xdr, &iap->ia_atime))
0269             return false;
0270         iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
0271         break;
0272     default:
0273         return false;
0274     }
0275     if (xdr_stream_decode_u32(xdr, &set_it) < 0)
0276         return false;
0277     switch (set_it) {
0278     case DONT_CHANGE:
0279         break;
0280     case SET_TO_SERVER_TIME:
0281         iap->ia_valid |= ATTR_MTIME;
0282         break;
0283     case SET_TO_CLIENT_TIME:
0284         if (!svcxdr_decode_nfstime3(xdr, &iap->ia_mtime))
0285             return false;
0286         iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
0287         break;
0288     default:
0289         return false;
0290     }
0291 
0292     return true;
0293 }
0294 
0295 static bool
0296 svcxdr_decode_sattrguard3(struct xdr_stream *xdr, struct nfsd3_sattrargs *args)
0297 {
0298     __be32 *p;
0299     u32 check;
0300 
0301     if (xdr_stream_decode_bool(xdr, &check) < 0)
0302         return false;
0303     if (check) {
0304         p = xdr_inline_decode(xdr, XDR_UNIT * 2);
0305         if (!p)
0306             return false;
0307         args->check_guard = 1;
0308         args->guardtime = be32_to_cpup(p);
0309     } else
0310         args->check_guard = 0;
0311 
0312     return true;
0313 }
0314 
0315 static bool
0316 svcxdr_decode_specdata3(struct xdr_stream *xdr, struct nfsd3_mknodargs *args)
0317 {
0318     __be32 *p;
0319 
0320     p = xdr_inline_decode(xdr, XDR_UNIT * 2);
0321     if (!p)
0322         return false;
0323     args->major = be32_to_cpup(p++);
0324     args->minor = be32_to_cpup(p);
0325 
0326     return true;
0327 }
0328 
0329 static bool
0330 svcxdr_decode_devicedata3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
0331               struct nfsd3_mknodargs *args)
0332 {
0333     return svcxdr_decode_sattr3(rqstp, xdr, &args->attrs) &&
0334         svcxdr_decode_specdata3(xdr, args);
0335 }
0336 
0337 static bool
0338 svcxdr_encode_fattr3(struct svc_rqst *rqstp, struct xdr_stream *xdr,
0339              const struct svc_fh *fhp, const struct kstat *stat)
0340 {
0341     struct user_namespace *userns = nfsd_user_namespace(rqstp);
0342     __be32 *p;
0343     u64 fsid;
0344 
0345     p = xdr_reserve_space(xdr, XDR_UNIT * 21);
0346     if (!p)
0347         return false;
0348 
0349     *p++ = cpu_to_be32(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
0350     *p++ = cpu_to_be32((u32)(stat->mode & S_IALLUGO));
0351     *p++ = cpu_to_be32((u32)stat->nlink);
0352     *p++ = cpu_to_be32((u32)from_kuid_munged(userns, stat->uid));
0353     *p++ = cpu_to_be32((u32)from_kgid_munged(userns, stat->gid));
0354     if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN)
0355         p = xdr_encode_hyper(p, (u64)NFS3_MAXPATHLEN);
0356     else
0357         p = xdr_encode_hyper(p, (u64)stat->size);
0358 
0359     /* used */
0360     p = xdr_encode_hyper(p, ((u64)stat->blocks) << 9);
0361 
0362     /* rdev */
0363     *p++ = cpu_to_be32((u32)MAJOR(stat->rdev));
0364     *p++ = cpu_to_be32((u32)MINOR(stat->rdev));
0365 
0366     switch(fsid_source(fhp)) {
0367     case FSIDSOURCE_FSID:
0368         fsid = (u64)fhp->fh_export->ex_fsid;
0369         break;
0370     case FSIDSOURCE_UUID:
0371         fsid = ((u64 *)fhp->fh_export->ex_uuid)[0];
0372         fsid ^= ((u64 *)fhp->fh_export->ex_uuid)[1];
0373         break;
0374     default:
0375         fsid = (u64)huge_encode_dev(fhp->fh_dentry->d_sb->s_dev);
0376     }
0377     p = xdr_encode_hyper(p, fsid);
0378 
0379     /* fileid */
0380     p = xdr_encode_hyper(p, stat->ino);
0381 
0382     p = encode_nfstime3(p, &stat->atime);
0383     p = encode_nfstime3(p, &stat->mtime);
0384     encode_nfstime3(p, &stat->ctime);
0385 
0386     return true;
0387 }
0388 
0389 static bool
0390 svcxdr_encode_wcc_attr(struct xdr_stream *xdr, const struct svc_fh *fhp)
0391 {
0392     __be32 *p;
0393 
0394     p = xdr_reserve_space(xdr, XDR_UNIT * 6);
0395     if (!p)
0396         return false;
0397     p = xdr_encode_hyper(p, (u64)fhp->fh_pre_size);
0398     p = encode_nfstime3(p, &fhp->fh_pre_mtime);
0399     encode_nfstime3(p, &fhp->fh_pre_ctime);
0400 
0401     return true;
0402 }
0403 
0404 static bool
0405 svcxdr_encode_pre_op_attr(struct xdr_stream *xdr, const struct svc_fh *fhp)
0406 {
0407     if (!fhp->fh_pre_saved) {
0408         if (xdr_stream_encode_item_absent(xdr) < 0)
0409             return false;
0410         return true;
0411     }
0412 
0413     if (xdr_stream_encode_item_present(xdr) < 0)
0414         return false;
0415     return svcxdr_encode_wcc_attr(xdr, fhp);
0416 }
0417 
0418 /**
0419  * svcxdr_encode_post_op_attr - Encode NFSv3 post-op attributes
0420  * @rqstp: Context of a completed RPC transaction
0421  * @xdr: XDR stream
0422  * @fhp: File handle to encode
0423  *
0424  * Return values:
0425  *   %false: Send buffer space was exhausted
0426  *   %true: Success
0427  */
0428 bool
0429 svcxdr_encode_post_op_attr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
0430                const struct svc_fh *fhp)
0431 {
0432     struct dentry *dentry = fhp->fh_dentry;
0433     struct kstat stat;
0434 
0435     /*
0436      * The inode may be NULL if the call failed because of a
0437      * stale file handle. In this case, no attributes are
0438      * returned.
0439      */
0440     if (fhp->fh_no_wcc || !dentry || !d_really_is_positive(dentry))
0441         goto no_post_op_attrs;
0442     if (fh_getattr(fhp, &stat) != nfs_ok)
0443         goto no_post_op_attrs;
0444 
0445     if (xdr_stream_encode_item_present(xdr) < 0)
0446         return false;
0447     lease_get_mtime(d_inode(dentry), &stat.mtime);
0448     if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &stat))
0449         return false;
0450 
0451     return true;
0452 
0453 no_post_op_attrs:
0454     return xdr_stream_encode_item_absent(xdr) > 0;
0455 }
0456 
0457 /*
0458  * Encode weak cache consistency data
0459  */
0460 static bool
0461 svcxdr_encode_wcc_data(struct svc_rqst *rqstp, struct xdr_stream *xdr,
0462                const struct svc_fh *fhp)
0463 {
0464     struct dentry *dentry = fhp->fh_dentry;
0465 
0466     if (!dentry || !d_really_is_positive(dentry) || !fhp->fh_post_saved)
0467         goto neither;
0468 
0469     /* before */
0470     if (!svcxdr_encode_pre_op_attr(xdr, fhp))
0471         return false;
0472 
0473     /* after */
0474     if (xdr_stream_encode_item_present(xdr) < 0)
0475         return false;
0476     if (!svcxdr_encode_fattr3(rqstp, xdr, fhp, &fhp->fh_post_attr))
0477         return false;
0478 
0479     return true;
0480 
0481 neither:
0482     if (xdr_stream_encode_item_absent(xdr) < 0)
0483         return false;
0484     if (!svcxdr_encode_post_op_attr(rqstp, xdr, fhp))
0485         return false;
0486 
0487     return true;
0488 }
0489 
0490 /*
0491  * XDR decode functions
0492  */
0493 
0494 bool
0495 nfs3svc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0496 {
0497     struct nfsd_fhandle *args = rqstp->rq_argp;
0498 
0499     return svcxdr_decode_nfs_fh3(xdr, &args->fh);
0500 }
0501 
0502 bool
0503 nfs3svc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0504 {
0505     struct nfsd3_sattrargs *args = rqstp->rq_argp;
0506 
0507     return svcxdr_decode_nfs_fh3(xdr, &args->fh) &&
0508         svcxdr_decode_sattr3(rqstp, xdr, &args->attrs) &&
0509         svcxdr_decode_sattrguard3(xdr, args);
0510 }
0511 
0512 bool
0513 nfs3svc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0514 {
0515     struct nfsd3_diropargs *args = rqstp->rq_argp;
0516 
0517     return svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len);
0518 }
0519 
0520 bool
0521 nfs3svc_decode_accessargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0522 {
0523     struct nfsd3_accessargs *args = rqstp->rq_argp;
0524 
0525     if (!svcxdr_decode_nfs_fh3(xdr, &args->fh))
0526         return false;
0527     if (xdr_stream_decode_u32(xdr, &args->access) < 0)
0528         return false;
0529 
0530     return true;
0531 }
0532 
0533 bool
0534 nfs3svc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0535 {
0536     struct nfsd3_readargs *args = rqstp->rq_argp;
0537 
0538     if (!svcxdr_decode_nfs_fh3(xdr, &args->fh))
0539         return false;
0540     if (xdr_stream_decode_u64(xdr, &args->offset) < 0)
0541         return false;
0542     if (xdr_stream_decode_u32(xdr, &args->count) < 0)
0543         return false;
0544 
0545     return true;
0546 }
0547 
0548 bool
0549 nfs3svc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0550 {
0551     struct nfsd3_writeargs *args = rqstp->rq_argp;
0552     u32 max_blocksize = svc_max_payload(rqstp);
0553 
0554     if (!svcxdr_decode_nfs_fh3(xdr, &args->fh))
0555         return false;
0556     if (xdr_stream_decode_u64(xdr, &args->offset) < 0)
0557         return false;
0558     if (xdr_stream_decode_u32(xdr, &args->count) < 0)
0559         return false;
0560     if (xdr_stream_decode_u32(xdr, &args->stable) < 0)
0561         return false;
0562 
0563     /* opaque data */
0564     if (xdr_stream_decode_u32(xdr, &args->len) < 0)
0565         return false;
0566 
0567     /* request sanity */
0568     if (args->count != args->len)
0569         return false;
0570     if (args->count > max_blocksize) {
0571         args->count = max_blocksize;
0572         args->len = max_blocksize;
0573     }
0574     if (!xdr_stream_subsegment(xdr, &args->payload, args->count))
0575         return false;
0576 
0577     return true;
0578 }
0579 
0580 bool
0581 nfs3svc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0582 {
0583     struct nfsd3_createargs *args = rqstp->rq_argp;
0584 
0585     if (!svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len))
0586         return false;
0587     if (xdr_stream_decode_u32(xdr, &args->createmode) < 0)
0588         return false;
0589     switch (args->createmode) {
0590     case NFS3_CREATE_UNCHECKED:
0591     case NFS3_CREATE_GUARDED:
0592         return svcxdr_decode_sattr3(rqstp, xdr, &args->attrs);
0593     case NFS3_CREATE_EXCLUSIVE:
0594         args->verf = xdr_inline_decode(xdr, NFS3_CREATEVERFSIZE);
0595         if (!args->verf)
0596             return false;
0597         break;
0598     default:
0599         return false;
0600     }
0601     return true;
0602 }
0603 
0604 bool
0605 nfs3svc_decode_mkdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0606 {
0607     struct nfsd3_createargs *args = rqstp->rq_argp;
0608 
0609     return svcxdr_decode_diropargs3(xdr, &args->fh,
0610                     &args->name, &args->len) &&
0611         svcxdr_decode_sattr3(rqstp, xdr, &args->attrs);
0612 }
0613 
0614 bool
0615 nfs3svc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0616 {
0617     struct nfsd3_symlinkargs *args = rqstp->rq_argp;
0618     struct kvec *head = rqstp->rq_arg.head;
0619     struct kvec *tail = rqstp->rq_arg.tail;
0620     size_t remaining;
0621 
0622     if (!svcxdr_decode_diropargs3(xdr, &args->ffh, &args->fname, &args->flen))
0623         return false;
0624     if (!svcxdr_decode_sattr3(rqstp, xdr, &args->attrs))
0625         return false;
0626     if (xdr_stream_decode_u32(xdr, &args->tlen) < 0)
0627         return false;
0628 
0629     /* request sanity */
0630     remaining = head->iov_len + rqstp->rq_arg.page_len + tail->iov_len;
0631     remaining -= xdr_stream_pos(xdr);
0632     if (remaining < xdr_align_size(args->tlen))
0633         return false;
0634 
0635     args->first.iov_base = xdr->p;
0636     args->first.iov_len = head->iov_len - xdr_stream_pos(xdr);
0637 
0638     return true;
0639 }
0640 
0641 bool
0642 nfs3svc_decode_mknodargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0643 {
0644     struct nfsd3_mknodargs *args = rqstp->rq_argp;
0645 
0646     if (!svcxdr_decode_diropargs3(xdr, &args->fh, &args->name, &args->len))
0647         return false;
0648     if (xdr_stream_decode_u32(xdr, &args->ftype) < 0)
0649         return false;
0650     switch (args->ftype) {
0651     case NF3CHR:
0652     case NF3BLK:
0653         return svcxdr_decode_devicedata3(rqstp, xdr, args);
0654     case NF3SOCK:
0655     case NF3FIFO:
0656         return svcxdr_decode_sattr3(rqstp, xdr, &args->attrs);
0657     case NF3REG:
0658     case NF3DIR:
0659     case NF3LNK:
0660         /* Valid XDR but illegal file types */
0661         break;
0662     default:
0663         return false;
0664     }
0665 
0666     return true;
0667 }
0668 
0669 bool
0670 nfs3svc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0671 {
0672     struct nfsd3_renameargs *args = rqstp->rq_argp;
0673 
0674     return svcxdr_decode_diropargs3(xdr, &args->ffh,
0675                     &args->fname, &args->flen) &&
0676         svcxdr_decode_diropargs3(xdr, &args->tfh,
0677                      &args->tname, &args->tlen);
0678 }
0679 
0680 bool
0681 nfs3svc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0682 {
0683     struct nfsd3_linkargs *args = rqstp->rq_argp;
0684 
0685     return svcxdr_decode_nfs_fh3(xdr, &args->ffh) &&
0686         svcxdr_decode_diropargs3(xdr, &args->tfh,
0687                      &args->tname, &args->tlen);
0688 }
0689 
0690 bool
0691 nfs3svc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0692 {
0693     struct nfsd3_readdirargs *args = rqstp->rq_argp;
0694 
0695     if (!svcxdr_decode_nfs_fh3(xdr, &args->fh))
0696         return false;
0697     if (xdr_stream_decode_u64(xdr, &args->cookie) < 0)
0698         return false;
0699     args->verf = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
0700     if (!args->verf)
0701         return false;
0702     if (xdr_stream_decode_u32(xdr, &args->count) < 0)
0703         return false;
0704 
0705     return true;
0706 }
0707 
0708 bool
0709 nfs3svc_decode_readdirplusargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0710 {
0711     struct nfsd3_readdirargs *args = rqstp->rq_argp;
0712     u32 dircount;
0713 
0714     if (!svcxdr_decode_nfs_fh3(xdr, &args->fh))
0715         return false;
0716     if (xdr_stream_decode_u64(xdr, &args->cookie) < 0)
0717         return false;
0718     args->verf = xdr_inline_decode(xdr, NFS3_COOKIEVERFSIZE);
0719     if (!args->verf)
0720         return false;
0721     /* dircount is ignored */
0722     if (xdr_stream_decode_u32(xdr, &dircount) < 0)
0723         return false;
0724     if (xdr_stream_decode_u32(xdr, &args->count) < 0)
0725         return false;
0726 
0727     return true;
0728 }
0729 
0730 bool
0731 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0732 {
0733     struct nfsd3_commitargs *args = rqstp->rq_argp;
0734 
0735     if (!svcxdr_decode_nfs_fh3(xdr, &args->fh))
0736         return false;
0737     if (xdr_stream_decode_u64(xdr, &args->offset) < 0)
0738         return false;
0739     if (xdr_stream_decode_u32(xdr, &args->count) < 0)
0740         return false;
0741 
0742     return true;
0743 }
0744 
0745 /*
0746  * XDR encode functions
0747  */
0748 
0749 /* GETATTR */
0750 bool
0751 nfs3svc_encode_getattrres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0752 {
0753     struct nfsd3_attrstat *resp = rqstp->rq_resp;
0754 
0755     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
0756         return false;
0757     switch (resp->status) {
0758     case nfs_ok:
0759         lease_get_mtime(d_inode(resp->fh.fh_dentry), &resp->stat.mtime);
0760         if (!svcxdr_encode_fattr3(rqstp, xdr, &resp->fh, &resp->stat))
0761             return false;
0762         break;
0763     }
0764 
0765     return true;
0766 }
0767 
0768 /* SETATTR, REMOVE, RMDIR */
0769 bool
0770 nfs3svc_encode_wccstat(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0771 {
0772     struct nfsd3_attrstat *resp = rqstp->rq_resp;
0773 
0774     return svcxdr_encode_nfsstat3(xdr, resp->status) &&
0775         svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh);
0776 }
0777 
0778 /* LOOKUP */
0779 bool
0780 nfs3svc_encode_lookupres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0781 {
0782     struct nfsd3_diropres *resp = rqstp->rq_resp;
0783 
0784     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
0785         return false;
0786     switch (resp->status) {
0787     case nfs_ok:
0788         if (!svcxdr_encode_nfs_fh3(xdr, &resp->fh))
0789             return false;
0790         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
0791             return false;
0792         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh))
0793             return false;
0794         break;
0795     default:
0796         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->dirfh))
0797             return false;
0798     }
0799 
0800     return true;
0801 }
0802 
0803 /* ACCESS */
0804 bool
0805 nfs3svc_encode_accessres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0806 {
0807     struct nfsd3_accessres *resp = rqstp->rq_resp;
0808 
0809     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
0810         return false;
0811     switch (resp->status) {
0812     case nfs_ok:
0813         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
0814             return false;
0815         if (xdr_stream_encode_u32(xdr, resp->access) < 0)
0816             return false;
0817         break;
0818     default:
0819         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
0820             return false;
0821     }
0822 
0823     return true;
0824 }
0825 
0826 /* READLINK */
0827 bool
0828 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0829 {
0830     struct nfsd3_readlinkres *resp = rqstp->rq_resp;
0831     struct kvec *head = rqstp->rq_res.head;
0832 
0833     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
0834         return false;
0835     switch (resp->status) {
0836     case nfs_ok:
0837         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
0838             return false;
0839         if (xdr_stream_encode_u32(xdr, resp->len) < 0)
0840             return false;
0841         xdr_write_pages(xdr, resp->pages, 0, resp->len);
0842         if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0)
0843             return false;
0844         break;
0845     default:
0846         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
0847             return false;
0848     }
0849 
0850     return true;
0851 }
0852 
0853 /* READ */
0854 bool
0855 nfs3svc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0856 {
0857     struct nfsd3_readres *resp = rqstp->rq_resp;
0858     struct kvec *head = rqstp->rq_res.head;
0859 
0860     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
0861         return false;
0862     switch (resp->status) {
0863     case nfs_ok:
0864         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
0865             return false;
0866         if (xdr_stream_encode_u32(xdr, resp->count) < 0)
0867             return false;
0868         if (xdr_stream_encode_bool(xdr, resp->eof) < 0)
0869             return false;
0870         if (xdr_stream_encode_u32(xdr, resp->count) < 0)
0871             return false;
0872         xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base,
0873                 resp->count);
0874         if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0)
0875             return false;
0876         break;
0877     default:
0878         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
0879             return false;
0880     }
0881 
0882     return true;
0883 }
0884 
0885 /* WRITE */
0886 bool
0887 nfs3svc_encode_writeres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0888 {
0889     struct nfsd3_writeres *resp = rqstp->rq_resp;
0890 
0891     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
0892         return false;
0893     switch (resp->status) {
0894     case nfs_ok:
0895         if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh))
0896             return false;
0897         if (xdr_stream_encode_u32(xdr, resp->count) < 0)
0898             return false;
0899         if (xdr_stream_encode_u32(xdr, resp->committed) < 0)
0900             return false;
0901         if (!svcxdr_encode_writeverf3(xdr, resp->verf))
0902             return false;
0903         break;
0904     default:
0905         if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh))
0906             return false;
0907     }
0908 
0909     return true;
0910 }
0911 
0912 /* CREATE, MKDIR, SYMLINK, MKNOD */
0913 bool
0914 nfs3svc_encode_createres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0915 {
0916     struct nfsd3_diropres *resp = rqstp->rq_resp;
0917 
0918     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
0919         return false;
0920     switch (resp->status) {
0921     case nfs_ok:
0922         if (!svcxdr_encode_post_op_fh3(xdr, &resp->fh))
0923             return false;
0924         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
0925             return false;
0926         if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh))
0927             return false;
0928         break;
0929     default:
0930         if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->dirfh))
0931             return false;
0932     }
0933 
0934     return true;
0935 }
0936 
0937 /* RENAME */
0938 bool
0939 nfs3svc_encode_renameres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0940 {
0941     struct nfsd3_renameres *resp = rqstp->rq_resp;
0942 
0943     return svcxdr_encode_nfsstat3(xdr, resp->status) &&
0944         svcxdr_encode_wcc_data(rqstp, xdr, &resp->ffh) &&
0945         svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh);
0946 }
0947 
0948 /* LINK */
0949 bool
0950 nfs3svc_encode_linkres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0951 {
0952     struct nfsd3_linkres *resp = rqstp->rq_resp;
0953 
0954     return svcxdr_encode_nfsstat3(xdr, resp->status) &&
0955         svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh) &&
0956         svcxdr_encode_wcc_data(rqstp, xdr, &resp->tfh);
0957 }
0958 
0959 /* READDIR */
0960 bool
0961 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0962 {
0963     struct nfsd3_readdirres *resp = rqstp->rq_resp;
0964     struct xdr_buf *dirlist = &resp->dirlist;
0965 
0966     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
0967         return false;
0968     switch (resp->status) {
0969     case nfs_ok:
0970         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
0971             return false;
0972         if (!svcxdr_encode_cookieverf3(xdr, resp->verf))
0973             return false;
0974         xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len);
0975         /* no more entries */
0976         if (xdr_stream_encode_item_absent(xdr) < 0)
0977             return false;
0978         if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0)
0979             return false;
0980         break;
0981     default:
0982         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &resp->fh))
0983             return false;
0984     }
0985 
0986     return true;
0987 }
0988 
0989 static __be32
0990 compose_entry_fh(struct nfsd3_readdirres *cd, struct svc_fh *fhp,
0991          const char *name, int namlen, u64 ino)
0992 {
0993     struct svc_export   *exp;
0994     struct dentry       *dparent, *dchild;
0995     __be32 rv = nfserr_noent;
0996 
0997     dparent = cd->fh.fh_dentry;
0998     exp  = cd->fh.fh_export;
0999 
1000     if (isdotent(name, namlen)) {
1001         if (namlen == 2) {
1002             dchild = dget_parent(dparent);
1003             /*
1004              * Don't return filehandle for ".." if we're at
1005              * the filesystem or export root:
1006              */
1007             if (dchild == dparent)
1008                 goto out;
1009             if (dparent == exp->ex_path.dentry)
1010                 goto out;
1011         } else
1012             dchild = dget(dparent);
1013     } else
1014         dchild = lookup_positive_unlocked(name, dparent, namlen);
1015     if (IS_ERR(dchild))
1016         return rv;
1017     if (d_mountpoint(dchild))
1018         goto out;
1019     if (dchild->d_inode->i_ino != ino)
1020         goto out;
1021     rv = fh_compose(fhp, exp, dchild, &cd->fh);
1022 out:
1023     dput(dchild);
1024     return rv;
1025 }
1026 
1027 /**
1028  * nfs3svc_encode_cookie3 - Encode a directory offset cookie
1029  * @resp: readdir result context
1030  * @offset: offset cookie to encode
1031  *
1032  * The buffer space for the offset cookie has already been reserved
1033  * by svcxdr_encode_entry3_common().
1034  */
1035 void nfs3svc_encode_cookie3(struct nfsd3_readdirres *resp, u64 offset)
1036 {
1037     __be64 cookie = cpu_to_be64(offset);
1038 
1039     if (!resp->cookie_offset)
1040         return;
1041     write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie,
1042                    sizeof(cookie));
1043     resp->cookie_offset = 0;
1044 }
1045 
1046 static bool
1047 svcxdr_encode_entry3_common(struct nfsd3_readdirres *resp, const char *name,
1048                 int namlen, loff_t offset, u64 ino)
1049 {
1050     struct xdr_buf *dirlist = &resp->dirlist;
1051     struct xdr_stream *xdr = &resp->xdr;
1052 
1053     if (xdr_stream_encode_item_present(xdr) < 0)
1054         return false;
1055     /* fileid */
1056     if (xdr_stream_encode_u64(xdr, ino) < 0)
1057         return false;
1058     /* name */
1059     if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS3_MAXNAMLEN)) < 0)
1060         return false;
1061     /* cookie */
1062     resp->cookie_offset = dirlist->len;
1063     if (xdr_stream_encode_u64(xdr, OFFSET_MAX) < 0)
1064         return false;
1065 
1066     return true;
1067 }
1068 
1069 /**
1070  * nfs3svc_encode_entry3 - encode one NFSv3 READDIR entry
1071  * @data: directory context
1072  * @name: name of the object to be encoded
1073  * @namlen: length of that name, in bytes
1074  * @offset: the offset of the previous entry
1075  * @ino: the fileid of this entry
1076  * @d_type: unused
1077  *
1078  * Return values:
1079  *   %0: Entry was successfully encoded.
1080  *   %-EINVAL: An encoding problem occured, secondary status code in resp->common.err
1081  *
1082  * On exit, the following fields are updated:
1083  *   - resp->xdr
1084  *   - resp->common.err
1085  *   - resp->cookie_offset
1086  */
1087 int nfs3svc_encode_entry3(void *data, const char *name, int namlen,
1088               loff_t offset, u64 ino, unsigned int d_type)
1089 {
1090     struct readdir_cd *ccd = data;
1091     struct nfsd3_readdirres *resp = container_of(ccd,
1092                              struct nfsd3_readdirres,
1093                              common);
1094     unsigned int starting_length = resp->dirlist.len;
1095 
1096     /* The offset cookie for the previous entry */
1097     nfs3svc_encode_cookie3(resp, offset);
1098 
1099     if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino))
1100         goto out_toosmall;
1101 
1102     xdr_commit_encode(&resp->xdr);
1103     resp->common.err = nfs_ok;
1104     return 0;
1105 
1106 out_toosmall:
1107     resp->cookie_offset = 0;
1108     resp->common.err = nfserr_toosmall;
1109     resp->dirlist.len = starting_length;
1110     return -EINVAL;
1111 }
1112 
1113 static bool
1114 svcxdr_encode_entry3_plus(struct nfsd3_readdirres *resp, const char *name,
1115               int namlen, u64 ino)
1116 {
1117     struct xdr_stream *xdr = &resp->xdr;
1118     struct svc_fh *fhp = &resp->scratch;
1119     bool result;
1120 
1121     result = false;
1122     fh_init(fhp, NFS3_FHSIZE);
1123     if (compose_entry_fh(resp, fhp, name, namlen, ino) != nfs_ok)
1124         goto out_noattrs;
1125 
1126     if (!svcxdr_encode_post_op_attr(resp->rqstp, xdr, fhp))
1127         goto out;
1128     if (!svcxdr_encode_post_op_fh3(xdr, fhp))
1129         goto out;
1130     result = true;
1131 
1132 out:
1133     fh_put(fhp);
1134     return result;
1135 
1136 out_noattrs:
1137     if (xdr_stream_encode_item_absent(xdr) < 0)
1138         return false;
1139     if (xdr_stream_encode_item_absent(xdr) < 0)
1140         return false;
1141     return true;
1142 }
1143 
1144 /**
1145  * nfs3svc_encode_entryplus3 - encode one NFSv3 READDIRPLUS entry
1146  * @data: directory context
1147  * @name: name of the object to be encoded
1148  * @namlen: length of that name, in bytes
1149  * @offset: the offset of the previous entry
1150  * @ino: the fileid of this entry
1151  * @d_type: unused
1152  *
1153  * Return values:
1154  *   %0: Entry was successfully encoded.
1155  *   %-EINVAL: An encoding problem occured, secondary status code in resp->common.err
1156  *
1157  * On exit, the following fields are updated:
1158  *   - resp->xdr
1159  *   - resp->common.err
1160  *   - resp->cookie_offset
1161  */
1162 int nfs3svc_encode_entryplus3(void *data, const char *name, int namlen,
1163                   loff_t offset, u64 ino, unsigned int d_type)
1164 {
1165     struct readdir_cd *ccd = data;
1166     struct nfsd3_readdirres *resp = container_of(ccd,
1167                              struct nfsd3_readdirres,
1168                              common);
1169     unsigned int starting_length = resp->dirlist.len;
1170 
1171     /* The offset cookie for the previous entry */
1172     nfs3svc_encode_cookie3(resp, offset);
1173 
1174     if (!svcxdr_encode_entry3_common(resp, name, namlen, offset, ino))
1175         goto out_toosmall;
1176     if (!svcxdr_encode_entry3_plus(resp, name, namlen, ino))
1177         goto out_toosmall;
1178 
1179     xdr_commit_encode(&resp->xdr);
1180     resp->common.err = nfs_ok;
1181     return 0;
1182 
1183 out_toosmall:
1184     resp->cookie_offset = 0;
1185     resp->common.err = nfserr_toosmall;
1186     resp->dirlist.len = starting_length;
1187     return -EINVAL;
1188 }
1189 
1190 static bool
1191 svcxdr_encode_fsstat3resok(struct xdr_stream *xdr,
1192                const struct nfsd3_fsstatres *resp)
1193 {
1194     const struct kstatfs *s = &resp->stats;
1195     u64 bs = s->f_bsize;
1196     __be32 *p;
1197 
1198     p = xdr_reserve_space(xdr, XDR_UNIT * 13);
1199     if (!p)
1200         return false;
1201     p = xdr_encode_hyper(p, bs * s->f_blocks);  /* total bytes */
1202     p = xdr_encode_hyper(p, bs * s->f_bfree);   /* free bytes */
1203     p = xdr_encode_hyper(p, bs * s->f_bavail);  /* user available bytes */
1204     p = xdr_encode_hyper(p, s->f_files);        /* total inodes */
1205     p = xdr_encode_hyper(p, s->f_ffree);        /* free inodes */
1206     p = xdr_encode_hyper(p, s->f_ffree);        /* user available inodes */
1207     *p = cpu_to_be32(resp->invarsec);       /* mean unchanged time */
1208 
1209     return true;
1210 }
1211 
1212 /* FSSTAT */
1213 bool
1214 nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
1215 {
1216     struct nfsd3_fsstatres *resp = rqstp->rq_resp;
1217 
1218     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
1219         return false;
1220     switch (resp->status) {
1221     case nfs_ok:
1222         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
1223             return false;
1224         if (!svcxdr_encode_fsstat3resok(xdr, resp))
1225             return false;
1226         break;
1227     default:
1228         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
1229             return false;
1230     }
1231 
1232     return true;
1233 }
1234 
1235 static bool
1236 svcxdr_encode_fsinfo3resok(struct xdr_stream *xdr,
1237                const struct nfsd3_fsinfores *resp)
1238 {
1239     __be32 *p;
1240 
1241     p = xdr_reserve_space(xdr, XDR_UNIT * 12);
1242     if (!p)
1243         return false;
1244     *p++ = cpu_to_be32(resp->f_rtmax);
1245     *p++ = cpu_to_be32(resp->f_rtpref);
1246     *p++ = cpu_to_be32(resp->f_rtmult);
1247     *p++ = cpu_to_be32(resp->f_wtmax);
1248     *p++ = cpu_to_be32(resp->f_wtpref);
1249     *p++ = cpu_to_be32(resp->f_wtmult);
1250     *p++ = cpu_to_be32(resp->f_dtpref);
1251     p = xdr_encode_hyper(p, resp->f_maxfilesize);
1252     p = encode_nfstime3(p, &nfs3svc_time_delta);
1253     *p = cpu_to_be32(resp->f_properties);
1254 
1255     return true;
1256 }
1257 
1258 /* FSINFO */
1259 bool
1260 nfs3svc_encode_fsinfores(struct svc_rqst *rqstp, struct xdr_stream *xdr)
1261 {
1262     struct nfsd3_fsinfores *resp = rqstp->rq_resp;
1263 
1264     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
1265         return false;
1266     switch (resp->status) {
1267     case nfs_ok:
1268         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
1269             return false;
1270         if (!svcxdr_encode_fsinfo3resok(xdr, resp))
1271             return false;
1272         break;
1273     default:
1274         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
1275             return false;
1276     }
1277 
1278     return true;
1279 }
1280 
1281 static bool
1282 svcxdr_encode_pathconf3resok(struct xdr_stream *xdr,
1283                  const struct nfsd3_pathconfres *resp)
1284 {
1285     __be32 *p;
1286 
1287     p = xdr_reserve_space(xdr, XDR_UNIT * 6);
1288     if (!p)
1289         return false;
1290     *p++ = cpu_to_be32(resp->p_link_max);
1291     *p++ = cpu_to_be32(resp->p_name_max);
1292     p = xdr_encode_bool(p, resp->p_no_trunc);
1293     p = xdr_encode_bool(p, resp->p_chown_restricted);
1294     p = xdr_encode_bool(p, resp->p_case_insensitive);
1295     xdr_encode_bool(p, resp->p_case_preserving);
1296 
1297     return true;
1298 }
1299 
1300 /* PATHCONF */
1301 bool
1302 nfs3svc_encode_pathconfres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
1303 {
1304     struct nfsd3_pathconfres *resp = rqstp->rq_resp;
1305 
1306     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
1307         return false;
1308     switch (resp->status) {
1309     case nfs_ok:
1310         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
1311             return false;
1312         if (!svcxdr_encode_pathconf3resok(xdr, resp))
1313             return false;
1314         break;
1315     default:
1316         if (!svcxdr_encode_post_op_attr(rqstp, xdr, &nfs3svc_null_fh))
1317             return false;
1318     }
1319 
1320     return true;
1321 }
1322 
1323 /* COMMIT */
1324 bool
1325 nfs3svc_encode_commitres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
1326 {
1327     struct nfsd3_commitres *resp = rqstp->rq_resp;
1328 
1329     if (!svcxdr_encode_nfsstat3(xdr, resp->status))
1330         return false;
1331     switch (resp->status) {
1332     case nfs_ok:
1333         if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh))
1334             return false;
1335         if (!svcxdr_encode_writeverf3(xdr, resp->verf))
1336             return false;
1337         break;
1338     default:
1339         if (!svcxdr_encode_wcc_data(rqstp, xdr, &resp->fh))
1340             return false;
1341     }
1342 
1343     return true;
1344 }
1345 
1346 /*
1347  * XDR release functions
1348  */
1349 void
1350 nfs3svc_release_fhandle(struct svc_rqst *rqstp)
1351 {
1352     struct nfsd3_attrstat *resp = rqstp->rq_resp;
1353 
1354     fh_put(&resp->fh);
1355 }
1356 
1357 void
1358 nfs3svc_release_fhandle2(struct svc_rqst *rqstp)
1359 {
1360     struct nfsd3_fhandle_pair *resp = rqstp->rq_resp;
1361 
1362     fh_put(&resp->fh1);
1363     fh_put(&resp->fh2);
1364 }