linux/fs/nfsd/nfsxdr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * XDR support for nfsd
   4 *
   5 * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
   6 */
   7
   8#include "vfs.h"
   9#include "xdr.h"
  10#include "auth.h"
  11
  12/*
  13 * Mapping of S_IF* types to NFS file types
  14 */
  15static const u32 nfs_ftypes[] = {
  16        NFNON,  NFCHR,  NFCHR, NFBAD,
  17        NFDIR,  NFBAD,  NFBLK, NFBAD,
  18        NFREG,  NFBAD,  NFLNK, NFBAD,
  19        NFSOCK, NFBAD,  NFLNK, NFBAD,
  20};
  21
  22
  23/*
  24 * Basic NFSv2 data types (RFC 1094 Section 2.3)
  25 */
  26
  27/**
  28 * svcxdr_encode_stat - Encode an NFSv2 status code
  29 * @xdr: XDR stream
  30 * @status: status value to encode
  31 *
  32 * Return values:
  33 *   %false: Send buffer space was exhausted
  34 *   %true: Success
  35 */
  36bool
  37svcxdr_encode_stat(struct xdr_stream *xdr, __be32 status)
  38{
  39        __be32 *p;
  40
  41        p = xdr_reserve_space(xdr, sizeof(status));
  42        if (!p)
  43                return false;
  44        *p = status;
  45
  46        return true;
  47}
  48
  49/**
  50 * svcxdr_decode_fhandle - Decode an NFSv2 file handle
  51 * @xdr: XDR stream positioned at an encoded NFSv2 FH
  52 * @fhp: OUT: filled-in server file handle
  53 *
  54 * Return values:
  55 *  %false: The encoded file handle was not valid
  56 *  %true: @fhp has been initialized
  57 */
  58bool
  59svcxdr_decode_fhandle(struct xdr_stream *xdr, struct svc_fh *fhp)
  60{
  61        __be32 *p;
  62
  63        p = xdr_inline_decode(xdr, NFS_FHSIZE);
  64        if (!p)
  65                return false;
  66        fh_init(fhp, NFS_FHSIZE);
  67        memcpy(&fhp->fh_handle.fh_raw, p, NFS_FHSIZE);
  68        fhp->fh_handle.fh_size = NFS_FHSIZE;
  69
  70        return true;
  71}
  72
  73static bool
  74svcxdr_encode_fhandle(struct xdr_stream *xdr, const struct svc_fh *fhp)
  75{
  76        __be32 *p;
  77
  78        p = xdr_reserve_space(xdr, NFS_FHSIZE);
  79        if (!p)
  80                return false;
  81        memcpy(p, &fhp->fh_handle.fh_raw, NFS_FHSIZE);
  82
  83        return true;
  84}
  85
  86static __be32 *
  87encode_timeval(__be32 *p, const struct timespec64 *time)
  88{
  89        *p++ = cpu_to_be32((u32)time->tv_sec);
  90        if (time->tv_nsec)
  91                *p++ = cpu_to_be32(time->tv_nsec / NSEC_PER_USEC);
  92        else
  93                *p++ = xdr_zero;
  94        return p;
  95}
  96
  97static bool
  98svcxdr_decode_filename(struct xdr_stream *xdr, char **name, unsigned int *len)
  99{
 100        u32 size, i;
 101        __be32 *p;
 102        char *c;
 103
 104        if (xdr_stream_decode_u32(xdr, &size) < 0)
 105                return false;
 106        if (size == 0 || size > NFS_MAXNAMLEN)
 107                return false;
 108        p = xdr_inline_decode(xdr, size);
 109        if (!p)
 110                return false;
 111
 112        *len = size;
 113        *name = (char *)p;
 114        for (i = 0, c = *name; i < size; i++, c++)
 115                if (*c == '\0' || *c == '/')
 116                        return false;
 117
 118        return true;
 119}
 120
 121static bool
 122svcxdr_decode_diropargs(struct xdr_stream *xdr, struct svc_fh *fhp,
 123                        char **name, unsigned int *len)
 124{
 125        return svcxdr_decode_fhandle(xdr, fhp) &&
 126                svcxdr_decode_filename(xdr, name, len);
 127}
 128
 129static bool
 130svcxdr_decode_sattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 131                    struct iattr *iap)
 132{
 133        u32 tmp1, tmp2;
 134        __be32 *p;
 135
 136        p = xdr_inline_decode(xdr, XDR_UNIT * 8);
 137        if (!p)
 138                return false;
 139
 140        iap->ia_valid = 0;
 141
 142        /*
 143         * Some Sun clients put 0xffff in the mode field when they
 144         * mean 0xffffffff.
 145         */
 146        tmp1 = be32_to_cpup(p++);
 147        if (tmp1 != (u32)-1 && tmp1 != 0xffff) {
 148                iap->ia_valid |= ATTR_MODE;
 149                iap->ia_mode = tmp1;
 150        }
 151
 152        tmp1 = be32_to_cpup(p++);
 153        if (tmp1 != (u32)-1) {
 154                iap->ia_uid = make_kuid(nfsd_user_namespace(rqstp), tmp1);
 155                if (uid_valid(iap->ia_uid))
 156                        iap->ia_valid |= ATTR_UID;
 157        }
 158
 159        tmp1 = be32_to_cpup(p++);
 160        if (tmp1 != (u32)-1) {
 161                iap->ia_gid = make_kgid(nfsd_user_namespace(rqstp), tmp1);
 162                if (gid_valid(iap->ia_gid))
 163                        iap->ia_valid |= ATTR_GID;
 164        }
 165
 166        tmp1 = be32_to_cpup(p++);
 167        if (tmp1 != (u32)-1) {
 168                iap->ia_valid |= ATTR_SIZE;
 169                iap->ia_size = tmp1;
 170        }
 171
 172        tmp1 = be32_to_cpup(p++);
 173        tmp2 = be32_to_cpup(p++);
 174        if (tmp1 != (u32)-1 && tmp2 != (u32)-1) {
 175                iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
 176                iap->ia_atime.tv_sec = tmp1;
 177                iap->ia_atime.tv_nsec = tmp2 * NSEC_PER_USEC;
 178        }
 179
 180        tmp1 = be32_to_cpup(p++);
 181        tmp2 = be32_to_cpup(p++);
 182        if (tmp1 != (u32)-1 && tmp2 != (u32)-1) {
 183                iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
 184                iap->ia_mtime.tv_sec = tmp1;
 185                iap->ia_mtime.tv_nsec = tmp2 * NSEC_PER_USEC;
 186                /*
 187                 * Passing the invalid value useconds=1000000 for mtime
 188                 * is a Sun convention for "set both mtime and atime to
 189                 * current server time".  It's needed to make permissions
 190                 * checks for the "touch" program across v2 mounts to
 191                 * Solaris and Irix boxes work correctly. See description of
 192                 * sattr in section 6.1 of "NFS Illustrated" by
 193                 * Brent Callaghan, Addison-Wesley, ISBN 0-201-32750-5
 194                 */
 195                if (tmp2 == 1000000)
 196                        iap->ia_valid &= ~(ATTR_ATIME_SET|ATTR_MTIME_SET);
 197        }
 198
 199        return true;
 200}
 201
 202/**
 203 * svcxdr_encode_fattr - Encode NFSv2 file attributes
 204 * @rqstp: Context of a completed RPC transaction
 205 * @xdr: XDR stream
 206 * @fhp: File handle to encode
 207 * @stat: Attributes to encode
 208 *
 209 * Return values:
 210 *   %false: Send buffer space was exhausted
 211 *   %true: Success
 212 */
 213bool
 214svcxdr_encode_fattr(struct svc_rqst *rqstp, struct xdr_stream *xdr,
 215                    const struct svc_fh *fhp, const struct kstat *stat)
 216{
 217        struct user_namespace *userns = nfsd_user_namespace(rqstp);
 218        struct dentry *dentry = fhp->fh_dentry;
 219        int type = stat->mode & S_IFMT;
 220        struct timespec64 time;
 221        __be32 *p;
 222        u32 fsid;
 223
 224        p = xdr_reserve_space(xdr, XDR_UNIT * 17);
 225        if (!p)
 226                return false;
 227
 228        *p++ = cpu_to_be32(nfs_ftypes[type >> 12]);
 229        *p++ = cpu_to_be32((u32)stat->mode);
 230        *p++ = cpu_to_be32((u32)stat->nlink);
 231        *p++ = cpu_to_be32((u32)from_kuid_munged(userns, stat->uid));
 232        *p++ = cpu_to_be32((u32)from_kgid_munged(userns, stat->gid));
 233
 234        if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN)
 235                *p++ = cpu_to_be32(NFS_MAXPATHLEN);
 236        else
 237                *p++ = cpu_to_be32((u32) stat->size);
 238        *p++ = cpu_to_be32((u32) stat->blksize);
 239        if (S_ISCHR(type) || S_ISBLK(type))
 240                *p++ = cpu_to_be32(new_encode_dev(stat->rdev));
 241        else
 242                *p++ = cpu_to_be32(0xffffffff);
 243        *p++ = cpu_to_be32((u32)stat->blocks);
 244
 245        switch (fsid_source(fhp)) {
 246        case FSIDSOURCE_FSID:
 247                fsid = (u32)fhp->fh_export->ex_fsid;
 248                break;
 249        case FSIDSOURCE_UUID:
 250                fsid = ((u32 *)fhp->fh_export->ex_uuid)[0];
 251                fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[1];
 252                fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[2];
 253                fsid ^= ((u32 *)fhp->fh_export->ex_uuid)[3];
 254                break;
 255        default:
 256                fsid = new_encode_dev(stat->dev);
 257                break;
 258        }
 259        *p++ = cpu_to_be32(fsid);
 260
 261        *p++ = cpu_to_be32((u32)stat->ino);
 262        p = encode_timeval(p, &stat->atime);
 263        time = stat->mtime;
 264        lease_get_mtime(d_inode(dentry), &time);
 265        p = encode_timeval(p, &time);
 266        encode_timeval(p, &stat->ctime);
 267
 268        return true;
 269}
 270
 271/*
 272 * XDR decode functions
 273 */
 274
 275bool
 276nfssvc_decode_fhandleargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 277{
 278        struct nfsd_fhandle *args = rqstp->rq_argp;
 279
 280        return svcxdr_decode_fhandle(xdr, &args->fh);
 281}
 282
 283bool
 284nfssvc_decode_sattrargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 285{
 286        struct nfsd_sattrargs *args = rqstp->rq_argp;
 287
 288        return svcxdr_decode_fhandle(xdr, &args->fh) &&
 289                svcxdr_decode_sattr(rqstp, xdr, &args->attrs);
 290}
 291
 292bool
 293nfssvc_decode_diropargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 294{
 295        struct nfsd_diropargs *args = rqstp->rq_argp;
 296
 297        return svcxdr_decode_diropargs(xdr, &args->fh, &args->name, &args->len);
 298}
 299
 300bool
 301nfssvc_decode_readargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 302{
 303        struct nfsd_readargs *args = rqstp->rq_argp;
 304        u32 totalcount;
 305
 306        if (!svcxdr_decode_fhandle(xdr, &args->fh))
 307                return false;
 308        if (xdr_stream_decode_u32(xdr, &args->offset) < 0)
 309                return false;
 310        if (xdr_stream_decode_u32(xdr, &args->count) < 0)
 311                return false;
 312        /* totalcount is ignored */
 313        if (xdr_stream_decode_u32(xdr, &totalcount) < 0)
 314                return false;
 315
 316        return true;
 317}
 318
 319bool
 320nfssvc_decode_writeargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 321{
 322        struct nfsd_writeargs *args = rqstp->rq_argp;
 323        u32 beginoffset, totalcount;
 324
 325        if (!svcxdr_decode_fhandle(xdr, &args->fh))
 326                return false;
 327        /* beginoffset is ignored */
 328        if (xdr_stream_decode_u32(xdr, &beginoffset) < 0)
 329                return false;
 330        if (xdr_stream_decode_u32(xdr, &args->offset) < 0)
 331                return false;
 332        /* totalcount is ignored */
 333        if (xdr_stream_decode_u32(xdr, &totalcount) < 0)
 334                return false;
 335
 336        /* opaque data */
 337        if (xdr_stream_decode_u32(xdr, &args->len) < 0)
 338                return false;
 339        if (args->len > NFSSVC_MAXBLKSIZE_V2)
 340                return false;
 341        if (!xdr_stream_subsegment(xdr, &args->payload, args->len))
 342                return false;
 343
 344        return true;
 345}
 346
 347bool
 348nfssvc_decode_createargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 349{
 350        struct nfsd_createargs *args = rqstp->rq_argp;
 351
 352        return svcxdr_decode_diropargs(xdr, &args->fh,
 353                                       &args->name, &args->len) &&
 354                svcxdr_decode_sattr(rqstp, xdr, &args->attrs);
 355}
 356
 357bool
 358nfssvc_decode_renameargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 359{
 360        struct nfsd_renameargs *args = rqstp->rq_argp;
 361
 362        return svcxdr_decode_diropargs(xdr, &args->ffh,
 363                                       &args->fname, &args->flen) &&
 364                svcxdr_decode_diropargs(xdr, &args->tfh,
 365                                        &args->tname, &args->tlen);
 366}
 367
 368bool
 369nfssvc_decode_linkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 370{
 371        struct nfsd_linkargs *args = rqstp->rq_argp;
 372
 373        return svcxdr_decode_fhandle(xdr, &args->ffh) &&
 374                svcxdr_decode_diropargs(xdr, &args->tfh,
 375                                        &args->tname, &args->tlen);
 376}
 377
 378bool
 379nfssvc_decode_symlinkargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 380{
 381        struct nfsd_symlinkargs *args = rqstp->rq_argp;
 382        struct kvec *head = rqstp->rq_arg.head;
 383
 384        if (!svcxdr_decode_diropargs(xdr, &args->ffh, &args->fname, &args->flen))
 385                return false;
 386        if (xdr_stream_decode_u32(xdr, &args->tlen) < 0)
 387                return false;
 388        if (args->tlen == 0)
 389                return false;
 390
 391        args->first.iov_len = head->iov_len - xdr_stream_pos(xdr);
 392        args->first.iov_base = xdr_inline_decode(xdr, args->tlen);
 393        if (!args->first.iov_base)
 394                return false;
 395        return svcxdr_decode_sattr(rqstp, xdr, &args->attrs);
 396}
 397
 398bool
 399nfssvc_decode_readdirargs(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 400{
 401        struct nfsd_readdirargs *args = rqstp->rq_argp;
 402
 403        if (!svcxdr_decode_fhandle(xdr, &args->fh))
 404                return false;
 405        if (xdr_stream_decode_u32(xdr, &args->cookie) < 0)
 406                return false;
 407        if (xdr_stream_decode_u32(xdr, &args->count) < 0)
 408                return false;
 409
 410        return true;
 411}
 412
 413/*
 414 * XDR encode functions
 415 */
 416
 417bool
 418nfssvc_encode_statres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 419{
 420        struct nfsd_stat *resp = rqstp->rq_resp;
 421
 422        return svcxdr_encode_stat(xdr, resp->status);
 423}
 424
 425bool
 426nfssvc_encode_attrstatres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 427{
 428        struct nfsd_attrstat *resp = rqstp->rq_resp;
 429
 430        if (!svcxdr_encode_stat(xdr, resp->status))
 431                return false;
 432        switch (resp->status) {
 433        case nfs_ok:
 434                if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
 435                        return false;
 436                break;
 437        }
 438
 439        return true;
 440}
 441
 442bool
 443nfssvc_encode_diropres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 444{
 445        struct nfsd_diropres *resp = rqstp->rq_resp;
 446
 447        if (!svcxdr_encode_stat(xdr, resp->status))
 448                return false;
 449        switch (resp->status) {
 450        case nfs_ok:
 451                if (!svcxdr_encode_fhandle(xdr, &resp->fh))
 452                        return false;
 453                if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
 454                        return false;
 455                break;
 456        }
 457
 458        return true;
 459}
 460
 461bool
 462nfssvc_encode_readlinkres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 463{
 464        struct nfsd_readlinkres *resp = rqstp->rq_resp;
 465        struct kvec *head = rqstp->rq_res.head;
 466
 467        if (!svcxdr_encode_stat(xdr, resp->status))
 468                return false;
 469        switch (resp->status) {
 470        case nfs_ok:
 471                if (xdr_stream_encode_u32(xdr, resp->len) < 0)
 472                        return false;
 473                xdr_write_pages(xdr, &resp->page, 0, resp->len);
 474                if (svc_encode_result_payload(rqstp, head->iov_len, resp->len) < 0)
 475                        return false;
 476                break;
 477        }
 478
 479        return true;
 480}
 481
 482bool
 483nfssvc_encode_readres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 484{
 485        struct nfsd_readres *resp = rqstp->rq_resp;
 486        struct kvec *head = rqstp->rq_res.head;
 487
 488        if (!svcxdr_encode_stat(xdr, resp->status))
 489                return false;
 490        switch (resp->status) {
 491        case nfs_ok:
 492                if (!svcxdr_encode_fattr(rqstp, xdr, &resp->fh, &resp->stat))
 493                        return false;
 494                if (xdr_stream_encode_u32(xdr, resp->count) < 0)
 495                        return false;
 496                xdr_write_pages(xdr, resp->pages, rqstp->rq_res.page_base,
 497                                resp->count);
 498                if (svc_encode_result_payload(rqstp, head->iov_len, resp->count) < 0)
 499                        return false;
 500                break;
 501        }
 502
 503        return true;
 504}
 505
 506bool
 507nfssvc_encode_readdirres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 508{
 509        struct nfsd_readdirres *resp = rqstp->rq_resp;
 510        struct xdr_buf *dirlist = &resp->dirlist;
 511
 512        if (!svcxdr_encode_stat(xdr, resp->status))
 513                return false;
 514        switch (resp->status) {
 515        case nfs_ok:
 516                xdr_write_pages(xdr, dirlist->pages, 0, dirlist->len);
 517                /* no more entries */
 518                if (xdr_stream_encode_item_absent(xdr) < 0)
 519                        return false;
 520                if (xdr_stream_encode_bool(xdr, resp->common.err == nfserr_eof) < 0)
 521                        return false;
 522                break;
 523        }
 524
 525        return true;
 526}
 527
 528bool
 529nfssvc_encode_statfsres(struct svc_rqst *rqstp, struct xdr_stream *xdr)
 530{
 531        struct nfsd_statfsres *resp = rqstp->rq_resp;
 532        struct kstatfs  *stat = &resp->stats;
 533        __be32 *p;
 534
 535        if (!svcxdr_encode_stat(xdr, resp->status))
 536                return false;
 537        switch (resp->status) {
 538        case nfs_ok:
 539                p = xdr_reserve_space(xdr, XDR_UNIT * 5);
 540                if (!p)
 541                        return false;
 542                *p++ = cpu_to_be32(NFSSVC_MAXBLKSIZE_V2);
 543                *p++ = cpu_to_be32(stat->f_bsize);
 544                *p++ = cpu_to_be32(stat->f_blocks);
 545                *p++ = cpu_to_be32(stat->f_bfree);
 546                *p = cpu_to_be32(stat->f_bavail);
 547                break;
 548        }
 549
 550        return true;
 551}
 552
 553/**
 554 * nfssvc_encode_nfscookie - Encode a directory offset cookie
 555 * @resp: readdir result context
 556 * @offset: offset cookie to encode
 557 *
 558 * The buffer space for the offset cookie has already been reserved
 559 * by svcxdr_encode_entry_common().
 560 */
 561void nfssvc_encode_nfscookie(struct nfsd_readdirres *resp, u32 offset)
 562{
 563        __be32 cookie = cpu_to_be32(offset);
 564
 565        if (!resp->cookie_offset)
 566                return;
 567
 568        write_bytes_to_xdr_buf(&resp->dirlist, resp->cookie_offset, &cookie,
 569                               sizeof(cookie));
 570        resp->cookie_offset = 0;
 571}
 572
 573static bool
 574svcxdr_encode_entry_common(struct nfsd_readdirres *resp, const char *name,
 575                           int namlen, loff_t offset, u64 ino)
 576{
 577        struct xdr_buf *dirlist = &resp->dirlist;
 578        struct xdr_stream *xdr = &resp->xdr;
 579
 580        if (xdr_stream_encode_item_present(xdr) < 0)
 581                return false;
 582        /* fileid */
 583        if (xdr_stream_encode_u32(xdr, (u32)ino) < 0)
 584                return false;
 585        /* name */
 586        if (xdr_stream_encode_opaque(xdr, name, min(namlen, NFS2_MAXNAMLEN)) < 0)
 587                return false;
 588        /* cookie */
 589        resp->cookie_offset = dirlist->len;
 590        if (xdr_stream_encode_u32(xdr, ~0U) < 0)
 591                return false;
 592
 593        return true;
 594}
 595
 596/**
 597 * nfssvc_encode_entry - encode one NFSv2 READDIR entry
 598 * @data: directory context
 599 * @name: name of the object to be encoded
 600 * @namlen: length of that name, in bytes
 601 * @offset: the offset of the previous entry
 602 * @ino: the fileid of this entry
 603 * @d_type: unused
 604 *
 605 * Return values:
 606 *   %0: Entry was successfully encoded.
 607 *   %-EINVAL: An encoding problem occured, secondary status code in resp->common.err
 608 *
 609 * On exit, the following fields are updated:
 610 *   - resp->xdr
 611 *   - resp->common.err
 612 *   - resp->cookie_offset
 613 */
 614int nfssvc_encode_entry(void *data, const char *name, int namlen,
 615                        loff_t offset, u64 ino, unsigned int d_type)
 616{
 617        struct readdir_cd *ccd = data;
 618        struct nfsd_readdirres *resp = container_of(ccd,
 619                                                    struct nfsd_readdirres,
 620                                                    common);
 621        unsigned int starting_length = resp->dirlist.len;
 622
 623        /* The offset cookie for the previous entry */
 624        nfssvc_encode_nfscookie(resp, offset);
 625
 626        if (!svcxdr_encode_entry_common(resp, name, namlen, offset, ino))
 627                goto out_toosmall;
 628
 629        xdr_commit_encode(&resp->xdr);
 630        resp->common.err = nfs_ok;
 631        return 0;
 632
 633out_toosmall:
 634        resp->cookie_offset = 0;
 635        resp->common.err = nfserr_toosmall;
 636        resp->dirlist.len = starting_length;
 637        return -EINVAL;
 638}
 639
 640/*
 641 * XDR release functions
 642 */
 643void nfssvc_release_attrstat(struct svc_rqst *rqstp)
 644{
 645        struct nfsd_attrstat *resp = rqstp->rq_resp;
 646
 647        fh_put(&resp->fh);
 648}
 649
 650void nfssvc_release_diropres(struct svc_rqst *rqstp)
 651{
 652        struct nfsd_diropres *resp = rqstp->rq_resp;
 653
 654        fh_put(&resp->fh);
 655}
 656
 657void nfssvc_release_readres(struct svc_rqst *rqstp)
 658{
 659        struct nfsd_readres *resp = rqstp->rq_resp;
 660
 661        fh_put(&resp->fh);
 662}
 663