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