xref: /OK3568_Linux_fs/kernel/fs/nfsd/nfsproc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Process version 2 NFS requests.
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
6*4882a593Smuzhiyun  */
7*4882a593Smuzhiyun 
8*4882a593Smuzhiyun #include <linux/namei.h>
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include "cache.h"
11*4882a593Smuzhiyun #include "xdr.h"
12*4882a593Smuzhiyun #include "vfs.h"
13*4882a593Smuzhiyun 
14*4882a593Smuzhiyun #define NFSDDBG_FACILITY		NFSDDBG_PROC
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun static __be32
nfsd_proc_null(struct svc_rqst * rqstp)17*4882a593Smuzhiyun nfsd_proc_null(struct svc_rqst *rqstp)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun 	return rpc_success;
20*4882a593Smuzhiyun }
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun /*
23*4882a593Smuzhiyun  * Get a file's attributes
24*4882a593Smuzhiyun  * N.B. After this call resp->fh needs an fh_put
25*4882a593Smuzhiyun  */
26*4882a593Smuzhiyun static __be32
nfsd_proc_getattr(struct svc_rqst * rqstp)27*4882a593Smuzhiyun nfsd_proc_getattr(struct svc_rqst *rqstp)
28*4882a593Smuzhiyun {
29*4882a593Smuzhiyun 	struct nfsd_fhandle *argp = rqstp->rq_argp;
30*4882a593Smuzhiyun 	struct nfsd_attrstat *resp = rqstp->rq_resp;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	dprintk("nfsd: GETATTR  %s\n", SVCFH_fmt(&argp->fh));
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun 	fh_copy(&resp->fh, &argp->fh);
35*4882a593Smuzhiyun 	resp->status = fh_verify(rqstp, &resp->fh, 0,
36*4882a593Smuzhiyun 				 NFSD_MAY_NOP | NFSD_MAY_BYPASS_GSS_ON_ROOT);
37*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
38*4882a593Smuzhiyun 		goto out;
39*4882a593Smuzhiyun 	resp->status = fh_getattr(&resp->fh, &resp->stat);
40*4882a593Smuzhiyun out:
41*4882a593Smuzhiyun 	return rpc_success;
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
44*4882a593Smuzhiyun /*
45*4882a593Smuzhiyun  * Set a file's attributes
46*4882a593Smuzhiyun  * N.B. After this call resp->fh needs an fh_put
47*4882a593Smuzhiyun  */
48*4882a593Smuzhiyun static __be32
nfsd_proc_setattr(struct svc_rqst * rqstp)49*4882a593Smuzhiyun nfsd_proc_setattr(struct svc_rqst *rqstp)
50*4882a593Smuzhiyun {
51*4882a593Smuzhiyun 	struct nfsd_sattrargs *argp = rqstp->rq_argp;
52*4882a593Smuzhiyun 	struct nfsd_attrstat *resp = rqstp->rq_resp;
53*4882a593Smuzhiyun 	struct iattr *iap = &argp->attrs;
54*4882a593Smuzhiyun 	struct svc_fh *fhp;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun 	dprintk("nfsd: SETATTR  %s, valid=%x, size=%ld\n",
57*4882a593Smuzhiyun 		SVCFH_fmt(&argp->fh),
58*4882a593Smuzhiyun 		argp->attrs.ia_valid, (long) argp->attrs.ia_size);
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	fhp = fh_copy(&resp->fh, &argp->fh);
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	/*
63*4882a593Smuzhiyun 	 * NFSv2 does not differentiate between "set-[ac]time-to-now"
64*4882a593Smuzhiyun 	 * which only requires access, and "set-[ac]time-to-X" which
65*4882a593Smuzhiyun 	 * requires ownership.
66*4882a593Smuzhiyun 	 * So if it looks like it might be "set both to the same time which
67*4882a593Smuzhiyun 	 * is close to now", and if setattr_prepare fails, then we
68*4882a593Smuzhiyun 	 * convert to "set to now" instead of "set to explicit time"
69*4882a593Smuzhiyun 	 *
70*4882a593Smuzhiyun 	 * We only call setattr_prepare as the last test as technically
71*4882a593Smuzhiyun 	 * it is not an interface that we should be using.
72*4882a593Smuzhiyun 	 */
73*4882a593Smuzhiyun #define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
74*4882a593Smuzhiyun #define	MAX_TOUCH_TIME_ERROR (30*60)
75*4882a593Smuzhiyun 	if ((iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET &&
76*4882a593Smuzhiyun 	    iap->ia_mtime.tv_sec == iap->ia_atime.tv_sec) {
77*4882a593Smuzhiyun 		/*
78*4882a593Smuzhiyun 		 * Looks probable.
79*4882a593Smuzhiyun 		 *
80*4882a593Smuzhiyun 		 * Now just make sure time is in the right ballpark.
81*4882a593Smuzhiyun 		 * Solaris, at least, doesn't seem to care what the time
82*4882a593Smuzhiyun 		 * request is.  We require it be within 30 minutes of now.
83*4882a593Smuzhiyun 		 */
84*4882a593Smuzhiyun 		time64_t delta = iap->ia_atime.tv_sec - ktime_get_real_seconds();
85*4882a593Smuzhiyun 
86*4882a593Smuzhiyun 		resp->status = fh_verify(rqstp, fhp, 0, NFSD_MAY_NOP);
87*4882a593Smuzhiyun 		if (resp->status != nfs_ok)
88*4882a593Smuzhiyun 			goto out;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 		if (delta < 0)
91*4882a593Smuzhiyun 			delta = -delta;
92*4882a593Smuzhiyun 		if (delta < MAX_TOUCH_TIME_ERROR &&
93*4882a593Smuzhiyun 		    setattr_prepare(fhp->fh_dentry, iap) != 0) {
94*4882a593Smuzhiyun 			/*
95*4882a593Smuzhiyun 			 * Turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME.
96*4882a593Smuzhiyun 			 * This will cause notify_change to set these times
97*4882a593Smuzhiyun 			 * to "now"
98*4882a593Smuzhiyun 			 */
99*4882a593Smuzhiyun 			iap->ia_valid &= ~BOTH_TIME_SET;
100*4882a593Smuzhiyun 		}
101*4882a593Smuzhiyun 	}
102*4882a593Smuzhiyun 
103*4882a593Smuzhiyun 	resp->status = nfsd_setattr(rqstp, fhp, iap, 0, (time64_t)0);
104*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
105*4882a593Smuzhiyun 		goto out;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	resp->status = fh_getattr(&resp->fh, &resp->stat);
108*4882a593Smuzhiyun out:
109*4882a593Smuzhiyun 	return rpc_success;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun /* Obsolete, replaced by MNTPROC_MNT. */
113*4882a593Smuzhiyun static __be32
nfsd_proc_root(struct svc_rqst * rqstp)114*4882a593Smuzhiyun nfsd_proc_root(struct svc_rqst *rqstp)
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	return rpc_success;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun  * Look up a path name component
121*4882a593Smuzhiyun  * Note: the dentry in the resp->fh may be negative if the file
122*4882a593Smuzhiyun  * doesn't exist yet.
123*4882a593Smuzhiyun  * N.B. After this call resp->fh needs an fh_put
124*4882a593Smuzhiyun  */
125*4882a593Smuzhiyun static __be32
nfsd_proc_lookup(struct svc_rqst * rqstp)126*4882a593Smuzhiyun nfsd_proc_lookup(struct svc_rqst *rqstp)
127*4882a593Smuzhiyun {
128*4882a593Smuzhiyun 	struct nfsd_diropargs *argp = rqstp->rq_argp;
129*4882a593Smuzhiyun 	struct nfsd_diropres *resp = rqstp->rq_resp;
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	dprintk("nfsd: LOOKUP   %s %.*s\n",
132*4882a593Smuzhiyun 		SVCFH_fmt(&argp->fh), argp->len, argp->name);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	fh_init(&resp->fh, NFS_FHSIZE);
135*4882a593Smuzhiyun 	resp->status = nfsd_lookup(rqstp, &argp->fh, argp->name, argp->len,
136*4882a593Smuzhiyun 				   &resp->fh);
137*4882a593Smuzhiyun 	fh_put(&argp->fh);
138*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
139*4882a593Smuzhiyun 		goto out;
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	resp->status = fh_getattr(&resp->fh, &resp->stat);
142*4882a593Smuzhiyun out:
143*4882a593Smuzhiyun 	return rpc_success;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
146*4882a593Smuzhiyun /*
147*4882a593Smuzhiyun  * Read a symlink.
148*4882a593Smuzhiyun  */
149*4882a593Smuzhiyun static __be32
nfsd_proc_readlink(struct svc_rqst * rqstp)150*4882a593Smuzhiyun nfsd_proc_readlink(struct svc_rqst *rqstp)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	struct nfsd_readlinkargs *argp = rqstp->rq_argp;
153*4882a593Smuzhiyun 	struct nfsd_readlinkres *resp = rqstp->rq_resp;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	dprintk("nfsd: READLINK %s\n", SVCFH_fmt(&argp->fh));
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	/* Read the symlink. */
158*4882a593Smuzhiyun 	resp->len = NFS_MAXPATHLEN;
159*4882a593Smuzhiyun 	resp->status = nfsd_readlink(rqstp, &argp->fh, argp->buffer, &resp->len);
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun 	fh_put(&argp->fh);
162*4882a593Smuzhiyun 	return rpc_success;
163*4882a593Smuzhiyun }
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun /*
166*4882a593Smuzhiyun  * Read a portion of a file.
167*4882a593Smuzhiyun  * N.B. After this call resp->fh needs an fh_put
168*4882a593Smuzhiyun  */
169*4882a593Smuzhiyun static __be32
nfsd_proc_read(struct svc_rqst * rqstp)170*4882a593Smuzhiyun nfsd_proc_read(struct svc_rqst *rqstp)
171*4882a593Smuzhiyun {
172*4882a593Smuzhiyun 	struct nfsd_readargs *argp = rqstp->rq_argp;
173*4882a593Smuzhiyun 	struct nfsd_readres *resp = rqstp->rq_resp;
174*4882a593Smuzhiyun 	u32 eof;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	dprintk("nfsd: READ    %s %d bytes at %d\n",
177*4882a593Smuzhiyun 		SVCFH_fmt(&argp->fh),
178*4882a593Smuzhiyun 		argp->count, argp->offset);
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	/* Obtain buffer pointer for payload. 19 is 1 word for
181*4882a593Smuzhiyun 	 * status, 17 words for fattr, and 1 word for the byte count.
182*4882a593Smuzhiyun 	 */
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	if (NFSSVC_MAXBLKSIZE_V2 < argp->count) {
185*4882a593Smuzhiyun 		char buf[RPC_MAX_ADDRBUFLEN];
186*4882a593Smuzhiyun 		printk(KERN_NOTICE
187*4882a593Smuzhiyun 			"oversized read request from %s (%d bytes)\n",
188*4882a593Smuzhiyun 				svc_print_addr(rqstp, buf, sizeof(buf)),
189*4882a593Smuzhiyun 				argp->count);
190*4882a593Smuzhiyun 		argp->count = NFSSVC_MAXBLKSIZE_V2;
191*4882a593Smuzhiyun 	}
192*4882a593Smuzhiyun 	svc_reserve_auth(rqstp, (19<<2) + argp->count + 4);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	resp->count = argp->count;
195*4882a593Smuzhiyun 	resp->status = nfsd_read(rqstp, fh_copy(&resp->fh, &argp->fh),
196*4882a593Smuzhiyun 				 argp->offset,
197*4882a593Smuzhiyun 				 rqstp->rq_vec, argp->vlen,
198*4882a593Smuzhiyun 				 &resp->count,
199*4882a593Smuzhiyun 				 &eof);
200*4882a593Smuzhiyun 	if (resp->status == nfs_ok)
201*4882a593Smuzhiyun 		resp->status = fh_getattr(&resp->fh, &resp->stat);
202*4882a593Smuzhiyun 	else if (resp->status == nfserr_jukebox)
203*4882a593Smuzhiyun 		return rpc_drop_reply;
204*4882a593Smuzhiyun 	return rpc_success;
205*4882a593Smuzhiyun }
206*4882a593Smuzhiyun 
207*4882a593Smuzhiyun /* Reserved */
208*4882a593Smuzhiyun static __be32
nfsd_proc_writecache(struct svc_rqst * rqstp)209*4882a593Smuzhiyun nfsd_proc_writecache(struct svc_rqst *rqstp)
210*4882a593Smuzhiyun {
211*4882a593Smuzhiyun 	return rpc_success;
212*4882a593Smuzhiyun }
213*4882a593Smuzhiyun 
214*4882a593Smuzhiyun /*
215*4882a593Smuzhiyun  * Write data to a file
216*4882a593Smuzhiyun  * N.B. After this call resp->fh needs an fh_put
217*4882a593Smuzhiyun  */
218*4882a593Smuzhiyun static __be32
nfsd_proc_write(struct svc_rqst * rqstp)219*4882a593Smuzhiyun nfsd_proc_write(struct svc_rqst *rqstp)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	struct nfsd_writeargs *argp = rqstp->rq_argp;
222*4882a593Smuzhiyun 	struct nfsd_attrstat *resp = rqstp->rq_resp;
223*4882a593Smuzhiyun 	unsigned long cnt = argp->len;
224*4882a593Smuzhiyun 	unsigned int nvecs;
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	dprintk("nfsd: WRITE    %s %u bytes at %d\n",
227*4882a593Smuzhiyun 		SVCFH_fmt(&argp->fh),
228*4882a593Smuzhiyun 		argp->len, argp->offset);
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	nvecs = svc_fill_write_vector(rqstp, rqstp->rq_arg.pages,
231*4882a593Smuzhiyun 				      &argp->first, cnt);
232*4882a593Smuzhiyun 	if (!nvecs) {
233*4882a593Smuzhiyun 		resp->status = nfserr_io;
234*4882a593Smuzhiyun 		goto out;
235*4882a593Smuzhiyun 	}
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	resp->status = nfsd_write(rqstp, fh_copy(&resp->fh, &argp->fh),
238*4882a593Smuzhiyun 				  argp->offset, rqstp->rq_vec, nvecs,
239*4882a593Smuzhiyun 				  &cnt, NFS_DATA_SYNC, NULL);
240*4882a593Smuzhiyun 	if (resp->status == nfs_ok)
241*4882a593Smuzhiyun 		resp->status = fh_getattr(&resp->fh, &resp->stat);
242*4882a593Smuzhiyun 	else if (resp->status == nfserr_jukebox)
243*4882a593Smuzhiyun 		return rpc_drop_reply;
244*4882a593Smuzhiyun out:
245*4882a593Smuzhiyun 	return rpc_success;
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun /*
249*4882a593Smuzhiyun  * CREATE processing is complicated. The keyword here is `overloaded.'
250*4882a593Smuzhiyun  * The parent directory is kept locked between the check for existence
251*4882a593Smuzhiyun  * and the actual create() call in compliance with VFS protocols.
252*4882a593Smuzhiyun  * N.B. After this call _both_ argp->fh and resp->fh need an fh_put
253*4882a593Smuzhiyun  */
254*4882a593Smuzhiyun static __be32
nfsd_proc_create(struct svc_rqst * rqstp)255*4882a593Smuzhiyun nfsd_proc_create(struct svc_rqst *rqstp)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	struct nfsd_createargs *argp = rqstp->rq_argp;
258*4882a593Smuzhiyun 	struct nfsd_diropres *resp = rqstp->rq_resp;
259*4882a593Smuzhiyun 	svc_fh		*dirfhp = &argp->fh;
260*4882a593Smuzhiyun 	svc_fh		*newfhp = &resp->fh;
261*4882a593Smuzhiyun 	struct iattr	*attr = &argp->attrs;
262*4882a593Smuzhiyun 	struct inode	*inode;
263*4882a593Smuzhiyun 	struct dentry	*dchild;
264*4882a593Smuzhiyun 	int		type, mode;
265*4882a593Smuzhiyun 	int		hosterr;
266*4882a593Smuzhiyun 	dev_t		rdev = 0, wanted = new_decode_dev(attr->ia_size);
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 	dprintk("nfsd: CREATE   %s %.*s\n",
269*4882a593Smuzhiyun 		SVCFH_fmt(dirfhp), argp->len, argp->name);
270*4882a593Smuzhiyun 
271*4882a593Smuzhiyun 	/* First verify the parent file handle */
272*4882a593Smuzhiyun 	resp->status = fh_verify(rqstp, dirfhp, S_IFDIR, NFSD_MAY_EXEC);
273*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
274*4882a593Smuzhiyun 		goto done; /* must fh_put dirfhp even on error */
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	/* Check for NFSD_MAY_WRITE in nfsd_create if necessary */
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	resp->status = nfserr_exist;
279*4882a593Smuzhiyun 	if (isdotent(argp->name, argp->len))
280*4882a593Smuzhiyun 		goto done;
281*4882a593Smuzhiyun 	hosterr = fh_want_write(dirfhp);
282*4882a593Smuzhiyun 	if (hosterr) {
283*4882a593Smuzhiyun 		resp->status = nfserrno(hosterr);
284*4882a593Smuzhiyun 		goto done;
285*4882a593Smuzhiyun 	}
286*4882a593Smuzhiyun 
287*4882a593Smuzhiyun 	fh_lock_nested(dirfhp, I_MUTEX_PARENT);
288*4882a593Smuzhiyun 	dchild = lookup_one_len(argp->name, dirfhp->fh_dentry, argp->len);
289*4882a593Smuzhiyun 	if (IS_ERR(dchild)) {
290*4882a593Smuzhiyun 		resp->status = nfserrno(PTR_ERR(dchild));
291*4882a593Smuzhiyun 		goto out_unlock;
292*4882a593Smuzhiyun 	}
293*4882a593Smuzhiyun 	fh_init(newfhp, NFS_FHSIZE);
294*4882a593Smuzhiyun 	resp->status = fh_compose(newfhp, dirfhp->fh_export, dchild, dirfhp);
295*4882a593Smuzhiyun 	if (!resp->status && d_really_is_negative(dchild))
296*4882a593Smuzhiyun 		resp->status = nfserr_noent;
297*4882a593Smuzhiyun 	dput(dchild);
298*4882a593Smuzhiyun 	if (resp->status) {
299*4882a593Smuzhiyun 		if (resp->status != nfserr_noent)
300*4882a593Smuzhiyun 			goto out_unlock;
301*4882a593Smuzhiyun 		/*
302*4882a593Smuzhiyun 		 * If the new file handle wasn't verified, we can't tell
303*4882a593Smuzhiyun 		 * whether the file exists or not. Time to bail ...
304*4882a593Smuzhiyun 		 */
305*4882a593Smuzhiyun 		resp->status = nfserr_acces;
306*4882a593Smuzhiyun 		if (!newfhp->fh_dentry) {
307*4882a593Smuzhiyun 			printk(KERN_WARNING
308*4882a593Smuzhiyun 				"nfsd_proc_create: file handle not verified\n");
309*4882a593Smuzhiyun 			goto out_unlock;
310*4882a593Smuzhiyun 		}
311*4882a593Smuzhiyun 	}
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	inode = d_inode(newfhp->fh_dentry);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	/* Unfudge the mode bits */
316*4882a593Smuzhiyun 	if (attr->ia_valid & ATTR_MODE) {
317*4882a593Smuzhiyun 		type = attr->ia_mode & S_IFMT;
318*4882a593Smuzhiyun 		mode = attr->ia_mode & ~S_IFMT;
319*4882a593Smuzhiyun 		if (!type) {
320*4882a593Smuzhiyun 			/* no type, so if target exists, assume same as that,
321*4882a593Smuzhiyun 			 * else assume a file */
322*4882a593Smuzhiyun 			if (inode) {
323*4882a593Smuzhiyun 				type = inode->i_mode & S_IFMT;
324*4882a593Smuzhiyun 				switch(type) {
325*4882a593Smuzhiyun 				case S_IFCHR:
326*4882a593Smuzhiyun 				case S_IFBLK:
327*4882a593Smuzhiyun 					/* reserve rdev for later checking */
328*4882a593Smuzhiyun 					rdev = inode->i_rdev;
329*4882a593Smuzhiyun 					attr->ia_valid |= ATTR_SIZE;
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun 					fallthrough;
332*4882a593Smuzhiyun 				case S_IFIFO:
333*4882a593Smuzhiyun 					/* this is probably a permission check..
334*4882a593Smuzhiyun 					 * at least IRIX implements perm checking on
335*4882a593Smuzhiyun 					 *   echo thing > device-special-file-or-pipe
336*4882a593Smuzhiyun 					 * by doing a CREATE with type==0
337*4882a593Smuzhiyun 					 */
338*4882a593Smuzhiyun 					resp->status = nfsd_permission(rqstp,
339*4882a593Smuzhiyun 								 newfhp->fh_export,
340*4882a593Smuzhiyun 								 newfhp->fh_dentry,
341*4882a593Smuzhiyun 								 NFSD_MAY_WRITE|NFSD_MAY_LOCAL_ACCESS);
342*4882a593Smuzhiyun 					if (resp->status && resp->status != nfserr_rofs)
343*4882a593Smuzhiyun 						goto out_unlock;
344*4882a593Smuzhiyun 				}
345*4882a593Smuzhiyun 			} else
346*4882a593Smuzhiyun 				type = S_IFREG;
347*4882a593Smuzhiyun 		}
348*4882a593Smuzhiyun 	} else if (inode) {
349*4882a593Smuzhiyun 		type = inode->i_mode & S_IFMT;
350*4882a593Smuzhiyun 		mode = inode->i_mode & ~S_IFMT;
351*4882a593Smuzhiyun 	} else {
352*4882a593Smuzhiyun 		type = S_IFREG;
353*4882a593Smuzhiyun 		mode = 0;	/* ??? */
354*4882a593Smuzhiyun 	}
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 	attr->ia_valid |= ATTR_MODE;
357*4882a593Smuzhiyun 	attr->ia_mode = mode;
358*4882a593Smuzhiyun 
359*4882a593Smuzhiyun 	/* Special treatment for non-regular files according to the
360*4882a593Smuzhiyun 	 * gospel of sun micro
361*4882a593Smuzhiyun 	 */
362*4882a593Smuzhiyun 	if (type != S_IFREG) {
363*4882a593Smuzhiyun 		if (type != S_IFBLK && type != S_IFCHR) {
364*4882a593Smuzhiyun 			rdev = 0;
365*4882a593Smuzhiyun 		} else if (type == S_IFCHR && !(attr->ia_valid & ATTR_SIZE)) {
366*4882a593Smuzhiyun 			/* If you think you've seen the worst, grok this. */
367*4882a593Smuzhiyun 			type = S_IFIFO;
368*4882a593Smuzhiyun 		} else {
369*4882a593Smuzhiyun 			/* Okay, char or block special */
370*4882a593Smuzhiyun 			if (!rdev)
371*4882a593Smuzhiyun 				rdev = wanted;
372*4882a593Smuzhiyun 		}
373*4882a593Smuzhiyun 
374*4882a593Smuzhiyun 		/* we've used the SIZE information, so discard it */
375*4882a593Smuzhiyun 		attr->ia_valid &= ~ATTR_SIZE;
376*4882a593Smuzhiyun 
377*4882a593Smuzhiyun 		/* Make sure the type and device matches */
378*4882a593Smuzhiyun 		resp->status = nfserr_exist;
379*4882a593Smuzhiyun 		if (inode && inode_wrong_type(inode, type))
380*4882a593Smuzhiyun 			goto out_unlock;
381*4882a593Smuzhiyun 	}
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun 	resp->status = nfs_ok;
384*4882a593Smuzhiyun 	if (!inode) {
385*4882a593Smuzhiyun 		/* File doesn't exist. Create it and set attrs */
386*4882a593Smuzhiyun 		resp->status = nfsd_create_locked(rqstp, dirfhp, argp->name,
387*4882a593Smuzhiyun 						  argp->len, attr, type, rdev,
388*4882a593Smuzhiyun 						  newfhp);
389*4882a593Smuzhiyun 	} else if (type == S_IFREG) {
390*4882a593Smuzhiyun 		dprintk("nfsd:   existing %s, valid=%x, size=%ld\n",
391*4882a593Smuzhiyun 			argp->name, attr->ia_valid, (long) attr->ia_size);
392*4882a593Smuzhiyun 		/* File already exists. We ignore all attributes except
393*4882a593Smuzhiyun 		 * size, so that creat() behaves exactly like
394*4882a593Smuzhiyun 		 * open(..., O_CREAT|O_TRUNC|O_WRONLY).
395*4882a593Smuzhiyun 		 */
396*4882a593Smuzhiyun 		attr->ia_valid &= ATTR_SIZE;
397*4882a593Smuzhiyun 		if (attr->ia_valid)
398*4882a593Smuzhiyun 			resp->status = nfsd_setattr(rqstp, newfhp, attr, 0,
399*4882a593Smuzhiyun 						    (time64_t)0);
400*4882a593Smuzhiyun 	}
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun out_unlock:
403*4882a593Smuzhiyun 	/* We don't really need to unlock, as fh_put does it. */
404*4882a593Smuzhiyun 	fh_unlock(dirfhp);
405*4882a593Smuzhiyun 	fh_drop_write(dirfhp);
406*4882a593Smuzhiyun done:
407*4882a593Smuzhiyun 	fh_put(dirfhp);
408*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
409*4882a593Smuzhiyun 		goto out;
410*4882a593Smuzhiyun 	resp->status = fh_getattr(&resp->fh, &resp->stat);
411*4882a593Smuzhiyun out:
412*4882a593Smuzhiyun 	return rpc_success;
413*4882a593Smuzhiyun }
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun static __be32
nfsd_proc_remove(struct svc_rqst * rqstp)416*4882a593Smuzhiyun nfsd_proc_remove(struct svc_rqst *rqstp)
417*4882a593Smuzhiyun {
418*4882a593Smuzhiyun 	struct nfsd_diropargs *argp = rqstp->rq_argp;
419*4882a593Smuzhiyun 	struct nfsd_stat *resp = rqstp->rq_resp;
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	dprintk("nfsd: REMOVE   %s %.*s\n", SVCFH_fmt(&argp->fh),
422*4882a593Smuzhiyun 		argp->len, argp->name);
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	/* Unlink. -SIFDIR means file must not be a directory */
425*4882a593Smuzhiyun 	resp->status = nfsd_unlink(rqstp, &argp->fh, -S_IFDIR,
426*4882a593Smuzhiyun 				   argp->name, argp->len);
427*4882a593Smuzhiyun 	fh_put(&argp->fh);
428*4882a593Smuzhiyun 	return rpc_success;
429*4882a593Smuzhiyun }
430*4882a593Smuzhiyun 
431*4882a593Smuzhiyun static __be32
nfsd_proc_rename(struct svc_rqst * rqstp)432*4882a593Smuzhiyun nfsd_proc_rename(struct svc_rqst *rqstp)
433*4882a593Smuzhiyun {
434*4882a593Smuzhiyun 	struct nfsd_renameargs *argp = rqstp->rq_argp;
435*4882a593Smuzhiyun 	struct nfsd_stat *resp = rqstp->rq_resp;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	dprintk("nfsd: RENAME   %s %.*s -> \n",
438*4882a593Smuzhiyun 		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname);
439*4882a593Smuzhiyun 	dprintk("nfsd:        ->  %s %.*s\n",
440*4882a593Smuzhiyun 		SVCFH_fmt(&argp->tfh), argp->tlen, argp->tname);
441*4882a593Smuzhiyun 
442*4882a593Smuzhiyun 	resp->status = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
443*4882a593Smuzhiyun 				   &argp->tfh, argp->tname, argp->tlen);
444*4882a593Smuzhiyun 	fh_put(&argp->ffh);
445*4882a593Smuzhiyun 	fh_put(&argp->tfh);
446*4882a593Smuzhiyun 	return rpc_success;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun static __be32
nfsd_proc_link(struct svc_rqst * rqstp)450*4882a593Smuzhiyun nfsd_proc_link(struct svc_rqst *rqstp)
451*4882a593Smuzhiyun {
452*4882a593Smuzhiyun 	struct nfsd_linkargs *argp = rqstp->rq_argp;
453*4882a593Smuzhiyun 	struct nfsd_stat *resp = rqstp->rq_resp;
454*4882a593Smuzhiyun 
455*4882a593Smuzhiyun 	dprintk("nfsd: LINK     %s ->\n",
456*4882a593Smuzhiyun 		SVCFH_fmt(&argp->ffh));
457*4882a593Smuzhiyun 	dprintk("nfsd:    %s %.*s\n",
458*4882a593Smuzhiyun 		SVCFH_fmt(&argp->tfh),
459*4882a593Smuzhiyun 		argp->tlen,
460*4882a593Smuzhiyun 		argp->tname);
461*4882a593Smuzhiyun 
462*4882a593Smuzhiyun 	resp->status = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
463*4882a593Smuzhiyun 				 &argp->ffh);
464*4882a593Smuzhiyun 	fh_put(&argp->ffh);
465*4882a593Smuzhiyun 	fh_put(&argp->tfh);
466*4882a593Smuzhiyun 	return rpc_success;
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun 
469*4882a593Smuzhiyun static __be32
nfsd_proc_symlink(struct svc_rqst * rqstp)470*4882a593Smuzhiyun nfsd_proc_symlink(struct svc_rqst *rqstp)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun 	struct nfsd_symlinkargs *argp = rqstp->rq_argp;
473*4882a593Smuzhiyun 	struct nfsd_stat *resp = rqstp->rq_resp;
474*4882a593Smuzhiyun 	struct svc_fh	newfh;
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	if (argp->tlen > NFS_MAXPATHLEN) {
477*4882a593Smuzhiyun 		resp->status = nfserr_nametoolong;
478*4882a593Smuzhiyun 		goto out;
479*4882a593Smuzhiyun 	}
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	argp->tname = svc_fill_symlink_pathname(rqstp, &argp->first,
482*4882a593Smuzhiyun 						page_address(rqstp->rq_arg.pages[0]),
483*4882a593Smuzhiyun 						argp->tlen);
484*4882a593Smuzhiyun 	if (IS_ERR(argp->tname)) {
485*4882a593Smuzhiyun 		resp->status = nfserrno(PTR_ERR(argp->tname));
486*4882a593Smuzhiyun 		goto out;
487*4882a593Smuzhiyun 	}
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	dprintk("nfsd: SYMLINK  %s %.*s -> %.*s\n",
490*4882a593Smuzhiyun 		SVCFH_fmt(&argp->ffh), argp->flen, argp->fname,
491*4882a593Smuzhiyun 		argp->tlen, argp->tname);
492*4882a593Smuzhiyun 
493*4882a593Smuzhiyun 	fh_init(&newfh, NFS_FHSIZE);
494*4882a593Smuzhiyun 	resp->status = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
495*4882a593Smuzhiyun 				    argp->tname, &newfh);
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun 	kfree(argp->tname);
498*4882a593Smuzhiyun 	fh_put(&argp->ffh);
499*4882a593Smuzhiyun 	fh_put(&newfh);
500*4882a593Smuzhiyun out:
501*4882a593Smuzhiyun 	return rpc_success;
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun /*
505*4882a593Smuzhiyun  * Make directory. This operation is not idempotent.
506*4882a593Smuzhiyun  * N.B. After this call resp->fh needs an fh_put
507*4882a593Smuzhiyun  */
508*4882a593Smuzhiyun static __be32
nfsd_proc_mkdir(struct svc_rqst * rqstp)509*4882a593Smuzhiyun nfsd_proc_mkdir(struct svc_rqst *rqstp)
510*4882a593Smuzhiyun {
511*4882a593Smuzhiyun 	struct nfsd_createargs *argp = rqstp->rq_argp;
512*4882a593Smuzhiyun 	struct nfsd_diropres *resp = rqstp->rq_resp;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	dprintk("nfsd: MKDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	if (resp->fh.fh_dentry) {
517*4882a593Smuzhiyun 		printk(KERN_WARNING
518*4882a593Smuzhiyun 			"nfsd_proc_mkdir: response already verified??\n");
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 	argp->attrs.ia_valid &= ~ATTR_SIZE;
522*4882a593Smuzhiyun 	fh_init(&resp->fh, NFS_FHSIZE);
523*4882a593Smuzhiyun 	resp->status = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
524*4882a593Smuzhiyun 				   &argp->attrs, S_IFDIR, 0, &resp->fh);
525*4882a593Smuzhiyun 	fh_put(&argp->fh);
526*4882a593Smuzhiyun 	if (resp->status != nfs_ok)
527*4882a593Smuzhiyun 		goto out;
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	resp->status = fh_getattr(&resp->fh, &resp->stat);
530*4882a593Smuzhiyun out:
531*4882a593Smuzhiyun 	return rpc_success;
532*4882a593Smuzhiyun }
533*4882a593Smuzhiyun 
534*4882a593Smuzhiyun /*
535*4882a593Smuzhiyun  * Remove a directory
536*4882a593Smuzhiyun  */
537*4882a593Smuzhiyun static __be32
nfsd_proc_rmdir(struct svc_rqst * rqstp)538*4882a593Smuzhiyun nfsd_proc_rmdir(struct svc_rqst *rqstp)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	struct nfsd_diropargs *argp = rqstp->rq_argp;
541*4882a593Smuzhiyun 	struct nfsd_stat *resp = rqstp->rq_resp;
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	dprintk("nfsd: RMDIR    %s %.*s\n", SVCFH_fmt(&argp->fh), argp->len, argp->name);
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	resp->status = nfsd_unlink(rqstp, &argp->fh, S_IFDIR,
546*4882a593Smuzhiyun 				   argp->name, argp->len);
547*4882a593Smuzhiyun 	fh_put(&argp->fh);
548*4882a593Smuzhiyun 	return rpc_success;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun /*
552*4882a593Smuzhiyun  * Read a portion of a directory.
553*4882a593Smuzhiyun  */
554*4882a593Smuzhiyun static __be32
nfsd_proc_readdir(struct svc_rqst * rqstp)555*4882a593Smuzhiyun nfsd_proc_readdir(struct svc_rqst *rqstp)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun 	struct nfsd_readdirargs *argp = rqstp->rq_argp;
558*4882a593Smuzhiyun 	struct nfsd_readdirres *resp = rqstp->rq_resp;
559*4882a593Smuzhiyun 	int		count;
560*4882a593Smuzhiyun 	loff_t		offset;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	dprintk("nfsd: READDIR  %s %d bytes at %d\n",
563*4882a593Smuzhiyun 		SVCFH_fmt(&argp->fh),
564*4882a593Smuzhiyun 		argp->count, argp->cookie);
565*4882a593Smuzhiyun 
566*4882a593Smuzhiyun 	/* Shrink to the client read size */
567*4882a593Smuzhiyun 	count = (argp->count >> 2) - 2;
568*4882a593Smuzhiyun 
569*4882a593Smuzhiyun 	/* Make sure we've room for the NULL ptr & eof flag */
570*4882a593Smuzhiyun 	count -= 2;
571*4882a593Smuzhiyun 	if (count < 0)
572*4882a593Smuzhiyun 		count = 0;
573*4882a593Smuzhiyun 
574*4882a593Smuzhiyun 	resp->buffer = argp->buffer;
575*4882a593Smuzhiyun 	resp->offset = NULL;
576*4882a593Smuzhiyun 	resp->buflen = count;
577*4882a593Smuzhiyun 	resp->common.err = nfs_ok;
578*4882a593Smuzhiyun 	/* Read directory and encode entries on the fly */
579*4882a593Smuzhiyun 	offset = argp->cookie;
580*4882a593Smuzhiyun 	resp->status = nfsd_readdir(rqstp, &argp->fh, &offset,
581*4882a593Smuzhiyun 				    &resp->common, nfssvc_encode_entry);
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 	resp->count = resp->buffer - argp->buffer;
584*4882a593Smuzhiyun 	if (resp->offset)
585*4882a593Smuzhiyun 		*resp->offset = htonl(offset);
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	fh_put(&argp->fh);
588*4882a593Smuzhiyun 	return rpc_success;
589*4882a593Smuzhiyun }
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun /*
592*4882a593Smuzhiyun  * Get file system info
593*4882a593Smuzhiyun  */
594*4882a593Smuzhiyun static __be32
nfsd_proc_statfs(struct svc_rqst * rqstp)595*4882a593Smuzhiyun nfsd_proc_statfs(struct svc_rqst *rqstp)
596*4882a593Smuzhiyun {
597*4882a593Smuzhiyun 	struct nfsd_fhandle *argp = rqstp->rq_argp;
598*4882a593Smuzhiyun 	struct nfsd_statfsres *resp = rqstp->rq_resp;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	dprintk("nfsd: STATFS   %s\n", SVCFH_fmt(&argp->fh));
601*4882a593Smuzhiyun 
602*4882a593Smuzhiyun 	resp->status = nfsd_statfs(rqstp, &argp->fh, &resp->stats,
603*4882a593Smuzhiyun 				   NFSD_MAY_BYPASS_GSS_ON_ROOT);
604*4882a593Smuzhiyun 	fh_put(&argp->fh);
605*4882a593Smuzhiyun 	return rpc_success;
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun 
608*4882a593Smuzhiyun /*
609*4882a593Smuzhiyun  * NFSv2 Server procedures.
610*4882a593Smuzhiyun  * Only the results of non-idempotent operations are cached.
611*4882a593Smuzhiyun  */
612*4882a593Smuzhiyun struct nfsd_void { int dummy; };
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun #define ST 1		/* status */
615*4882a593Smuzhiyun #define FH 8		/* filehandle */
616*4882a593Smuzhiyun #define	AT 18		/* attributes */
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun static const struct svc_procedure nfsd_procedures2[18] = {
619*4882a593Smuzhiyun 	[NFSPROC_NULL] = {
620*4882a593Smuzhiyun 		.pc_func = nfsd_proc_null,
621*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_void,
622*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_void,
623*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_void),
624*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_void),
625*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
626*4882a593Smuzhiyun 		.pc_xdrressize = 0,
627*4882a593Smuzhiyun 	},
628*4882a593Smuzhiyun 	[NFSPROC_GETATTR] = {
629*4882a593Smuzhiyun 		.pc_func = nfsd_proc_getattr,
630*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_fhandle,
631*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_attrstat,
632*4882a593Smuzhiyun 		.pc_release = nfssvc_release_attrstat,
633*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_fhandle),
634*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_attrstat),
635*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
636*4882a593Smuzhiyun 		.pc_xdrressize = ST+AT,
637*4882a593Smuzhiyun 	},
638*4882a593Smuzhiyun 	[NFSPROC_SETATTR] = {
639*4882a593Smuzhiyun 		.pc_func = nfsd_proc_setattr,
640*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_sattrargs,
641*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_attrstat,
642*4882a593Smuzhiyun 		.pc_release = nfssvc_release_attrstat,
643*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_sattrargs),
644*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_attrstat),
645*4882a593Smuzhiyun 		.pc_cachetype = RC_REPLBUFF,
646*4882a593Smuzhiyun 		.pc_xdrressize = ST+AT,
647*4882a593Smuzhiyun 	},
648*4882a593Smuzhiyun 	[NFSPROC_ROOT] = {
649*4882a593Smuzhiyun 		.pc_func = nfsd_proc_root,
650*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_void,
651*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_void,
652*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_void),
653*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_void),
654*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
655*4882a593Smuzhiyun 		.pc_xdrressize = 0,
656*4882a593Smuzhiyun 	},
657*4882a593Smuzhiyun 	[NFSPROC_LOOKUP] = {
658*4882a593Smuzhiyun 		.pc_func = nfsd_proc_lookup,
659*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_diropargs,
660*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_diropres,
661*4882a593Smuzhiyun 		.pc_release = nfssvc_release_diropres,
662*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_diropargs),
663*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_diropres),
664*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
665*4882a593Smuzhiyun 		.pc_xdrressize = ST+FH+AT,
666*4882a593Smuzhiyun 	},
667*4882a593Smuzhiyun 	[NFSPROC_READLINK] = {
668*4882a593Smuzhiyun 		.pc_func = nfsd_proc_readlink,
669*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_readlinkargs,
670*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_readlinkres,
671*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_readlinkargs),
672*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_readlinkres),
673*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
674*4882a593Smuzhiyun 		.pc_xdrressize = ST+1+NFS_MAXPATHLEN/4,
675*4882a593Smuzhiyun 	},
676*4882a593Smuzhiyun 	[NFSPROC_READ] = {
677*4882a593Smuzhiyun 		.pc_func = nfsd_proc_read,
678*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_readargs,
679*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_readres,
680*4882a593Smuzhiyun 		.pc_release = nfssvc_release_readres,
681*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_readargs),
682*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_readres),
683*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
684*4882a593Smuzhiyun 		.pc_xdrressize = ST+AT+1+NFSSVC_MAXBLKSIZE_V2/4,
685*4882a593Smuzhiyun 	},
686*4882a593Smuzhiyun 	[NFSPROC_WRITECACHE] = {
687*4882a593Smuzhiyun 		.pc_func = nfsd_proc_writecache,
688*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_void,
689*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_void,
690*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_void),
691*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_void),
692*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
693*4882a593Smuzhiyun 		.pc_xdrressize = 0,
694*4882a593Smuzhiyun 	},
695*4882a593Smuzhiyun 	[NFSPROC_WRITE] = {
696*4882a593Smuzhiyun 		.pc_func = nfsd_proc_write,
697*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_writeargs,
698*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_attrstat,
699*4882a593Smuzhiyun 		.pc_release = nfssvc_release_attrstat,
700*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_writeargs),
701*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_attrstat),
702*4882a593Smuzhiyun 		.pc_cachetype = RC_REPLBUFF,
703*4882a593Smuzhiyun 		.pc_xdrressize = ST+AT,
704*4882a593Smuzhiyun 	},
705*4882a593Smuzhiyun 	[NFSPROC_CREATE] = {
706*4882a593Smuzhiyun 		.pc_func = nfsd_proc_create,
707*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_createargs,
708*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_diropres,
709*4882a593Smuzhiyun 		.pc_release = nfssvc_release_diropres,
710*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_createargs),
711*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_diropres),
712*4882a593Smuzhiyun 		.pc_cachetype = RC_REPLBUFF,
713*4882a593Smuzhiyun 		.pc_xdrressize = ST+FH+AT,
714*4882a593Smuzhiyun 	},
715*4882a593Smuzhiyun 	[NFSPROC_REMOVE] = {
716*4882a593Smuzhiyun 		.pc_func = nfsd_proc_remove,
717*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_diropargs,
718*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_stat,
719*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_diropargs),
720*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_stat),
721*4882a593Smuzhiyun 		.pc_cachetype = RC_REPLSTAT,
722*4882a593Smuzhiyun 		.pc_xdrressize = ST,
723*4882a593Smuzhiyun 	},
724*4882a593Smuzhiyun 	[NFSPROC_RENAME] = {
725*4882a593Smuzhiyun 		.pc_func = nfsd_proc_rename,
726*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_renameargs,
727*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_stat,
728*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_renameargs),
729*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_stat),
730*4882a593Smuzhiyun 		.pc_cachetype = RC_REPLSTAT,
731*4882a593Smuzhiyun 		.pc_xdrressize = ST,
732*4882a593Smuzhiyun 	},
733*4882a593Smuzhiyun 	[NFSPROC_LINK] = {
734*4882a593Smuzhiyun 		.pc_func = nfsd_proc_link,
735*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_linkargs,
736*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_stat,
737*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_linkargs),
738*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_stat),
739*4882a593Smuzhiyun 		.pc_cachetype = RC_REPLSTAT,
740*4882a593Smuzhiyun 		.pc_xdrressize = ST,
741*4882a593Smuzhiyun 	},
742*4882a593Smuzhiyun 	[NFSPROC_SYMLINK] = {
743*4882a593Smuzhiyun 		.pc_func = nfsd_proc_symlink,
744*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_symlinkargs,
745*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_stat,
746*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_symlinkargs),
747*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_stat),
748*4882a593Smuzhiyun 		.pc_cachetype = RC_REPLSTAT,
749*4882a593Smuzhiyun 		.pc_xdrressize = ST,
750*4882a593Smuzhiyun 	},
751*4882a593Smuzhiyun 	[NFSPROC_MKDIR] = {
752*4882a593Smuzhiyun 		.pc_func = nfsd_proc_mkdir,
753*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_createargs,
754*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_diropres,
755*4882a593Smuzhiyun 		.pc_release = nfssvc_release_diropres,
756*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_createargs),
757*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_diropres),
758*4882a593Smuzhiyun 		.pc_cachetype = RC_REPLBUFF,
759*4882a593Smuzhiyun 		.pc_xdrressize = ST+FH+AT,
760*4882a593Smuzhiyun 	},
761*4882a593Smuzhiyun 	[NFSPROC_RMDIR] = {
762*4882a593Smuzhiyun 		.pc_func = nfsd_proc_rmdir,
763*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_diropargs,
764*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_stat,
765*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_diropargs),
766*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_stat),
767*4882a593Smuzhiyun 		.pc_cachetype = RC_REPLSTAT,
768*4882a593Smuzhiyun 		.pc_xdrressize = ST,
769*4882a593Smuzhiyun 	},
770*4882a593Smuzhiyun 	[NFSPROC_READDIR] = {
771*4882a593Smuzhiyun 		.pc_func = nfsd_proc_readdir,
772*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_readdirargs,
773*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_readdirres,
774*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_readdirargs),
775*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_readdirres),
776*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
777*4882a593Smuzhiyun 	},
778*4882a593Smuzhiyun 	[NFSPROC_STATFS] = {
779*4882a593Smuzhiyun 		.pc_func = nfsd_proc_statfs,
780*4882a593Smuzhiyun 		.pc_decode = nfssvc_decode_fhandle,
781*4882a593Smuzhiyun 		.pc_encode = nfssvc_encode_statfsres,
782*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd_fhandle),
783*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd_statfsres),
784*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
785*4882a593Smuzhiyun 		.pc_xdrressize = ST+5,
786*4882a593Smuzhiyun 	},
787*4882a593Smuzhiyun };
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun 
790*4882a593Smuzhiyun static unsigned int nfsd_count2[ARRAY_SIZE(nfsd_procedures2)];
791*4882a593Smuzhiyun const struct svc_version nfsd_version2 = {
792*4882a593Smuzhiyun 	.vs_vers	= 2,
793*4882a593Smuzhiyun 	.vs_nproc	= 18,
794*4882a593Smuzhiyun 	.vs_proc	= nfsd_procedures2,
795*4882a593Smuzhiyun 	.vs_count	= nfsd_count2,
796*4882a593Smuzhiyun 	.vs_dispatch	= nfsd_dispatch,
797*4882a593Smuzhiyun 	.vs_xdrsize	= NFS2_SVC_XDRSIZE,
798*4882a593Smuzhiyun };
799*4882a593Smuzhiyun 
800*4882a593Smuzhiyun /*
801*4882a593Smuzhiyun  * Map errnos to NFS errnos.
802*4882a593Smuzhiyun  */
803*4882a593Smuzhiyun __be32
nfserrno(int errno)804*4882a593Smuzhiyun nfserrno (int errno)
805*4882a593Smuzhiyun {
806*4882a593Smuzhiyun 	static struct {
807*4882a593Smuzhiyun 		__be32	nfserr;
808*4882a593Smuzhiyun 		int	syserr;
809*4882a593Smuzhiyun 	} nfs_errtbl[] = {
810*4882a593Smuzhiyun 		{ nfs_ok, 0 },
811*4882a593Smuzhiyun 		{ nfserr_perm, -EPERM },
812*4882a593Smuzhiyun 		{ nfserr_noent, -ENOENT },
813*4882a593Smuzhiyun 		{ nfserr_io, -EIO },
814*4882a593Smuzhiyun 		{ nfserr_nxio, -ENXIO },
815*4882a593Smuzhiyun 		{ nfserr_fbig, -E2BIG },
816*4882a593Smuzhiyun 		{ nfserr_acces, -EACCES },
817*4882a593Smuzhiyun 		{ nfserr_exist, -EEXIST },
818*4882a593Smuzhiyun 		{ nfserr_xdev, -EXDEV },
819*4882a593Smuzhiyun 		{ nfserr_mlink, -EMLINK },
820*4882a593Smuzhiyun 		{ nfserr_nodev, -ENODEV },
821*4882a593Smuzhiyun 		{ nfserr_notdir, -ENOTDIR },
822*4882a593Smuzhiyun 		{ nfserr_isdir, -EISDIR },
823*4882a593Smuzhiyun 		{ nfserr_inval, -EINVAL },
824*4882a593Smuzhiyun 		{ nfserr_fbig, -EFBIG },
825*4882a593Smuzhiyun 		{ nfserr_nospc, -ENOSPC },
826*4882a593Smuzhiyun 		{ nfserr_rofs, -EROFS },
827*4882a593Smuzhiyun 		{ nfserr_mlink, -EMLINK },
828*4882a593Smuzhiyun 		{ nfserr_nametoolong, -ENAMETOOLONG },
829*4882a593Smuzhiyun 		{ nfserr_notempty, -ENOTEMPTY },
830*4882a593Smuzhiyun #ifdef EDQUOT
831*4882a593Smuzhiyun 		{ nfserr_dquot, -EDQUOT },
832*4882a593Smuzhiyun #endif
833*4882a593Smuzhiyun 		{ nfserr_stale, -ESTALE },
834*4882a593Smuzhiyun 		{ nfserr_jukebox, -ETIMEDOUT },
835*4882a593Smuzhiyun 		{ nfserr_jukebox, -ERESTARTSYS },
836*4882a593Smuzhiyun 		{ nfserr_jukebox, -EAGAIN },
837*4882a593Smuzhiyun 		{ nfserr_jukebox, -EWOULDBLOCK },
838*4882a593Smuzhiyun 		{ nfserr_jukebox, -ENOMEM },
839*4882a593Smuzhiyun 		{ nfserr_io, -ETXTBSY },
840*4882a593Smuzhiyun 		{ nfserr_notsupp, -EOPNOTSUPP },
841*4882a593Smuzhiyun 		{ nfserr_toosmall, -ETOOSMALL },
842*4882a593Smuzhiyun 		{ nfserr_serverfault, -ESERVERFAULT },
843*4882a593Smuzhiyun 		{ nfserr_serverfault, -ENFILE },
844*4882a593Smuzhiyun 		{ nfserr_io, -EUCLEAN },
845*4882a593Smuzhiyun 		{ nfserr_perm, -ENOKEY },
846*4882a593Smuzhiyun 	};
847*4882a593Smuzhiyun 	int	i;
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 	for (i = 0; i < ARRAY_SIZE(nfs_errtbl); i++) {
850*4882a593Smuzhiyun 		if (nfs_errtbl[i].syserr == errno)
851*4882a593Smuzhiyun 			return nfs_errtbl[i].nfserr;
852*4882a593Smuzhiyun 	}
853*4882a593Smuzhiyun 	WARN_ONCE(1, "nfsd: non-standard errno: %d\n", errno);
854*4882a593Smuzhiyun 	return nfserr_io;
855*4882a593Smuzhiyun }
856*4882a593Smuzhiyun 
857