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