linux-old/fs/nfsd/nfsproc.c
<<
>>
Prefs
   1/*
   2 * nfsproc2.c   Process version 2 NFS requests.
   3 * linux/fs/nfsd/nfs2proc.c
   4 * 
   5 * Process version 2 NFS requests.
   6 *
   7 * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
   8 */
   9
  10#include <linux/linkage.h>
  11#include <linux/sched.h>
  12#include <linux/errno.h>
  13#include <linux/locks.h>
  14#include <linux/fs.h>
  15#include <linux/stat.h>
  16#include <linux/fcntl.h>
  17#include <linux/net.h>
  18#include <linux/in.h>
  19#include <linux/version.h>
  20#include <linux/unistd.h>
  21#include <linux/slab.h>
  22
  23#include <linux/sunrpc/svc.h>
  24#include <linux/nfsd/nfsd.h>
  25#include <linux/nfsd/cache.h>
  26#include <linux/nfsd/xdr.h>
  27
  28typedef struct svc_rqst svc_rqst;
  29typedef struct svc_buf  svc_buf;
  30
  31#define NFSDDBG_FACILITY                NFSDDBG_PROC
  32
  33
  34static void
  35svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr)
  36{
  37        *ptr = buf->buf + nr;
  38        *len = buf->buflen - buf->len - nr;
  39}
  40
  41static int
  42nfsd_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
  43{
  44        return nfs_ok;
  45}
  46
  47/*
  48 * Get a file's attributes
  49 * N.B. After this call resp->fh needs an fh_put
  50 */
  51static int
  52nfsd_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
  53                                          struct nfsd_attrstat *resp)
  54{
  55        dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
  56
  57        fh_copy(&resp->fh, &argp->fh);
  58        return fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
  59}
  60
  61/*
  62 * Set a file's attributes
  63 * N.B. After this call resp->fh needs an fh_put
  64 */
  65static int
  66nfsd_proc_setattr(struct svc_rqst *rqstp, struct nfsd_sattrargs *argp,
  67                                          struct nfsd_attrstat  *resp)
  68{
  69        dprintk("nfsd: SETATTR  %s, valid=%x, size=%ld\n",
  70                SVCFH_fmt(&argp->fh),
  71                argp->attrs.ia_valid, (long) argp->attrs.ia_size);
  72
  73        fh_copy(&resp->fh, &argp->fh);
  74        return nfsd_setattr(rqstp, &resp->fh, &argp->attrs,0, (time_t)0);
  75}
  76
  77/*
  78 * Look up a path name component
  79 * Note: the dentry in the resp->fh may be negative if the file
  80 * doesn't exist yet.
  81 * N.B. After this call resp->fh needs an fh_put
  82 */
  83static int
  84nfsd_proc_lookup(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
  85                                         struct nfsd_diropres  *resp)
  86{
  87        int     nfserr;
  88
  89        dprintk("nfsd: LOOKUP   %s %.*s\n",
  90                SVCFH_fmt(&argp->fh), argp->len, argp->name);
  91
  92        fh_init(&resp->fh, NFS_FHSIZE);
  93        nfserr = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
  94                                 &resp->fh);
  95
  96        fh_put(&argp->fh);
  97        return nfserr;
  98}
  99
 100/*
 101 * Read a symlink.
 102 */
 103static int
 104nfsd_proc_readlink(struct svc_rqst *rqstp, struct nfsd_fhandle     *argp,
 105                                           struct nfsd_readlinkres *resp)
 106{
 107        u32             *path;
 108        int             dummy, nfserr;
 109
 110        dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
 111
 112        /* Reserve room for status and path length */
 113        svcbuf_reserve(&rqstp->rq_resbuf, &path, &dummy, 2);
 114
 115        /* Read the symlink. */
 116        resp->len = NFS_MAXPATHLEN;
 117        nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len);
 118
 119        fh_put(&argp->fh);
 120        return nfserr;
 121}
 122
 123/*
 124 * Read a portion of a file.
 125 * N.B. After this call resp->fh needs an fh_put
 126 */
 127static int
 128nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp,
 129                                       struct nfsd_readres  *resp)
 130{
 131        u32 *   buffer;
 132        int     nfserr, avail;
 133
 134        dprintk("nfsd: READ    %s %d bytes at %d\n",
 135                SVCFH_fmt(&argp->fh),
 136                argp->count, argp->offset);
 137
 138        /* Obtain buffer pointer for payload. 19 is 1 word for
 139         * status, 17 words for fattr, and 1 word for the byte count.
 140         */
 141        svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &avail, 19);
 142
 143        if ((avail << 2) < argp->count) {
 144                printk(KERN_NOTICE
 145                        "oversized read request from %08x:%d (%d bytes)\n",
 146                                ntohl(rqstp->rq_addr.sin_addr.s_addr),
 147                                ntohs(rqstp->rq_addr.sin_port),
 148                                argp->count);
 149                argp->count = avail << 2;
 150        }
 151        svc_reserve(rqstp, (19<<2) + argp->count + 4);
 152
 153        resp->count = argp->count;
 154        nfserr = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
 155                                  argp->offset,
 156                                  (char *) buffer,
 157                                  &resp->count);
 158
 159        return nfserr;
 160}
 161
 162/*
 163 * Write data to a file
 164 * N.B. After this call resp->fh needs an fh_put
 165 */
 166static int
 167nfsd_proc_write(struct svc_rqst *rqstp, struct nfsd_writeargs *argp,
 168                                        struct nfsd_attrstat  *resp)
 169{
 170        int     nfserr;
 171        int     stable = 1;
 172
 173        dprintk("nfsd: WRITE    %s %d bytes at %d\n",
 174                SVCFH_fmt(&argp->fh),
 175                argp->len, argp->offset);
 176
 177        nfserr = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
 178                                   argp->offset,
 179                                   argp->data,
 180                                   argp->len,
 181                                   &stable);
 182        return nfserr;
 183}
 184
 185/*
 186 * CREATE processing is complicated. The keyword here is `overloaded.'
 187 * The parent directory is kept locked between the check for existence
 188 * and the actual create() call in compliance with VFS protocols.
 189 * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
 190 */
 191static int
 192nfsd_proc_create(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
 193                                         struct nfsd_diropres   *resp)
 194{
 195        svc_fh          *dirfhp = &argp->fh;
 196        svc_fh          *newfhp = &resp->fh;
 197        struct iattr    *attr = &argp->attrs;
 198        struct inode    *inode;
 199        struct dentry   *dchild;
 200        int             nfserr, type, mode;
 201        dev_t           rdev = NODEV;
 202
 203        dprintk("nfsd: CREATE   %s %.*s\n",
 204                SVCFH_fmt(dirfhp), argp->len, argp->name);
 205
 206        /* First verify the parent file handle */
 207        nfserr = fh_verify(rqstp, dirfhp, S_IFDIR, MAY_EXEC);
 208        if (nfserr)
 209                goto done; /* must fh_put dirfhp even on error */
 210
 211        /* Check for MAY_WRITE in nfsd_create if necessary */
 212
 213        nfserr = nfserr_acces;
 214        if (!argp->len)
 215                goto done;
 216        nfserr = nfserr_exist;
 217        if (isdotent(argp->name, argp->len))
 218                goto done;
 219        fh_lock(dirfhp);
 220        dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
 221        if (IS_ERR(dchild)) {
 222                nfserr = nfserrno(PTR_ERR(dchild));
 223                goto out_unlock;
 224        }
 225        fh_init(newfhp, NFS_FHSIZE);
 226        nfserr = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
 227        if (!nfserr && !dchild->d_inode)
 228                nfserr = nfserr_noent;
 229        if (nfserr) {
 230                if (nfserr != nfserr_noent)
 231                        goto out_unlock;
 232                /*
 233                 * If the new file handle wasn't verified, we can't tell
 234                 * whether the file exists or not. Time to bail ...
 235                 */
 236                nfserr = nfserr_acces;
 237                if (!newfhp->fh_dentry) {
 238                        printk(KERN_WARNING 
 239                                "nfsd_proc_create: file handle not verified\n");
 240                        goto out_unlock;
 241                }
 242        }
 243
 244        inode = newfhp->fh_dentry->d_inode;
 245
 246        /* Unfudge the mode bits */
 247        if (attr->ia_valid & ATTR_MODE) { 
 248                type = attr->ia_mode & S_IFMT;
 249                mode = attr->ia_mode & ~S_IFMT;
 250                if (!type) {
 251                        /* no type, so if target exists, assume same as that,
 252                         * else assume a file */
 253                        if (inode) {
 254                                type = inode->i_mode & S_IFMT;
 255                                switch(type) {
 256                                case S_IFCHR:
 257                                case S_IFBLK:
 258                                        /* reserve rdev for later checking */
 259                                        attr->ia_size = inode->i_rdev;
 260                                        attr->ia_valid |= ATTR_SIZE;
 261
 262                                        /* FALLTHROUGH */
 263                                case S_IFIFO:
 264                                        /* this is probably a permission check..
 265                                         * at least IRIX implements perm checking on
 266                                         *   echo thing > device-special-file-or-pipe
 267                                         * by doing a CREATE with type==0
 268                                         */
 269                                        nfserr = nfsd_permission(newfhp->fh_export,
 270                                                                 newfhp->fh_dentry,
 271                                                                 MAY_WRITE|_NFSD_IRIX_BOGOSITY);
 272                                        if (nfserr && nfserr != nfserr_rofs)
 273                                                goto out_unlock;
 274                                }
 275                        } else
 276                                type = S_IFREG;
 277                }
 278        } else if (inode) {
 279                type = inode->i_mode & S_IFMT;
 280                mode = inode->i_mode & ~S_IFMT;
 281        } else {
 282                type = S_IFREG;
 283                mode = 0;       /* ??? */
 284        }
 285
 286        attr->ia_valid |= ATTR_MODE;
 287        attr->ia_mode = mode;
 288
 289        /* Special treatment for non-regular files according to the
 290         * gospel of sun micro
 291         */
 292        if (type != S_IFREG) {
 293                int     is_borc = 0;
 294                u32     size = attr->ia_size;
 295
 296                rdev = (dev_t) size;
 297                if (type != S_IFBLK && type != S_IFCHR) {
 298                        rdev = 0;
 299                } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
 300                        /* If you think you've seen the worst, grok this. */
 301                        type = S_IFIFO;
 302                } else if (size != rdev) {
 303                        /* dev got truncated because of 16bit Linux dev_t */
 304                        nfserr = nfserr_inval;
 305                        goto out_unlock;
 306                } else {
 307                        /* Okay, char or block special */
 308                        is_borc = 1;
 309                }
 310
 311                /* we've used the SIZE information, so discard it */
 312                attr->ia_valid &= ~ATTR_SIZE;
 313
 314                /* Make sure the type and device matches */
 315                nfserr = nfserr_exist;
 316                if (inode && (type != (inode->i_mode & S_IFMT) || 
 317                    (is_borc && inode->i_rdev != rdev)))
 318                        goto out_unlock;
 319        }
 320        
 321        nfserr = 0;
 322        if (!inode) {
 323                /* File doesn't exist. Create it and set attrs */
 324                nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
 325                                        attr, type, rdev, newfhp);
 326        } else if (type == S_IFREG) {
 327                dprintk("nfsd:   existing %s, valid=%x, size=%ld\n",
 328                        argp->name, attr->ia_valid, (long) attr->ia_size);
 329                /* File already exists. We ignore all attributes except
 330                 * size, so that creat() behaves exactly like
 331                 * open(..., O_CREAT|O_TRUNC|O_WRONLY).
 332                 */
 333                attr->ia_valid &= ATTR_SIZE;
 334                if (attr->ia_valid)
 335                        nfserr = nfsd_setattr(rqstp, newfhp, attr, 0, (time_t)0);
 336        }
 337
 338out_unlock:
 339        /* We don't really need to unlock, as fh_put does it. */
 340        fh_unlock(dirfhp);
 341
 342done:
 343        fh_put(dirfhp);
 344        return nfserr;
 345}
 346
 347static int
 348nfsd_proc_remove(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
 349                                         void                  *resp)
 350{
 351        int     nfserr;
 352
 353        dprintk("nfsd: REMOVE   %s %.*s\n", SVCFH_fmt(&argp->fh),
 354                argp->len, argp->name);
 355
 356        /* Unlink. -SIFDIR means file must not be a directory */
 357        nfserr = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR, argp->name, argp->len);
 358        fh_put(&argp->fh);
 359        return nfserr;
 360}
 361
 362static int
 363nfsd_proc_rename(struct svc_rqst *rqstp, struct nfsd_renameargs *argp,
 364                                         void                   *resp)
 365{
 366        int     nfserr;
 367
 368        dprintk("nfsd: RENAME   %s %.*s -> \n",
 369                SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
 370        dprintk("nfsd:        ->  %s %.*s\n",
 371                SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
 372
 373        nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
 374                                    &argp->tfh, argp->tname, argp->tlen);
 375        fh_put(&argp->ffh);
 376        fh_put(&argp->tfh);
 377        return nfserr;
 378}
 379
 380static int
 381nfsd_proc_link(struct svc_rqst *rqstp, struct nfsd_linkargs *argp,
 382                                void                        *resp)
 383{
 384        int     nfserr;
 385
 386        dprintk("nfsd: LINK     %s ->\n",
 387                SVCFH_fmt(&argp->ffh));
 388        dprintk("nfsd:    %s %.*s\n",
 389                SVCFH_fmt(&argp->tfh),
 390                argp->tlen,
 391                argp->tname);
 392
 393        nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
 394                                  &argp->ffh);
 395        fh_put(&argp->ffh);
 396        fh_put(&argp->tfh);
 397        return nfserr;
 398}
 399
 400static int
 401nfsd_proc_symlink(struct svc_rqst *rqstp, struct nfsd_symlinkargs *argp,
 402                                          void                    *resp)
 403{
 404        struct svc_fh   newfh;
 405        int             nfserr;
 406
 407        dprintk("nfsd: SYMLINK  %s %.*s -> %.*s\n",
 408                SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
 409                argp->tlen, argp->tname);
 410
 411        fh_init(&newfh, NFS_FHSIZE);
 412        /*
 413         * Create the link, look up new file and set attrs.
 414         */
 415        nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
 416                                                 argp->tname, argp->tlen,
 417                                                 &newfh, &argp->attrs);
 418
 419
 420        fh_put(&argp->ffh);
 421        fh_put(&newfh);
 422        return nfserr;
 423}
 424
 425/*
 426 * Make directory. This operation is not idempotent.
 427 * N.B. After this call resp->fh needs an fh_put
 428 */
 429static int
 430nfsd_proc_mkdir(struct svc_rqst *rqstp, struct nfsd_createargs *argp,
 431                                        struct nfsd_diropres   *resp)
 432{
 433        int     nfserr;
 434
 435        dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
 436
 437        if (resp->fh.fh_dentry) {
 438                printk(KERN_WARNING
 439                        "nfsd_proc_mkdir: response already verified??\n");
 440        }
 441
 442        argp->attrs.ia_valid &= ~ATTR_SIZE;
 443        fh_init(&resp->fh, NFS_FHSIZE);
 444        nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
 445                                    &argp->attrs, S_IFDIR, 0, &resp->fh);
 446        fh_put(&argp->fh);
 447        return nfserr;
 448}
 449
 450/*
 451 * Remove a directory
 452 */
 453static int
 454nfsd_proc_rmdir(struct svc_rqst *rqstp, struct nfsd_diropargs *argp,
 455                                        void                  *resp)
 456{
 457        int     nfserr;
 458
 459        dprintk("nfsd: RMDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
 460
 461        nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
 462        fh_put(&argp->fh);
 463        return nfserr;
 464}
 465
 466/*
 467 * Read a portion of a directory.
 468 */
 469static int
 470nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
 471                                          struct nfsd_readdirres  *resp)
 472{
 473        u32 *           buffer;
 474        int             nfserr, count;
 475
 476        dprintk("nfsd: READDIR  %s %d bytes at %d\n",
 477                SVCFH_fmt(&argp->fh),           
 478                argp->count, argp->cookie);
 479
 480        /* Reserve buffer space for status */
 481        svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count, 1);
 482
 483        /* Shrink to the client read size */
 484        if (count > (argp->count >> 2))
 485                count = argp->count >> 2;
 486
 487        /* Make sure we've room for the NULL ptr & eof flag */
 488        count -= 2;
 489        if (count < 0)
 490                count = 0;
 491
 492        /* Read directory and encode entries on the fly */
 493        nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie, 
 494                              nfssvc_encode_entry,
 495                              buffer, &count, NULL);
 496        resp->count = count;
 497
 498        fh_put(&argp->fh);
 499        return nfserr;
 500}
 501
 502/*
 503 * Get file system info
 504 */
 505static int
 506nfsd_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle   *argp,
 507                                          struct nfsd_statfsres *resp)
 508{
 509        int     nfserr;
 510
 511        dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
 512
 513        nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
 514        fh_put(&argp->fh);
 515        return nfserr;
 516}
 517
 518/*
 519 * NFSv2 Server procedures.
 520 * Only the results of non-idempotent operations are cached.
 521 */
 522#define nfsd_proc_none          NULL
 523#define nfssvc_release_none     NULL
 524struct nfsd_void { int dummy; };
 525
 526#define PROC(name, argt, rest, relt, cache, respsize)   \
 527 { (svc_procfunc) nfsd_proc_##name,             \
 528   (kxdrproc_t) nfssvc_decode_##argt,           \
 529   (kxdrproc_t) nfssvc_encode_##rest,           \
 530   (kxdrproc_t) nfssvc_release_##relt,          \
 531   sizeof(struct nfsd_##argt),                  \
 532   sizeof(struct nfsd_##rest),                  \
 533   0,                                           \
 534   cache,                                       \
 535   respsize,                                    \
 536 }
 537
 538#define ST 1            /* status */
 539#define FH 8            /* filehandle */
 540#define AT 18           /* attributes */
 541
 542struct svc_procedure            nfsd_procedures2[18] = {
 543  PROC(null,     void,          void,           none,           RC_NOCACHE, ST),
 544  PROC(getattr,  fhandle,       attrstat,       fhandle,        RC_NOCACHE, ST+AT),
 545  PROC(setattr,  sattrargs,     attrstat,       fhandle,        RC_REPLBUFF, ST+AT),
 546  PROC(none,     void,          void,           none,           RC_NOCACHE, ST),
 547  PROC(lookup,   diropargs,     diropres,       fhandle,        RC_NOCACHE, ST+FH+AT),
 548  PROC(readlink, fhandle,       readlinkres,    none,           RC_NOCACHE, ST+1+NFS_MAXPATHLEN/4),
 549  PROC(read,     readargs,      readres,        fhandle,        RC_NOCACHE, ST+AT+1+NFSSVC_MAXBLKSIZE),
 550  PROC(none,     void,          void,           none,           RC_NOCACHE, ST),
 551  PROC(write,    writeargs,     attrstat,       fhandle,        RC_REPLBUFF, ST+AT),
 552  PROC(create,   createargs,    diropres,       fhandle,        RC_REPLBUFF, ST+FH+AT),
 553  PROC(remove,   diropargs,     void,           none,           RC_REPLSTAT, ST),
 554  PROC(rename,   renameargs,    void,           none,           RC_REPLSTAT, ST),
 555  PROC(link,     linkargs,      void,           none,           RC_REPLSTAT, ST),
 556  PROC(symlink,  symlinkargs,   void,           none,           RC_REPLSTAT, ST),
 557  PROC(mkdir,    createargs,    diropres,       fhandle,        RC_REPLBUFF, ST+FH+AT),
 558  PROC(rmdir,    diropargs,     void,           none,           RC_REPLSTAT, ST),
 559  PROC(readdir,  readdirargs,   readdirres,     none,           RC_REPLBUFF, 0),
 560  PROC(statfs,   fhandle,       statfsres,      none,           RC_NOCACHE, ST+5),
 561};
 562
 563
 564/*
 565 * Map errnos to NFS errnos.
 566 */
 567int
 568nfserrno (int errno)
 569{
 570        static struct {
 571                int     nfserr;
 572                int     syserr;
 573        } nfs_errtbl[] = {
 574                { nfs_ok, 0 },
 575                { nfserr_perm, -EPERM },
 576                { nfserr_noent, -ENOENT },
 577                { nfserr_io, -EIO },
 578                { nfserr_nxio, -ENXIO },
 579                { nfserr_acces, -EACCES },
 580                { nfserr_exist, -EEXIST },
 581                { nfserr_xdev, -EXDEV },
 582                { nfserr_mlink, -EMLINK },
 583                { nfserr_nodev, -ENODEV },
 584                { nfserr_notdir, -ENOTDIR },
 585                { nfserr_isdir, -EISDIR },
 586                { nfserr_inval, -EINVAL },
 587                { nfserr_fbig, -EFBIG },
 588                { nfserr_nospc, -ENOSPC },
 589                { nfserr_rofs, -EROFS },
 590                { nfserr_mlink, -EMLINK },
 591                { nfserr_nametoolong, -ENAMETOOLONG },
 592                { nfserr_notempty, -ENOTEMPTY },
 593#ifdef EDQUOT
 594                { nfserr_dquot, -EDQUOT },
 595#endif
 596                { nfserr_stale, -ESTALE },
 597                { nfserr_dropit, -ENOMEM },
 598                { -1, -EIO }
 599        };
 600        int     i;
 601
 602        for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
 603                if (nfs_errtbl[i].syserr == errno)
 604                        return nfs_errtbl[i].nfserr;
 605        }
 606        printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno);
 607        return nfserr_io;
 608}
 609
 610
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.