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