cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

nfs3proc.c (27547B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Process version 3 NFS requests.
      4 *
      5 * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
      6 */
      7
      8#include <linux/fs.h>
      9#include <linux/ext2_fs.h>
     10#include <linux/magic.h>
     11#include <linux/namei.h>
     12
     13#include "cache.h"
     14#include "xdr3.h"
     15#include "vfs.h"
     16
     17#define NFSDDBG_FACILITY		NFSDDBG_PROC
     18
     19static int	nfs3_ftypes[] = {
     20	0,			/* NF3NON */
     21	S_IFREG,		/* NF3REG */
     22	S_IFDIR,		/* NF3DIR */
     23	S_IFBLK,		/* NF3BLK */
     24	S_IFCHR,		/* NF3CHR */
     25	S_IFLNK,		/* NF3LNK */
     26	S_IFSOCK,		/* NF3SOCK */
     27	S_IFIFO,		/* NF3FIFO */
     28};
     29
     30/*
     31 * NULL call.
     32 */
     33static __be32
     34nfsd3_proc_null(struct svc_rqst *rqstp)
     35{
     36	return rpc_success;
     37}
     38
     39/*
     40 * Get a file's attributes
     41 */
     42static __be32
     43nfsd3_proc_getattr(struct svc_rqst *rqstp)
     44{
     45	struct nfsd_fhandle *argp = rqstp->rq_argp;
     46	struct nfsd3_attrstat *resp = rqstp->rq_resp;
     47
     48	dprintk("nfsd: GETATTR(3)  %s\n",
     49		SVCFH_fmt(&argp->fh));
     50
     51	fh_copy(&resp->fh, &argp->fh);
     52	resp->status = fh_verify(rqstp, &resp->fh, 0,
     53				 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
     54	if (resp->status != nfs_ok)
     55		goto out;
     56
     57	resp->status = fh_getattr(&resp->fh, &resp->stat);
     58out:
     59	return rpc_success;
     60}
     61
     62/*
     63 * Set a file's attributes
     64 */
     65static __be32
     66nfsd3_proc_setattr(struct svc_rqst *rqstp)
     67{
     68	struct nfsd3_sattrargs *argp = rqstp->rq_argp;
     69	struct nfsd3_attrstat *resp = rqstp->rq_resp;
     70
     71	dprintk("nfsd: SETATTR(3)  %s\n",
     72				SVCFH_fmt(&argp->fh));
     73
     74	fh_copy(&resp->fh, &argp->fh);
     75	resp->status = nfsd_setattr(rqstp, &resp->fh, &argp->attrs,
     76				    argp->check_guard, argp->guardtime);
     77	return rpc_success;
     78}
     79
     80/*
     81 * Look up a path name component
     82 */
     83static __be32
     84nfsd3_proc_lookup(struct svc_rqst *rqstp)
     85{
     86	struct nfsd3_diropargs *argp = rqstp->rq_argp;
     87	struct nfsd3_diropres  *resp = rqstp->rq_resp;
     88
     89	dprintk("nfsd: LOOKUP(3)   %s %.*s\n",
     90				SVCFH_fmt(&argp->fh),
     91				argp->len,
     92				argp->name);
     93
     94	fh_copy(&resp->dirfh, &argp->fh);
     95	fh_init(&resp->fh, NFS3_FHSIZE);
     96
     97	resp->status = nfsd_lookup(rqstp, &resp->dirfh,
     98				   argp->name, argp->len,
     99				   &resp->fh);
    100	return rpc_success;
    101}
    102
    103/*
    104 * Check file access
    105 */
    106static __be32
    107nfsd3_proc_access(struct svc_rqst *rqstp)
    108{
    109	struct nfsd3_accessargs *argp = rqstp->rq_argp;
    110	struct nfsd3_accessres *resp = rqstp->rq_resp;
    111
    112	dprintk("nfsd: ACCESS(3)   %s 0x%x\n",
    113				SVCFH_fmt(&argp->fh),
    114				argp->access);
    115
    116	fh_copy(&resp->fh, &argp->fh);
    117	resp->access = argp->access;
    118	resp->status = nfsd_access(rqstp, &resp->fh, &resp->access, NULL);
    119	return rpc_success;
    120}
    121
    122/*
    123 * Read a symlink.
    124 */
    125static __be32
    126nfsd3_proc_readlink(struct svc_rqst *rqstp)
    127{
    128	struct nfsd_fhandle *argp = rqstp->rq_argp;
    129	struct nfsd3_readlinkres *resp = rqstp->rq_resp;
    130
    131	dprintk("nfsd: READLINK(3) %s\n", SVCFH_fmt(&argp->fh));
    132
    133	/* Read the symlink. */
    134	fh_copy(&resp->fh, &argp->fh);
    135	resp->len = NFS3_MAXPATHLEN;
    136	resp->pages = rqstp->rq_next_page++;
    137	resp->status = nfsd_readlink(rqstp, &resp->fh,
    138				     page_address(*resp->pages), &resp->len);
    139	return rpc_success;
    140}
    141
    142/*
    143 * Read a portion of a file.
    144 */
    145static __be32
    146nfsd3_proc_read(struct svc_rqst *rqstp)
    147{
    148	struct nfsd3_readargs *argp = rqstp->rq_argp;
    149	struct nfsd3_readres *resp = rqstp->rq_resp;
    150	u32 max_blocksize = svc_max_payload(rqstp);
    151	unsigned int len;
    152	int v;
    153
    154	dprintk("nfsd: READ(3) %s %lu bytes at %Lu\n",
    155				SVCFH_fmt(&argp->fh),
    156				(unsigned long) argp->count,
    157				(unsigned long long) argp->offset);
    158
    159	argp->count = min_t(u32, argp->count, max_blocksize);
    160	if (argp->offset > (u64)OFFSET_MAX)
    161		argp->offset = (u64)OFFSET_MAX;
    162	if (argp->offset + argp->count > (u64)OFFSET_MAX)
    163		argp->count = (u64)OFFSET_MAX - argp->offset;
    164
    165	v = 0;
    166	len = argp->count;
    167	resp->pages = rqstp->rq_next_page;
    168	while (len > 0) {
    169		struct page *page = *(rqstp->rq_next_page++);
    170
    171		rqstp->rq_vec[v].iov_base = page_address(page);
    172		rqstp->rq_vec[v].iov_len = min_t(unsigned int, len, PAGE_SIZE);
    173		len -= rqstp->rq_vec[v].iov_len;
    174		v++;
    175	}
    176
    177	/* Obtain buffer pointer for payload.
    178	 * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
    179	 * + 1 (xdr opaque byte count) = 26
    180	 */
    181	resp->count = argp->count;
    182	svc_reserve_auth(rqstp, ((1 + NFS3_POST_OP_ATTR_WORDS + 3)<<2) + resp->count +4);
    183
    184	fh_copy(&resp->fh, &argp->fh);
    185	resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
    186				 rqstp->rq_vec, v, &resp->count, &resp->eof);
    187	return rpc_success;
    188}
    189
    190/*
    191 * Write data to a file
    192 */
    193static __be32
    194nfsd3_proc_write(struct svc_rqst *rqstp)
    195{
    196	struct nfsd3_writeargs *argp = rqstp->rq_argp;
    197	struct nfsd3_writeres *resp = rqstp->rq_resp;
    198	unsigned long cnt = argp->len;
    199	unsigned int nvecs;
    200
    201	dprintk("nfsd: WRITE(3)    %s %d bytes at %Lu%s\n",
    202				SVCFH_fmt(&argp->fh),
    203				argp->len,
    204				(unsigned long long) argp->offset,
    205				argp->stable? " stable" : "");
    206
    207	resp->status = nfserr_fbig;
    208	if (argp->offset > (u64)OFFSET_MAX ||
    209	    argp->offset + argp->len > (u64)OFFSET_MAX)
    210		return rpc_success;
    211
    212	fh_copy(&resp->fh, &argp->fh);
    213	resp->committed = argp->stable;
    214	nvecs = svc_fill_write_vector(rqstp, &argp->payload);
    215
    216	resp->status = nfsd_write(rqstp, &resp->fh, argp->offset,
    217				  rqstp->rq_vec, nvecs, &cnt,
    218				  resp->committed, resp->verf);
    219	resp->count = cnt;
    220	return rpc_success;
    221}
    222
    223/*
    224 * Implement NFSv3's unchecked, guarded, and exclusive CREATE
    225 * semantics for regular files. Except for the created file,
    226 * this operation is stateless on the server.
    227 *
    228 * Upon return, caller must release @fhp and @resfhp.
    229 */
    230static __be32
    231nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
    232		  struct svc_fh *resfhp, struct nfsd3_createargs *argp)
    233{
    234	struct iattr *iap = &argp->attrs;
    235	struct dentry *parent, *child;
    236	__u32 v_mtime, v_atime;
    237	struct inode *inode;
    238	__be32 status;
    239	int host_err;
    240
    241	if (isdotent(argp->name, argp->len))
    242		return nfserr_exist;
    243	if (!(iap->ia_valid & ATTR_MODE))
    244		iap->ia_mode = 0;
    245
    246	status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_EXEC);
    247	if (status != nfs_ok)
    248		return status;
    249
    250	parent = fhp->fh_dentry;
    251	inode = d_inode(parent);
    252
    253	host_err = fh_want_write(fhp);
    254	if (host_err)
    255		return nfserrno(host_err);
    256
    257	fh_lock_nested(fhp, I_MUTEX_PARENT);
    258
    259	child = lookup_one_len(argp->name, parent, argp->len);
    260	if (IS_ERR(child)) {
    261		status = nfserrno(PTR_ERR(child));
    262		goto out;
    263	}
    264
    265	if (d_really_is_negative(child)) {
    266		status = fh_verify(rqstp, fhp, S_IFDIR, NFSD_MAY_CREATE);
    267		if (status != nfs_ok)
    268			goto out;
    269	}
    270
    271	status = fh_compose(resfhp, fhp->fh_export, child, fhp);
    272	if (status != nfs_ok)
    273		goto out;
    274
    275	v_mtime = 0;
    276	v_atime = 0;
    277	if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
    278		u32 *verifier = (u32 *)argp->verf;
    279
    280		/*
    281		 * Solaris 7 gets confused (bugid 4218508) if these have
    282		 * the high bit set, as do xfs filesystems without the
    283		 * "bigtime" feature. So just clear the high bits.
    284		 */
    285		v_mtime = verifier[0] & 0x7fffffff;
    286		v_atime = verifier[1] & 0x7fffffff;
    287	}
    288
    289	if (d_really_is_positive(child)) {
    290		status = nfs_ok;
    291
    292		switch (argp->createmode) {
    293		case NFS3_CREATE_UNCHECKED:
    294			if (!d_is_reg(child))
    295				break;
    296			iap->ia_valid &= ATTR_SIZE;
    297			goto set_attr;
    298		case NFS3_CREATE_GUARDED:
    299			status = nfserr_exist;
    300			break;
    301		case NFS3_CREATE_EXCLUSIVE:
    302			if (d_inode(child)->i_mtime.tv_sec == v_mtime &&
    303			    d_inode(child)->i_atime.tv_sec == v_atime &&
    304			    d_inode(child)->i_size == 0) {
    305				break;
    306			}
    307			status = nfserr_exist;
    308		}
    309		goto out;
    310	}
    311
    312	if (!IS_POSIXACL(inode))
    313		iap->ia_mode &= ~current_umask();
    314
    315	host_err = vfs_create(&init_user_ns, inode, child, iap->ia_mode, true);
    316	if (host_err < 0) {
    317		status = nfserrno(host_err);
    318		goto out;
    319	}
    320
    321	/* A newly created file already has a file size of zero. */
    322	if ((iap->ia_valid & ATTR_SIZE) && (iap->ia_size == 0))
    323		iap->ia_valid &= ~ATTR_SIZE;
    324	if (argp->createmode == NFS3_CREATE_EXCLUSIVE) {
    325		iap->ia_valid = ATTR_MTIME | ATTR_ATIME |
    326				ATTR_MTIME_SET | ATTR_ATIME_SET;
    327		iap->ia_mtime.tv_sec = v_mtime;
    328		iap->ia_atime.tv_sec = v_atime;
    329		iap->ia_mtime.tv_nsec = 0;
    330		iap->ia_atime.tv_nsec = 0;
    331	}
    332
    333set_attr:
    334	status = nfsd_create_setattr(rqstp, fhp, resfhp, iap);
    335
    336out:
    337	fh_unlock(fhp);
    338	if (child && !IS_ERR(child))
    339		dput(child);
    340	fh_drop_write(fhp);
    341	return status;
    342}
    343
    344static __be32
    345nfsd3_proc_create(struct svc_rqst *rqstp)
    346{
    347	struct nfsd3_createargs *argp = rqstp->rq_argp;
    348	struct nfsd3_diropres *resp = rqstp->rq_resp;
    349	svc_fh *dirfhp, *newfhp;
    350
    351	dprintk("nfsd: CREATE(3)   %s %.*s\n",
    352				SVCFH_fmt(&argp->fh),
    353				argp->len,
    354				argp->name);
    355
    356	dirfhp = fh_copy(&resp->dirfh, &argp->fh);
    357	newfhp = fh_init(&resp->fh, NFS3_FHSIZE);
    358
    359	resp->status = nfsd3_create_file(rqstp, dirfhp, newfhp, argp);
    360	return rpc_success;
    361}
    362
    363/*
    364 * Make directory. This operation is not idempotent.
    365 */
    366static __be32
    367nfsd3_proc_mkdir(struct svc_rqst *rqstp)
    368{
    369	struct nfsd3_createargs *argp = rqstp->rq_argp;
    370	struct nfsd3_diropres *resp = rqstp->rq_resp;
    371
    372	dprintk("nfsd: MKDIR(3)    %s %.*s\n",
    373				SVCFH_fmt(&argp->fh),
    374				argp->len,
    375				argp->name);
    376
    377	argp->attrs.ia_valid &= ~ATTR_SIZE;
    378	fh_copy(&resp->dirfh, &argp->fh);
    379	fh_init(&resp->fh, NFS3_FHSIZE);
    380	resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
    381				   &argp->attrs, S_IFDIR, 0, &resp->fh);
    382	fh_unlock(&resp->dirfh);
    383	return rpc_success;
    384}
    385
    386static __be32
    387nfsd3_proc_symlink(struct svc_rqst *rqstp)
    388{
    389	struct nfsd3_symlinkargs *argp = rqstp->rq_argp;
    390	struct nfsd3_diropres *resp = rqstp->rq_resp;
    391
    392	if (argp->tlen == 0) {
    393		resp->status = nfserr_inval;
    394		goto out;
    395	}
    396	if (argp->tlen > NFS3_MAXPATHLEN) {
    397		resp->status = nfserr_nametoolong;
    398		goto out;
    399	}
    400
    401	argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
    402						page_address(rqstp->rq_arg.pages[0]),
    403						argp->tlen);
    404	if (IS_ERR(argp->tname)) {
    405		resp->status = nfserrno(PTR_ERR(argp->tname));
    406		goto out;
    407	}
    408
    409	dprintk("nfsd: SYMLINK(3)  %s %.*s -> %.*s\n",
    410				SVCFH_fmt(&argp->ffh),
    411				argp->flen, argp->fname,
    412				argp->tlen, argp->tname);
    413
    414	fh_copy(&resp->dirfh, &argp->ffh);
    415	fh_init(&resp->fh, NFS3_FHSIZE);
    416	resp->status = nfsd_symlink(rqstp, &resp->dirfh, argp->fname,
    417				    argp->flen, argp->tname, &resp->fh);
    418	kfree(argp->tname);
    419out:
    420	return rpc_success;
    421}
    422
    423/*
    424 * Make socket/fifo/device.
    425 */
    426static __be32
    427nfsd3_proc_mknod(struct svc_rqst *rqstp)
    428{
    429	struct nfsd3_mknodargs *argp = rqstp->rq_argp;
    430	struct nfsd3_diropres  *resp = rqstp->rq_resp;
    431	int type;
    432	dev_t	rdev = 0;
    433
    434	dprintk("nfsd: MKNOD(3)    %s %.*s\n",
    435				SVCFH_fmt(&argp->fh),
    436				argp->len,
    437				argp->name);
    438
    439	fh_copy(&resp->dirfh, &argp->fh);
    440	fh_init(&resp->fh, NFS3_FHSIZE);
    441
    442	if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
    443		rdev = MKDEV(argp->major, argp->minor);
    444		if (MAJOR(rdev) != argp->major ||
    445		    MINOR(rdev) != argp->minor) {
    446			resp->status = nfserr_inval;
    447			goto out;
    448		}
    449	} else if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO) {
    450		resp->status = nfserr_badtype;
    451		goto out;
    452	}
    453
    454	type = nfs3_ftypes[argp->ftype];
    455	resp->status = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
    456				   &argp->attrs, type, rdev, &resp->fh);
    457	fh_unlock(&resp->dirfh);
    458out:
    459	return rpc_success;
    460}
    461
    462/*
    463 * Remove file/fifo/socket etc.
    464 */
    465static __be32
    466nfsd3_proc_remove(struct svc_rqst *rqstp)
    467{
    468	struct nfsd3_diropargs *argp = rqstp->rq_argp;
    469	struct nfsd3_attrstat *resp = rqstp->rq_resp;
    470
    471	dprintk("nfsd: REMOVE(3)   %s %.*s\n",
    472				SVCFH_fmt(&argp->fh),
    473				argp->len,
    474				argp->name);
    475
    476	/* Unlink. -S_IFDIR means file must not be a directory */
    477	fh_copy(&resp->fh, &argp->fh);
    478	resp->status = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR,
    479				   argp->name, argp->len);
    480	fh_unlock(&resp->fh);
    481	return rpc_success;
    482}
    483
    484/*
    485 * Remove a directory
    486 */
    487static __be32
    488nfsd3_proc_rmdir(struct svc_rqst *rqstp)
    489{
    490	struct nfsd3_diropargs *argp = rqstp->rq_argp;
    491	struct nfsd3_attrstat *resp = rqstp->rq_resp;
    492
    493	dprintk("nfsd: RMDIR(3)    %s %.*s\n",
    494				SVCFH_fmt(&argp->fh),
    495				argp->len,
    496				argp->name);
    497
    498	fh_copy(&resp->fh, &argp->fh);
    499	resp->status = nfsd_unlink(rqstp, &resp->fh, S_IFDIR,
    500				   argp->name, argp->len);
    501	fh_unlock(&resp->fh);
    502	return rpc_success;
    503}
    504
    505static __be32
    506nfsd3_proc_rename(struct svc_rqst *rqstp)
    507{
    508	struct nfsd3_renameargs *argp = rqstp->rq_argp;
    509	struct nfsd3_renameres *resp = rqstp->rq_resp;
    510
    511	dprintk("nfsd: RENAME(3)   %s %.*s ->\n",
    512				SVCFH_fmt(&argp->ffh),
    513				argp->flen,
    514				argp->fname);
    515	dprintk("nfsd: -> %s %.*s\n",
    516				SVCFH_fmt(&argp->tfh),
    517				argp->tlen,
    518				argp->tname);
    519
    520	fh_copy(&resp->ffh, &argp->ffh);
    521	fh_copy(&resp->tfh, &argp->tfh);
    522	resp->status = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
    523				   &resp->tfh, argp->tname, argp->tlen);
    524	return rpc_success;
    525}
    526
    527static __be32
    528nfsd3_proc_link(struct svc_rqst *rqstp)
    529{
    530	struct nfsd3_linkargs *argp = rqstp->rq_argp;
    531	struct nfsd3_linkres  *resp = rqstp->rq_resp;
    532
    533	dprintk("nfsd: LINK(3)     %s ->\n",
    534				SVCFH_fmt(&argp->ffh));
    535	dprintk("nfsd:   -> %s %.*s\n",
    536				SVCFH_fmt(&argp->tfh),
    537				argp->tlen,
    538				argp->tname);
    539
    540	fh_copy(&resp->fh,  &argp->ffh);
    541	fh_copy(&resp->tfh, &argp->tfh);
    542	resp->status = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
    543				 &resp->fh);
    544	return rpc_success;
    545}
    546
    547static void nfsd3_init_dirlist_pages(struct svc_rqst *rqstp,
    548				     struct nfsd3_readdirres *resp,
    549				     u32 count)
    550{
    551	struct xdr_buf *buf = &resp->dirlist;
    552	struct xdr_stream *xdr = &resp->xdr;
    553
    554	count = clamp(count, (u32)(XDR_UNIT * 2), svc_max_payload(rqstp));
    555
    556	memset(buf, 0, sizeof(*buf));
    557
    558	/* Reserve room for the NULL ptr & eof flag (-2 words) */
    559	buf->buflen = count - XDR_UNIT * 2;
    560	buf->pages = rqstp->rq_next_page;
    561	rqstp->rq_next_page += (buf->buflen + PAGE_SIZE - 1) >> PAGE_SHIFT;
    562
    563	/* This is xdr_init_encode(), but it assumes that
    564	 * the head kvec has already been consumed. */
    565	xdr_set_scratch_buffer(xdr, NULL, 0);
    566	xdr->buf = buf;
    567	xdr->page_ptr = buf->pages;
    568	xdr->iov = NULL;
    569	xdr->p = page_address(*buf->pages);
    570	xdr->end = (void *)xdr->p + min_t(u32, buf->buflen, PAGE_SIZE);
    571	xdr->rqst = NULL;
    572}
    573
    574/*
    575 * Read a portion of a directory.
    576 */
    577static __be32
    578nfsd3_proc_readdir(struct svc_rqst *rqstp)
    579{
    580	struct nfsd3_readdirargs *argp = rqstp->rq_argp;
    581	struct nfsd3_readdirres  *resp = rqstp->rq_resp;
    582	loff_t		offset;
    583
    584	dprintk("nfsd: READDIR(3)  %s %d bytes at %d\n",
    585				SVCFH_fmt(&argp->fh),
    586				argp->count, (u32) argp->cookie);
    587
    588	nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
    589
    590	fh_copy(&resp->fh, &argp->fh);
    591	resp->common.err = nfs_ok;
    592	resp->cookie_offset = 0;
    593	resp->rqstp = rqstp;
    594	offset = argp->cookie;
    595	resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
    596				    &resp->common, nfs3svc_encode_entry3);
    597	memcpy(resp->verf, argp->verf, 8);
    598	nfs3svc_encode_cookie3(resp, offset);
    599
    600	/* Recycle only pages that were part of the reply */
    601	rqstp->rq_next_page = resp->xdr.page_ptr + 1;
    602
    603	return rpc_success;
    604}
    605
    606/*
    607 * Read a portion of a directory, including file handles and attrs.
    608 * For now, we choose to ignore the dircount parameter.
    609 */
    610static __be32
    611nfsd3_proc_readdirplus(struct svc_rqst *rqstp)
    612{
    613	struct nfsd3_readdirargs *argp = rqstp->rq_argp;
    614	struct nfsd3_readdirres  *resp = rqstp->rq_resp;
    615	loff_t	offset;
    616
    617	dprintk("nfsd: READDIR+(3) %s %d bytes at %d\n",
    618				SVCFH_fmt(&argp->fh),
    619				argp->count, (u32) argp->cookie);
    620
    621	nfsd3_init_dirlist_pages(rqstp, resp, argp->count);
    622
    623	fh_copy(&resp->fh, &argp->fh);
    624	resp->common.err = nfs_ok;
    625	resp->cookie_offset = 0;
    626	resp->rqstp = rqstp;
    627	offset = argp->cookie;
    628
    629	resp->status = fh_verify(rqstp, &resp->fh, S_IFDIR, NFSD_MAY_NOP);
    630	if (resp->status != nfs_ok)
    631		goto out;
    632
    633	if (resp->fh.fh_export->ex_flags & NFSEXP_NOREADDIRPLUS) {
    634		resp->status = nfserr_notsupp;
    635		goto out;
    636	}
    637
    638	resp->status = nfsd_readdir(rqstp, &resp->fh, &offset,
    639				    &resp->common, nfs3svc_encode_entryplus3);
    640	memcpy(resp->verf, argp->verf, 8);
    641	nfs3svc_encode_cookie3(resp, offset);
    642
    643	/* Recycle only pages that were part of the reply */
    644	rqstp->rq_next_page = resp->xdr.page_ptr + 1;
    645
    646out:
    647	return rpc_success;
    648}
    649
    650/*
    651 * Get file system stats
    652 */
    653static __be32
    654nfsd3_proc_fsstat(struct svc_rqst *rqstp)
    655{
    656	struct nfsd_fhandle *argp = rqstp->rq_argp;
    657	struct nfsd3_fsstatres *resp = rqstp->rq_resp;
    658
    659	dprintk("nfsd: FSSTAT(3)   %s\n",
    660				SVCFH_fmt(&argp->fh));
    661
    662	resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats, 0);
    663	fh_put(&argp->fh);
    664	return rpc_success;
    665}
    666
    667/*
    668 * Get file system info
    669 */
    670static __be32
    671nfsd3_proc_fsinfo(struct svc_rqst *rqstp)
    672{
    673	struct nfsd_fhandle *argp = rqstp->rq_argp;
    674	struct nfsd3_fsinfores *resp = rqstp->rq_resp;
    675	u32	max_blocksize = svc_max_payload(rqstp);
    676
    677	dprintk("nfsd: FSINFO(3)   %s\n",
    678				SVCFH_fmt(&argp->fh));
    679
    680	resp->f_rtmax  = max_blocksize;
    681	resp->f_rtpref = max_blocksize;
    682	resp->f_rtmult = PAGE_SIZE;
    683	resp->f_wtmax  = max_blocksize;
    684	resp->f_wtpref = max_blocksize;
    685	resp->f_wtmult = PAGE_SIZE;
    686	resp->f_dtpref = max_blocksize;
    687	resp->f_maxfilesize = ~(u32) 0;
    688	resp->f_properties = NFS3_FSF_DEFAULT;
    689
    690	resp->status = fh_verify(rqstp, &argp->fh, 0,
    691				 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
    692
    693	/* Check special features of the file system. May request
    694	 * different read/write sizes for file systems known to have
    695	 * problems with large blocks */
    696	if (resp->status == nfs_ok) {
    697		struct super_block *sb = argp->fh.fh_dentry->d_sb;
    698
    699		/* Note that we don't care for remote fs's here */
    700		if (sb->s_magic == MSDOS_SUPER_MAGIC) {
    701			resp->f_properties = NFS3_FSF_BILLYBOY;
    702		}
    703		resp->f_maxfilesize = sb->s_maxbytes;
    704	}
    705
    706	fh_put(&argp->fh);
    707	return rpc_success;
    708}
    709
    710/*
    711 * Get pathconf info for the specified file
    712 */
    713static __be32
    714nfsd3_proc_pathconf(struct svc_rqst *rqstp)
    715{
    716	struct nfsd_fhandle *argp = rqstp->rq_argp;
    717	struct nfsd3_pathconfres *resp = rqstp->rq_resp;
    718
    719	dprintk("nfsd: PATHCONF(3) %s\n",
    720				SVCFH_fmt(&argp->fh));
    721
    722	/* Set default pathconf */
    723	resp->p_link_max = 255;		/* at least */
    724	resp->p_name_max = 255;		/* at least */
    725	resp->p_no_trunc = 0;
    726	resp->p_chown_restricted = 1;
    727	resp->p_case_insensitive = 0;
    728	resp->p_case_preserving = 1;
    729
    730	resp->status = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
    731
    732	if (resp->status == nfs_ok) {
    733		struct super_block *sb = argp->fh.fh_dentry->d_sb;
    734
    735		/* Note that we don't care for remote fs's here */
    736		switch (sb->s_magic) {
    737		case EXT2_SUPER_MAGIC:
    738			resp->p_link_max = EXT2_LINK_MAX;
    739			resp->p_name_max = EXT2_NAME_LEN;
    740			break;
    741		case MSDOS_SUPER_MAGIC:
    742			resp->p_case_insensitive = 1;
    743			resp->p_case_preserving  = 0;
    744			break;
    745		}
    746	}
    747
    748	fh_put(&argp->fh);
    749	return rpc_success;
    750}
    751
    752/*
    753 * Commit a file (range) to stable storage.
    754 */
    755static __be32
    756nfsd3_proc_commit(struct svc_rqst *rqstp)
    757{
    758	struct nfsd3_commitargs *argp = rqstp->rq_argp;
    759	struct nfsd3_commitres *resp = rqstp->rq_resp;
    760
    761	dprintk("nfsd: COMMIT(3)   %s %u@%Lu\n",
    762				SVCFH_fmt(&argp->fh),
    763				argp->count,
    764				(unsigned long long) argp->offset);
    765
    766	fh_copy(&resp->fh, &argp->fh);
    767	resp->status = nfsd_commit(rqstp, &resp->fh, argp->offset,
    768				   argp->count, resp->verf);
    769	return rpc_success;
    770}
    771
    772
    773/*
    774 * NFSv3 Server procedures.
    775 * Only the results of non-idempotent operations are cached.
    776 */
    777#define nfs3svc_encode_attrstatres	nfs3svc_encode_attrstat
    778#define nfs3svc_encode_wccstatres	nfs3svc_encode_wccstat
    779#define nfsd3_mkdirargs			nfsd3_createargs
    780#define nfsd3_readdirplusargs		nfsd3_readdirargs
    781#define nfsd3_fhandleargs		nfsd_fhandle
    782#define nfsd3_attrstatres		nfsd3_attrstat
    783#define nfsd3_wccstatres		nfsd3_attrstat
    784#define nfsd3_createres			nfsd3_diropres
    785
    786#define ST 1		/* status*/
    787#define FH 17		/* filehandle with length */
    788#define AT 21		/* attributes */
    789#define pAT (1+AT)	/* post attributes - conditional */
    790#define WC (7+pAT)	/* WCC attributes */
    791
    792static const struct svc_procedure nfsd_procedures3[22] = {
    793	[NFS3PROC_NULL] = {
    794		.pc_func = nfsd3_proc_null,
    795		.pc_decode = nfssvc_decode_voidarg,
    796		.pc_encode = nfssvc_encode_voidres,
    797		.pc_argsize = sizeof(struct nfsd_voidargs),
    798		.pc_ressize = sizeof(struct nfsd_voidres),
    799		.pc_cachetype = RC_NOCACHE,
    800		.pc_xdrressize = ST,
    801		.pc_name = "NULL",
    802	},
    803	[NFS3PROC_GETATTR] = {
    804		.pc_func = nfsd3_proc_getattr,
    805		.pc_decode = nfs3svc_decode_fhandleargs,
    806		.pc_encode = nfs3svc_encode_getattrres,
    807		.pc_release = nfs3svc_release_fhandle,
    808		.pc_argsize = sizeof(struct nfsd_fhandle),
    809		.pc_ressize = sizeof(struct nfsd3_attrstatres),
    810		.pc_cachetype = RC_NOCACHE,
    811		.pc_xdrressize = ST+AT,
    812		.pc_name = "GETATTR",
    813	},
    814	[NFS3PROC_SETATTR] = {
    815		.pc_func = nfsd3_proc_setattr,
    816		.pc_decode = nfs3svc_decode_sattrargs,
    817		.pc_encode = nfs3svc_encode_wccstatres,
    818		.pc_release = nfs3svc_release_fhandle,
    819		.pc_argsize = sizeof(struct nfsd3_sattrargs),
    820		.pc_ressize = sizeof(struct nfsd3_wccstatres),
    821		.pc_cachetype = RC_REPLBUFF,
    822		.pc_xdrressize = ST+WC,
    823		.pc_name = "SETATTR",
    824	},
    825	[NFS3PROC_LOOKUP] = {
    826		.pc_func = nfsd3_proc_lookup,
    827		.pc_decode = nfs3svc_decode_diropargs,
    828		.pc_encode = nfs3svc_encode_lookupres,
    829		.pc_release = nfs3svc_release_fhandle2,
    830		.pc_argsize = sizeof(struct nfsd3_diropargs),
    831		.pc_ressize = sizeof(struct nfsd3_diropres),
    832		.pc_cachetype = RC_NOCACHE,
    833		.pc_xdrressize = ST+FH+pAT+pAT,
    834		.pc_name = "LOOKUP",
    835	},
    836	[NFS3PROC_ACCESS] = {
    837		.pc_func = nfsd3_proc_access,
    838		.pc_decode = nfs3svc_decode_accessargs,
    839		.pc_encode = nfs3svc_encode_accessres,
    840		.pc_release = nfs3svc_release_fhandle,
    841		.pc_argsize = sizeof(struct nfsd3_accessargs),
    842		.pc_ressize = sizeof(struct nfsd3_accessres),
    843		.pc_cachetype = RC_NOCACHE,
    844		.pc_xdrressize = ST+pAT+1,
    845		.pc_name = "ACCESS",
    846	},
    847	[NFS3PROC_READLINK] = {
    848		.pc_func = nfsd3_proc_readlink,
    849		.pc_decode = nfs3svc_decode_fhandleargs,
    850		.pc_encode = nfs3svc_encode_readlinkres,
    851		.pc_release = nfs3svc_release_fhandle,
    852		.pc_argsize = sizeof(struct nfsd_fhandle),
    853		.pc_ressize = sizeof(struct nfsd3_readlinkres),
    854		.pc_cachetype = RC_NOCACHE,
    855		.pc_xdrressize = ST+pAT+1+NFS3_MAXPATHLEN/4,
    856		.pc_name = "READLINK",
    857	},
    858	[NFS3PROC_READ] = {
    859		.pc_func = nfsd3_proc_read,
    860		.pc_decode = nfs3svc_decode_readargs,
    861		.pc_encode = nfs3svc_encode_readres,
    862		.pc_release = nfs3svc_release_fhandle,
    863		.pc_argsize = sizeof(struct nfsd3_readargs),
    864		.pc_ressize = sizeof(struct nfsd3_readres),
    865		.pc_cachetype = RC_NOCACHE,
    866		.pc_xdrressize = ST+pAT+4+NFSSVC_MAXBLKSIZE/4,
    867		.pc_name = "READ",
    868	},
    869	[NFS3PROC_WRITE] = {
    870		.pc_func = nfsd3_proc_write,
    871		.pc_decode = nfs3svc_decode_writeargs,
    872		.pc_encode = nfs3svc_encode_writeres,
    873		.pc_release = nfs3svc_release_fhandle,
    874		.pc_argsize = sizeof(struct nfsd3_writeargs),
    875		.pc_ressize = sizeof(struct nfsd3_writeres),
    876		.pc_cachetype = RC_REPLBUFF,
    877		.pc_xdrressize = ST+WC+4,
    878		.pc_name = "WRITE",
    879	},
    880	[NFS3PROC_CREATE] = {
    881		.pc_func = nfsd3_proc_create,
    882		.pc_decode = nfs3svc_decode_createargs,
    883		.pc_encode = nfs3svc_encode_createres,
    884		.pc_release = nfs3svc_release_fhandle2,
    885		.pc_argsize = sizeof(struct nfsd3_createargs),
    886		.pc_ressize = sizeof(struct nfsd3_createres),
    887		.pc_cachetype = RC_REPLBUFF,
    888		.pc_xdrressize = ST+(1+FH+pAT)+WC,
    889		.pc_name = "CREATE",
    890	},
    891	[NFS3PROC_MKDIR] = {
    892		.pc_func = nfsd3_proc_mkdir,
    893		.pc_decode = nfs3svc_decode_mkdirargs,
    894		.pc_encode = nfs3svc_encode_createres,
    895		.pc_release = nfs3svc_release_fhandle2,
    896		.pc_argsize = sizeof(struct nfsd3_mkdirargs),
    897		.pc_ressize = sizeof(struct nfsd3_createres),
    898		.pc_cachetype = RC_REPLBUFF,
    899		.pc_xdrressize = ST+(1+FH+pAT)+WC,
    900		.pc_name = "MKDIR",
    901	},
    902	[NFS3PROC_SYMLINK] = {
    903		.pc_func = nfsd3_proc_symlink,
    904		.pc_decode = nfs3svc_decode_symlinkargs,
    905		.pc_encode = nfs3svc_encode_createres,
    906		.pc_release = nfs3svc_release_fhandle2,
    907		.pc_argsize = sizeof(struct nfsd3_symlinkargs),
    908		.pc_ressize = sizeof(struct nfsd3_createres),
    909		.pc_cachetype = RC_REPLBUFF,
    910		.pc_xdrressize = ST+(1+FH+pAT)+WC,
    911		.pc_name = "SYMLINK",
    912	},
    913	[NFS3PROC_MKNOD] = {
    914		.pc_func = nfsd3_proc_mknod,
    915		.pc_decode = nfs3svc_decode_mknodargs,
    916		.pc_encode = nfs3svc_encode_createres,
    917		.pc_release = nfs3svc_release_fhandle2,
    918		.pc_argsize = sizeof(struct nfsd3_mknodargs),
    919		.pc_ressize = sizeof(struct nfsd3_createres),
    920		.pc_cachetype = RC_REPLBUFF,
    921		.pc_xdrressize = ST+(1+FH+pAT)+WC,
    922		.pc_name = "MKNOD",
    923	},
    924	[NFS3PROC_REMOVE] = {
    925		.pc_func = nfsd3_proc_remove,
    926		.pc_decode = nfs3svc_decode_diropargs,
    927		.pc_encode = nfs3svc_encode_wccstatres,
    928		.pc_release = nfs3svc_release_fhandle,
    929		.pc_argsize = sizeof(struct nfsd3_diropargs),
    930		.pc_ressize = sizeof(struct nfsd3_wccstatres),
    931		.pc_cachetype = RC_REPLBUFF,
    932		.pc_xdrressize = ST+WC,
    933		.pc_name = "REMOVE",
    934	},
    935	[NFS3PROC_RMDIR] = {
    936		.pc_func = nfsd3_proc_rmdir,
    937		.pc_decode = nfs3svc_decode_diropargs,
    938		.pc_encode = nfs3svc_encode_wccstatres,
    939		.pc_release = nfs3svc_release_fhandle,
    940		.pc_argsize = sizeof(struct nfsd3_diropargs),
    941		.pc_ressize = sizeof(struct nfsd3_wccstatres),
    942		.pc_cachetype = RC_REPLBUFF,
    943		.pc_xdrressize = ST+WC,
    944		.pc_name = "RMDIR",
    945	},
    946	[NFS3PROC_RENAME] = {
    947		.pc_func = nfsd3_proc_rename,
    948		.pc_decode = nfs3svc_decode_renameargs,
    949		.pc_encode = nfs3svc_encode_renameres,
    950		.pc_release = nfs3svc_release_fhandle2,
    951		.pc_argsize = sizeof(struct nfsd3_renameargs),
    952		.pc_ressize = sizeof(struct nfsd3_renameres),
    953		.pc_cachetype = RC_REPLBUFF,
    954		.pc_xdrressize = ST+WC+WC,
    955		.pc_name = "RENAME",
    956	},
    957	[NFS3PROC_LINK] = {
    958		.pc_func = nfsd3_proc_link,
    959		.pc_decode = nfs3svc_decode_linkargs,
    960		.pc_encode = nfs3svc_encode_linkres,
    961		.pc_release = nfs3svc_release_fhandle2,
    962		.pc_argsize = sizeof(struct nfsd3_linkargs),
    963		.pc_ressize = sizeof(struct nfsd3_linkres),
    964		.pc_cachetype = RC_REPLBUFF,
    965		.pc_xdrressize = ST+pAT+WC,
    966		.pc_name = "LINK",
    967	},
    968	[NFS3PROC_READDIR] = {
    969		.pc_func = nfsd3_proc_readdir,
    970		.pc_decode = nfs3svc_decode_readdirargs,
    971		.pc_encode = nfs3svc_encode_readdirres,
    972		.pc_release = nfs3svc_release_fhandle,
    973		.pc_argsize = sizeof(struct nfsd3_readdirargs),
    974		.pc_ressize = sizeof(struct nfsd3_readdirres),
    975		.pc_cachetype = RC_NOCACHE,
    976		.pc_name = "READDIR",
    977	},
    978	[NFS3PROC_READDIRPLUS] = {
    979		.pc_func = nfsd3_proc_readdirplus,
    980		.pc_decode = nfs3svc_decode_readdirplusargs,
    981		.pc_encode = nfs3svc_encode_readdirres,
    982		.pc_release = nfs3svc_release_fhandle,
    983		.pc_argsize = sizeof(struct nfsd3_readdirplusargs),
    984		.pc_ressize = sizeof(struct nfsd3_readdirres),
    985		.pc_cachetype = RC_NOCACHE,
    986		.pc_name = "READDIRPLUS",
    987	},
    988	[NFS3PROC_FSSTAT] = {
    989		.pc_func = nfsd3_proc_fsstat,
    990		.pc_decode = nfs3svc_decode_fhandleargs,
    991		.pc_encode = nfs3svc_encode_fsstatres,
    992		.pc_argsize = sizeof(struct nfsd3_fhandleargs),
    993		.pc_ressize = sizeof(struct nfsd3_fsstatres),
    994		.pc_cachetype = RC_NOCACHE,
    995		.pc_xdrressize = ST+pAT+2*6+1,
    996		.pc_name = "FSSTAT",
    997	},
    998	[NFS3PROC_FSINFO] = {
    999		.pc_func = nfsd3_proc_fsinfo,
   1000		.pc_decode = nfs3svc_decode_fhandleargs,
   1001		.pc_encode = nfs3svc_encode_fsinfores,
   1002		.pc_argsize = sizeof(struct nfsd3_fhandleargs),
   1003		.pc_ressize = sizeof(struct nfsd3_fsinfores),
   1004		.pc_cachetype = RC_NOCACHE,
   1005		.pc_xdrressize = ST+pAT+12,
   1006		.pc_name = "FSINFO",
   1007	},
   1008	[NFS3PROC_PATHCONF] = {
   1009		.pc_func = nfsd3_proc_pathconf,
   1010		.pc_decode = nfs3svc_decode_fhandleargs,
   1011		.pc_encode = nfs3svc_encode_pathconfres,
   1012		.pc_argsize = sizeof(struct nfsd3_fhandleargs),
   1013		.pc_ressize = sizeof(struct nfsd3_pathconfres),
   1014		.pc_cachetype = RC_NOCACHE,
   1015		.pc_xdrressize = ST+pAT+6,
   1016		.pc_name = "PATHCONF",
   1017	},
   1018	[NFS3PROC_COMMIT] = {
   1019		.pc_func = nfsd3_proc_commit,
   1020		.pc_decode = nfs3svc_decode_commitargs,
   1021		.pc_encode = nfs3svc_encode_commitres,
   1022		.pc_release = nfs3svc_release_fhandle,
   1023		.pc_argsize = sizeof(struct nfsd3_commitargs),
   1024		.pc_ressize = sizeof(struct nfsd3_commitres),
   1025		.pc_cachetype = RC_NOCACHE,
   1026		.pc_xdrressize = ST+WC+2,
   1027		.pc_name = "COMMIT",
   1028	},
   1029};
   1030
   1031static unsigned int nfsd_count3[ARRAY_SIZE(nfsd_procedures3)];
   1032const struct svc_version nfsd_version3 = {
   1033	.vs_vers	= 3,
   1034	.vs_nproc	= 22,
   1035	.vs_proc	= nfsd_procedures3,
   1036	.vs_dispatch	= nfsd_dispatch,
   1037	.vs_count	= nfsd_count3,
   1038	.vs_xdrsize	= NFS3_SVC_XDRSIZE,
   1039};