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