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