162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Process version 2 NFS requests.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/namei.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "cache.h"
1162306a36Sopenharmony_ci#include "xdr.h"
1262306a36Sopenharmony_ci#include "vfs.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define NFSDDBG_FACILITY		NFSDDBG_PROC
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_cistatic __be32
1762306a36Sopenharmony_cinfsd_proc_null(struct svc_rqst *rqstp)
1862306a36Sopenharmony_ci{
1962306a36Sopenharmony_ci	return rpc_success;
2062306a36Sopenharmony_ci}
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci/*
2362306a36Sopenharmony_ci * Get a file's attributes
2462306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put
2562306a36Sopenharmony_ci */
2662306a36Sopenharmony_cistatic __be32
2762306a36Sopenharmony_cinfsd_proc_getattr(struct svc_rqst *rqstp)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	struct nfsd_fhandle *argp = rqstp->rq_argp;
3062306a36Sopenharmony_ci	struct nfsd_attrstat *resp = rqstp->rq_resp;
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	fh_copy(&resp->fh, &argp->fh);
3562306a36Sopenharmony_ci	resp->status = fh_verify(rqstp, &resp->fh, 0,
3662306a36Sopenharmony_ci				 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
3762306a36Sopenharmony_ci	if (resp->status != nfs_ok)
3862306a36Sopenharmony_ci		goto out;
3962306a36Sopenharmony_ci	resp->status = fh_getattr(&resp->fh, &resp->stat);
4062306a36Sopenharmony_ciout:
4162306a36Sopenharmony_ci	return rpc_success;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci/*
4562306a36Sopenharmony_ci * Set a file's attributes
4662306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put
4762306a36Sopenharmony_ci */
4862306a36Sopenharmony_cistatic __be32
4962306a36Sopenharmony_cinfsd_proc_setattr(struct svc_rqst *rqstp)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	struct nfsd_sattrargs *argp = rqstp->rq_argp;
5262306a36Sopenharmony_ci	struct nfsd_attrstat *resp = rqstp->rq_resp;
5362306a36Sopenharmony_ci	struct iattr *iap = &argp->attrs;
5462306a36Sopenharmony_ci	struct nfsd_attrs attrs = {
5562306a36Sopenharmony_ci		.na_iattr	= iap,
5662306a36Sopenharmony_ci	};
5762306a36Sopenharmony_ci	struct svc_fh *fhp;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	dprintk("nfsd: SETATTR  %s, valid=%x, size=%ld\n",
6062306a36Sopenharmony_ci		SVCFH_fmt(&argp->fh),
6162306a36Sopenharmony_ci		argp->attrs.ia_valid, (long) argp->attrs.ia_size);
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	fhp = fh_copy(&resp->fh, &argp->fh);
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci	/*
6662306a36Sopenharmony_ci	 * NFSv2 does not differentiate between "set-[ac]time-to-now"
6762306a36Sopenharmony_ci	 * which only requires access, and "set-[ac]time-to-X" which
6862306a36Sopenharmony_ci	 * requires ownership.
6962306a36Sopenharmony_ci	 * So if it looks like it might be "set both to the same time which
7062306a36Sopenharmony_ci	 * is close to now", and if setattr_prepare fails, then we
7162306a36Sopenharmony_ci	 * convert to "set to now" instead of "set to explicit time"
7262306a36Sopenharmony_ci	 *
7362306a36Sopenharmony_ci	 * We only call setattr_prepare as the last test as technically
7462306a36Sopenharmony_ci	 * it is not an interface that we should be using.
7562306a36Sopenharmony_ci	 */
7662306a36Sopenharmony_ci#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
7762306a36Sopenharmony_ci#define	MAX_TOUCH_TIME_ERROR (30*60)
7862306a36Sopenharmony_ci	if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
7962306a36Sopenharmony_ci	    iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
8062306a36Sopenharmony_ci		/*
8162306a36Sopenharmony_ci		 * Looks probable.
8262306a36Sopenharmony_ci		 *
8362306a36Sopenharmony_ci		 * Now just make sure time is in the right ballpark.
8462306a36Sopenharmony_ci		 * Solaris, at least, doesn't seem to care what the time
8562306a36Sopenharmony_ci		 * request is.  We require it be within 30 minutes of now.
8662306a36Sopenharmony_ci		 */
8762306a36Sopenharmony_ci		time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds();
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci		resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
9062306a36Sopenharmony_ci		if (resp->status != nfs_ok)
9162306a36Sopenharmony_ci			goto out;
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci		if (delta < 0)
9462306a36Sopenharmony_ci			delta = -delta;
9562306a36Sopenharmony_ci		if (delta < MAX_TOUCH_TIME_ERROR &&
9662306a36Sopenharmony_ci		    setattr_prepare(&nop_mnt_idmap, fhp->fh_dentry, iap) != 0) {
9762306a36Sopenharmony_ci			/*
9862306a36Sopenharmony_ci			 * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
9962306a36Sopenharmony_ci			 * This will cause notify_change to set these times
10062306a36Sopenharmony_ci			 * to "now"
10162306a36Sopenharmony_ci			 */
10262306a36Sopenharmony_ci			iap->ia_valid &= ~BOTH_TIME_SET;
10362306a36Sopenharmony_ci		}
10462306a36Sopenharmony_ci	}
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci	resp->status = nfsd_setattr(rqstp, fhp, &attrs, 0, (time64_t)0);
10762306a36Sopenharmony_ci	if (resp->status != nfs_ok)
10862306a36Sopenharmony_ci		goto out;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	resp->status = fh_getattr(&resp->fh, &resp->stat);
11162306a36Sopenharmony_ciout:
11262306a36Sopenharmony_ci	return rpc_success;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/* Obsolete, replaced by MNTPROC_MNT. */
11662306a36Sopenharmony_cistatic __be32
11762306a36Sopenharmony_cinfsd_proc_root(struct svc_rqst *rqstp)
11862306a36Sopenharmony_ci{
11962306a36Sopenharmony_ci	return rpc_success;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci/*
12362306a36Sopenharmony_ci * Look up a path name component
12462306a36Sopenharmony_ci * Note: the dentry in the resp->fh may be negative if the file
12562306a36Sopenharmony_ci * doesn't exist yet.
12662306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put
12762306a36Sopenharmony_ci */
12862306a36Sopenharmony_cistatic __be32
12962306a36Sopenharmony_cinfsd_proc_lookup(struct svc_rqst *rqstp)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct nfsd_diropargs *argp = rqstp->rq_argp;
13262306a36Sopenharmony_ci	struct nfsd_diropres *resp = rqstp->rq_resp;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	dprintk("nfsd: LOOKUP   %s %.*s\n",
13562306a36Sopenharmony_ci		SVCFH_fmt(&argp->fh), argp->len, argp->name);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	fh_init(&resp->fh, NFS_FHSIZE);
13862306a36Sopenharmony_ci	resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
13962306a36Sopenharmony_ci				   &resp->fh);
14062306a36Sopenharmony_ci	fh_put(&argp->fh);
14162306a36Sopenharmony_ci	if (resp->status != nfs_ok)
14262306a36Sopenharmony_ci		goto out;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	resp->status = fh_getattr(&resp->fh, &resp->stat);
14562306a36Sopenharmony_ciout:
14662306a36Sopenharmony_ci	return rpc_success;
14762306a36Sopenharmony_ci}
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci/*
15062306a36Sopenharmony_ci * Read a symlink.
15162306a36Sopenharmony_ci */
15262306a36Sopenharmony_cistatic __be32
15362306a36Sopenharmony_cinfsd_proc_readlink(struct svc_rqst *rqstp)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	struct nfsd_fhandle *argp = rqstp->rq_argp;
15662306a36Sopenharmony_ci	struct nfsd_readlinkres *resp = rqstp->rq_resp;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	/* Read the symlink. */
16162306a36Sopenharmony_ci	resp->len = NFS_MAXPATHLEN;
16262306a36Sopenharmony_ci	resp->page = *(rqstp->rq_next_page++);
16362306a36Sopenharmony_ci	resp->status = nfsd_readlink(rqstp, &argp->fh,
16462306a36Sopenharmony_ci				     page_address(resp->page), &resp->len);
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	fh_put(&argp->fh);
16762306a36Sopenharmony_ci	return rpc_success;
16862306a36Sopenharmony_ci}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci/*
17162306a36Sopenharmony_ci * Read a portion of a file.
17262306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put
17362306a36Sopenharmony_ci */
17462306a36Sopenharmony_cistatic __be32
17562306a36Sopenharmony_cinfsd_proc_read(struct svc_rqst *rqstp)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	struct nfsd_readargs *argp = rqstp->rq_argp;
17862306a36Sopenharmony_ci	struct nfsd_readres *resp = rqstp->rq_resp;
17962306a36Sopenharmony_ci	u32 eof;
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	dprintk("nfsd: READ    %s %d bytes at %d\n",
18262306a36Sopenharmony_ci		SVCFH_fmt(&argp->fh),
18362306a36Sopenharmony_ci		argp->count, argp->offset);
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	argp->count = min_t(u32, argp->count, NFSSVC_MAXBLKSIZE_V2);
18662306a36Sopenharmony_ci	argp->count = min_t(u32, argp->count, rqstp->rq_res.buflen);
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	resp->pages = rqstp->rq_next_page;
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	/* Obtain buffer pointer for payload. 19 is 1 word for
19162306a36Sopenharmony_ci	 * status, 17 words for fattr, and 1 word for the byte count.
19262306a36Sopenharmony_ci	 */
19362306a36Sopenharmony_ci	svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	resp->count = argp->count;
19662306a36Sopenharmony_ci	fh_copy(&resp->fh, &argp->fh);
19762306a36Sopenharmony_ci	resp->status = nfsd_read(rqstp, &resp->fh, argp->offset,
19862306a36Sopenharmony_ci				 &resp->count, &eof);
19962306a36Sopenharmony_ci	if (resp->status == nfs_ok)
20062306a36Sopenharmony_ci		resp->status = fh_getattr(&resp->fh, &resp->stat);
20162306a36Sopenharmony_ci	else if (resp->status == nfserr_jukebox)
20262306a36Sopenharmony_ci		set_bit(RQ_DROPME, &rqstp->rq_flags);
20362306a36Sopenharmony_ci	return rpc_success;
20462306a36Sopenharmony_ci}
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci/* Reserved */
20762306a36Sopenharmony_cistatic __be32
20862306a36Sopenharmony_cinfsd_proc_writecache(struct svc_rqst *rqstp)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	return rpc_success;
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci/*
21462306a36Sopenharmony_ci * Write data to a file
21562306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put
21662306a36Sopenharmony_ci */
21762306a36Sopenharmony_cistatic __be32
21862306a36Sopenharmony_cinfsd_proc_write(struct svc_rqst *rqstp)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	struct nfsd_writeargs *argp = rqstp->rq_argp;
22162306a36Sopenharmony_ci	struct nfsd_attrstat *resp = rqstp->rq_resp;
22262306a36Sopenharmony_ci	unsigned long cnt = argp->len;
22362306a36Sopenharmony_ci	unsigned int nvecs;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	dprintk("nfsd: WRITE    %s %u bytes at %d\n",
22662306a36Sopenharmony_ci		SVCFH_fmt(&argp->fh),
22762306a36Sopenharmony_ci		argp->len, argp->offset);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	nvecs = svc_fill_write_vector(rqstp, &argp->payload);
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
23262306a36Sopenharmony_ci				  argp->offset, rqstp->rq_vec, nvecs,
23362306a36Sopenharmony_ci				  &cnt, NFS_DATA_SYNC, NULL);
23462306a36Sopenharmony_ci	if (resp->status == nfs_ok)
23562306a36Sopenharmony_ci		resp->status = fh_getattr(&resp->fh, &resp->stat);
23662306a36Sopenharmony_ci	else if (resp->status == nfserr_jukebox)
23762306a36Sopenharmony_ci		set_bit(RQ_DROPME, &rqstp->rq_flags);
23862306a36Sopenharmony_ci	return rpc_success;
23962306a36Sopenharmony_ci}
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci/*
24262306a36Sopenharmony_ci * CREATE processing is complicated. The keyword here is `overloaded.'
24362306a36Sopenharmony_ci * The parent directory is kept locked between the check for existence
24462306a36Sopenharmony_ci * and the actual create() call in compliance with VFS protocols.
24562306a36Sopenharmony_ci * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
24662306a36Sopenharmony_ci */
24762306a36Sopenharmony_cistatic __be32
24862306a36Sopenharmony_cinfsd_proc_create(struct svc_rqst *rqstp)
24962306a36Sopenharmony_ci{
25062306a36Sopenharmony_ci	struct nfsd_createargs *argp = rqstp->rq_argp;
25162306a36Sopenharmony_ci	struct nfsd_diropres *resp = rqstp->rq_resp;
25262306a36Sopenharmony_ci	svc_fh		*dirfhp = &argp->fh;
25362306a36Sopenharmony_ci	svc_fh		*newfhp = &resp->fh;
25462306a36Sopenharmony_ci	struct iattr	*attr = &argp->attrs;
25562306a36Sopenharmony_ci	struct nfsd_attrs attrs = {
25662306a36Sopenharmony_ci		.na_iattr	= attr,
25762306a36Sopenharmony_ci	};
25862306a36Sopenharmony_ci	struct inode	*inode;
25962306a36Sopenharmony_ci	struct dentry	*dchild;
26062306a36Sopenharmony_ci	int		type, mode;
26162306a36Sopenharmony_ci	int		hosterr;
26262306a36Sopenharmony_ci	dev_t		rdev = 0, wanted = new_decode_dev(attr->ia_size);
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	dprintk("nfsd: CREATE   %s %.*s\n",
26562306a36Sopenharmony_ci		SVCFH_fmt(dirfhp), argp->len, argp->name);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	/* First verify the parent file handle */
26862306a36Sopenharmony_ci	resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
26962306a36Sopenharmony_ci	if (resp->status != nfs_ok)
27062306a36Sopenharmony_ci		goto done; /* must fh_put dirfhp even on error */
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	/* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	resp->status = nfserr_exist;
27562306a36Sopenharmony_ci	if (isdotent(argp->name, argp->len))
27662306a36Sopenharmony_ci		goto done;
27762306a36Sopenharmony_ci	hosterr = fh_want_write(dirfhp);
27862306a36Sopenharmony_ci	if (hosterr) {
27962306a36Sopenharmony_ci		resp->status = nfserrno(hosterr);
28062306a36Sopenharmony_ci		goto done;
28162306a36Sopenharmony_ci	}
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	inode_lock_nested(dirfhp->fh_dentry->d_inode, I_MUTEX_PARENT);
28462306a36Sopenharmony_ci	dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
28562306a36Sopenharmony_ci	if (IS_ERR(dchild)) {
28662306a36Sopenharmony_ci		resp->status = nfserrno(PTR_ERR(dchild));
28762306a36Sopenharmony_ci		goto out_unlock;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci	fh_init(newfhp, NFS_FHSIZE);
29062306a36Sopenharmony_ci	resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
29162306a36Sopenharmony_ci	if (!resp->status && d_really_is_negative(dchild))
29262306a36Sopenharmony_ci		resp->status = nfserr_noent;
29362306a36Sopenharmony_ci	dput(dchild);
29462306a36Sopenharmony_ci	if (resp->status) {
29562306a36Sopenharmony_ci		if (resp->status != nfserr_noent)
29662306a36Sopenharmony_ci			goto out_unlock;
29762306a36Sopenharmony_ci		/*
29862306a36Sopenharmony_ci		 * If the new file handle wasn't verified, we can't tell
29962306a36Sopenharmony_ci		 * whether the file exists or not. Time to bail ...
30062306a36Sopenharmony_ci		 */
30162306a36Sopenharmony_ci		resp->status = nfserr_acces;
30262306a36Sopenharmony_ci		if (!newfhp->fh_dentry) {
30362306a36Sopenharmony_ci			printk(KERN_WARNING
30462306a36Sopenharmony_ci				"nfsd_proc_create: file handle not verified\n");
30562306a36Sopenharmony_ci			goto out_unlock;
30662306a36Sopenharmony_ci		}
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	inode = d_inode(newfhp->fh_dentry);
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	/* Unfudge the mode bits */
31262306a36Sopenharmony_ci	if (attr->ia_valid & ATTR_MODE) {
31362306a36Sopenharmony_ci		type = attr->ia_mode & S_IFMT;
31462306a36Sopenharmony_ci		mode = attr->ia_mode & ~S_IFMT;
31562306a36Sopenharmony_ci		if (!type) {
31662306a36Sopenharmony_ci			/* no type, so if target exists, assume same as that,
31762306a36Sopenharmony_ci			 * else assume a file */
31862306a36Sopenharmony_ci			if (inode) {
31962306a36Sopenharmony_ci				type = inode->i_mode & S_IFMT;
32062306a36Sopenharmony_ci				switch(type) {
32162306a36Sopenharmony_ci				case S_IFCHR:
32262306a36Sopenharmony_ci				case S_IFBLK:
32362306a36Sopenharmony_ci					/* reserve rdev for later checking */
32462306a36Sopenharmony_ci					rdev = inode->i_rdev;
32562306a36Sopenharmony_ci					attr->ia_valid |= ATTR_SIZE;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci					fallthrough;
32862306a36Sopenharmony_ci				case S_IFIFO:
32962306a36Sopenharmony_ci					/* this is probably a permission check..
33062306a36Sopenharmony_ci					 * at least IRIX implements perm checking on
33162306a36Sopenharmony_ci					 *   echo thing > device-special-file-or-pipe
33262306a36Sopenharmony_ci					 * by doing a CREATE with type==0
33362306a36Sopenharmony_ci					 */
33462306a36Sopenharmony_ci					resp->status = nfsd_permission(rqstp,
33562306a36Sopenharmony_ci								 newfhp->fh_export,
33662306a36Sopenharmony_ci								 newfhp->fh_dentry,
33762306a36Sopenharmony_ci								 NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
33862306a36Sopenharmony_ci					if (resp->status && resp->status != nfserr_rofs)
33962306a36Sopenharmony_ci						goto out_unlock;
34062306a36Sopenharmony_ci				}
34162306a36Sopenharmony_ci			} else
34262306a36Sopenharmony_ci				type = S_IFREG;
34362306a36Sopenharmony_ci		}
34462306a36Sopenharmony_ci	} else if (inode) {
34562306a36Sopenharmony_ci		type = inode->i_mode & S_IFMT;
34662306a36Sopenharmony_ci		mode = inode->i_mode & ~S_IFMT;
34762306a36Sopenharmony_ci	} else {
34862306a36Sopenharmony_ci		type = S_IFREG;
34962306a36Sopenharmony_ci		mode = 0;	/* ??? */
35062306a36Sopenharmony_ci	}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	attr->ia_valid |= ATTR_MODE;
35362306a36Sopenharmony_ci	attr->ia_mode = mode;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	/* Special treatment for non-regular files according to the
35662306a36Sopenharmony_ci	 * gospel of sun micro
35762306a36Sopenharmony_ci	 */
35862306a36Sopenharmony_ci	if (type != S_IFREG) {
35962306a36Sopenharmony_ci		if (type != S_IFBLK && type != S_IFCHR) {
36062306a36Sopenharmony_ci			rdev = 0;
36162306a36Sopenharmony_ci		} else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
36262306a36Sopenharmony_ci			/* If you think you've seen the worst, grok this. */
36362306a36Sopenharmony_ci			type = S_IFIFO;
36462306a36Sopenharmony_ci		} else {
36562306a36Sopenharmony_ci			/* Okay, char or block special */
36662306a36Sopenharmony_ci			if (!rdev)
36762306a36Sopenharmony_ci				rdev = wanted;
36862306a36Sopenharmony_ci		}
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		/* we've used the SIZE information, so discard it */
37162306a36Sopenharmony_ci		attr->ia_valid &= ~ATTR_SIZE;
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ci		/* Make sure the type and device matches */
37462306a36Sopenharmony_ci		resp->status = nfserr_exist;
37562306a36Sopenharmony_ci		if (inode && inode_wrong_type(inode, type))
37662306a36Sopenharmony_ci			goto out_unlock;
37762306a36Sopenharmony_ci	}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	resp->status = nfs_ok;
38062306a36Sopenharmony_ci	if (!inode) {
38162306a36Sopenharmony_ci		/* File doesn't exist. Create it and set attrs */
38262306a36Sopenharmony_ci		resp->status = nfsd_create_locked(rqstp, dirfhp, &attrs, type,
38362306a36Sopenharmony_ci						  rdev, newfhp);
38462306a36Sopenharmony_ci	} else if (type == S_IFREG) {
38562306a36Sopenharmony_ci		dprintk("nfsd:   existing %s, valid=%x, size=%ld\n",
38662306a36Sopenharmony_ci			argp->name, attr->ia_valid, (long) attr->ia_size);
38762306a36Sopenharmony_ci		/* File already exists. We ignore all attributes except
38862306a36Sopenharmony_ci		 * size, so that creat() behaves exactly like
38962306a36Sopenharmony_ci		 * open(..., O_CREAT|O_TRUNC|O_WRONLY).
39062306a36Sopenharmony_ci		 */
39162306a36Sopenharmony_ci		attr->ia_valid &= ATTR_SIZE;
39262306a36Sopenharmony_ci		if (attr->ia_valid)
39362306a36Sopenharmony_ci			resp->status = nfsd_setattr(rqstp, newfhp, &attrs, 0,
39462306a36Sopenharmony_ci						    (time64_t)0);
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ciout_unlock:
39862306a36Sopenharmony_ci	inode_unlock(dirfhp->fh_dentry->d_inode);
39962306a36Sopenharmony_ci	fh_drop_write(dirfhp);
40062306a36Sopenharmony_cidone:
40162306a36Sopenharmony_ci	fh_put(dirfhp);
40262306a36Sopenharmony_ci	if (resp->status != nfs_ok)
40362306a36Sopenharmony_ci		goto out;
40462306a36Sopenharmony_ci	resp->status = fh_getattr(&resp->fh, &resp->stat);
40562306a36Sopenharmony_ciout:
40662306a36Sopenharmony_ci	return rpc_success;
40762306a36Sopenharmony_ci}
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cistatic __be32
41062306a36Sopenharmony_cinfsd_proc_remove(struct svc_rqst *rqstp)
41162306a36Sopenharmony_ci{
41262306a36Sopenharmony_ci	struct nfsd_diropargs *argp = rqstp->rq_argp;
41362306a36Sopenharmony_ci	struct nfsd_stat *resp = rqstp->rq_resp;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	dprintk("nfsd: REMOVE   %s %.*s\n", SVCFH_fmt(&argp->fh),
41662306a36Sopenharmony_ci		argp->len, argp->name);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* Unlink. -SIFDIR means file must not be a directory */
41962306a36Sopenharmony_ci	resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR,
42062306a36Sopenharmony_ci				   argp->name, argp->len);
42162306a36Sopenharmony_ci	fh_put(&argp->fh);
42262306a36Sopenharmony_ci	return rpc_success;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic __be32
42662306a36Sopenharmony_cinfsd_proc_rename(struct svc_rqst *rqstp)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	struct nfsd_renameargs *argp = rqstp->rq_argp;
42962306a36Sopenharmony_ci	struct nfsd_stat *resp = rqstp->rq_resp;
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	dprintk("nfsd: RENAME   %s %.*s -> \n",
43262306a36Sopenharmony_ci		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
43362306a36Sopenharmony_ci	dprintk("nfsd:        ->  %s %.*s\n",
43462306a36Sopenharmony_ci		SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	resp->status = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
43762306a36Sopenharmony_ci				   &argp->tfh, argp->tname, argp->tlen);
43862306a36Sopenharmony_ci	fh_put(&argp->ffh);
43962306a36Sopenharmony_ci	fh_put(&argp->tfh);
44062306a36Sopenharmony_ci	return rpc_success;
44162306a36Sopenharmony_ci}
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_cistatic __be32
44462306a36Sopenharmony_cinfsd_proc_link(struct svc_rqst *rqstp)
44562306a36Sopenharmony_ci{
44662306a36Sopenharmony_ci	struct nfsd_linkargs *argp = rqstp->rq_argp;
44762306a36Sopenharmony_ci	struct nfsd_stat *resp = rqstp->rq_resp;
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_ci	dprintk("nfsd: LINK     %s ->\n",
45062306a36Sopenharmony_ci		SVCFH_fmt(&argp->ffh));
45162306a36Sopenharmony_ci	dprintk("nfsd:    %s %.*s\n",
45262306a36Sopenharmony_ci		SVCFH_fmt(&argp->tfh),
45362306a36Sopenharmony_ci		argp->tlen,
45462306a36Sopenharmony_ci		argp->tname);
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	resp->status = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
45762306a36Sopenharmony_ci				 &argp->ffh);
45862306a36Sopenharmony_ci	fh_put(&argp->ffh);
45962306a36Sopenharmony_ci	fh_put(&argp->tfh);
46062306a36Sopenharmony_ci	return rpc_success;
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_cistatic __be32
46462306a36Sopenharmony_cinfsd_proc_symlink(struct svc_rqst *rqstp)
46562306a36Sopenharmony_ci{
46662306a36Sopenharmony_ci	struct nfsd_symlinkargs *argp = rqstp->rq_argp;
46762306a36Sopenharmony_ci	struct nfsd_stat *resp = rqstp->rq_resp;
46862306a36Sopenharmony_ci	struct nfsd_attrs attrs = {
46962306a36Sopenharmony_ci		.na_iattr	= &argp->attrs,
47062306a36Sopenharmony_ci	};
47162306a36Sopenharmony_ci	struct svc_fh	newfh;
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	if (argp->tlen > NFS_MAXPATHLEN) {
47462306a36Sopenharmony_ci		resp->status = nfserr_nametoolong;
47562306a36Sopenharmony_ci		goto out;
47662306a36Sopenharmony_ci	}
47762306a36Sopenharmony_ci
47862306a36Sopenharmony_ci	argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
47962306a36Sopenharmony_ci						page_address(rqstp->rq_arg.pages[0]),
48062306a36Sopenharmony_ci						argp->tlen);
48162306a36Sopenharmony_ci	if (IS_ERR(argp->tname)) {
48262306a36Sopenharmony_ci		resp->status = nfserrno(PTR_ERR(argp->tname));
48362306a36Sopenharmony_ci		goto out;
48462306a36Sopenharmony_ci	}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_ci	dprintk("nfsd: SYMLINK  %s %.*s -> %.*s\n",
48762306a36Sopenharmony_ci		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
48862306a36Sopenharmony_ci		argp->tlen, argp->tname);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	fh_init(&newfh, NFS_FHSIZE);
49162306a36Sopenharmony_ci	resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
49262306a36Sopenharmony_ci				    argp->tname, &attrs, &newfh);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	kfree(argp->tname);
49562306a36Sopenharmony_ci	fh_put(&argp->ffh);
49662306a36Sopenharmony_ci	fh_put(&newfh);
49762306a36Sopenharmony_ciout:
49862306a36Sopenharmony_ci	return rpc_success;
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/*
50262306a36Sopenharmony_ci * Make directory. This operation is not idempotent.
50362306a36Sopenharmony_ci * N.B. After this call resp->fh needs an fh_put
50462306a36Sopenharmony_ci */
50562306a36Sopenharmony_cistatic __be32
50662306a36Sopenharmony_cinfsd_proc_mkdir(struct svc_rqst *rqstp)
50762306a36Sopenharmony_ci{
50862306a36Sopenharmony_ci	struct nfsd_createargs *argp = rqstp->rq_argp;
50962306a36Sopenharmony_ci	struct nfsd_diropres *resp = rqstp->rq_resp;
51062306a36Sopenharmony_ci	struct nfsd_attrs attrs = {
51162306a36Sopenharmony_ci		.na_iattr	= &argp->attrs,
51262306a36Sopenharmony_ci	};
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (resp->fh.fh_dentry) {
51762306a36Sopenharmony_ci		printk(KERN_WARNING
51862306a36Sopenharmony_ci			"nfsd_proc_mkdir: response already verified??\n");
51962306a36Sopenharmony_ci	}
52062306a36Sopenharmony_ci
52162306a36Sopenharmony_ci	argp->attrs.ia_valid &= ~ATTR_SIZE;
52262306a36Sopenharmony_ci	fh_init(&resp->fh, NFS_FHSIZE);
52362306a36Sopenharmony_ci	resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
52462306a36Sopenharmony_ci				   &attrs, S_IFDIR, 0, &resp->fh);
52562306a36Sopenharmony_ci	fh_put(&argp->fh);
52662306a36Sopenharmony_ci	if (resp->status != nfs_ok)
52762306a36Sopenharmony_ci		goto out;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	resp->status = fh_getattr(&resp->fh, &resp->stat);
53062306a36Sopenharmony_ciout:
53162306a36Sopenharmony_ci	return rpc_success;
53262306a36Sopenharmony_ci}
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci/*
53562306a36Sopenharmony_ci * Remove a directory
53662306a36Sopenharmony_ci */
53762306a36Sopenharmony_cistatic __be32
53862306a36Sopenharmony_cinfsd_proc_rmdir(struct svc_rqst *rqstp)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct nfsd_diropargs *argp = rqstp->rq_argp;
54162306a36Sopenharmony_ci	struct nfsd_stat *resp = rqstp->rq_resp;
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ci	dprintk("nfsd: RMDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	resp->status = nfsd_unlink(rqstp, &argp->fh, S_IFDIR,
54662306a36Sopenharmony_ci				   argp->name, argp->len);
54762306a36Sopenharmony_ci	fh_put(&argp->fh);
54862306a36Sopenharmony_ci	return rpc_success;
54962306a36Sopenharmony_ci}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_cistatic void nfsd_init_dirlist_pages(struct svc_rqst *rqstp,
55262306a36Sopenharmony_ci				    struct nfsd_readdirres *resp,
55362306a36Sopenharmony_ci				    u32 count)
55462306a36Sopenharmony_ci{
55562306a36Sopenharmony_ci	struct xdr_buf *buf = &resp->dirlist;
55662306a36Sopenharmony_ci	struct xdr_stream *xdr = &resp->xdr;
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci	memset(buf, 0, sizeof(*buf));
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	/* Reserve room for the NULL ptr & eof flag (-2 words) */
56162306a36Sopenharmony_ci	buf->buflen = clamp(count, (u32)(XDR_UNIT * 2), (u32)PAGE_SIZE);
56262306a36Sopenharmony_ci	buf->buflen -= XDR_UNIT * 2;
56362306a36Sopenharmony_ci	buf->pages = rqstp->rq_next_page;
56462306a36Sopenharmony_ci	rqstp->rq_next_page++;
56562306a36Sopenharmony_ci
56662306a36Sopenharmony_ci	xdr_init_encode_pages(xdr, buf, buf->pages,  NULL);
56762306a36Sopenharmony_ci}
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci/*
57062306a36Sopenharmony_ci * Read a portion of a directory.
57162306a36Sopenharmony_ci */
57262306a36Sopenharmony_cistatic __be32
57362306a36Sopenharmony_cinfsd_proc_readdir(struct svc_rqst *rqstp)
57462306a36Sopenharmony_ci{
57562306a36Sopenharmony_ci	struct nfsd_readdirargs *argp = rqstp->rq_argp;
57662306a36Sopenharmony_ci	struct nfsd_readdirres *resp = rqstp->rq_resp;
57762306a36Sopenharmony_ci	loff_t		offset;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	dprintk("nfsd: READDIR  %s %d bytes at %d\n",
58062306a36Sopenharmony_ci		SVCFH_fmt(&argp->fh),
58162306a36Sopenharmony_ci		argp->count, argp->cookie);
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	nfsd_init_dirlist_pages(rqstp, resp, argp->count);
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	resp->common.err = nfs_ok;
58662306a36Sopenharmony_ci	resp->cookie_offset = 0;
58762306a36Sopenharmony_ci	offset = argp->cookie;
58862306a36Sopenharmony_ci	resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
58962306a36Sopenharmony_ci				    &resp->common, nfssvc_encode_entry);
59062306a36Sopenharmony_ci	nfssvc_encode_nfscookie(resp, offset);
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	fh_put(&argp->fh);
59362306a36Sopenharmony_ci	return rpc_success;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci/*
59762306a36Sopenharmony_ci * Get file system info
59862306a36Sopenharmony_ci */
59962306a36Sopenharmony_cistatic __be32
60062306a36Sopenharmony_cinfsd_proc_statfs(struct svc_rqst *rqstp)
60162306a36Sopenharmony_ci{
60262306a36Sopenharmony_ci	struct nfsd_fhandle *argp = rqstp->rq_argp;
60362306a36Sopenharmony_ci	struct nfsd_statfsres *resp = rqstp->rq_resp;
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
60862306a36Sopenharmony_ci				   NFSD_MAY_BYPASS_GSS_ON_ROOT);
60962306a36Sopenharmony_ci	fh_put(&argp->fh);
61062306a36Sopenharmony_ci	return rpc_success;
61162306a36Sopenharmony_ci}
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci/*
61462306a36Sopenharmony_ci * NFSv2 Server procedures.
61562306a36Sopenharmony_ci * Only the results of non-idempotent operations are cached.
61662306a36Sopenharmony_ci */
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci#define ST 1		/* status */
61962306a36Sopenharmony_ci#define FH 8		/* filehandle */
62062306a36Sopenharmony_ci#define	AT 18		/* attributes */
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cistatic const struct svc_procedure nfsd_procedures2[18] = {
62362306a36Sopenharmony_ci	[NFSPROC_NULL] = {
62462306a36Sopenharmony_ci		.pc_func = nfsd_proc_null,
62562306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_voidarg,
62662306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_voidres,
62762306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_voidargs),
62862306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_voidargs),
62962306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_voidres),
63062306a36Sopenharmony_ci		.pc_cachetype = RC_NOCACHE,
63162306a36Sopenharmony_ci		.pc_xdrressize = 0,
63262306a36Sopenharmony_ci		.pc_name = "NULL",
63362306a36Sopenharmony_ci	},
63462306a36Sopenharmony_ci	[NFSPROC_GETATTR] = {
63562306a36Sopenharmony_ci		.pc_func = nfsd_proc_getattr,
63662306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_fhandleargs,
63762306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_attrstatres,
63862306a36Sopenharmony_ci		.pc_release = nfssvc_release_attrstat,
63962306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_fhandle),
64062306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_fhandle),
64162306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_attrstat),
64262306a36Sopenharmony_ci		.pc_cachetype = RC_NOCACHE,
64362306a36Sopenharmony_ci		.pc_xdrressize = ST+AT,
64462306a36Sopenharmony_ci		.pc_name = "GETATTR",
64562306a36Sopenharmony_ci	},
64662306a36Sopenharmony_ci	[NFSPROC_SETATTR] = {
64762306a36Sopenharmony_ci		.pc_func = nfsd_proc_setattr,
64862306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_sattrargs,
64962306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_attrstatres,
65062306a36Sopenharmony_ci		.pc_release = nfssvc_release_attrstat,
65162306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_sattrargs),
65262306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_sattrargs),
65362306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_attrstat),
65462306a36Sopenharmony_ci		.pc_cachetype = RC_REPLBUFF,
65562306a36Sopenharmony_ci		.pc_xdrressize = ST+AT,
65662306a36Sopenharmony_ci		.pc_name = "SETATTR",
65762306a36Sopenharmony_ci	},
65862306a36Sopenharmony_ci	[NFSPROC_ROOT] = {
65962306a36Sopenharmony_ci		.pc_func = nfsd_proc_root,
66062306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_voidarg,
66162306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_voidres,
66262306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_voidargs),
66362306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_voidargs),
66462306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_voidres),
66562306a36Sopenharmony_ci		.pc_cachetype = RC_NOCACHE,
66662306a36Sopenharmony_ci		.pc_xdrressize = 0,
66762306a36Sopenharmony_ci		.pc_name = "ROOT",
66862306a36Sopenharmony_ci	},
66962306a36Sopenharmony_ci	[NFSPROC_LOOKUP] = {
67062306a36Sopenharmony_ci		.pc_func = nfsd_proc_lookup,
67162306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_diropargs,
67262306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_diropres,
67362306a36Sopenharmony_ci		.pc_release = nfssvc_release_diropres,
67462306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_diropargs),
67562306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_diropargs),
67662306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_diropres),
67762306a36Sopenharmony_ci		.pc_cachetype = RC_NOCACHE,
67862306a36Sopenharmony_ci		.pc_xdrressize = ST+FH+AT,
67962306a36Sopenharmony_ci		.pc_name = "LOOKUP",
68062306a36Sopenharmony_ci	},
68162306a36Sopenharmony_ci	[NFSPROC_READLINK] = {
68262306a36Sopenharmony_ci		.pc_func = nfsd_proc_readlink,
68362306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_fhandleargs,
68462306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_readlinkres,
68562306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_fhandle),
68662306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_fhandle),
68762306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_readlinkres),
68862306a36Sopenharmony_ci		.pc_cachetype = RC_NOCACHE,
68962306a36Sopenharmony_ci		.pc_xdrressize = ST+1+NFS_MAXPATHLEN/4,
69062306a36Sopenharmony_ci		.pc_name = "READLINK",
69162306a36Sopenharmony_ci	},
69262306a36Sopenharmony_ci	[NFSPROC_READ] = {
69362306a36Sopenharmony_ci		.pc_func = nfsd_proc_read,
69462306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_readargs,
69562306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_readres,
69662306a36Sopenharmony_ci		.pc_release = nfssvc_release_readres,
69762306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_readargs),
69862306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_readargs),
69962306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_readres),
70062306a36Sopenharmony_ci		.pc_cachetype = RC_NOCACHE,
70162306a36Sopenharmony_ci		.pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
70262306a36Sopenharmony_ci		.pc_name = "READ",
70362306a36Sopenharmony_ci	},
70462306a36Sopenharmony_ci	[NFSPROC_WRITECACHE] = {
70562306a36Sopenharmony_ci		.pc_func = nfsd_proc_writecache,
70662306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_voidarg,
70762306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_voidres,
70862306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_voidargs),
70962306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_voidargs),
71062306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_voidres),
71162306a36Sopenharmony_ci		.pc_cachetype = RC_NOCACHE,
71262306a36Sopenharmony_ci		.pc_xdrressize = 0,
71362306a36Sopenharmony_ci		.pc_name = "WRITECACHE",
71462306a36Sopenharmony_ci	},
71562306a36Sopenharmony_ci	[NFSPROC_WRITE] = {
71662306a36Sopenharmony_ci		.pc_func = nfsd_proc_write,
71762306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_writeargs,
71862306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_attrstatres,
71962306a36Sopenharmony_ci		.pc_release = nfssvc_release_attrstat,
72062306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_writeargs),
72162306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_writeargs),
72262306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_attrstat),
72362306a36Sopenharmony_ci		.pc_cachetype = RC_REPLBUFF,
72462306a36Sopenharmony_ci		.pc_xdrressize = ST+AT,
72562306a36Sopenharmony_ci		.pc_name = "WRITE",
72662306a36Sopenharmony_ci	},
72762306a36Sopenharmony_ci	[NFSPROC_CREATE] = {
72862306a36Sopenharmony_ci		.pc_func = nfsd_proc_create,
72962306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_createargs,
73062306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_diropres,
73162306a36Sopenharmony_ci		.pc_release = nfssvc_release_diropres,
73262306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_createargs),
73362306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_createargs),
73462306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_diropres),
73562306a36Sopenharmony_ci		.pc_cachetype = RC_REPLBUFF,
73662306a36Sopenharmony_ci		.pc_xdrressize = ST+FH+AT,
73762306a36Sopenharmony_ci		.pc_name = "CREATE",
73862306a36Sopenharmony_ci	},
73962306a36Sopenharmony_ci	[NFSPROC_REMOVE] = {
74062306a36Sopenharmony_ci		.pc_func = nfsd_proc_remove,
74162306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_diropargs,
74262306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_statres,
74362306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_diropargs),
74462306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_diropargs),
74562306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_stat),
74662306a36Sopenharmony_ci		.pc_cachetype = RC_REPLSTAT,
74762306a36Sopenharmony_ci		.pc_xdrressize = ST,
74862306a36Sopenharmony_ci		.pc_name = "REMOVE",
74962306a36Sopenharmony_ci	},
75062306a36Sopenharmony_ci	[NFSPROC_RENAME] = {
75162306a36Sopenharmony_ci		.pc_func = nfsd_proc_rename,
75262306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_renameargs,
75362306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_statres,
75462306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_renameargs),
75562306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_renameargs),
75662306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_stat),
75762306a36Sopenharmony_ci		.pc_cachetype = RC_REPLSTAT,
75862306a36Sopenharmony_ci		.pc_xdrressize = ST,
75962306a36Sopenharmony_ci		.pc_name = "RENAME",
76062306a36Sopenharmony_ci	},
76162306a36Sopenharmony_ci	[NFSPROC_LINK] = {
76262306a36Sopenharmony_ci		.pc_func = nfsd_proc_link,
76362306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_linkargs,
76462306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_statres,
76562306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_linkargs),
76662306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_linkargs),
76762306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_stat),
76862306a36Sopenharmony_ci		.pc_cachetype = RC_REPLSTAT,
76962306a36Sopenharmony_ci		.pc_xdrressize = ST,
77062306a36Sopenharmony_ci		.pc_name = "LINK",
77162306a36Sopenharmony_ci	},
77262306a36Sopenharmony_ci	[NFSPROC_SYMLINK] = {
77362306a36Sopenharmony_ci		.pc_func = nfsd_proc_symlink,
77462306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_symlinkargs,
77562306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_statres,
77662306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_symlinkargs),
77762306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_symlinkargs),
77862306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_stat),
77962306a36Sopenharmony_ci		.pc_cachetype = RC_REPLSTAT,
78062306a36Sopenharmony_ci		.pc_xdrressize = ST,
78162306a36Sopenharmony_ci		.pc_name = "SYMLINK",
78262306a36Sopenharmony_ci	},
78362306a36Sopenharmony_ci	[NFSPROC_MKDIR] = {
78462306a36Sopenharmony_ci		.pc_func = nfsd_proc_mkdir,
78562306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_createargs,
78662306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_diropres,
78762306a36Sopenharmony_ci		.pc_release = nfssvc_release_diropres,
78862306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_createargs),
78962306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_createargs),
79062306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_diropres),
79162306a36Sopenharmony_ci		.pc_cachetype = RC_REPLBUFF,
79262306a36Sopenharmony_ci		.pc_xdrressize = ST+FH+AT,
79362306a36Sopenharmony_ci		.pc_name = "MKDIR",
79462306a36Sopenharmony_ci	},
79562306a36Sopenharmony_ci	[NFSPROC_RMDIR] = {
79662306a36Sopenharmony_ci		.pc_func = nfsd_proc_rmdir,
79762306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_diropargs,
79862306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_statres,
79962306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_diropargs),
80062306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_diropargs),
80162306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_stat),
80262306a36Sopenharmony_ci		.pc_cachetype = RC_REPLSTAT,
80362306a36Sopenharmony_ci		.pc_xdrressize = ST,
80462306a36Sopenharmony_ci		.pc_name = "RMDIR",
80562306a36Sopenharmony_ci	},
80662306a36Sopenharmony_ci	[NFSPROC_READDIR] = {
80762306a36Sopenharmony_ci		.pc_func = nfsd_proc_readdir,
80862306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_readdirargs,
80962306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_readdirres,
81062306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_readdirargs),
81162306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_readdirargs),
81262306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_readdirres),
81362306a36Sopenharmony_ci		.pc_cachetype = RC_NOCACHE,
81462306a36Sopenharmony_ci		.pc_name = "READDIR",
81562306a36Sopenharmony_ci	},
81662306a36Sopenharmony_ci	[NFSPROC_STATFS] = {
81762306a36Sopenharmony_ci		.pc_func = nfsd_proc_statfs,
81862306a36Sopenharmony_ci		.pc_decode = nfssvc_decode_fhandleargs,
81962306a36Sopenharmony_ci		.pc_encode = nfssvc_encode_statfsres,
82062306a36Sopenharmony_ci		.pc_argsize = sizeof(struct nfsd_fhandle),
82162306a36Sopenharmony_ci		.pc_argzero = sizeof(struct nfsd_fhandle),
82262306a36Sopenharmony_ci		.pc_ressize = sizeof(struct nfsd_statfsres),
82362306a36Sopenharmony_ci		.pc_cachetype = RC_NOCACHE,
82462306a36Sopenharmony_ci		.pc_xdrressize = ST+5,
82562306a36Sopenharmony_ci		.pc_name = "STATFS",
82662306a36Sopenharmony_ci	},
82762306a36Sopenharmony_ci};
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_cistatic DEFINE_PER_CPU_ALIGNED(unsigned long,
83062306a36Sopenharmony_ci			      nfsd_count2[ARRAY_SIZE(nfsd_procedures2)]);
83162306a36Sopenharmony_ciconst struct svc_version nfsd_version2 = {
83262306a36Sopenharmony_ci	.vs_vers	= 2,
83362306a36Sopenharmony_ci	.vs_nproc	= ARRAY_SIZE(nfsd_procedures2),
83462306a36Sopenharmony_ci	.vs_proc	= nfsd_procedures2,
83562306a36Sopenharmony_ci	.vs_count	= nfsd_count2,
83662306a36Sopenharmony_ci	.vs_dispatch	= nfsd_dispatch,
83762306a36Sopenharmony_ci	.vs_xdrsize	= NFS2_SVC_XDRSIZE,
83862306a36Sopenharmony_ci};
839