linux/fs/nfsd/nfs3proc.c
<<
>>
Prefs
   1/*
   2 * Process version 3 NFS requests.
   3 *
   4 * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
   5 */
   6
   7#include <linux/fs.h>
   8#include <linux/ext2_fs.h>
   9#include <linux/magic.h>
  10
  11#include "cache.h"
  12#include "xdr3.h"
  13#include "vfs.h"
  14
  15#define NFSDDBG_FACILITY                NFSDDBG_PROC
  16
  17#define RETURN_STATUS(st)       { resp->status = (st); return (st); }
  18
  19static int      nfs3_ftypes[] = {
  20        0,                      /* NF3NON */
  21        S_IFREG,                /* NF3REG */
  22        S_IFDIR,                /* NF3DIR */
  23        S_IFBLK,                /* NF3BLK */
  24        S_IFCHR,                /* NF3CHR */
  25        S_IFLNK,                /* NF3LNK */
  26        S_IFSOCK,               /* NF3SOCK */
  27        S_IFIFO,                /* NF3FIFO */
  28};
  29
  30/*
  31 * NULL call.
  32 */
  33static __be32
  34nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
  35{
  36        return nfs_ok;
  37}
  38
  39/*
  40 * Get a file's attributes
  41 */
  42static __be32
  43nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
  44                                           struct nfsd3_attrstat *resp)
  45{
  46        __be32  nfserr;
  47
  48        dprintk("nfsd: GETATTR(3)  %s\n",
  49                SVCFH_fmt(&argp->fh));
  50
  51        fh_copy(&resp->fh, &argp->fh);
  52        nfserr = fh_verify(rqstp, &resp->fh, 0,
  53                        NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
  54        if (nfserr)
  55                RETURN_STATUS(nfserr);
  56
  57        nfserr = fh_getattr(&resp->fh, &resp->stat);
  58
  59        RETURN_STATUS(nfserr);
  60}
  61
  62/*
  63 * Set a file's attributes
  64 */
  65static __be32
  66nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
  67                                           struct nfsd3_attrstat  *resp)
  68{
  69        __be32  nfserr;
  70
  71        dprintk("nfsd: SETATTR(3)  %s\n",
  72                                SVCFH_fmt(&argp->fh));
  73
  74        fh_copy(&resp->fh, &argp->fh);
  75        nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
  76                              argp->check_guard, argp->guardtime);
  77        RETURN_STATUS(nfserr);
  78}
  79
  80/*
  81 * Look up a path name component
  82 */
  83static __be32
  84nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
  85                                          struct nfsd3_diropres  *resp)
  86{
  87        __be32  nfserr;
  88
  89        dprintk("nfsd: LOOKUP(3)   %s %.*s\n",
  90                                SVCFH_fmt(&argp->fh),
  91                                argp->len,
  92                                argp->name);
  93
  94        fh_copy(&resp->dirfh, &argp->fh);
  95        fh_init(&resp->fh, NFS3_FHSIZE);
  96
  97        nfserr = nfsd_lookup(rqstp, &resp->dirfh,
  98                                    argp->name,
  99                                    argp->len,
 100                                    &resp->fh);
 101        RETURN_STATUS(nfserr);
 102}
 103
 104/*
 105 * Check file access
 106 */
 107static __be32
 108nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
 109                                          struct nfsd3_accessres *resp)
 110{
 111        __be32  nfserr;
 112
 113        dprintk("nfsd: ACCESS(3)   %s 0x%x\n",
 114                                SVCFH_fmt(&argp->fh),
 115                                argp->access);
 116
 117        fh_copy(&resp->fh, &argp->fh);
 118        resp->access = argp->access;
 119        nfserr = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
 120        RETURN_STATUS(nfserr);
 121}
 122
 123/*
 124 * Read a symlink.
 125 */
 126static __be32
 127nfsd3_proc_readlink(struct svc_rqst *rqstp, struct nfsd3_readlinkargs *argp,
 128                                           struct nfsd3_readlinkres *resp)
 129{
 130        __be32 nfserr;
 131
 132        dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
 133
 134        /* Read the symlink. */
 135        fh_copy(&resp->fh, &argp->fh);
 136        resp->len = NFS3_MAXPATHLEN;
 137        nfserr = nfsd_readlink(rqstp, &resp->fh, argp->buffer, &resp->len);
 138        RETURN_STATUS(nfserr);
 139}
 140
 141/*
 142 * Read a portion of a file.
 143 */
 144static __be32
 145nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
 146                                        struct nfsd3_readres  *resp)
 147{
 148        __be32  nfserr;
 149        u32     max_blocksize = svc_max_payload(rqstp);
 150        unsigned long cnt = min(argp->count, max_blocksize);
 151
 152        dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
 153                                SVCFH_fmt(&argp->fh),
 154                                (unsigned long) argp->count,
 155                                (unsigned long long) argp->offset);
 156
 157        /* Obtain buffer pointer for payload.
 158         * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
 159         * + 1 (xdr opaque byte count) = 26
 160         */
 161        resp->count = cnt;
 162        svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
 163
 164        fh_copy(&resp->fh, &argp->fh);
 165        nfserr = nfsd_read(rqstp, &resp->fh,
 166                                  argp->offset,
 167                                  rqstp->rq_vec, argp->vlen,
 168                                  &resp->count);
 169        if (nfserr == 0) {
 170                struct inode    *inode = d_inode(resp->fh.fh_dentry);
 171                resp->eof = nfsd_eof_on_read(cnt, resp->count, argp->offset,
 172                                                        inode->i_size);
 173        }
 174
 175        RETURN_STATUS(nfserr);
 176}
 177
 178/*
 179 * Write data to a file
 180 */
 181static __be32
 182nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
 183                                         struct nfsd3_writeres  *resp)
 184{
 185        __be32  nfserr;
 186        unsigned long cnt = argp->len;
 187
 188        dprintk("nfsd: WRITE(3)    %s %d bytes at %Lu%s\n",
 189                                SVCFH_fmt(&argp->fh),
 190                                argp->len,
 191                                (unsigned long long) argp->offset,
 192                                argp->stable? " stable" : "");
 193
 194        fh_copy(&resp->fh, &argp->fh);
 195        resp->committed = argp->stable;
 196        nfserr = nfsd_write(rqstp, &resp->fh, NULL,
 197                                   argp->offset,
 198                                   rqstp->rq_vec, argp->vlen,
 199                                   &cnt,
 200                                   &resp->committed);
 201        resp->count = cnt;
 202        RETURN_STATUS(nfserr);
 203}
 204
 205/*
 206 * With NFSv3, CREATE processing is a lot easier than with NFSv2.
 207 * At least in theory; we'll see how it fares in practice when the
 208 * first reports about SunOS compatibility problems start to pour in...
 209 */
 210static __be32
 211nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
 212                                          struct nfsd3_diropres   *resp)
 213{
 214        svc_fh          *dirfhp, *newfhp = NULL;
 215        struct iattr    *attr;
 216        __be32          nfserr;
 217
 218        dprintk("nfsd: CREATE(3)   %s %.*s\n",
 219                                SVCFH_fmt(&argp->fh),
 220                                argp->len,
 221                                argp->name);
 222
 223        dirfhp = fh_copy(&resp->dirfh, &argp->fh);
 224        newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
 225        attr   = &argp->attrs;
 226
 227        /* Unfudge the mode bits */
 228        attr->ia_mode &= ~S_IFMT;
 229        if (!(attr->ia_valid & ATTR_MODE)) { 
 230                attr->ia_valid |= ATTR_MODE;
 231                attr->ia_mode = S_IFREG;
 232        } else {
 233                attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG;
 234        }
 235
 236        /* Now create the file and set attributes */
 237        nfserr = do_nfsd_create(rqstp, dirfhp, argp->name, argp->len,
 238                                attr, newfhp,
 239                                argp->createmode, (u32 *)argp->verf, NULL, NULL);
 240
 241        RETURN_STATUS(nfserr);
 242}
 243
 244/*
 245 * Make directory. This operation is not idempotent.
 246 */
 247static __be32
 248nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
 249                                         struct nfsd3_diropres   *resp)
 250{
 251        __be32  nfserr;
 252
 253        dprintk("nfsd: MKDIR(3)    %s %.*s\n",
 254                                SVCFH_fmt(&argp->fh),
 255                                argp->len,
 256                                argp->name);
 257
 258        argp->attrs.ia_valid &= ~ATTR_SIZE;
 259        fh_copy(&resp->dirfh, &argp->fh);
 260        fh_init(&resp->fh, NFS3_FHSIZE);
 261        nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
 262                                    &argp->attrs, S_IFDIR, 0, &resp->fh);
 263        fh_unlock(&resp->dirfh);
 264        RETURN_STATUS(nfserr);
 265}
 266
 267static __be32
 268nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
 269                                           struct nfsd3_diropres    *resp)
 270{
 271        __be32  nfserr;
 272
 273        dprintk("nfsd: SYMLINK(3)  %s %.*s -> %.*s\n",
 274                                SVCFH_fmt(&argp->ffh),
 275                                argp->flen, argp->fname,
 276                                argp->tlen, argp->tname);
 277
 278        fh_copy(&resp->dirfh, &argp->ffh);
 279        fh_init(&resp->fh, NFS3_FHSIZE);
 280        nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
 281                                                   argp->tname, &resp->fh);
 282        RETURN_STATUS(nfserr);
 283}
 284
 285/*
 286 * Make socket/fifo/device.
 287 */
 288static __be32
 289nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
 290                                         struct nfsd3_diropres  *resp)
 291{
 292        __be32  nfserr;
 293        int type;
 294        dev_t   rdev = 0;
 295
 296        dprintk("nfsd: MKNOD(3)    %s %.*s\n",
 297                                SVCFH_fmt(&argp->fh),
 298                                argp->len,
 299                                argp->name);
 300
 301        fh_copy(&resp->dirfh, &argp->fh);
 302        fh_init(&resp->fh, NFS3_FHSIZE);
 303
 304        if (argp->ftype == 0 || argp->ftype >= NF3BAD)
 305                RETURN_STATUS(nfserr_inval);
 306        if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
 307                rdev = MKDEV(argp->major, argp->minor);
 308                if (MAJOR(rdev) != argp->major ||
 309                    MINOR(rdev) != argp->minor)
 310                        RETURN_STATUS(nfserr_inval);
 311        } else
 312                if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
 313                        RETURN_STATUS(nfserr_inval);
 314
 315        type = nfs3_ftypes[argp->ftype];
 316        nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
 317                                    &argp->attrs, type, rdev, &resp->fh);
 318        fh_unlock(&resp->dirfh);
 319        RETURN_STATUS(nfserr);
 320}
 321
 322/*
 323 * Remove file/fifo/socket etc.
 324 */
 325static __be32
 326nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
 327                                          struct nfsd3_attrstat  *resp)
 328{
 329        __be32  nfserr;
 330
 331        dprintk("nfsd: REMOVE(3)   %s %.*s\n",
 332                                SVCFH_fmt(&argp->fh),
 333                                argp->len,
 334                                argp->name);
 335
 336        /* Unlink. -S_IFDIR means file must not be a directory */
 337        fh_copy(&resp->fh, &argp->fh);
 338        nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
 339        fh_unlock(&resp->fh);
 340        RETURN_STATUS(nfserr);
 341}
 342
 343/*
 344 * Remove a directory
 345 */
 346static __be32
 347nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
 348                                         struct nfsd3_attrstat  *resp)
 349{
 350        __be32  nfserr;
 351
 352        dprintk("nfsd: RMDIR(3)    %s %.*s\n",
 353                                SVCFH_fmt(&argp->fh),
 354                                argp->len,
 355                                argp->name);
 356
 357        fh_copy(&resp->fh, &argp->fh);
 358        nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
 359        fh_unlock(&resp->fh);
 360        RETURN_STATUS(nfserr);
 361}
 362
 363static __be32
 364nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
 365                                          struct nfsd3_renameres  *resp)
 366{
 367        __be32  nfserr;
 368
 369        dprintk("nfsd: RENAME(3)   %s %.*s ->\n",
 370                                SVCFH_fmt(&argp->ffh),
 371                                argp->flen,
 372                                argp->fname);
 373        dprintk("nfsd: -> %s %.*s\n",
 374                                SVCFH_fmt(&argp->tfh),
 375                                argp->tlen,
 376                                argp->tname);
 377
 378        fh_copy(&resp->ffh, &argp->ffh);
 379        fh_copy(&resp->tfh, &argp->tfh);
 380        nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
 381                                    &resp->tfh, argp->tname, argp->tlen);
 382        RETURN_STATUS(nfserr);
 383}
 384
 385static __be32
 386nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
 387                                        struct nfsd3_linkres  *resp)
 388{
 389        __be32  nfserr;
 390
 391        dprintk("nfsd: LINK(3)     %s ->\n",
 392                                SVCFH_fmt(&argp->ffh));
 393        dprintk("nfsd:   -> %s %.*s\n",
 394                                SVCFH_fmt(&argp->tfh),
 395                                argp->tlen,
 396                                argp->tname);
 397
 398        fh_copy(&resp->fh,  &argp->ffh);
 399        fh_copy(&resp->tfh, &argp->tfh);
 400        nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
 401                                  &resp->fh);
 402        RETURN_STATUS(nfserr);
 403}
 404
 405/*
 406 * Read a portion of a directory.
 407 */
 408static __be32
 409nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
 410                                           struct nfsd3_readdirres  *resp)
 411{
 412        __be32          nfserr;
 413        int             count;
 414
 415        dprintk("nfsd: READDIR(3)  %s %d bytes at %d\n",
 416                                SVCFH_fmt(&argp->fh),
 417                                argp->count, (u32) argp->cookie);
 418
 419        /* Make sure we've room for the NULL ptr & eof flag, and shrink to
 420         * client read size */
 421        count = (argp->count >> 2) - 2;
 422
 423        /* Read directory and encode entries on the fly */
 424        fh_copy(&resp->fh, &argp->fh);
 425
 426        resp->buflen = count;
 427        resp->common.err = nfs_ok;
 428        resp->buffer = argp->buffer;
 429        resp->rqstp = rqstp;
 430        nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t*) &argp->cookie, 
 431                                        &resp->common, nfs3svc_encode_entry);
 432        memcpy(resp->verf, argp->verf, 8);
 433        resp->count = resp->buffer - argp->buffer;
 434        if (resp->offset)
 435                xdr_encode_hyper(resp->offset, argp->cookie);
 436
 437        RETURN_STATUS(nfserr);
 438}
 439
 440/*
 441 * Read a portion of a directory, including file handles and attrs.
 442 * For now, we choose to ignore the dircount parameter.
 443 */
 444static __be32
 445nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
 446                                               struct nfsd3_readdirres  *resp)
 447{
 448        __be32  nfserr;
 449        int     count = 0;
 450        loff_t  offset;
 451        struct page **p;
 452        caddr_t page_addr = NULL;
 453
 454        dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
 455                                SVCFH_fmt(&argp->fh),
 456                                argp->count, (u32) argp->cookie);
 457
 458        /* Convert byte count to number of words (i.e. >> 2),
 459         * and reserve room for the NULL ptr & eof flag (-2 words) */
 460        resp->count = (argp->count >> 2) - 2;
 461
 462        /* Read directory and encode entries on the fly */
 463        fh_copy(&resp->fh, &argp->fh);
 464
 465        resp->common.err = nfs_ok;
 466        resp->buffer = argp->buffer;
 467        resp->buflen = resp->count;
 468        resp->rqstp = rqstp;
 469        offset = argp->cookie;
 470
 471        nfserr = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP);
 472        if (nfserr)
 473                RETURN_STATUS(nfserr);
 474
 475        if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS)
 476                RETURN_STATUS(nfserr_notsupp);
 477
 478        nfserr = nfsd_readdir(rqstp, &resp->fh,
 479                                     &offset,
 480                                     &resp->common,
 481                                     nfs3svc_encode_entry_plus);
 482        memcpy(resp->verf, argp->verf, 8);
 483        for (p = rqstp->rq_respages + 1; p < rqstp->rq_next_page; p++) {
 484                page_addr = page_address(*p);
 485
 486                if (((caddr_t)resp->buffer >= page_addr) &&
 487                    ((caddr_t)resp->buffer < page_addr + PAGE_SIZE)) {
 488                        count += (caddr_t)resp->buffer - page_addr;
 489                        break;
 490                }
 491                count += PAGE_SIZE;
 492        }
 493        resp->count = count >> 2;
 494        if (resp->offset) {
 495                if (unlikely(resp->offset1)) {
 496                        /* we ended up with offset on a page boundary */
 497                        *resp->offset = htonl(offset >> 32);
 498                        *resp->offset1 = htonl(offset & 0xffffffff);
 499                        resp->offset1 = NULL;
 500                } else {
 501                        xdr_encode_hyper(resp->offset, offset);
 502                }
 503        }
 504
 505        RETURN_STATUS(nfserr);
 506}
 507
 508/*
 509 * Get file system stats
 510 */
 511static __be32
 512nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
 513                                           struct nfsd3_fsstatres *resp)
 514{
 515        __be32  nfserr;
 516
 517        dprintk("nfsd: FSSTAT(3)   %s\n",
 518                                SVCFH_fmt(&argp->fh));
 519
 520        nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
 521        fh_put(&argp->fh);
 522        RETURN_STATUS(nfserr);
 523}
 524
 525/*
 526 * Get file system info
 527 */
 528static __be32
 529nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
 530                                           struct nfsd3_fsinfores *resp)
 531{
 532        __be32  nfserr;
 533        u32     max_blocksize = svc_max_payload(rqstp);
 534
 535        dprintk("nfsd: FSINFO(3)   %s\n",
 536                                SVCFH_fmt(&argp->fh));
 537
 538        resp->f_rtmax  = max_blocksize;
 539        resp->f_rtpref = max_blocksize;
 540        resp->f_rtmult = PAGE_SIZE;
 541        resp->f_wtmax  = max_blocksize;
 542        resp->f_wtpref = max_blocksize;
 543        resp->f_wtmult = PAGE_SIZE;
 544        resp->f_dtpref = PAGE_SIZE;
 545        resp->f_maxfilesize = ~(u32) 0;
 546        resp->f_properties = NFS3_FSF_DEFAULT;
 547
 548        nfserr = fh_verify(rqstp, &argp->fh, 0,
 549                        NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
 550
 551        /* Check special features of the file system. May request
 552         * different read/write sizes for file systems known to have
 553         * problems with large blocks */
 554        if (nfserr == 0) {
 555                struct super_block *sb = d_inode(argp->fh.fh_dentry)->i_sb;
 556
 557                /* Note that we don't care for remote fs's here */
 558                if (sb->s_magic == MSDOS_SUPER_MAGIC) {
 559                        resp->f_properties = NFS3_FSF_BILLYBOY;
 560                }
 561                resp->f_maxfilesize = sb->s_maxbytes;
 562        }
 563
 564        fh_put(&argp->fh);
 565        RETURN_STATUS(nfserr);
 566}
 567
 568/*
 569 * Get pathconf info for the specified file
 570 */
 571static __be32
 572nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle      *argp,
 573                                             struct nfsd3_pathconfres *resp)
 574{
 575        __be32  nfserr;
 576
 577        dprintk("nfsd: PATHCONF(3) %s\n",
 578                                SVCFH_fmt(&argp->fh));
 579
 580        /* Set default pathconf */
 581        resp->p_link_max = 255;         /* at least */
 582        resp->p_name_max = 255;         /* at least */
 583        resp->p_no_trunc = 0;
 584        resp->p_chown_restricted = 1;
 585        resp->p_case_insensitive = 0;
 586        resp->p_case_preserving = 1;
 587
 588        nfserr = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
 589
 590        if (nfserr == 0) {
 591                struct super_block *sb = d_inode(argp->fh.fh_dentry)->i_sb;
 592
 593                /* Note that we don't care for remote fs's here */
 594                switch (sb->s_magic) {
 595                case EXT2_SUPER_MAGIC:
 596                        resp->p_link_max = EXT2_LINK_MAX;
 597                        resp->p_name_max = EXT2_NAME_LEN;
 598                        break;
 599                case MSDOS_SUPER_MAGIC:
 600                        resp->p_case_insensitive = 1;
 601                        resp->p_case_preserving  = 0;
 602                        break;
 603                }
 604        }
 605
 606        fh_put(&argp->fh);
 607        RETURN_STATUS(nfserr);
 608}
 609
 610
 611/*
 612 * Commit a file (range) to stable storage.
 613 */
 614static __be32
 615nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
 616                                           struct nfsd3_commitres  *resp)
 617{
 618        __be32  nfserr;
 619
 620        dprintk("nfsd: COMMIT(3)   %s %u@%Lu\n",
 621                                SVCFH_fmt(&argp->fh),
 622                                argp->count,
 623                                (unsigned long long) argp->offset);
 624
 625        if (argp->offset > NFS_OFFSET_MAX)
 626                RETURN_STATUS(nfserr_inval);
 627
 628        fh_copy(&resp->fh, &argp->fh);
 629        nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
 630
 631        RETURN_STATUS(nfserr);
 632}
 633
 634
 635/*
 636 * NFSv3 Server procedures.
 637 * Only the results of non-idempotent operations are cached.
 638 */
 639#define nfs3svc_decode_fhandleargs      nfs3svc_decode_fhandle
 640#define nfs3svc_encode_attrstatres      nfs3svc_encode_attrstat
 641#define nfs3svc_encode_wccstatres       nfs3svc_encode_wccstat
 642#define nfsd3_mkdirargs                 nfsd3_createargs
 643#define nfsd3_readdirplusargs           nfsd3_readdirargs
 644#define nfsd3_fhandleargs               nfsd_fhandle
 645#define nfsd3_fhandleres                nfsd3_attrstat
 646#define nfsd3_attrstatres               nfsd3_attrstat
 647#define nfsd3_wccstatres                nfsd3_attrstat
 648#define nfsd3_createres                 nfsd3_diropres
 649#define nfsd3_voidres                   nfsd3_voidargs
 650struct nfsd3_voidargs { int dummy; };
 651
 652#define PROC(name, argt, rest, relt, cache, respsize)   \
 653 { (svc_procfunc) nfsd3_proc_##name,            \
 654   (kxdrproc_t) nfs3svc_decode_##argt##args,    \
 655   (kxdrproc_t) nfs3svc_encode_##rest##res,     \
 656   (kxdrproc_t) nfs3svc_release_##relt,         \
 657   sizeof(struct nfsd3_##argt##args),           \
 658   sizeof(struct nfsd3_##rest##res),            \
 659   0,                                           \
 660   cache,                                       \
 661   respsize,                                    \
 662 }
 663
 664#define ST 1            /* status*/
 665#define FH 17           /* filehandle with length */
 666#define AT 21           /* attributes */
 667#define pAT (1+AT)      /* post attributes - conditional */
 668#define WC (7+pAT)      /* WCC attributes */
 669
 670static struct svc_procedure             nfsd_procedures3[22] = {
 671        [NFS3PROC_NULL] = {
 672                .pc_func = (svc_procfunc) nfsd3_proc_null,
 673                .pc_encode = (kxdrproc_t) nfs3svc_encode_voidres,
 674                .pc_argsize = sizeof(struct nfsd3_voidargs),
 675                .pc_ressize = sizeof(struct nfsd3_voidres),
 676                .pc_cachetype = RC_NOCACHE,
 677                .pc_xdrressize = ST,
 678        },
 679        [NFS3PROC_GETATTR] = {
 680                .pc_func = (svc_procfunc) nfsd3_proc_getattr,
 681                .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
 682                .pc_encode = (kxdrproc_t) nfs3svc_encode_attrstatres,
 683                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 684                .pc_argsize = sizeof(struct nfsd3_fhandleargs),
 685                .pc_ressize = sizeof(struct nfsd3_attrstatres),
 686                .pc_cachetype = RC_NOCACHE,
 687                .pc_xdrressize = ST+AT,
 688        },
 689        [NFS3PROC_SETATTR] = {
 690                .pc_func = (svc_procfunc) nfsd3_proc_setattr,
 691                .pc_decode = (kxdrproc_t) nfs3svc_decode_sattrargs,
 692                .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
 693                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 694                .pc_argsize = sizeof(struct nfsd3_sattrargs),
 695                .pc_ressize = sizeof(struct nfsd3_wccstatres),
 696                .pc_cachetype = RC_REPLBUFF,
 697                .pc_xdrressize = ST+WC,
 698        },
 699        [NFS3PROC_LOOKUP] = {
 700                .pc_func = (svc_procfunc) nfsd3_proc_lookup,
 701                .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
 702                .pc_encode = (kxdrproc_t) nfs3svc_encode_diropres,
 703                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
 704                .pc_argsize = sizeof(struct nfsd3_diropargs),
 705                .pc_ressize = sizeof(struct nfsd3_diropres),
 706                .pc_cachetype = RC_NOCACHE,
 707                .pc_xdrressize = ST+FH+pAT+pAT,
 708        },
 709        [NFS3PROC_ACCESS] = {
 710                .pc_func = (svc_procfunc) nfsd3_proc_access,
 711                .pc_decode = (kxdrproc_t) nfs3svc_decode_accessargs,
 712                .pc_encode = (kxdrproc_t) nfs3svc_encode_accessres,
 713                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 714                .pc_argsize = sizeof(struct nfsd3_accessargs),
 715                .pc_ressize = sizeof(struct nfsd3_accessres),
 716                .pc_cachetype = RC_NOCACHE,
 717                .pc_xdrressize = ST+pAT+1,
 718        },
 719        [NFS3PROC_READLINK] = {
 720                .pc_func = (svc_procfunc) nfsd3_proc_readlink,
 721                .pc_decode = (kxdrproc_t) nfs3svc_decode_readlinkargs,
 722                .pc_encode = (kxdrproc_t) nfs3svc_encode_readlinkres,
 723                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 724                .pc_argsize = sizeof(struct nfsd3_readlinkargs),
 725                .pc_ressize = sizeof(struct nfsd3_readlinkres),
 726                .pc_cachetype = RC_NOCACHE,
 727                .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
 728        },
 729        [NFS3PROC_READ] = {
 730                .pc_func = (svc_procfunc) nfsd3_proc_read,
 731                .pc_decode = (kxdrproc_t) nfs3svc_decode_readargs,
 732                .pc_encode = (kxdrproc_t) nfs3svc_encode_readres,
 733                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 734                .pc_argsize = sizeof(struct nfsd3_readargs),
 735                .pc_ressize = sizeof(struct nfsd3_readres),
 736                .pc_cachetype = RC_NOCACHE,
 737                .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
 738        },
 739        [NFS3PROC_WRITE] = {
 740                .pc_func = (svc_procfunc) nfsd3_proc_write,
 741                .pc_decode = (kxdrproc_t) nfs3svc_decode_writeargs,
 742                .pc_encode = (kxdrproc_t) nfs3svc_encode_writeres,
 743                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 744                .pc_argsize = sizeof(struct nfsd3_writeargs),
 745                .pc_ressize = sizeof(struct nfsd3_writeres),
 746                .pc_cachetype = RC_REPLBUFF,
 747                .pc_xdrressize = ST+WC+4,
 748        },
 749        [NFS3PROC_CREATE] = {
 750                .pc_func = (svc_procfunc) nfsd3_proc_create,
 751                .pc_decode = (kxdrproc_t) nfs3svc_decode_createargs,
 752                .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
 753                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
 754                .pc_argsize = sizeof(struct nfsd3_createargs),
 755                .pc_ressize = sizeof(struct nfsd3_createres),
 756                .pc_cachetype = RC_REPLBUFF,
 757                .pc_xdrressize = ST+(1+FH+pAT)+WC,
 758        },
 759        [NFS3PROC_MKDIR] = {
 760                .pc_func = (svc_procfunc) nfsd3_proc_mkdir,
 761                .pc_decode = (kxdrproc_t) nfs3svc_decode_mkdirargs,
 762                .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
 763                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
 764                .pc_argsize = sizeof(struct nfsd3_mkdirargs),
 765                .pc_ressize = sizeof(struct nfsd3_createres),
 766                .pc_cachetype = RC_REPLBUFF,
 767                .pc_xdrressize = ST+(1+FH+pAT)+WC,
 768        },
 769        [NFS3PROC_SYMLINK] = {
 770                .pc_func = (svc_procfunc) nfsd3_proc_symlink,
 771                .pc_decode = (kxdrproc_t) nfs3svc_decode_symlinkargs,
 772                .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
 773                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
 774                .pc_argsize = sizeof(struct nfsd3_symlinkargs),
 775                .pc_ressize = sizeof(struct nfsd3_createres),
 776                .pc_cachetype = RC_REPLBUFF,
 777                .pc_xdrressize = ST+(1+FH+pAT)+WC,
 778        },
 779        [NFS3PROC_MKNOD] = {
 780                .pc_func = (svc_procfunc) nfsd3_proc_mknod,
 781                .pc_decode = (kxdrproc_t) nfs3svc_decode_mknodargs,
 782                .pc_encode = (kxdrproc_t) nfs3svc_encode_createres,
 783                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
 784                .pc_argsize = sizeof(struct nfsd3_mknodargs),
 785                .pc_ressize = sizeof(struct nfsd3_createres),
 786                .pc_cachetype = RC_REPLBUFF,
 787                .pc_xdrressize = ST+(1+FH+pAT)+WC,
 788        },
 789        [NFS3PROC_REMOVE] = {
 790                .pc_func = (svc_procfunc) nfsd3_proc_remove,
 791                .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
 792                .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
 793                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 794                .pc_argsize = sizeof(struct nfsd3_diropargs),
 795                .pc_ressize = sizeof(struct nfsd3_wccstatres),
 796                .pc_cachetype = RC_REPLBUFF,
 797                .pc_xdrressize = ST+WC,
 798        },
 799        [NFS3PROC_RMDIR] = {
 800                .pc_func = (svc_procfunc) nfsd3_proc_rmdir,
 801                .pc_decode = (kxdrproc_t) nfs3svc_decode_diropargs,
 802                .pc_encode = (kxdrproc_t) nfs3svc_encode_wccstatres,
 803                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 804                .pc_argsize = sizeof(struct nfsd3_diropargs),
 805                .pc_ressize = sizeof(struct nfsd3_wccstatres),
 806                .pc_cachetype = RC_REPLBUFF,
 807                .pc_xdrressize = ST+WC,
 808        },
 809        [NFS3PROC_RENAME] = {
 810                .pc_func = (svc_procfunc) nfsd3_proc_rename,
 811                .pc_decode = (kxdrproc_t) nfs3svc_decode_renameargs,
 812                .pc_encode = (kxdrproc_t) nfs3svc_encode_renameres,
 813                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
 814                .pc_argsize = sizeof(struct nfsd3_renameargs),
 815                .pc_ressize = sizeof(struct nfsd3_renameres),
 816                .pc_cachetype = RC_REPLBUFF,
 817                .pc_xdrressize = ST+WC+WC,
 818        },
 819        [NFS3PROC_LINK] = {
 820                .pc_func = (svc_procfunc) nfsd3_proc_link,
 821                .pc_decode = (kxdrproc_t) nfs3svc_decode_linkargs,
 822                .pc_encode = (kxdrproc_t) nfs3svc_encode_linkres,
 823                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle2,
 824                .pc_argsize = sizeof(struct nfsd3_linkargs),
 825                .pc_ressize = sizeof(struct nfsd3_linkres),
 826                .pc_cachetype = RC_REPLBUFF,
 827                .pc_xdrressize = ST+pAT+WC,
 828        },
 829        [NFS3PROC_READDIR] = {
 830                .pc_func = (svc_procfunc) nfsd3_proc_readdir,
 831                .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirargs,
 832                .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
 833                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 834                .pc_argsize = sizeof(struct nfsd3_readdirargs),
 835                .pc_ressize = sizeof(struct nfsd3_readdirres),
 836                .pc_cachetype = RC_NOCACHE,
 837        },
 838        [NFS3PROC_READDIRPLUS] = {
 839                .pc_func = (svc_procfunc) nfsd3_proc_readdirplus,
 840                .pc_decode = (kxdrproc_t) nfs3svc_decode_readdirplusargs,
 841                .pc_encode = (kxdrproc_t) nfs3svc_encode_readdirres,
 842                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 843                .pc_argsize = sizeof(struct nfsd3_readdirplusargs),
 844                .pc_ressize = sizeof(struct nfsd3_readdirres),
 845                .pc_cachetype = RC_NOCACHE,
 846        },
 847        [NFS3PROC_FSSTAT] = {
 848                .pc_func = (svc_procfunc) nfsd3_proc_fsstat,
 849                .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
 850                .pc_encode = (kxdrproc_t) nfs3svc_encode_fsstatres,
 851                .pc_argsize = sizeof(struct nfsd3_fhandleargs),
 852                .pc_ressize = sizeof(struct nfsd3_fsstatres),
 853                .pc_cachetype = RC_NOCACHE,
 854                .pc_xdrressize = ST+pAT+2*6+1,
 855        },
 856        [NFS3PROC_FSINFO] = {
 857                .pc_func = (svc_procfunc) nfsd3_proc_fsinfo,
 858                .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
 859                .pc_encode = (kxdrproc_t) nfs3svc_encode_fsinfores,
 860                .pc_argsize = sizeof(struct nfsd3_fhandleargs),
 861                .pc_ressize = sizeof(struct nfsd3_fsinfores),
 862                .pc_cachetype = RC_NOCACHE,
 863                .pc_xdrressize = ST+pAT+12,
 864        },
 865        [NFS3PROC_PATHCONF] = {
 866                .pc_func = (svc_procfunc) nfsd3_proc_pathconf,
 867                .pc_decode = (kxdrproc_t) nfs3svc_decode_fhandleargs,
 868                .pc_encode = (kxdrproc_t) nfs3svc_encode_pathconfres,
 869                .pc_argsize = sizeof(struct nfsd3_fhandleargs),
 870                .pc_ressize = sizeof(struct nfsd3_pathconfres),
 871                .pc_cachetype = RC_NOCACHE,
 872                .pc_xdrressize = ST+pAT+6,
 873        },
 874        [NFS3PROC_COMMIT] = {
 875                .pc_func = (svc_procfunc) nfsd3_proc_commit,
 876                .pc_decode = (kxdrproc_t) nfs3svc_decode_commitargs,
 877                .pc_encode = (kxdrproc_t) nfs3svc_encode_commitres,
 878                .pc_release = (kxdrproc_t) nfs3svc_release_fhandle,
 879                .pc_argsize = sizeof(struct nfsd3_commitargs),
 880                .pc_ressize = sizeof(struct nfsd3_commitres),
 881                .pc_cachetype = RC_NOCACHE,
 882                .pc_xdrressize = ST+WC+2,
 883        },
 884};
 885
 886struct svc_version      nfsd_version3 = {
 887                .vs_vers        = 3,
 888                .vs_nproc       = 22,
 889                .vs_proc        = nfsd_procedures3,
 890                .vs_dispatch    = nfsd_dispatch,
 891                .vs_xdrsize     = NFS3_SVC_XDRSIZE,
 892};
 893