Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * XDR support for nfsd
0004  *
0005  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
0006  */
0007 
0008 #include "vfs.h"
0009 #include "xdr.h"
0010 #include "auth.h"
0011 
0012 /*
0013  * Mapping of S_IF* types to NFS file types
0014  */
0015 static const u32 nfs_ftypes[] = {
0016     NFNON,  NFCHR,  NFCHR, NFBAD,
0017     NFDIR,  NFBAD,  NFBLK, NFBAD,
0018     NFREG,  NFBAD,  NFLNK, NFBAD,
0019     NFSOCK, NFBAD,  NFLNK, NFBAD,
0020 };
0021 
0022 
0023 /*
0024  * Basic NFSv2 data types (RFC 1094 Section 2.3)
0025  */
0026 
0027 /**
0028  * svcxdr_encode_stat - Encode an NFSv2 status code
0029  * @xdr: XDR stream
0030  * @status: status value to encode
0031  *
0032  * Return values:
0033  *   %false: Send buffer space was exhausted
0034  *   %true: Success
0035  */
0036 bool
0037 svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status)
0038 {
0039     __be32 *p;
0040 
0041     p = xdr_reserve_space(xdr, sizeof(status));
0042     if (!p)
0043         return false;
0044     *p = status;
0045 
0046     return true;
0047 }
0048 
0049 /**
0050  * svcxdr_decode_fhandle - Decode an NFSv2 file handle
0051  * @xdr: XDR stream positioned at an encoded NFSv2 FH
0052  * @fhp: OUT: filled-in server file handle
0053  *
0054  * Return values:
0055  *  %false: The encoded file handle was not valid
0056  *  %true: @fhp has been initialized
0057  */
0058 bool
0059 svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp)
0060 {
0061     __be32 *p;
0062 
0063     p = xdr_inline_decode(xdr, NFS_FHSIZE);
0064     if (!p)
0065         return false;
0066     fh_init(fhp, NFS_FHSIZE);
0067     memcpy(&fhp->fh_handle.fh_raw, p, NFS_FHSIZE);
0068     fhp->fh_handle.fh_size = NFS_FHSIZE;
0069 
0070     return true;
0071 }
0072 
0073 static bool
0074 svcxdr_encode_fhandle(struct xdr_stream *xdr, const struct svc_fh *fhp)
0075 {
0076     __be32 *p;
0077 
0078     p = xdr_reserve_space(xdr, NFS_FHSIZE);
0079     if (!p)
0080         return false;
0081     memcpy(p, &fhp->fh_handle.fh_raw, NFS_FHSIZE);
0082 
0083     return true;
0084 }
0085 
0086 static __be32 *
0087 encode_timeval(__be32 *p, const struct timespec64 *time)
0088 {
0089     *p++ = cpu_to_be32((u32)time->tv_sec);
0090     if (time->tv_nsec)
0091         *p++ = cpu_to_be32(time->tv_nsec / NSEC_PER_USEC);
0092     else
0093         *p++ = xdr_zero;
0094     return p;
0095 }
0096 
0097 static bool
0098 svcxdr_decode_filename(struct xdr_stream *xdr, char **name, unsigned int *len)
0099 {
0100     u32 size, i;
0101     __be32 *p;
0102     char *c;
0103 
0104     if (xdr_stream_decode_u32(xdr, &size) < 0)
0105         return false;
0106     if (size == 0 || size > NFS_MAXNAMLEN)
0107         return false;
0108     p = xdr_inline_decode(xdr, size);
0109     if (!p)
0110         return false;
0111 
0112     *len = size;
0113     *name = (char *)p;
0114     for (i = 0, c = *name; i < size; i++, c++)
0115         if (*c == '\0' || *c == '/')
0116             return false;
0117 
0118     return true;
0119 }
0120 
0121 static bool
0122 svcxdr_decode_diropargs(struct xdr_stream *xdr, struct svc_fh *fhp,
0123             char **name, unsigned int *len)
0124 {
0125     return svcxdr_decode_fhandle(xdr, fhp) &&
0126         svcxdr_decode_filename(xdr, name, len);
0127 }
0128 
0129 static bool
0130 svcxdr_decode_sattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
0131             struct iattr *iap)
0132 {
0133     u32 tmp1, tmp2;
0134     __be32 *p;
0135 
0136     p = xdr_inline_decode(xdr, XDR_UNIT * 8);
0137     if (!p)
0138         return false;
0139 
0140     iap->ia_valid = 0;
0141 
0142     /*
0143      * Some Sun clients put 0xffff in the mode field when they
0144      * mean 0xffffffff.
0145      */
0146     tmp1 = be32_to_cpup(p++);
0147     if (tmp1 != (u32)-1 && tmp1 != 0xffff) {
0148         iap->ia_valid |= ATTR_MODE;
0149         iap->ia_mode = tmp1;
0150     }
0151 
0152     tmp1 = be32_to_cpup(p++);
0153     if (tmp1 != (u32)-1) {
0154         iap->ia_uid = make_kuid(nfsd_user_namespace(rqstp), tmp1);
0155         if (uid_valid(iap->ia_uid))
0156             iap->ia_valid |= ATTR_UID;
0157     }
0158 
0159     tmp1 = be32_to_cpup(p++);
0160     if (tmp1 != (u32)-1) {
0161         iap->ia_gid = make_kgid(nfsd_user_namespace(rqstp), tmp1);
0162         if (gid_valid(iap->ia_gid))
0163             iap->ia_valid |= ATTR_GID;
0164     }
0165 
0166     tmp1 = be32_to_cpup(p++);
0167     if (tmp1 != (u32)-1) {
0168         iap->ia_valid |= ATTR_SIZE;
0169         iap->ia_size = tmp1;
0170     }
0171 
0172     tmp1 = be32_to_cpup(p++);
0173     tmp2 = be32_to_cpup(p++);
0174     if (tmp1 != (u32)-1 && tmp2 != (u32)-1) {
0175         iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
0176         iap->ia_atime.tv_sec = tmp1;
0177         iap->ia_atime.tv_nsec = tmp2 * NSEC_PER_USEC;
0178     }
0179 
0180     tmp1 = be32_to_cpup(p++);
0181     tmp2 = be32_to_cpup(p++);
0182     if (tmp1 != (u32)-1 && tmp2 != (u32)-1) {
0183         iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
0184         iap->ia_mtime.tv_sec = tmp1;
0185         iap->ia_mtime.tv_nsec = tmp2 * NSEC_PER_USEC;
0186         /*
0187          * Passing the invalid value useconds=1000000 for mtime
0188          * is a Sun convention for "set both mtime and atime to
0189          * current server time".  It's needed to make permissions
0190          * checks for the "touch" program across v2 mounts to
0191          * Solaris and Irix boxes work correctly. See description of
0192          * sattr in section 6.1 of "NFS Illustrated" by
0193          * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
0194          */
0195         if (tmp2 == 1000000)
0196             iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET);
0197     }
0198 
0199     return true;
0200 }
0201 
0202 /**
0203  * svcxdr_encode_fattr - Encode NFSv2 file attributes
0204  * @rqstp: Context of a completed RPC transaction
0205  * @xdr: XDR stream
0206  * @fhp: File handle to encode
0207  * @stat: Attributes to encode
0208  *
0209  * Return values:
0210  *   %false: Send buffer space was exhausted
0211  *   %true: Success
0212  */
0213 bool
0214 svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
0215             const struct svc_fh *fhp, const struct kstat *stat)
0216 {
0217     struct user_namespace *userns = nfsd_user_namespace(rqstp);
0218     struct dentry *dentry = fhp->fh_dentry;
0219     int type = stat->mode & S_IFMT;
0220     struct timespec64 time;
0221     __be32 *p;
0222     u32 fsid;
0223 
0224     p = xdr_reserve_space(xdr, XDR_UNIT * 17);
0225     if (!p)
0226         return false;
0227 
0228     *p++ = cpu_to_be32(nfs_ftypes[type >> 12]);
0229     *p++ = cpu_to_be32((u32)stat->mode);
0230     *p++ = cpu_to_be32((u32)stat->nlink);
0231     *p++ = cpu_to_be32((u32)from_kuid_munged(userns, stat->uid));
0232     *p++ = cpu_to_be32((u32)from_kgid_munged(userns, stat->gid));
0233 
0234     if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN)
0235         *p++ = cpu_to_be32(NFS_MAXPATHLEN);
0236     else
0237         *p++ = cpu_to_be32((u32) stat->size);
0238     *p++ = cpu_to_be32((u32) stat->blksize);
0239     if (S_ISCHR(type) || S_ISBLK(type))
0240         *p++ = cpu_to_be32(new_encode_dev(stat->rdev));
0241     else
0242         *p++ = cpu_to_be32(0xffffffff);
0243     *p++ = cpu_to_be32((u32)stat->blocks);
0244 
0245     switch (fsid_source(fhp)) {
0246     case FSIDSOURCE_FSID:
0247         fsid = (u32)fhp->fh_export->ex_fsid;
0248         break;
0249     case FSIDSOURCE_UUID:
0250         fsid = ((u32 *)fhp->fh_export->ex_uuid)[0];
0251         fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[1];
0252         fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[2];
0253         fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[3];
0254         break;
0255     default:
0256         fsid = new_encode_dev(stat->dev);
0257         break;
0258     }
0259     *p++ = cpu_to_be32(fsid);
0260 
0261     *p++ = cpu_to_be32((u32)stat->ino);
0262     p = encode_timeval(p, &stat->atime);
0263     time = stat->mtime;
0264     lease_get_mtime(d_inode(dentry), &time);
0265     p = encode_timeval(p, &time);
0266     encode_timeval(p, &stat->ctime);
0267 
0268     return true;
0269 }
0270 
0271 /*
0272  * XDR decode functions
0273  */
0274 
0275 bool
0276 nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0277 {
0278     struct nfsd_fhandle *args = rqstp->rq_argp;
0279 
0280     return svcxdr_decode_fhandle(xdr, &args->fh);
0281 }
0282 
0283 bool
0284 nfssvc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0285 {
0286     struct nfsd_sattrargs *args = rqstp->rq_argp;
0287 
0288     return svcxdr_decode_fhandle(xdr, &args->fh) &&
0289         svcxdr_decode_sattr(rqstp, xdr, &args->attrs);
0290 }
0291 
0292 bool
0293 nfssvc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0294 {
0295     struct nfsd_diropargs *args = rqstp->rq_argp;
0296 
0297     return svcxdr_decode_diropargs(xdr, &args->fh, &args->name, &args->len);
0298 }
0299 
0300 bool
0301 nfssvc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0302 {
0303     struct nfsd_readargs *args = rqstp->rq_argp;
0304     u32 totalcount;
0305 
0306     if (!svcxdr_decode_fhandle(xdr, &args->fh))
0307         return false;
0308     if (xdr_stream_decode_u32(xdr, &args->offset) < 0)
0309         return false;
0310     if (xdr_stream_decode_u32(xdr, &args->count) < 0)
0311         return false;
0312     /* totalcount is ignored */
0313     if (xdr_stream_decode_u32(xdr, &totalcount) < 0)
0314         return false;
0315 
0316     return true;
0317 }
0318 
0319 bool
0320 nfssvc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0321 {
0322     struct nfsd_writeargs *args = rqstp->rq_argp;
0323     u32 beginoffset, totalcount;
0324 
0325     if (!svcxdr_decode_fhandle(xdr, &args->fh))
0326         return false;
0327     /* beginoffset is ignored */
0328     if (xdr_stream_decode_u32(xdr, &beginoffset) < 0)
0329         return false;
0330     if (xdr_stream_decode_u32(xdr, &args->offset) < 0)
0331         return false;
0332     /* totalcount is ignored */
0333     if (xdr_stream_decode_u32(xdr, &totalcount) < 0)
0334         return false;
0335 
0336     /* opaque data */
0337     if (xdr_stream_decode_u32(xdr, &args->len) < 0)
0338         return false;
0339     if (args->len > NFSSVC_MAXBLKSIZE_V2)
0340         return false;
0341     if (!xdr_stream_subsegment(xdr, &args->payload, args->len))
0342         return false;
0343 
0344     return true;
0345 }
0346 
0347 bool
0348 nfssvc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0349 {
0350     struct nfsd_createargs *args = rqstp->rq_argp;
0351 
0352     return svcxdr_decode_diropargs(xdr, &args->fh,
0353                        &args->name, &args->len) &&
0354         svcxdr_decode_sattr(rqstp, xdr, &args->attrs);
0355 }
0356 
0357 bool
0358 nfssvc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0359 {
0360     struct nfsd_renameargs *args = rqstp->rq_argp;
0361 
0362     return svcxdr_decode_diropargs(xdr, &args->ffh,
0363                        &args->fname, &args->flen) &&
0364         svcxdr_decode_diropargs(xdr, &args->tfh,
0365                     &args->tname, &args->tlen);
0366 }
0367 
0368 bool
0369 nfssvc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0370 {
0371     struct nfsd_linkargs *args = rqstp->rq_argp;
0372 
0373     return svcxdr_decode_fhandle(xdr, &args->ffh) &&
0374         svcxdr_decode_diropargs(xdr, &args->tfh,
0375                     &args->tname, &args->tlen);
0376 }
0377 
0378 bool
0379 nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0380 {
0381     struct nfsd_symlinkargs *args = rqstp->rq_argp;
0382     struct kvec *head = rqstp->rq_arg.head;
0383 
0384     if (!svcxdr_decode_diropargs(xdr, &args->ffh, &args->fname, &args->flen))
0385         return false;
0386     if (xdr_stream_decode_u32(xdr, &args->tlen) < 0)
0387         return false;
0388     if (args->tlen == 0)
0389         return false;
0390 
0391     args->first.iov_len = head->iov_len - xdr_stream_pos(xdr);
0392     args->first.iov_base = xdr_inline_decode(xdr, args->tlen);
0393     if (!args->first.iov_base)
0394         return false;
0395     return svcxdr_decode_sattr(rqstp, xdr, &args->attrs);
0396 }
0397 
0398 bool
0399 nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0400 {
0401     struct nfsd_readdirargs *args = rqstp->rq_argp;
0402 
0403     if (!svcxdr_decode_fhandle(xdr, &args->fh))
0404         return false;
0405     if (xdr_stream_decode_u32(xdr, &args->cookie) < 0)
0406         return false;
0407     if (xdr_stream_decode_u32(xdr, &args->count) < 0)
0408         return false;
0409 
0410     return true;
0411 }
0412 
0413 /*
0414  * XDR encode functions
0415  */
0416 
0417 bool
0418 nfssvc_encode_statres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0419 {
0420     struct nfsd_stat *resp = rqstp->rq_resp;
0421 
0422     return svcxdr_encode_stat(xdr, resp->status);
0423 }
0424 
0425 bool
0426 nfssvc_encode_attrstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0427 {
0428     struct nfsd_attrstat *resp = rqstp->rq_resp;
0429 
0430     if (!svcxdr_encode_stat(xdr, resp->status))
0431         return false;
0432     switch (resp->status) {
0433     case nfs_ok:
0434         if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
0435             return false;
0436         break;
0437     }
0438 
0439     return true;
0440 }
0441 
0442 bool
0443 nfssvc_encode_diropres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0444 {
0445     struct nfsd_diropres *resp = rqstp->rq_resp;
0446 
0447     if (!svcxdr_encode_stat(xdr, resp->status))
0448         return false;
0449     switch (resp->status) {
0450     case nfs_ok:
0451         if (!svcxdr_encode_fhandle(xdr, &resp->fh))
0452             return false;
0453         if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
0454             return false;
0455         break;
0456     }
0457 
0458     return true;
0459 }
0460 
0461 bool
0462 nfssvc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0463 {
0464     struct nfsd_readlinkres *resp = rqstp->rq_resp;
0465     struct kvec *head = rqstp->rq_res.head;
0466 
0467     if (!svcxdr_encode_stat(xdr, resp->status))
0468         return false;
0469     switch (resp->status) {
0470     case nfs_ok:
0471         if (xdr_stream_encode_u32(xdr, resp->len) < 0)
0472             return false;
0473         xdr_write_pages(xdr, &resp->page, 0, resp->len);
0474         if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0)
0475             return false;
0476         break;
0477     }
0478 
0479     return true;
0480 }
0481 
0482 bool
0483 nfssvc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0484 {
0485     struct nfsd_readres *resp = rqstp->rq_resp;
0486     struct kvec *head = rqstp->rq_res.head;
0487 
0488     if (!svcxdr_encode_stat(xdr, resp->status))
0489         return false;
0490     switch (resp->status) {
0491     case nfs_ok:
0492         if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
0493             return false;
0494         if (xdr_stream_encode_u32(xdr, resp->count) < 0)
0495             return false;
0496         xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base,
0497                 resp->count);
0498         if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0)
0499             return false;
0500         break;
0501     }
0502 
0503     return true;
0504 }
0505 
0506 bool
0507 nfssvc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0508 {
0509     struct nfsd_readdirres *resp = rqstp->rq_resp;
0510     struct xdr_buf *dirlist = &resp->dirlist;
0511 
0512     if (!svcxdr_encode_stat(xdr, resp->status))
0513         return false;
0514     switch (resp->status) {
0515     case nfs_ok:
0516         xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len);
0517         /* no more entries */
0518         if (xdr_stream_encode_item_absent(xdr) < 0)
0519             return false;
0520         if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0)
0521             return false;
0522         break;
0523     }
0524 
0525     return true;
0526 }
0527 
0528 bool
0529 nfssvc_encode_statfsres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
0530 {
0531     struct nfsd_statfsres *resp = rqstp->rq_resp;
0532     struct kstatfs  *stat = &resp->stats;
0533     __be32 *p;
0534 
0535     if (!svcxdr_encode_stat(xdr, resp->status))
0536         return false;
0537     switch (resp->status) {
0538     case nfs_ok:
0539         p = xdr_reserve_space(xdr, XDR_UNIT * 5);
0540         if (!p)
0541             return false;
0542         *p++ = cpu_to_be32(NFSSVC_MAXBLKSIZE_V2);
0543         *p++ = cpu_to_be32(stat->f_bsize);
0544         *p++ = cpu_to_be32(stat->f_blocks);
0545         *p++ = cpu_to_be32(stat->f_bfree);
0546         *p = cpu_to_be32(stat->f_bavail);
0547         break;
0548     }
0549 
0550     return true;
0551 }
0552 
0553 /**
0554  * nfssvc_encode_nfscookie - Encode a directory offset cookie
0555  * @resp: readdir result context
0556  * @offset: offset cookie to encode
0557  *
0558  * The buffer space for the offset cookie has already been reserved
0559  * by svcxdr_encode_entry_common().
0560  */
0561 void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset)
0562 {
0563     __be32 cookie = cpu_to_be32(offset);
0564 
0565     if (!resp->cookie_offset)
0566         return;
0567 
0568     write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie,
0569                    sizeof(cookie));
0570     resp->cookie_offset = 0;
0571 }
0572 
0573 static bool
0574 svcxdr_encode_entry_common(struct nfsd_readdirres *resp, const char *name,
0575                int namlen, loff_t offset, u64 ino)
0576 {
0577     struct xdr_buf *dirlist = &resp->dirlist;
0578     struct xdr_stream *xdr = &resp->xdr;
0579 
0580     if (xdr_stream_encode_item_present(xdr) < 0)
0581         return false;
0582     /* fileid */
0583     if (xdr_stream_encode_u32(xdr, (u32)ino) < 0)
0584         return false;
0585     /* name */
0586     if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS2_MAXNAMLEN)) < 0)
0587         return false;
0588     /* cookie */
0589     resp->cookie_offset = dirlist->len;
0590     if (xdr_stream_encode_u32(xdr, ~0U) < 0)
0591         return false;
0592 
0593     return true;
0594 }
0595 
0596 /**
0597  * nfssvc_encode_entry - encode one NFSv2 READDIR entry
0598  * @data: directory context
0599  * @name: name of the object to be encoded
0600  * @namlen: length of that name, in bytes
0601  * @offset: the offset of the previous entry
0602  * @ino: the fileid of this entry
0603  * @d_type: unused
0604  *
0605  * Return values:
0606  *   %0: Entry was successfully encoded.
0607  *   %-EINVAL: An encoding problem occured, secondary status code in resp->common.err
0608  *
0609  * On exit, the following fields are updated:
0610  *   - resp->xdr
0611  *   - resp->common.err
0612  *   - resp->cookie_offset
0613  */
0614 int nfssvc_encode_entry(void *data, const char *name, int namlen,
0615             loff_t offset, u64 ino, unsigned int d_type)
0616 {
0617     struct readdir_cd *ccd = data;
0618     struct nfsd_readdirres *resp = container_of(ccd,
0619                             struct nfsd_readdirres,
0620                             common);
0621     unsigned int starting_length = resp->dirlist.len;
0622 
0623     /* The offset cookie for the previous entry */
0624     nfssvc_encode_nfscookie(resp, offset);
0625 
0626     if (!svcxdr_encode_entry_common(resp, name, namlen, offset, ino))
0627         goto out_toosmall;
0628 
0629     xdr_commit_encode(&resp->xdr);
0630     resp->common.err = nfs_ok;
0631     return 0;
0632 
0633 out_toosmall:
0634     resp->cookie_offset = 0;
0635     resp->common.err = nfserr_toosmall;
0636     resp->dirlist.len = starting_length;
0637     return -EINVAL;
0638 }
0639 
0640 /*
0641  * XDR release functions
0642  */
0643 void nfssvc_release_attrstat(struct svc_rqst *rqstp)
0644 {
0645     struct nfsd_attrstat *resp = rqstp->rq_resp;
0646 
0647     fh_put(&resp->fh);
0648 }
0649 
0650 void nfssvc_release_diropres(struct svc_rqst *rqstp)
0651 {
0652     struct nfsd_diropres *resp = rqstp->rq_resp;
0653 
0654     fh_put(&resp->fh);
0655 }
0656 
0657 void nfssvc_release_readres(struct svc_rqst *rqstp)
0658 {
0659     struct nfsd_readres *resp = rqstp->rq_resp;
0660 
0661     fh_put(&resp->fh);
0662 }