Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Process version 2 NFS requests.
0004  *
0005  * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
0006  */
0007 
0008 #include <linux/namei.h>
0009 
0010 #include "cache.h"
0011 #include "xdr.h"
0012 #include "vfs.h"
0013 
0014 #define NFSDDBG_FACILITY        NFSDDBG_PROC
0015 
0016 static __be32
0017 nfsd_proc_null(struct svc_rqst *rqstp)
0018 {
0019     return rpc_success;
0020 }
0021 
0022 /*
0023  * Get a file's attributes
0024  * N.B. After this call resp->fh needs an fh_put
0025  */
0026 static __be32
0027 nfsd_proc_getattr(struct svc_rqst *rqstp)
0028 {
0029     struct nfsd_fhandle *argp = rqstp->rq_argp;
0030     struct nfsd_attrstat *resp = rqstp->rq_resp;
0031 
0032     dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
0033 
0034     fh_copy(&resp->fh, &argp->fh);
0035     resp->status = fh_verify(rqstp, &resp->fh, 0,
0036                  NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
0037     if (resp->status != nfs_ok)
0038         goto out;
0039     resp->status = fh_getattr(&resp->fh, &resp->stat);
0040 out:
0041     return rpc_success;
0042 }
0043 
0044 /*
0045  * Set a file's attributes
0046  * N.B. After this call resp->fh needs an fh_put
0047  */
0048 static __be32
0049 nfsd_proc_setattr(struct svc_rqst *rqstp)
0050 {
0051     struct nfsd_sattrargs *argp = rqstp->rq_argp;
0052     struct nfsd_attrstat *resp = rqstp->rq_resp;
0053     struct iattr *iap = &argp->attrs;
0054     struct nfsd_attrs attrs = {
0055         .na_iattr   = iap,
0056     };
0057     struct svc_fh *fhp;
0058 
0059     dprintk("nfsd: SETATTR  %s, valid=%x, size=%ld\n",
0060         SVCFH_fmt(&argp->fh),
0061         argp->attrs.ia_valid, (long) argp->attrs.ia_size);
0062 
0063     fhp = fh_copy(&resp->fh, &argp->fh);
0064 
0065     /*
0066      * NFSv2 does not differentiate between "set-[ac]time-to-now"
0067      * which only requires access, and "set-[ac]time-to-X" which
0068      * requires ownership.
0069      * So if it looks like it might be "set both to the same time which
0070      * is close to now", and if setattr_prepare fails, then we
0071      * convert to "set to now" instead of "set to explicit time"
0072      *
0073      * We only call setattr_prepare as the last test as technically
0074      * it is not an interface that we should be using.
0075      */
0076 #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
0077 #define MAX_TOUCH_TIME_ERROR (30*60)
0078     if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
0079         iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
0080         /*
0081          * Looks probable.
0082          *
0083          * Now just make sure time is in the right ballpark.
0084          * Solaris, at least, doesn't seem to care what the time
0085          * request is.  We require it be within 30 minutes of now.
0086          */
0087         time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds();
0088 
0089         resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
0090         if (resp->status != nfs_ok)
0091             goto out;
0092 
0093         if (delta < 0)
0094             delta = -delta;
0095         if (delta < MAX_TOUCH_TIME_ERROR &&
0096             setattr_prepare(&init_user_ns, fhp->fh_dentry, iap) != 0) {
0097             /*
0098              * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
0099              * This will cause notify_change to set these times
0100              * to "now"
0101              */
0102             iap->ia_valid &= ~BOTH_TIME_SET;
0103         }
0104     }
0105 
0106     resp->status = nfsd_setattr(rqstp, fhp, &attrs, 0, (time64_t)0);
0107     if (resp->status != nfs_ok)
0108         goto out;
0109 
0110     resp->status = fh_getattr(&resp->fh, &resp->stat);
0111 out:
0112     return rpc_success;
0113 }
0114 
0115 /* Obsolete, replaced by MNTPROC_MNT. */
0116 static __be32
0117 nfsd_proc_root(struct svc_rqst *rqstp)
0118 {
0119     return rpc_success;
0120 }
0121 
0122 /*
0123  * Look up a path name component
0124  * Note: the dentry in the resp->fh may be negative if the file
0125  * doesn't exist yet.
0126  * N.B. After this call resp->fh needs an fh_put
0127  */
0128 static __be32
0129 nfsd_proc_lookup(struct svc_rqst *rqstp)
0130 {
0131     struct nfsd_diropargs *argp = rqstp->rq_argp;
0132     struct nfsd_diropres *resp = rqstp->rq_resp;
0133 
0134     dprintk("nfsd: LOOKUP   %s %.*s\n",
0135         SVCFH_fmt(&argp->fh), argp->len, argp->name);
0136 
0137     fh_init(&resp->fh, NFS_FHSIZE);
0138     resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
0139                    &resp->fh);
0140     fh_put(&argp->fh);
0141     if (resp->status != nfs_ok)
0142         goto out;
0143 
0144     resp->status = fh_getattr(&resp->fh, &resp->stat);
0145 out:
0146     return rpc_success;
0147 }
0148 
0149 /*
0150  * Read a symlink.
0151  */
0152 static __be32
0153 nfsd_proc_readlink(struct svc_rqst *rqstp)
0154 {
0155     struct nfsd_fhandle *argp = rqstp->rq_argp;
0156     struct nfsd_readlinkres *resp = rqstp->rq_resp;
0157 
0158     dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
0159 
0160     /* Read the symlink. */
0161     resp->len = NFS_MAXPATHLEN;
0162     resp->page = *(rqstp->rq_next_page++);
0163     resp->status = nfsd_readlink(rqstp, &argp->fh,
0164                      page_address(resp->page), &resp->len);
0165 
0166     fh_put(&argp->fh);
0167     return rpc_success;
0168 }
0169 
0170 /*
0171  * Read a portion of a file.
0172  * N.B. After this call resp->fh needs an fh_put
0173  */
0174 static __be32
0175 nfsd_proc_read(struct svc_rqst *rqstp)
0176 {
0177     struct nfsd_readargs *argp = rqstp->rq_argp;
0178     struct nfsd_readres *resp = rqstp->rq_resp;
0179     unsigned int len;
0180     u32 eof;
0181     int v;
0182 
0183     dprintk("nfsd: READ    %s %d bytes at %d\n",
0184         SVCFH_fmt(&argp->fh),
0185         argp->count, argp->offset);
0186 
0187     argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2);
0188 
0189     v = 0;
0190     len = argp->count;
0191     resp->pages = rqstp->rq_next_page;
0192     while (len > 0) {
0193         struct page *page = *(rqstp->rq_next_page++);
0194 
0195         rqstp->rq_vec[v].iov_base = page_address(page);
0196         rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE);
0197         len -= rqstp->rq_vec[v].iov_len;
0198         v++;
0199     }
0200 
0201     /* Obtain buffer pointer for payload. 19 is 1 word for
0202      * status, 17 words for fattr, and 1 word for the byte count.
0203      */
0204     svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
0205 
0206     resp->count = argp->count;
0207     fh_copy(&resp->fh, &argp->fh);
0208     resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
0209                  rqstp->rq_vec, v, &resp->count, &eof);
0210     if (resp->status == nfs_ok)
0211         resp->status = fh_getattr(&resp->fh, &resp->stat);
0212     else if (resp->status == nfserr_jukebox)
0213         return rpc_drop_reply;
0214     return rpc_success;
0215 }
0216 
0217 /* Reserved */
0218 static __be32
0219 nfsd_proc_writecache(struct svc_rqst *rqstp)
0220 {
0221     return rpc_success;
0222 }
0223 
0224 /*
0225  * Write data to a file
0226  * N.B. After this call resp->fh needs an fh_put
0227  */
0228 static __be32
0229 nfsd_proc_write(struct svc_rqst *rqstp)
0230 {
0231     struct nfsd_writeargs *argp = rqstp->rq_argp;
0232     struct nfsd_attrstat *resp = rqstp->rq_resp;
0233     unsigned long cnt = argp->len;
0234     unsigned int nvecs;
0235 
0236     dprintk("nfsd: WRITE    %s %u bytes at %d\n",
0237         SVCFH_fmt(&argp->fh),
0238         argp->len, argp->offset);
0239 
0240     nvecs = svc_fill_write_vector(rqstp, &argp->payload);
0241 
0242     resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
0243                   argp->offset, rqstp->rq_vec, nvecs,
0244                   &cnt, NFS_DATA_SYNC, NULL);
0245     if (resp->status == nfs_ok)
0246         resp->status = fh_getattr(&resp->fh, &resp->stat);
0247     else if (resp->status == nfserr_jukebox)
0248         return rpc_drop_reply;
0249     return rpc_success;
0250 }
0251 
0252 /*
0253  * CREATE processing is complicated. The keyword here is `overloaded.'
0254  * The parent directory is kept locked between the check for existence
0255  * and the actual create() call in compliance with VFS protocols.
0256  * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
0257  */
0258 static __be32
0259 nfsd_proc_create(struct svc_rqst *rqstp)
0260 {
0261     struct nfsd_createargs *argp = rqstp->rq_argp;
0262     struct nfsd_diropres *resp = rqstp->rq_resp;
0263     svc_fh      *dirfhp = &argp->fh;
0264     svc_fh      *newfhp = &resp->fh;
0265     struct iattr    *attr = &argp->attrs;
0266     struct nfsd_attrs attrs = {
0267         .na_iattr   = attr,
0268     };
0269     struct inode    *inode;
0270     struct dentry   *dchild;
0271     int     type, mode;
0272     int     hosterr;
0273     dev_t       rdev = 0, wanted = new_decode_dev(attr->ia_size);
0274 
0275     dprintk("nfsd: CREATE   %s %.*s\n",
0276         SVCFH_fmt(dirfhp), argp->len, argp->name);
0277 
0278     /* First verify the parent file handle */
0279     resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
0280     if (resp->status != nfs_ok)
0281         goto done; /* must fh_put dirfhp even on error */
0282 
0283     /* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
0284 
0285     resp->status = nfserr_exist;
0286     if (isdotent(argp->name, argp->len))
0287         goto done;
0288     hosterr = fh_want_write(dirfhp);
0289     if (hosterr) {
0290         resp->status = nfserrno(hosterr);
0291         goto done;
0292     }
0293 
0294     inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT);
0295     dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
0296     if (IS_ERR(dchild)) {
0297         resp->status = nfserrno(PTR_ERR(dchild));
0298         goto out_unlock;
0299     }
0300     fh_init(newfhp, NFS_FHSIZE);
0301     resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
0302     if (!resp->status && d_really_is_negative(dchild))
0303         resp->status = nfserr_noent;
0304     dput(dchild);
0305     if (resp->status) {
0306         if (resp->status != nfserr_noent)
0307             goto out_unlock;
0308         /*
0309          * If the new file handle wasn't verified, we can't tell
0310          * whether the file exists or not. Time to bail ...
0311          */
0312         resp->status = nfserr_acces;
0313         if (!newfhp->fh_dentry) {
0314             printk(KERN_WARNING 
0315                 "nfsd_proc_create: file handle not verified\n");
0316             goto out_unlock;
0317         }
0318     }
0319 
0320     inode = d_inode(newfhp->fh_dentry);
0321 
0322     /* Unfudge the mode bits */
0323     if (attr->ia_valid & ATTR_MODE) {
0324         type = attr->ia_mode & S_IFMT;
0325         mode = attr->ia_mode & ~S_IFMT;
0326         if (!type) {
0327             /* no type, so if target exists, assume same as that,
0328              * else assume a file */
0329             if (inode) {
0330                 type = inode->i_mode & S_IFMT;
0331                 switch(type) {
0332                 case S_IFCHR:
0333                 case S_IFBLK:
0334                     /* reserve rdev for later checking */
0335                     rdev = inode->i_rdev;
0336                     attr->ia_valid |= ATTR_SIZE;
0337 
0338                     fallthrough;
0339                 case S_IFIFO:
0340                     /* this is probably a permission check..
0341                      * at least IRIX implements perm checking on
0342                      *   echo thing > device-special-file-or-pipe
0343                      * by doing a CREATE with type==0
0344                      */
0345                     resp->status = nfsd_permission(rqstp,
0346                                  newfhp->fh_export,
0347                                  newfhp->fh_dentry,
0348                                  NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
0349                     if (resp->status && resp->status != nfserr_rofs)
0350                         goto out_unlock;
0351                 }
0352             } else
0353                 type = S_IFREG;
0354         }
0355     } else if (inode) {
0356         type = inode->i_mode & S_IFMT;
0357         mode = inode->i_mode & ~S_IFMT;
0358     } else {
0359         type = S_IFREG;
0360         mode = 0;   /* ??? */
0361     }
0362 
0363     attr->ia_valid |= ATTR_MODE;
0364     attr->ia_mode = mode;
0365 
0366     /* Special treatment for non-regular files according to the
0367      * gospel of sun micro
0368      */
0369     if (type != S_IFREG) {
0370         if (type != S_IFBLK && type != S_IFCHR) {
0371             rdev = 0;
0372         } else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
0373             /* If you think you've seen the worst, grok this. */
0374             type = S_IFIFO;
0375         } else {
0376             /* Okay, char or block special */
0377             if (!rdev)
0378                 rdev = wanted;
0379         }
0380 
0381         /* we've used the SIZE information, so discard it */
0382         attr->ia_valid &= ~ATTR_SIZE;
0383 
0384         /* Make sure the type and device matches */
0385         resp->status = nfserr_exist;
0386         if (inode && inode_wrong_type(inode, type))
0387             goto out_unlock;
0388     }
0389 
0390     resp->status = nfs_ok;
0391     if (!inode) {
0392         /* File doesn't exist. Create it and set attrs */
0393         resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name,
0394                           argp->len, &attrs, type, rdev,
0395                           newfhp);
0396     } else if (type == S_IFREG) {
0397         dprintk("nfsd:   existing %s, valid=%x, size=%ld\n",
0398             argp->name, attr->ia_valid, (long) attr->ia_size);
0399         /* File already exists. We ignore all attributes except
0400          * size, so that creat() behaves exactly like
0401          * open(..., O_CREAT|O_TRUNC|O_WRONLY).
0402          */
0403         attr->ia_valid &= ATTR_SIZE;
0404         if (attr->ia_valid)
0405             resp->status = nfsd_setattr(rqstp, newfhp, &attrs, 0,
0406                             (time64_t)0);
0407     }
0408 
0409 out_unlock:
0410     inode_unlock(dirfhp->fh_dentry->d_inode);
0411     fh_drop_write(dirfhp);
0412 done:
0413     fh_put(dirfhp);
0414     if (resp->status != nfs_ok)
0415         goto out;
0416     resp->status = fh_getattr(&resp->fh, &resp->stat);
0417 out:
0418     return rpc_success;
0419 }
0420 
0421 static __be32
0422 nfsd_proc_remove(struct svc_rqst *rqstp)
0423 {
0424     struct nfsd_diropargs *argp = rqstp->rq_argp;
0425     struct nfsd_stat *resp = rqstp->rq_resp;
0426 
0427     dprintk("nfsd: REMOVE   %s %.*s\n", SVCFH_fmt(&argp->fh),
0428         argp->len, argp->name);
0429 
0430     /* Unlink. -SIFDIR means file must not be a directory */
0431     resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR,
0432                    argp->name, argp->len);
0433     fh_put(&argp->fh);
0434     return rpc_success;
0435 }
0436 
0437 static __be32
0438 nfsd_proc_rename(struct svc_rqst *rqstp)
0439 {
0440     struct nfsd_renameargs *argp = rqstp->rq_argp;
0441     struct nfsd_stat *resp = rqstp->rq_resp;
0442 
0443     dprintk("nfsd: RENAME   %s %.*s -> \n",
0444         SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
0445     dprintk("nfsd:        ->  %s %.*s\n",
0446         SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
0447 
0448     resp->status = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
0449                    &argp->tfh, argp->tname, argp->tlen);
0450     fh_put(&argp->ffh);
0451     fh_put(&argp->tfh);
0452     return rpc_success;
0453 }
0454 
0455 static __be32
0456 nfsd_proc_link(struct svc_rqst *rqstp)
0457 {
0458     struct nfsd_linkargs *argp = rqstp->rq_argp;
0459     struct nfsd_stat *resp = rqstp->rq_resp;
0460 
0461     dprintk("nfsd: LINK     %s ->\n",
0462         SVCFH_fmt(&argp->ffh));
0463     dprintk("nfsd:    %s %.*s\n",
0464         SVCFH_fmt(&argp->tfh),
0465         argp->tlen,
0466         argp->tname);
0467 
0468     resp->status = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
0469                  &argp->ffh);
0470     fh_put(&argp->ffh);
0471     fh_put(&argp->tfh);
0472     return rpc_success;
0473 }
0474 
0475 static __be32
0476 nfsd_proc_symlink(struct svc_rqst *rqstp)
0477 {
0478     struct nfsd_symlinkargs *argp = rqstp->rq_argp;
0479     struct nfsd_stat *resp = rqstp->rq_resp;
0480     struct nfsd_attrs attrs = {
0481         .na_iattr   = &argp->attrs,
0482     };
0483     struct svc_fh   newfh;
0484 
0485     if (argp->tlen > NFS_MAXPATHLEN) {
0486         resp->status = nfserr_nametoolong;
0487         goto out;
0488     }
0489 
0490     argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
0491                         page_address(rqstp->rq_arg.pages[0]),
0492                         argp->tlen);
0493     if (IS_ERR(argp->tname)) {
0494         resp->status = nfserrno(PTR_ERR(argp->tname));
0495         goto out;
0496     }
0497 
0498     dprintk("nfsd: SYMLINK  %s %.*s -> %.*s\n",
0499         SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
0500         argp->tlen, argp->tname);
0501 
0502     fh_init(&newfh, NFS_FHSIZE);
0503     resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
0504                     argp->tname, &attrs, &newfh);
0505 
0506     kfree(argp->tname);
0507     fh_put(&argp->ffh);
0508     fh_put(&newfh);
0509 out:
0510     return rpc_success;
0511 }
0512 
0513 /*
0514  * Make directory. This operation is not idempotent.
0515  * N.B. After this call resp->fh needs an fh_put
0516  */
0517 static __be32
0518 nfsd_proc_mkdir(struct svc_rqst *rqstp)
0519 {
0520     struct nfsd_createargs *argp = rqstp->rq_argp;
0521     struct nfsd_diropres *resp = rqstp->rq_resp;
0522     struct nfsd_attrs attrs = {
0523         .na_iattr   = &argp->attrs,
0524     };
0525 
0526     dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
0527 
0528     if (resp->fh.fh_dentry) {
0529         printk(KERN_WARNING
0530             "nfsd_proc_mkdir: response already verified??\n");
0531     }
0532 
0533     argp->attrs.ia_valid &= ~ATTR_SIZE;
0534     fh_init(&resp->fh, NFS_FHSIZE);
0535     resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
0536                    &attrs, S_IFDIR, 0, &resp->fh);
0537     fh_put(&argp->fh);
0538     if (resp->status != nfs_ok)
0539         goto out;
0540 
0541     resp->status = fh_getattr(&resp->fh, &resp->stat);
0542 out:
0543     return rpc_success;
0544 }
0545 
0546 /*
0547  * Remove a directory
0548  */
0549 static __be32
0550 nfsd_proc_rmdir(struct svc_rqst *rqstp)
0551 {
0552     struct nfsd_diropargs *argp = rqstp->rq_argp;
0553     struct nfsd_stat *resp = rqstp->rq_resp;
0554 
0555     dprintk("nfsd: RMDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
0556 
0557     resp->status = nfsd_unlink(rqstp, &argp->fh, S_IFDIR,
0558                    argp->name, argp->len);
0559     fh_put(&argp->fh);
0560     return rpc_success;
0561 }
0562 
0563 static void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
0564                     struct nfsd_readdirres *resp,
0565                     u32 count)
0566 {
0567     struct xdr_buf *buf = &resp->dirlist;
0568     struct xdr_stream *xdr = &resp->xdr;
0569 
0570     count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp));
0571 
0572     memset(buf, 0, sizeof(*buf));
0573 
0574     /* Reserve room for the NULL ptr & eof flag (-2 words) */
0575     buf->buflen = count - XDR_UNIT * 2;
0576     buf->pages = rqstp->rq_next_page;
0577     rqstp->rq_next_page++;
0578 
0579     /* This is xdr_init_encode(), but it assumes that
0580      * the head kvec has already been consumed. */
0581     xdr_set_scratch_buffer(xdr, NULL, 0);
0582     xdr->buf = buf;
0583     xdr->page_ptr = buf->pages;
0584     xdr->iov = NULL;
0585     xdr->p = page_address(*buf->pages);
0586     xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE);
0587     xdr->rqst = NULL;
0588 }
0589 
0590 /*
0591  * Read a portion of a directory.
0592  */
0593 static __be32
0594 nfsd_proc_readdir(struct svc_rqst *rqstp)
0595 {
0596     struct nfsd_readdirargs *argp = rqstp->rq_argp;
0597     struct nfsd_readdirres *resp = rqstp->rq_resp;
0598     loff_t      offset;
0599 
0600     dprintk("nfsd: READDIR  %s %d bytes at %d\n",
0601         SVCFH_fmt(&argp->fh),       
0602         argp->count, argp->cookie);
0603 
0604     nfsd_init_dirlist_pages(rqstp, resp, argp->count);
0605 
0606     resp->common.err = nfs_ok;
0607     resp->cookie_offset = 0;
0608     offset = argp->cookie;
0609     resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
0610                     &resp->common, nfssvc_encode_entry);
0611     nfssvc_encode_nfscookie(resp, offset);
0612 
0613     fh_put(&argp->fh);
0614     return rpc_success;
0615 }
0616 
0617 /*
0618  * Get file system info
0619  */
0620 static __be32
0621 nfsd_proc_statfs(struct svc_rqst *rqstp)
0622 {
0623     struct nfsd_fhandle *argp = rqstp->rq_argp;
0624     struct nfsd_statfsres *resp = rqstp->rq_resp;
0625 
0626     dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
0627 
0628     resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
0629                    NFSD_MAY_BYPASS_GSS_ON_ROOT);
0630     fh_put(&argp->fh);
0631     return rpc_success;
0632 }
0633 
0634 /*
0635  * NFSv2 Server procedures.
0636  * Only the results of non-idempotent operations are cached.
0637  */
0638 
0639 #define ST 1        /* status */
0640 #define FH 8        /* filehandle */
0641 #define AT 18       /* attributes */
0642 
0643 static const struct svc_procedure nfsd_procedures2[18] = {
0644     [NFSPROC_NULL] = {
0645         .pc_func = nfsd_proc_null,
0646         .pc_decode = nfssvc_decode_voidarg,
0647         .pc_encode = nfssvc_encode_voidres,
0648         .pc_argsize = sizeof(struct nfsd_voidargs),
0649         .pc_ressize = sizeof(struct nfsd_voidres),
0650         .pc_cachetype = RC_NOCACHE,
0651         .pc_xdrressize = 0,
0652         .pc_name = "NULL",
0653     },
0654     [NFSPROC_GETATTR] = {
0655         .pc_func = nfsd_proc_getattr,
0656         .pc_decode = nfssvc_decode_fhandleargs,
0657         .pc_encode = nfssvc_encode_attrstatres,
0658         .pc_release = nfssvc_release_attrstat,
0659         .pc_argsize = sizeof(struct nfsd_fhandle),
0660         .pc_ressize = sizeof(struct nfsd_attrstat),
0661         .pc_cachetype = RC_NOCACHE,
0662         .pc_xdrressize = ST+AT,
0663         .pc_name = "GETATTR",
0664     },
0665     [NFSPROC_SETATTR] = {
0666         .pc_func = nfsd_proc_setattr,
0667         .pc_decode = nfssvc_decode_sattrargs,
0668         .pc_encode = nfssvc_encode_attrstatres,
0669         .pc_release = nfssvc_release_attrstat,
0670         .pc_argsize = sizeof(struct nfsd_sattrargs),
0671         .pc_ressize = sizeof(struct nfsd_attrstat),
0672         .pc_cachetype = RC_REPLBUFF,
0673         .pc_xdrressize = ST+AT,
0674         .pc_name = "SETATTR",
0675     },
0676     [NFSPROC_ROOT] = {
0677         .pc_func = nfsd_proc_root,
0678         .pc_decode = nfssvc_decode_voidarg,
0679         .pc_encode = nfssvc_encode_voidres,
0680         .pc_argsize = sizeof(struct nfsd_voidargs),
0681         .pc_ressize = sizeof(struct nfsd_voidres),
0682         .pc_cachetype = RC_NOCACHE,
0683         .pc_xdrressize = 0,
0684         .pc_name = "ROOT",
0685     },
0686     [NFSPROC_LOOKUP] = {
0687         .pc_func = nfsd_proc_lookup,
0688         .pc_decode = nfssvc_decode_diropargs,
0689         .pc_encode = nfssvc_encode_diropres,
0690         .pc_release = nfssvc_release_diropres,
0691         .pc_argsize = sizeof(struct nfsd_diropargs),
0692         .pc_ressize = sizeof(struct nfsd_diropres),
0693         .pc_cachetype = RC_NOCACHE,
0694         .pc_xdrressize = ST+FH+AT,
0695         .pc_name = "LOOKUP",
0696     },
0697     [NFSPROC_READLINK] = {
0698         .pc_func = nfsd_proc_readlink,
0699         .pc_decode = nfssvc_decode_fhandleargs,
0700         .pc_encode = nfssvc_encode_readlinkres,
0701         .pc_argsize = sizeof(struct nfsd_fhandle),
0702         .pc_ressize = sizeof(struct nfsd_readlinkres),
0703         .pc_cachetype = RC_NOCACHE,
0704         .pc_xdrressize = ST+1+NFS_MAXPATHLEN/4,
0705         .pc_name = "READLINK",
0706     },
0707     [NFSPROC_READ] = {
0708         .pc_func = nfsd_proc_read,
0709         .pc_decode = nfssvc_decode_readargs,
0710         .pc_encode = nfssvc_encode_readres,
0711         .pc_release = nfssvc_release_readres,
0712         .pc_argsize = sizeof(struct nfsd_readargs),
0713         .pc_ressize = sizeof(struct nfsd_readres),
0714         .pc_cachetype = RC_NOCACHE,
0715         .pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
0716         .pc_name = "READ",
0717     },
0718     [NFSPROC_WRITECACHE] = {
0719         .pc_func = nfsd_proc_writecache,
0720         .pc_decode = nfssvc_decode_voidarg,
0721         .pc_encode = nfssvc_encode_voidres,
0722         .pc_argsize = sizeof(struct nfsd_voidargs),
0723         .pc_ressize = sizeof(struct nfsd_voidres),
0724         .pc_cachetype = RC_NOCACHE,
0725         .pc_xdrressize = 0,
0726         .pc_name = "WRITECACHE",
0727     },
0728     [NFSPROC_WRITE] = {
0729         .pc_func = nfsd_proc_write,
0730         .pc_decode = nfssvc_decode_writeargs,
0731         .pc_encode = nfssvc_encode_attrstatres,
0732         .pc_release = nfssvc_release_attrstat,
0733         .pc_argsize = sizeof(struct nfsd_writeargs),
0734         .pc_ressize = sizeof(struct nfsd_attrstat),
0735         .pc_cachetype = RC_REPLBUFF,
0736         .pc_xdrressize = ST+AT,
0737         .pc_name = "WRITE",
0738     },
0739     [NFSPROC_CREATE] = {
0740         .pc_func = nfsd_proc_create,
0741         .pc_decode = nfssvc_decode_createargs,
0742         .pc_encode = nfssvc_encode_diropres,
0743         .pc_release = nfssvc_release_diropres,
0744         .pc_argsize = sizeof(struct nfsd_createargs),
0745         .pc_ressize = sizeof(struct nfsd_diropres),
0746         .pc_cachetype = RC_REPLBUFF,
0747         .pc_xdrressize = ST+FH+AT,
0748         .pc_name = "CREATE",
0749     },
0750     [NFSPROC_REMOVE] = {
0751         .pc_func = nfsd_proc_remove,
0752         .pc_decode = nfssvc_decode_diropargs,
0753         .pc_encode = nfssvc_encode_statres,
0754         .pc_argsize = sizeof(struct nfsd_diropargs),
0755         .pc_ressize = sizeof(struct nfsd_stat),
0756         .pc_cachetype = RC_REPLSTAT,
0757         .pc_xdrressize = ST,
0758         .pc_name = "REMOVE",
0759     },
0760     [NFSPROC_RENAME] = {
0761         .pc_func = nfsd_proc_rename,
0762         .pc_decode = nfssvc_decode_renameargs,
0763         .pc_encode = nfssvc_encode_statres,
0764         .pc_argsize = sizeof(struct nfsd_renameargs),
0765         .pc_ressize = sizeof(struct nfsd_stat),
0766         .pc_cachetype = RC_REPLSTAT,
0767         .pc_xdrressize = ST,
0768         .pc_name = "RENAME",
0769     },
0770     [NFSPROC_LINK] = {
0771         .pc_func = nfsd_proc_link,
0772         .pc_decode = nfssvc_decode_linkargs,
0773         .pc_encode = nfssvc_encode_statres,
0774         .pc_argsize = sizeof(struct nfsd_linkargs),
0775         .pc_ressize = sizeof(struct nfsd_stat),
0776         .pc_cachetype = RC_REPLSTAT,
0777         .pc_xdrressize = ST,
0778         .pc_name = "LINK",
0779     },
0780     [NFSPROC_SYMLINK] = {
0781         .pc_func = nfsd_proc_symlink,
0782         .pc_decode = nfssvc_decode_symlinkargs,
0783         .pc_encode = nfssvc_encode_statres,
0784         .pc_argsize = sizeof(struct nfsd_symlinkargs),
0785         .pc_ressize = sizeof(struct nfsd_stat),
0786         .pc_cachetype = RC_REPLSTAT,
0787         .pc_xdrressize = ST,
0788         .pc_name = "SYMLINK",
0789     },
0790     [NFSPROC_MKDIR] = {
0791         .pc_func = nfsd_proc_mkdir,
0792         .pc_decode = nfssvc_decode_createargs,
0793         .pc_encode = nfssvc_encode_diropres,
0794         .pc_release = nfssvc_release_diropres,
0795         .pc_argsize = sizeof(struct nfsd_createargs),
0796         .pc_ressize = sizeof(struct nfsd_diropres),
0797         .pc_cachetype = RC_REPLBUFF,
0798         .pc_xdrressize = ST+FH+AT,
0799         .pc_name = "MKDIR",
0800     },
0801     [NFSPROC_RMDIR] = {
0802         .pc_func = nfsd_proc_rmdir,
0803         .pc_decode = nfssvc_decode_diropargs,
0804         .pc_encode = nfssvc_encode_statres,
0805         .pc_argsize = sizeof(struct nfsd_diropargs),
0806         .pc_ressize = sizeof(struct nfsd_stat),
0807         .pc_cachetype = RC_REPLSTAT,
0808         .pc_xdrressize = ST,
0809         .pc_name = "RMDIR",
0810     },
0811     [NFSPROC_READDIR] = {
0812         .pc_func = nfsd_proc_readdir,
0813         .pc_decode = nfssvc_decode_readdirargs,
0814         .pc_encode = nfssvc_encode_readdirres,
0815         .pc_argsize = sizeof(struct nfsd_readdirargs),
0816         .pc_ressize = sizeof(struct nfsd_readdirres),
0817         .pc_cachetype = RC_NOCACHE,
0818         .pc_name = "READDIR",
0819     },
0820     [NFSPROC_STATFS] = {
0821         .pc_func = nfsd_proc_statfs,
0822         .pc_decode = nfssvc_decode_fhandleargs,
0823         .pc_encode = nfssvc_encode_statfsres,
0824         .pc_argsize = sizeof(struct nfsd_fhandle),
0825         .pc_ressize = sizeof(struct nfsd_statfsres),
0826         .pc_cachetype = RC_NOCACHE,
0827         .pc_xdrressize = ST+5,
0828         .pc_name = "STATFS",
0829     },
0830 };
0831 
0832 
0833 static unsigned int nfsd_count2[ARRAY_SIZE(nfsd_procedures2)];
0834 const struct svc_version nfsd_version2 = {
0835     .vs_vers    = 2,
0836     .vs_nproc   = 18,
0837     .vs_proc    = nfsd_procedures2,
0838     .vs_count   = nfsd_count2,
0839     .vs_dispatch    = nfsd_dispatch,
0840     .vs_xdrsize = NFS2_SVC_XDRSIZE,
0841 };
0842 
0843 /*
0844  * Map errnos to NFS errnos.
0845  */
0846 __be32
0847 nfserrno (int errno)
0848 {
0849     static struct {
0850         __be32  nfserr;
0851         int syserr;
0852     } nfs_errtbl[] = {
0853         { nfs_ok, 0 },
0854         { nfserr_perm, -EPERM },
0855         { nfserr_noent, -ENOENT },
0856         { nfserr_io, -EIO },
0857         { nfserr_nxio, -ENXIO },
0858         { nfserr_fbig, -E2BIG },
0859         { nfserr_stale, -EBADF },
0860         { nfserr_acces, -EACCES },
0861         { nfserr_exist, -EEXIST },
0862         { nfserr_xdev, -EXDEV },
0863         { nfserr_mlink, -EMLINK },
0864         { nfserr_nodev, -ENODEV },
0865         { nfserr_notdir, -ENOTDIR },
0866         { nfserr_isdir, -EISDIR },
0867         { nfserr_inval, -EINVAL },
0868         { nfserr_fbig, -EFBIG },
0869         { nfserr_nospc, -ENOSPC },
0870         { nfserr_rofs, -EROFS },
0871         { nfserr_mlink, -EMLINK },
0872         { nfserr_nametoolong, -ENAMETOOLONG },
0873         { nfserr_notempty, -ENOTEMPTY },
0874 #ifdef EDQUOT
0875         { nfserr_dquot, -EDQUOT },
0876 #endif
0877         { nfserr_stale, -ESTALE },
0878         { nfserr_jukebox, -ETIMEDOUT },
0879         { nfserr_jukebox, -ERESTARTSYS },
0880         { nfserr_jukebox, -EAGAIN },
0881         { nfserr_jukebox, -EWOULDBLOCK },
0882         { nfserr_jukebox, -ENOMEM },
0883         { nfserr_io, -ETXTBSY },
0884         { nfserr_notsupp, -EOPNOTSUPP },
0885         { nfserr_toosmall, -ETOOSMALL },
0886         { nfserr_serverfault, -ESERVERFAULT },
0887         { nfserr_serverfault, -ENFILE },
0888         { nfserr_io, -EREMOTEIO },
0889         { nfserr_stale, -EOPENSTALE },
0890         { nfserr_io, -EUCLEAN },
0891         { nfserr_perm, -ENOKEY },
0892         { nfserr_no_grace, -ENOGRACE},
0893     };
0894     int i;
0895 
0896     for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
0897         if (nfs_errtbl[i].syserr == errno)
0898             return nfs_errtbl[i].nfserr;
0899     }
0900     WARN_ONCE(1, "nfsd: non-standard errno: %d\n", errno);
0901     return nfserr_io;
0902 }
0903