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