Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Process version 3 NFS requests.
0004  *
0005  * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
0006  */
0007 
0008 #include <linux/fs.h>
0009 #include <linux/ext2_fs.h>
0010 #include <linux/magic.h>
0011 #include <linux/namei.h>
0012 
0013 #include "cache.h"
0014 #include "xdr3.h"
0015 #include "vfs.h"
0016 
0017 #define NFSDDBG_FACILITY        NFSDDBG_PROC
0018 
0019 static int  nfs3_ftypes[] = {
0020     0,          /* NF3NON */
0021     S_IFREG,        /* NF3REG */
0022     S_IFDIR,        /* NF3DIR */
0023     S_IFBLK,        /* NF3BLK */
0024     S_IFCHR,        /* NF3CHR */
0025     S_IFLNK,        /* NF3LNK */
0026     S_IFSOCK,       /* NF3SOCK */
0027     S_IFIFO,        /* NF3FIFO */
0028 };
0029 
0030 /*
0031  * NULL call.
0032  */
0033 static __be32
0034 nfsd3_proc_null(struct svc_rqst *rqstp)
0035 {
0036     return rpc_success;
0037 }
0038 
0039 /*
0040  * Get a file's attributes
0041  */
0042 static __be32
0043 nfsd3_proc_getattr(struct svc_rqst *rqstp)
0044 {
0045     struct nfsd_fhandle *argp = rqstp->rq_argp;
0046     struct nfsd3_attrstat *resp = rqstp->rq_resp;
0047 
0048     dprintk("nfsd: GETATTR(3)  %s\n",
0049         SVCFH_fmt(&argp->fh));
0050 
0051     fh_copy(&resp->fh, &argp->fh);
0052     resp->status = fh_verify(rqstp, &resp->fh, 0,
0053                  NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
0054     if (resp->status != nfs_ok)
0055         goto out;
0056 
0057     resp->status = fh_getattr(&resp->fh, &resp->stat);
0058 out:
0059     return rpc_success;
0060 }
0061 
0062 /*
0063  * Set a file's attributes
0064  */
0065 static __be32
0066 nfsd3_proc_setattr(struct svc_rqst *rqstp)
0067 {
0068     struct nfsd3_sattrargs *argp = rqstp->rq_argp;
0069     struct nfsd3_attrstat *resp = rqstp->rq_resp;
0070     struct nfsd_attrs attrs = {
0071         .na_iattr   = &argp->attrs,
0072     };
0073 
0074     dprintk("nfsd: SETATTR(3)  %s\n",
0075                 SVCFH_fmt(&argp->fh));
0076 
0077     fh_copy(&resp->fh, &argp->fh);
0078     resp->status = nfsd_setattr(rqstp, &resp->fh, &attrs,
0079                     argp->check_guard, argp->guardtime);
0080     return rpc_success;
0081 }
0082 
0083 /*
0084  * Look up a path name component
0085  */
0086 static __be32
0087 nfsd3_proc_lookup(struct svc_rqst *rqstp)
0088 {
0089     struct nfsd3_diropargs *argp = rqstp->rq_argp;
0090     struct nfsd3_diropres  *resp = rqstp->rq_resp;
0091 
0092     dprintk("nfsd: LOOKUP(3)   %s %.*s\n",
0093                 SVCFH_fmt(&argp->fh),
0094                 argp->len,
0095                 argp->name);
0096 
0097     fh_copy(&resp->dirfh, &argp->fh);
0098     fh_init(&resp->fh, NFS3_FHSIZE);
0099 
0100     resp->status = nfsd_lookup(rqstp, &resp->dirfh,
0101                    argp->name, argp->len,
0102                    &resp->fh);
0103     return rpc_success;
0104 }
0105 
0106 /*
0107  * Check file access
0108  */
0109 static __be32
0110 nfsd3_proc_access(struct svc_rqst *rqstp)
0111 {
0112     struct nfsd3_accessargs *argp = rqstp->rq_argp;
0113     struct nfsd3_accessres *resp = rqstp->rq_resp;
0114 
0115     dprintk("nfsd: ACCESS(3)   %s 0x%x\n",
0116                 SVCFH_fmt(&argp->fh),
0117                 argp->access);
0118 
0119     fh_copy(&resp->fh, &argp->fh);
0120     resp->access = argp->access;
0121     resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
0122     return rpc_success;
0123 }
0124 
0125 /*
0126  * Read a symlink.
0127  */
0128 static __be32
0129 nfsd3_proc_readlink(struct svc_rqst *rqstp)
0130 {
0131     struct nfsd_fhandle *argp = rqstp->rq_argp;
0132     struct nfsd3_readlinkres *resp = rqstp->rq_resp;
0133 
0134     dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
0135 
0136     /* Read the symlink. */
0137     fh_copy(&resp->fh, &argp->fh);
0138     resp->len = NFS3_MAXPATHLEN;
0139     resp->pages = rqstp->rq_next_page++;
0140     resp->status = nfsd_readlink(rqstp, &resp->fh,
0141                      page_address(*resp->pages), &resp->len);
0142     return rpc_success;
0143 }
0144 
0145 /*
0146  * Read a portion of a file.
0147  */
0148 static __be32
0149 nfsd3_proc_read(struct svc_rqst *rqstp)
0150 {
0151     struct nfsd3_readargs *argp = rqstp->rq_argp;
0152     struct nfsd3_readres *resp = rqstp->rq_resp;
0153     u32 max_blocksize = svc_max_payload(rqstp);
0154     unsigned int len;
0155     int v;
0156 
0157     dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
0158                 SVCFH_fmt(&argp->fh),
0159                 (unsigned long) argp->count,
0160                 (unsigned long long) argp->offset);
0161 
0162     argp->count = min_t(u32, argp->count, max_blocksize);
0163     if (argp->offset > (u64)OFFSET_MAX)
0164         argp->offset = (u64)OFFSET_MAX;
0165     if (argp->offset + argp->count > (u64)OFFSET_MAX)
0166         argp->count = (u64)OFFSET_MAX - argp->offset;
0167 
0168     v = 0;
0169     len = argp->count;
0170     resp->pages = rqstp->rq_next_page;
0171     while (len > 0) {
0172         struct page *page = *(rqstp->rq_next_page++);
0173 
0174         rqstp->rq_vec[v].iov_base = page_address(page);
0175         rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE);
0176         len -= rqstp->rq_vec[v].iov_len;
0177         v++;
0178     }
0179 
0180     /* Obtain buffer pointer for payload.
0181      * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
0182      * + 1 (xdr opaque byte count) = 26
0183      */
0184     resp->count = argp->count;
0185     svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
0186 
0187     fh_copy(&resp->fh, &argp->fh);
0188     resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
0189                  rqstp->rq_vec, v, &resp->count, &resp->eof);
0190     return rpc_success;
0191 }
0192 
0193 /*
0194  * Write data to a file
0195  */
0196 static __be32
0197 nfsd3_proc_write(struct svc_rqst *rqstp)
0198 {
0199     struct nfsd3_writeargs *argp = rqstp->rq_argp;
0200     struct nfsd3_writeres *resp = rqstp->rq_resp;
0201     unsigned long cnt = argp->len;
0202     unsigned int nvecs;
0203 
0204     dprintk("nfsd: WRITE(3)    %s %d bytes at %Lu%s\n",
0205                 SVCFH_fmt(&argp->fh),
0206                 argp->len,
0207                 (unsigned long long) argp->offset,
0208                 argp->stable? " stable" : "");
0209 
0210     resp->status = nfserr_fbig;
0211     if (argp->offset > (u64)OFFSET_MAX ||
0212         argp->offset + argp->len > (u64)OFFSET_MAX)
0213         return rpc_success;
0214 
0215     fh_copy(&resp->fh, &argp->fh);
0216     resp->committed = argp->stable;
0217     nvecs = svc_fill_write_vector(rqstp, &argp->payload);
0218 
0219     resp->status = nfsd_write(rqstp, &resp->fh, argp->offset,
0220                   rqstp->rq_vec, nvecs, &cnt,
0221                   resp->committed, resp->verf);
0222     resp->count = cnt;
0223     return rpc_success;
0224 }
0225 
0226 /*
0227  * Implement NFSv3's unchecked, guarded, and exclusive CREATE
0228  * semantics for regular files. Except for the created file,
0229  * this operation is stateless on the server.
0230  *
0231  * Upon return, caller must release @fhp and @resfhp.
0232  */
0233 static __be32
0234 nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
0235           struct svc_fh *resfhp, struct nfsd3_createargs *argp)
0236 {
0237     struct iattr *iap = &argp->attrs;
0238     struct dentry *parent, *child;
0239     struct nfsd_attrs attrs = {
0240         .na_iattr   = iap,
0241     };
0242     __u32 v_mtime, v_atime;
0243     struct inode *inode;
0244     __be32 status;
0245     int host_err;
0246 
0247     if (isdotent(argp->name, argp->len))
0248         return nfserr_exist;
0249     if (!(iap->ia_valid & ATTR_MODE))
0250         iap->ia_mode = 0;
0251 
0252     status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
0253     if (status != nfs_ok)
0254         return status;
0255 
0256     parent = fhp->fh_dentry;
0257     inode = d_inode(parent);
0258 
0259     host_err = fh_want_write(fhp);
0260     if (host_err)
0261         return nfserrno(host_err);
0262 
0263     inode_lock_nested(inode, I_MUTEX_PARENT);
0264 
0265     child = lookup_one_len(argp->name, parent, argp->len);
0266     if (IS_ERR(child)) {
0267         status = nfserrno(PTR_ERR(child));
0268         goto out;
0269     }
0270 
0271     if (d_really_is_negative(child)) {
0272         status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
0273         if (status != nfs_ok)
0274             goto out;
0275     }
0276 
0277     status = fh_compose(resfhp, fhp->fh_export, child, fhp);
0278     if (status != nfs_ok)
0279         goto out;
0280 
0281     v_mtime = 0;
0282     v_atime = 0;
0283     if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
0284         u32 *verifier = (u32 *)argp->verf;
0285 
0286         /*
0287          * Solaris 7 gets confused (bugid 4218508) if these have
0288          * the high bit set, as do xfs filesystems without the
0289          * "bigtime" feature. So just clear the high bits.
0290          */
0291         v_mtime = verifier[0] & 0x7fffffff;
0292         v_atime = verifier[1] & 0x7fffffff;
0293     }
0294 
0295     if (d_really_is_positive(child)) {
0296         status = nfs_ok;
0297 
0298         switch (argp->createmode) {
0299         case NFS3_CREATE_UNCHECKED:
0300             if (!d_is_reg(child))
0301                 break;
0302             iap->ia_valid &= ATTR_SIZE;
0303             goto set_attr;
0304         case NFS3_CREATE_GUARDED:
0305             status = nfserr_exist;
0306             break;
0307         case NFS3_CREATE_EXCLUSIVE:
0308             if (d_inode(child)->i_mtime.tv_sec == v_mtime &&
0309                 d_inode(child)->i_atime.tv_sec == v_atime &&
0310                 d_inode(child)->i_size == 0) {
0311                 break;
0312             }
0313             status = nfserr_exist;
0314         }
0315         goto out;
0316     }
0317 
0318     if (!IS_POSIXACL(inode))
0319         iap->ia_mode &= ~current_umask();
0320 
0321     fh_fill_pre_attrs(fhp);
0322     host_err = vfs_create(&init_user_ns, inode, child, iap->ia_mode, true);
0323     if (host_err < 0) {
0324         status = nfserrno(host_err);
0325         goto out;
0326     }
0327     fh_fill_post_attrs(fhp);
0328 
0329     /* A newly created file already has a file size of zero. */
0330     if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
0331         iap->ia_valid &= ~ATTR_SIZE;
0332     if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
0333         iap->ia_valid = ATTR_MTIME | ATTR_ATIME |
0334                 ATTR_MTIME_SET | ATTR_ATIME_SET;
0335         iap->ia_mtime.tv_sec = v_mtime;
0336         iap->ia_atime.tv_sec = v_atime;
0337         iap->ia_mtime.tv_nsec = 0;
0338         iap->ia_atime.tv_nsec = 0;
0339     }
0340 
0341 set_attr:
0342     status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
0343 
0344 out:
0345     inode_unlock(inode);
0346     if (child && !IS_ERR(child))
0347         dput(child);
0348     fh_drop_write(fhp);
0349     return status;
0350 }
0351 
0352 static __be32
0353 nfsd3_proc_create(struct svc_rqst *rqstp)
0354 {
0355     struct nfsd3_createargs *argp = rqstp->rq_argp;
0356     struct nfsd3_diropres *resp = rqstp->rq_resp;
0357     svc_fh *dirfhp, *newfhp;
0358 
0359     dprintk("nfsd: CREATE(3)   %s %.*s\n",
0360                 SVCFH_fmt(&argp->fh),
0361                 argp->len,
0362                 argp->name);
0363 
0364     dirfhp = fh_copy(&resp->dirfh, &argp->fh);
0365     newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
0366 
0367     resp->status = nfsd3_create_file(rqstp, dirfhp, newfhp, argp);
0368     return rpc_success;
0369 }
0370 
0371 /*
0372  * Make directory. This operation is not idempotent.
0373  */
0374 static __be32
0375 nfsd3_proc_mkdir(struct svc_rqst *rqstp)
0376 {
0377     struct nfsd3_createargs *argp = rqstp->rq_argp;
0378     struct nfsd3_diropres *resp = rqstp->rq_resp;
0379     struct nfsd_attrs attrs = {
0380         .na_iattr   = &argp->attrs,
0381     };
0382 
0383     dprintk("nfsd: MKDIR(3)    %s %.*s\n",
0384                 SVCFH_fmt(&argp->fh),
0385                 argp->len,
0386                 argp->name);
0387 
0388     argp->attrs.ia_valid &= ~ATTR_SIZE;
0389     fh_copy(&resp->dirfh, &argp->fh);
0390     fh_init(&resp->fh, NFS3_FHSIZE);
0391     resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
0392                    &attrs, S_IFDIR, 0, &resp->fh);
0393     return rpc_success;
0394 }
0395 
0396 static __be32
0397 nfsd3_proc_symlink(struct svc_rqst *rqstp)
0398 {
0399     struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
0400     struct nfsd3_diropres *resp = rqstp->rq_resp;
0401     struct nfsd_attrs attrs = {
0402         .na_iattr   = &argp->attrs,
0403     };
0404 
0405     if (argp->tlen == 0) {
0406         resp->status = nfserr_inval;
0407         goto out;
0408     }
0409     if (argp->tlen > NFS3_MAXPATHLEN) {
0410         resp->status = nfserr_nametoolong;
0411         goto out;
0412     }
0413 
0414     argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
0415                         page_address(rqstp->rq_arg.pages[0]),
0416                         argp->tlen);
0417     if (IS_ERR(argp->tname)) {
0418         resp->status = nfserrno(PTR_ERR(argp->tname));
0419         goto out;
0420     }
0421 
0422     dprintk("nfsd: SYMLINK(3)  %s %.*s -> %.*s\n",
0423                 SVCFH_fmt(&argp->ffh),
0424                 argp->flen, argp->fname,
0425                 argp->tlen, argp->tname);
0426 
0427     fh_copy(&resp->dirfh, &argp->ffh);
0428     fh_init(&resp->fh, NFS3_FHSIZE);
0429     resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname,
0430                     argp->flen, argp->tname, &attrs, &resp->fh);
0431     kfree(argp->tname);
0432 out:
0433     return rpc_success;
0434 }
0435 
0436 /*
0437  * Make socket/fifo/device.
0438  */
0439 static __be32
0440 nfsd3_proc_mknod(struct svc_rqst *rqstp)
0441 {
0442     struct nfsd3_mknodargs *argp = rqstp->rq_argp;
0443     struct nfsd3_diropres  *resp = rqstp->rq_resp;
0444     struct nfsd_attrs attrs = {
0445         .na_iattr   = &argp->attrs,
0446     };
0447     int type;
0448     dev_t   rdev = 0;
0449 
0450     dprintk("nfsd: MKNOD(3)    %s %.*s\n",
0451                 SVCFH_fmt(&argp->fh),
0452                 argp->len,
0453                 argp->name);
0454 
0455     fh_copy(&resp->dirfh, &argp->fh);
0456     fh_init(&resp->fh, NFS3_FHSIZE);
0457 
0458     if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
0459         rdev = MKDEV(argp->major, argp->minor);
0460         if (MAJOR(rdev) != argp->major ||
0461             MINOR(rdev) != argp->minor) {
0462             resp->status = nfserr_inval;
0463             goto out;
0464         }
0465     } else if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) {
0466         resp->status = nfserr_badtype;
0467         goto out;
0468     }
0469 
0470     type = nfs3_ftypes[argp->ftype];
0471     resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
0472                    &attrs, type, rdev, &resp->fh);
0473 out:
0474     return rpc_success;
0475 }
0476 
0477 /*
0478  * Remove file/fifo/socket etc.
0479  */
0480 static __be32
0481 nfsd3_proc_remove(struct svc_rqst *rqstp)
0482 {
0483     struct nfsd3_diropargs *argp = rqstp->rq_argp;
0484     struct nfsd3_attrstat *resp = rqstp->rq_resp;
0485 
0486     dprintk("nfsd: REMOVE(3)   %s %.*s\n",
0487                 SVCFH_fmt(&argp->fh),
0488                 argp->len,
0489                 argp->name);
0490 
0491     /* Unlink. -S_IFDIR means file must not be a directory */
0492     fh_copy(&resp->fh, &argp->fh);
0493     resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
0494                    argp->name, argp->len);
0495     return rpc_success;
0496 }
0497 
0498 /*
0499  * Remove a directory
0500  */
0501 static __be32
0502 nfsd3_proc_rmdir(struct svc_rqst *rqstp)
0503 {
0504     struct nfsd3_diropargs *argp = rqstp->rq_argp;
0505     struct nfsd3_attrstat *resp = rqstp->rq_resp;
0506 
0507     dprintk("nfsd: RMDIR(3)    %s %.*s\n",
0508                 SVCFH_fmt(&argp->fh),
0509                 argp->len,
0510                 argp->name);
0511 
0512     fh_copy(&resp->fh, &argp->fh);
0513     resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR,
0514                    argp->name, argp->len);
0515     return rpc_success;
0516 }
0517 
0518 static __be32
0519 nfsd3_proc_rename(struct svc_rqst *rqstp)
0520 {
0521     struct nfsd3_renameargs *argp = rqstp->rq_argp;
0522     struct nfsd3_renameres *resp = rqstp->rq_resp;
0523 
0524     dprintk("nfsd: RENAME(3)   %s %.*s ->\n",
0525                 SVCFH_fmt(&argp->ffh),
0526                 argp->flen,
0527                 argp->fname);
0528     dprintk("nfsd: -> %s %.*s\n",
0529                 SVCFH_fmt(&argp->tfh),
0530                 argp->tlen,
0531                 argp->tname);
0532 
0533     fh_copy(&resp->ffh, &argp->ffh);
0534     fh_copy(&resp->tfh, &argp->tfh);
0535     resp->status = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
0536                    &resp->tfh, argp->tname, argp->tlen);
0537     return rpc_success;
0538 }
0539 
0540 static __be32
0541 nfsd3_proc_link(struct svc_rqst *rqstp)
0542 {
0543     struct nfsd3_linkargs *argp = rqstp->rq_argp;
0544     struct nfsd3_linkres  *resp = rqstp->rq_resp;
0545 
0546     dprintk("nfsd: LINK(3)     %s ->\n",
0547                 SVCFH_fmt(&argp->ffh));
0548     dprintk("nfsd:   -> %s %.*s\n",
0549                 SVCFH_fmt(&argp->tfh),
0550                 argp->tlen,
0551                 argp->tname);
0552 
0553     fh_copy(&resp->fh,  &argp->ffh);
0554     fh_copy(&resp->tfh, &argp->tfh);
0555     resp->status = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
0556                  &resp->fh);
0557     return rpc_success;
0558 }
0559 
0560 static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
0561                      struct nfsd3_readdirres *resp,
0562                      u32 count)
0563 {
0564     struct xdr_buf *buf = &resp->dirlist;
0565     struct xdr_stream *xdr = &resp->xdr;
0566 
0567     count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp));
0568 
0569     memset(buf, 0, sizeof(*buf));
0570 
0571     /* Reserve room for the NULL ptr & eof flag (-2 words) */
0572     buf->buflen = count - XDR_UNIT * 2;
0573     buf->pages = rqstp->rq_next_page;
0574     rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
0575 
0576     /* This is xdr_init_encode(), but it assumes that
0577      * the head kvec has already been consumed. */
0578     xdr_set_scratch_buffer(xdr, NULL, 0);
0579     xdr->buf = buf;
0580     xdr->page_ptr = buf->pages;
0581     xdr->iov = NULL;
0582     xdr->p = page_address(*buf->pages);
0583     xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE);
0584     xdr->rqst = NULL;
0585 }
0586 
0587 /*
0588  * Read a portion of a directory.
0589  */
0590 static __be32
0591 nfsd3_proc_readdir(struct svc_rqst *rqstp)
0592 {
0593     struct nfsd3_readdirargs *argp = rqstp->rq_argp;
0594     struct nfsd3_readdirres  *resp = rqstp->rq_resp;
0595     loff_t      offset;
0596 
0597     dprintk("nfsd: READDIR(3)  %s %d bytes at %d\n",
0598                 SVCFH_fmt(&argp->fh),
0599                 argp->count, (u32) argp->cookie);
0600 
0601     nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
0602 
0603     fh_copy(&resp->fh, &argp->fh);
0604     resp->common.err = nfs_ok;
0605     resp->cookie_offset = 0;
0606     resp->rqstp = rqstp;
0607     offset = argp->cookie;
0608     resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
0609                     &resp->common, nfs3svc_encode_entry3);
0610     memcpy(resp->verf, argp->verf, 8);
0611     nfs3svc_encode_cookie3(resp, offset);
0612 
0613     /* Recycle only pages that were part of the reply */
0614     rqstp->rq_next_page = resp->xdr.page_ptr + 1;
0615 
0616     return rpc_success;
0617 }
0618 
0619 /*
0620  * Read a portion of a directory, including file handles and attrs.
0621  * For now, we choose to ignore the dircount parameter.
0622  */
0623 static __be32
0624 nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
0625 {
0626     struct nfsd3_readdirargs *argp = rqstp->rq_argp;
0627     struct nfsd3_readdirres  *resp = rqstp->rq_resp;
0628     loff_t  offset;
0629 
0630     dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
0631                 SVCFH_fmt(&argp->fh),
0632                 argp->count, (u32) argp->cookie);
0633 
0634     nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
0635 
0636     fh_copy(&resp->fh, &argp->fh);
0637     resp->common.err = nfs_ok;
0638     resp->cookie_offset = 0;
0639     resp->rqstp = rqstp;
0640     offset = argp->cookie;
0641 
0642     resp->status = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP);
0643     if (resp->status != nfs_ok)
0644         goto out;
0645 
0646     if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS) {
0647         resp->status = nfserr_notsupp;
0648         goto out;
0649     }
0650 
0651     resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
0652                     &resp->common, nfs3svc_encode_entryplus3);
0653     memcpy(resp->verf, argp->verf, 8);
0654     nfs3svc_encode_cookie3(resp, offset);
0655 
0656     /* Recycle only pages that were part of the reply */
0657     rqstp->rq_next_page = resp->xdr.page_ptr + 1;
0658 
0659 out:
0660     return rpc_success;
0661 }
0662 
0663 /*
0664  * Get file system stats
0665  */
0666 static __be32
0667 nfsd3_proc_fsstat(struct svc_rqst *rqstp)
0668 {
0669     struct nfsd_fhandle *argp = rqstp->rq_argp;
0670     struct nfsd3_fsstatres *resp = rqstp->rq_resp;
0671 
0672     dprintk("nfsd: FSSTAT(3)   %s\n",
0673                 SVCFH_fmt(&argp->fh));
0674 
0675     resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
0676     fh_put(&argp->fh);
0677     return rpc_success;
0678 }
0679 
0680 /*
0681  * Get file system info
0682  */
0683 static __be32
0684 nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
0685 {
0686     struct nfsd_fhandle *argp = rqstp->rq_argp;
0687     struct nfsd3_fsinfores *resp = rqstp->rq_resp;
0688     u32 max_blocksize = svc_max_payload(rqstp);
0689 
0690     dprintk("nfsd: FSINFO(3)   %s\n",
0691                 SVCFH_fmt(&argp->fh));
0692 
0693     resp->f_rtmax  = max_blocksize;
0694     resp->f_rtpref = max_blocksize;
0695     resp->f_rtmult = PAGE_SIZE;
0696     resp->f_wtmax  = max_blocksize;
0697     resp->f_wtpref = max_blocksize;
0698     resp->f_wtmult = PAGE_SIZE;
0699     resp->f_dtpref = max_blocksize;
0700     resp->f_maxfilesize = ~(u32) 0;
0701     resp->f_properties = NFS3_FSF_DEFAULT;
0702 
0703     resp->status = fh_verify(rqstp, &argp->fh, 0,
0704                  NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
0705 
0706     /* Check special features of the file system. May request
0707      * different read/write sizes for file systems known to have
0708      * problems with large blocks */
0709     if (resp->status == nfs_ok) {
0710         struct super_block *sb = argp->fh.fh_dentry->d_sb;
0711 
0712         /* Note that we don't care for remote fs's here */
0713         if (sb->s_magic == MSDOS_SUPER_MAGIC) {
0714             resp->f_properties = NFS3_FSF_BILLYBOY;
0715         }
0716         resp->f_maxfilesize = sb->s_maxbytes;
0717     }
0718 
0719     fh_put(&argp->fh);
0720     return rpc_success;
0721 }
0722 
0723 /*
0724  * Get pathconf info for the specified file
0725  */
0726 static __be32
0727 nfsd3_proc_pathconf(struct svc_rqst *rqstp)
0728 {
0729     struct nfsd_fhandle *argp = rqstp->rq_argp;
0730     struct nfsd3_pathconfres *resp = rqstp->rq_resp;
0731 
0732     dprintk("nfsd: PATHCONF(3) %s\n",
0733                 SVCFH_fmt(&argp->fh));
0734 
0735     /* Set default pathconf */
0736     resp->p_link_max = 255;     /* at least */
0737     resp->p_name_max = 255;     /* at least */
0738     resp->p_no_trunc = 0;
0739     resp->p_chown_restricted = 1;
0740     resp->p_case_insensitive = 0;
0741     resp->p_case_preserving = 1;
0742 
0743     resp->status = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
0744 
0745     if (resp->status == nfs_ok) {
0746         struct super_block *sb = argp->fh.fh_dentry->d_sb;
0747 
0748         /* Note that we don't care for remote fs's here */
0749         switch (sb->s_magic) {
0750         case EXT2_SUPER_MAGIC:
0751             resp->p_link_max = EXT2_LINK_MAX;
0752             resp->p_name_max = EXT2_NAME_LEN;
0753             break;
0754         case MSDOS_SUPER_MAGIC:
0755             resp->p_case_insensitive = 1;
0756             resp->p_case_preserving  = 0;
0757             break;
0758         }
0759     }
0760 
0761     fh_put(&argp->fh);
0762     return rpc_success;
0763 }
0764 
0765 /*
0766  * Commit a file (range) to stable storage.
0767  */
0768 static __be32
0769 nfsd3_proc_commit(struct svc_rqst *rqstp)
0770 {
0771     struct nfsd3_commitargs *argp = rqstp->rq_argp;
0772     struct nfsd3_commitres *resp = rqstp->rq_resp;
0773 
0774     dprintk("nfsd: COMMIT(3)   %s %u@%Lu\n",
0775                 SVCFH_fmt(&argp->fh),
0776                 argp->count,
0777                 (unsigned long long) argp->offset);
0778 
0779     fh_copy(&resp->fh, &argp->fh);
0780     resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
0781                    argp->count, resp->verf);
0782     return rpc_success;
0783 }
0784 
0785 
0786 /*
0787  * NFSv3 Server procedures.
0788  * Only the results of non-idempotent operations are cached.
0789  */
0790 #define nfs3svc_encode_attrstatres  nfs3svc_encode_attrstat
0791 #define nfs3svc_encode_wccstatres   nfs3svc_encode_wccstat
0792 #define nfsd3_mkdirargs         nfsd3_createargs
0793 #define nfsd3_readdirplusargs       nfsd3_readdirargs
0794 #define nfsd3_fhandleargs       nfsd_fhandle
0795 #define nfsd3_attrstatres       nfsd3_attrstat
0796 #define nfsd3_wccstatres        nfsd3_attrstat
0797 #define nfsd3_createres         nfsd3_diropres
0798 
0799 #define ST 1        /* status*/
0800 #define FH 17       /* filehandle with length */
0801 #define AT 21       /* attributes */
0802 #define pAT (1+AT)  /* post attributes - conditional */
0803 #define WC (7+pAT)  /* WCC attributes */
0804 
0805 static const struct svc_procedure nfsd_procedures3[22] = {
0806     [NFS3PROC_NULL] = {
0807         .pc_func = nfsd3_proc_null,
0808         .pc_decode = nfssvc_decode_voidarg,
0809         .pc_encode = nfssvc_encode_voidres,
0810         .pc_argsize = sizeof(struct nfsd_voidargs),
0811         .pc_ressize = sizeof(struct nfsd_voidres),
0812         .pc_cachetype = RC_NOCACHE,
0813         .pc_xdrressize = ST,
0814         .pc_name = "NULL",
0815     },
0816     [NFS3PROC_GETATTR] = {
0817         .pc_func = nfsd3_proc_getattr,
0818         .pc_decode = nfs3svc_decode_fhandleargs,
0819         .pc_encode = nfs3svc_encode_getattrres,
0820         .pc_release = nfs3svc_release_fhandle,
0821         .pc_argsize = sizeof(struct nfsd_fhandle),
0822         .pc_ressize = sizeof(struct nfsd3_attrstatres),
0823         .pc_cachetype = RC_NOCACHE,
0824         .pc_xdrressize = ST+AT,
0825         .pc_name = "GETATTR",
0826     },
0827     [NFS3PROC_SETATTR] = {
0828         .pc_func = nfsd3_proc_setattr,
0829         .pc_decode = nfs3svc_decode_sattrargs,
0830         .pc_encode = nfs3svc_encode_wccstatres,
0831         .pc_release = nfs3svc_release_fhandle,
0832         .pc_argsize = sizeof(struct nfsd3_sattrargs),
0833         .pc_ressize = sizeof(struct nfsd3_wccstatres),
0834         .pc_cachetype = RC_REPLBUFF,
0835         .pc_xdrressize = ST+WC,
0836         .pc_name = "SETATTR",
0837     },
0838     [NFS3PROC_LOOKUP] = {
0839         .pc_func = nfsd3_proc_lookup,
0840         .pc_decode = nfs3svc_decode_diropargs,
0841         .pc_encode = nfs3svc_encode_lookupres,
0842         .pc_release = nfs3svc_release_fhandle2,
0843         .pc_argsize = sizeof(struct nfsd3_diropargs),
0844         .pc_ressize = sizeof(struct nfsd3_diropres),
0845         .pc_cachetype = RC_NOCACHE,
0846         .pc_xdrressize = ST+FH+pAT+pAT,
0847         .pc_name = "LOOKUP",
0848     },
0849     [NFS3PROC_ACCESS] = {
0850         .pc_func = nfsd3_proc_access,
0851         .pc_decode = nfs3svc_decode_accessargs,
0852         .pc_encode = nfs3svc_encode_accessres,
0853         .pc_release = nfs3svc_release_fhandle,
0854         .pc_argsize = sizeof(struct nfsd3_accessargs),
0855         .pc_ressize = sizeof(struct nfsd3_accessres),
0856         .pc_cachetype = RC_NOCACHE,
0857         .pc_xdrressize = ST+pAT+1,
0858         .pc_name = "ACCESS",
0859     },
0860     [NFS3PROC_READLINK] = {
0861         .pc_func = nfsd3_proc_readlink,
0862         .pc_decode = nfs3svc_decode_fhandleargs,
0863         .pc_encode = nfs3svc_encode_readlinkres,
0864         .pc_release = nfs3svc_release_fhandle,
0865         .pc_argsize = sizeof(struct nfsd_fhandle),
0866         .pc_ressize = sizeof(struct nfsd3_readlinkres),
0867         .pc_cachetype = RC_NOCACHE,
0868         .pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
0869         .pc_name = "READLINK",
0870     },
0871     [NFS3PROC_READ] = {
0872         .pc_func = nfsd3_proc_read,
0873         .pc_decode = nfs3svc_decode_readargs,
0874         .pc_encode = nfs3svc_encode_readres,
0875         .pc_release = nfs3svc_release_fhandle,
0876         .pc_argsize = sizeof(struct nfsd3_readargs),
0877         .pc_ressize = sizeof(struct nfsd3_readres),
0878         .pc_cachetype = RC_NOCACHE,
0879         .pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
0880         .pc_name = "READ",
0881     },
0882     [NFS3PROC_WRITE] = {
0883         .pc_func = nfsd3_proc_write,
0884         .pc_decode = nfs3svc_decode_writeargs,
0885         .pc_encode = nfs3svc_encode_writeres,
0886         .pc_release = nfs3svc_release_fhandle,
0887         .pc_argsize = sizeof(struct nfsd3_writeargs),
0888         .pc_ressize = sizeof(struct nfsd3_writeres),
0889         .pc_cachetype = RC_REPLBUFF,
0890         .pc_xdrressize = ST+WC+4,
0891         .pc_name = "WRITE",
0892     },
0893     [NFS3PROC_CREATE] = {
0894         .pc_func = nfsd3_proc_create,
0895         .pc_decode = nfs3svc_decode_createargs,
0896         .pc_encode = nfs3svc_encode_createres,
0897         .pc_release = nfs3svc_release_fhandle2,
0898         .pc_argsize = sizeof(struct nfsd3_createargs),
0899         .pc_ressize = sizeof(struct nfsd3_createres),
0900         .pc_cachetype = RC_REPLBUFF,
0901         .pc_xdrressize = ST+(1+FH+pAT)+WC,
0902         .pc_name = "CREATE",
0903     },
0904     [NFS3PROC_MKDIR] = {
0905         .pc_func = nfsd3_proc_mkdir,
0906         .pc_decode = nfs3svc_decode_mkdirargs,
0907         .pc_encode = nfs3svc_encode_createres,
0908         .pc_release = nfs3svc_release_fhandle2,
0909         .pc_argsize = sizeof(struct nfsd3_mkdirargs),
0910         .pc_ressize = sizeof(struct nfsd3_createres),
0911         .pc_cachetype = RC_REPLBUFF,
0912         .pc_xdrressize = ST+(1+FH+pAT)+WC,
0913         .pc_name = "MKDIR",
0914     },
0915     [NFS3PROC_SYMLINK] = {
0916         .pc_func = nfsd3_proc_symlink,
0917         .pc_decode = nfs3svc_decode_symlinkargs,
0918         .pc_encode = nfs3svc_encode_createres,
0919         .pc_release = nfs3svc_release_fhandle2,
0920         .pc_argsize = sizeof(struct nfsd3_symlinkargs),
0921         .pc_ressize = sizeof(struct nfsd3_createres),
0922         .pc_cachetype = RC_REPLBUFF,
0923         .pc_xdrressize = ST+(1+FH+pAT)+WC,
0924         .pc_name = "SYMLINK",
0925     },
0926     [NFS3PROC_MKNOD] = {
0927         .pc_func = nfsd3_proc_mknod,
0928         .pc_decode = nfs3svc_decode_mknodargs,
0929         .pc_encode = nfs3svc_encode_createres,
0930         .pc_release = nfs3svc_release_fhandle2,
0931         .pc_argsize = sizeof(struct nfsd3_mknodargs),
0932         .pc_ressize = sizeof(struct nfsd3_createres),
0933         .pc_cachetype = RC_REPLBUFF,
0934         .pc_xdrressize = ST+(1+FH+pAT)+WC,
0935         .pc_name = "MKNOD",
0936     },
0937     [NFS3PROC_REMOVE] = {
0938         .pc_func = nfsd3_proc_remove,
0939         .pc_decode = nfs3svc_decode_diropargs,
0940         .pc_encode = nfs3svc_encode_wccstatres,
0941         .pc_release = nfs3svc_release_fhandle,
0942         .pc_argsize = sizeof(struct nfsd3_diropargs),
0943         .pc_ressize = sizeof(struct nfsd3_wccstatres),
0944         .pc_cachetype = RC_REPLBUFF,
0945         .pc_xdrressize = ST+WC,
0946         .pc_name = "REMOVE",
0947     },
0948     [NFS3PROC_RMDIR] = {
0949         .pc_func = nfsd3_proc_rmdir,
0950         .pc_decode = nfs3svc_decode_diropargs,
0951         .pc_encode = nfs3svc_encode_wccstatres,
0952         .pc_release = nfs3svc_release_fhandle,
0953         .pc_argsize = sizeof(struct nfsd3_diropargs),
0954         .pc_ressize = sizeof(struct nfsd3_wccstatres),
0955         .pc_cachetype = RC_REPLBUFF,
0956         .pc_xdrressize = ST+WC,
0957         .pc_name = "RMDIR",
0958     },
0959     [NFS3PROC_RENAME] = {
0960         .pc_func = nfsd3_proc_rename,
0961         .pc_decode = nfs3svc_decode_renameargs,
0962         .pc_encode = nfs3svc_encode_renameres,
0963         .pc_release = nfs3svc_release_fhandle2,
0964         .pc_argsize = sizeof(struct nfsd3_renameargs),
0965         .pc_ressize = sizeof(struct nfsd3_renameres),
0966         .pc_cachetype = RC_REPLBUFF,
0967         .pc_xdrressize = ST+WC+WC,
0968         .pc_name = "RENAME",
0969     },
0970     [NFS3PROC_LINK] = {
0971         .pc_func = nfsd3_proc_link,
0972         .pc_decode = nfs3svc_decode_linkargs,
0973         .pc_encode = nfs3svc_encode_linkres,
0974         .pc_release = nfs3svc_release_fhandle2,
0975         .pc_argsize = sizeof(struct nfsd3_linkargs),
0976         .pc_ressize = sizeof(struct nfsd3_linkres),
0977         .pc_cachetype = RC_REPLBUFF,
0978         .pc_xdrressize = ST+pAT+WC,
0979         .pc_name = "LINK",
0980     },
0981     [NFS3PROC_READDIR] = {
0982         .pc_func = nfsd3_proc_readdir,
0983         .pc_decode = nfs3svc_decode_readdirargs,
0984         .pc_encode = nfs3svc_encode_readdirres,
0985         .pc_release = nfs3svc_release_fhandle,
0986         .pc_argsize = sizeof(struct nfsd3_readdirargs),
0987         .pc_ressize = sizeof(struct nfsd3_readdirres),
0988         .pc_cachetype = RC_NOCACHE,
0989         .pc_name = "READDIR",
0990     },
0991     [NFS3PROC_READDIRPLUS] = {
0992         .pc_func = nfsd3_proc_readdirplus,
0993         .pc_decode = nfs3svc_decode_readdirplusargs,
0994         .pc_encode = nfs3svc_encode_readdirres,
0995         .pc_release = nfs3svc_release_fhandle,
0996         .pc_argsize = sizeof(struct nfsd3_readdirplusargs),
0997         .pc_ressize = sizeof(struct nfsd3_readdirres),
0998         .pc_cachetype = RC_NOCACHE,
0999         .pc_name = "READDIRPLUS",
1000     },
1001     [NFS3PROC_FSSTAT] = {
1002         .pc_func = nfsd3_proc_fsstat,
1003         .pc_decode = nfs3svc_decode_fhandleargs,
1004         .pc_encode = nfs3svc_encode_fsstatres,
1005         .pc_argsize = sizeof(struct nfsd3_fhandleargs),
1006         .pc_ressize = sizeof(struct nfsd3_fsstatres),
1007         .pc_cachetype = RC_NOCACHE,
1008         .pc_xdrressize = ST+pAT+2*6+1,
1009         .pc_name = "FSSTAT",
1010     },
1011     [NFS3PROC_FSINFO] = {
1012         .pc_func = nfsd3_proc_fsinfo,
1013         .pc_decode = nfs3svc_decode_fhandleargs,
1014         .pc_encode = nfs3svc_encode_fsinfores,
1015         .pc_argsize = sizeof(struct nfsd3_fhandleargs),
1016         .pc_ressize = sizeof(struct nfsd3_fsinfores),
1017         .pc_cachetype = RC_NOCACHE,
1018         .pc_xdrressize = ST+pAT+12,
1019         .pc_name = "FSINFO",
1020     },
1021     [NFS3PROC_PATHCONF] = {
1022         .pc_func = nfsd3_proc_pathconf,
1023         .pc_decode = nfs3svc_decode_fhandleargs,
1024         .pc_encode = nfs3svc_encode_pathconfres,
1025         .pc_argsize = sizeof(struct nfsd3_fhandleargs),
1026         .pc_ressize = sizeof(struct nfsd3_pathconfres),
1027         .pc_cachetype = RC_NOCACHE,
1028         .pc_xdrressize = ST+pAT+6,
1029         .pc_name = "PATHCONF",
1030     },
1031     [NFS3PROC_COMMIT] = {
1032         .pc_func = nfsd3_proc_commit,
1033         .pc_decode = nfs3svc_decode_commitargs,
1034         .pc_encode = nfs3svc_encode_commitres,
1035         .pc_release = nfs3svc_release_fhandle,
1036         .pc_argsize = sizeof(struct nfsd3_commitargs),
1037         .pc_ressize = sizeof(struct nfsd3_commitres),
1038         .pc_cachetype = RC_NOCACHE,
1039         .pc_xdrressize = ST+WC+2,
1040         .pc_name = "COMMIT",
1041     },
1042 };
1043 
1044 static unsigned int nfsd_count3[ARRAY_SIZE(nfsd_procedures3)];
1045 const struct svc_version nfsd_version3 = {
1046     .vs_vers    = 3,
1047     .vs_nproc   = 22,
1048     .vs_proc    = nfsd_procedures3,
1049     .vs_dispatch    = nfsd_dispatch,
1050     .vs_count   = nfsd_count3,
1051     .vs_xdrsize = NFS3_SVC_XDRSIZE,
1052 };