xref: /OK3568_Linux_fs/kernel/fs/nfsd/nfs4proc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *  Server-side procedures for NFSv4.
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *  Copyright (c) 2002 The Regents of the University of Michigan.
5*4882a593Smuzhiyun  *  All rights reserved.
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  *  Kendrick Smith <kmsmith@umich.edu>
8*4882a593Smuzhiyun  *  Andy Adamson   <andros@umich.edu>
9*4882a593Smuzhiyun  *
10*4882a593Smuzhiyun  *  Redistribution and use in source and binary forms, with or without
11*4882a593Smuzhiyun  *  modification, are permitted provided that the following conditions
12*4882a593Smuzhiyun  *  are met:
13*4882a593Smuzhiyun  *
14*4882a593Smuzhiyun  *  1. Redistributions of source code must retain the above copyright
15*4882a593Smuzhiyun  *     notice, this list of conditions and the following disclaimer.
16*4882a593Smuzhiyun  *  2. Redistributions in binary form must reproduce the above copyright
17*4882a593Smuzhiyun  *     notice, this list of conditions and the following disclaimer in the
18*4882a593Smuzhiyun  *     documentation and/or other materials provided with the distribution.
19*4882a593Smuzhiyun  *  3. Neither the name of the University nor the names of its
20*4882a593Smuzhiyun  *     contributors may be used to endorse or promote products derived
21*4882a593Smuzhiyun  *     from this software without specific prior written permission.
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
24*4882a593Smuzhiyun  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25*4882a593Smuzhiyun  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26*4882a593Smuzhiyun  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27*4882a593Smuzhiyun  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
28*4882a593Smuzhiyun  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
29*4882a593Smuzhiyun  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
30*4882a593Smuzhiyun  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31*4882a593Smuzhiyun  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32*4882a593Smuzhiyun  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*4882a593Smuzhiyun  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*4882a593Smuzhiyun  */
35*4882a593Smuzhiyun #include <linux/fs_struct.h>
36*4882a593Smuzhiyun #include <linux/file.h>
37*4882a593Smuzhiyun #include <linux/falloc.h>
38*4882a593Smuzhiyun #include <linux/slab.h>
39*4882a593Smuzhiyun #include <linux/kthread.h>
40*4882a593Smuzhiyun #include <linux/sunrpc/addr.h>
41*4882a593Smuzhiyun #include <linux/nfs_ssc.h>
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #include "idmap.h"
44*4882a593Smuzhiyun #include "cache.h"
45*4882a593Smuzhiyun #include "xdr4.h"
46*4882a593Smuzhiyun #include "vfs.h"
47*4882a593Smuzhiyun #include "current_stateid.h"
48*4882a593Smuzhiyun #include "netns.h"
49*4882a593Smuzhiyun #include "acl.h"
50*4882a593Smuzhiyun #include "pnfs.h"
51*4882a593Smuzhiyun #include "trace.h"
52*4882a593Smuzhiyun 
53*4882a593Smuzhiyun #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
54*4882a593Smuzhiyun #include <linux/security.h>
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun static inline void
nfsd4_security_inode_setsecctx(struct svc_fh * resfh,struct xdr_netobj * label,u32 * bmval)57*4882a593Smuzhiyun nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
58*4882a593Smuzhiyun {
59*4882a593Smuzhiyun 	struct inode *inode = d_inode(resfh->fh_dentry);
60*4882a593Smuzhiyun 	int status;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun 	inode_lock(inode);
63*4882a593Smuzhiyun 	status = security_inode_setsecctx(resfh->fh_dentry,
64*4882a593Smuzhiyun 		label->data, label->len);
65*4882a593Smuzhiyun 	inode_unlock(inode);
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 	if (status)
68*4882a593Smuzhiyun 		/*
69*4882a593Smuzhiyun 		 * XXX: We should really fail the whole open, but we may
70*4882a593Smuzhiyun 		 * already have created a new file, so it may be too
71*4882a593Smuzhiyun 		 * late.  For now this seems the least of evils:
72*4882a593Smuzhiyun 		 */
73*4882a593Smuzhiyun 		bmval[2] &= ~FATTR4_WORD2_SECURITY_LABEL;
74*4882a593Smuzhiyun 
75*4882a593Smuzhiyun 	return;
76*4882a593Smuzhiyun }
77*4882a593Smuzhiyun #else
78*4882a593Smuzhiyun static inline void
nfsd4_security_inode_setsecctx(struct svc_fh * resfh,struct xdr_netobj * label,u32 * bmval)79*4882a593Smuzhiyun nfsd4_security_inode_setsecctx(struct svc_fh *resfh, struct xdr_netobj *label, u32 *bmval)
80*4882a593Smuzhiyun { }
81*4882a593Smuzhiyun #endif
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun #define NFSDDBG_FACILITY		NFSDDBG_PROC
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun static u32 nfsd_attrmask[] = {
86*4882a593Smuzhiyun 	NFSD_WRITEABLE_ATTRS_WORD0,
87*4882a593Smuzhiyun 	NFSD_WRITEABLE_ATTRS_WORD1,
88*4882a593Smuzhiyun 	NFSD_WRITEABLE_ATTRS_WORD2
89*4882a593Smuzhiyun };
90*4882a593Smuzhiyun 
91*4882a593Smuzhiyun static u32 nfsd41_ex_attrmask[] = {
92*4882a593Smuzhiyun 	NFSD_SUPPATTR_EXCLCREAT_WORD0,
93*4882a593Smuzhiyun 	NFSD_SUPPATTR_EXCLCREAT_WORD1,
94*4882a593Smuzhiyun 	NFSD_SUPPATTR_EXCLCREAT_WORD2
95*4882a593Smuzhiyun };
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun static __be32
check_attr_support(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,u32 * bmval,u32 * writable)98*4882a593Smuzhiyun check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
99*4882a593Smuzhiyun 		   u32 *bmval, u32 *writable)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	struct dentry *dentry = cstate->current_fh.fh_dentry;
102*4882a593Smuzhiyun 	struct svc_export *exp = cstate->current_fh.fh_export;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 	if (!nfsd_attrs_supported(cstate->minorversion, bmval))
105*4882a593Smuzhiyun 		return nfserr_attrnotsupp;
106*4882a593Smuzhiyun 	if ((bmval[0] & FATTR4_WORD0_ACL) && !IS_POSIXACL(d_inode(dentry)))
107*4882a593Smuzhiyun 		return nfserr_attrnotsupp;
108*4882a593Smuzhiyun 	if ((bmval[2] & FATTR4_WORD2_SECURITY_LABEL) &&
109*4882a593Smuzhiyun 			!(exp->ex_flags & NFSEXP_SECURITY_LABEL))
110*4882a593Smuzhiyun 		return nfserr_attrnotsupp;
111*4882a593Smuzhiyun 	if (writable && !bmval_is_subset(bmval, writable))
112*4882a593Smuzhiyun 		return nfserr_inval;
113*4882a593Smuzhiyun 	if (writable && (bmval[2] & FATTR4_WORD2_MODE_UMASK) &&
114*4882a593Smuzhiyun 			(bmval[1] & FATTR4_WORD1_MODE))
115*4882a593Smuzhiyun 		return nfserr_inval;
116*4882a593Smuzhiyun 	return nfs_ok;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun static __be32
nfsd4_check_open_attributes(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,struct nfsd4_open * open)120*4882a593Smuzhiyun nfsd4_check_open_attributes(struct svc_rqst *rqstp,
121*4882a593Smuzhiyun 	struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
122*4882a593Smuzhiyun {
123*4882a593Smuzhiyun 	__be32 status = nfs_ok;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	if (open->op_create == NFS4_OPEN_CREATE) {
126*4882a593Smuzhiyun 		if (open->op_createmode == NFS4_CREATE_UNCHECKED
127*4882a593Smuzhiyun 		    || open->op_createmode == NFS4_CREATE_GUARDED)
128*4882a593Smuzhiyun 			status = check_attr_support(rqstp, cstate,
129*4882a593Smuzhiyun 					open->op_bmval, nfsd_attrmask);
130*4882a593Smuzhiyun 		else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1)
131*4882a593Smuzhiyun 			status = check_attr_support(rqstp, cstate,
132*4882a593Smuzhiyun 					open->op_bmval, nfsd41_ex_attrmask);
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	return status;
136*4882a593Smuzhiyun }
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun static int
is_create_with_attrs(struct nfsd4_open * open)139*4882a593Smuzhiyun is_create_with_attrs(struct nfsd4_open *open)
140*4882a593Smuzhiyun {
141*4882a593Smuzhiyun 	return open->op_create == NFS4_OPEN_CREATE
142*4882a593Smuzhiyun 		&& (open->op_createmode == NFS4_CREATE_UNCHECKED
143*4882a593Smuzhiyun 		    || open->op_createmode == NFS4_CREATE_GUARDED
144*4882a593Smuzhiyun 		    || open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun /*
148*4882a593Smuzhiyun  * if error occurs when setting the acl, just clear the acl bit
149*4882a593Smuzhiyun  * in the returned attr bitmap.
150*4882a593Smuzhiyun  */
151*4882a593Smuzhiyun static void
do_set_nfs4_acl(struct svc_rqst * rqstp,struct svc_fh * fhp,struct nfs4_acl * acl,u32 * bmval)152*4882a593Smuzhiyun do_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
153*4882a593Smuzhiyun 		struct nfs4_acl *acl, u32 *bmval)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	__be32 status;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	status = nfsd4_set_nfs4_acl(rqstp, fhp, acl);
158*4882a593Smuzhiyun 	if (status)
159*4882a593Smuzhiyun 		/*
160*4882a593Smuzhiyun 		 * We should probably fail the whole open at this point,
161*4882a593Smuzhiyun 		 * but we've already created the file, so it's too late;
162*4882a593Smuzhiyun 		 * So this seems the least of evils:
163*4882a593Smuzhiyun 		 */
164*4882a593Smuzhiyun 		bmval[0] &= ~FATTR4_WORD0_ACL;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun static inline void
fh_dup2(struct svc_fh * dst,struct svc_fh * src)168*4882a593Smuzhiyun fh_dup2(struct svc_fh *dst, struct svc_fh *src)
169*4882a593Smuzhiyun {
170*4882a593Smuzhiyun 	fh_put(dst);
171*4882a593Smuzhiyun 	dget(src->fh_dentry);
172*4882a593Smuzhiyun 	if (src->fh_export)
173*4882a593Smuzhiyun 		exp_get(src->fh_export);
174*4882a593Smuzhiyun 	*dst = *src;
175*4882a593Smuzhiyun }
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun static __be32
do_open_permission(struct svc_rqst * rqstp,struct svc_fh * current_fh,struct nfsd4_open * open,int accmode)178*4882a593Smuzhiyun do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode)
179*4882a593Smuzhiyun {
180*4882a593Smuzhiyun 	__be32 status;
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	if (open->op_truncate &&
183*4882a593Smuzhiyun 		!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
184*4882a593Smuzhiyun 		return nfserr_inval;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	accmode |= NFSD_MAY_READ_IF_EXEC;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
189*4882a593Smuzhiyun 		accmode |= NFSD_MAY_READ;
190*4882a593Smuzhiyun 	if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
191*4882a593Smuzhiyun 		accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC);
192*4882a593Smuzhiyun 	if (open->op_share_deny & NFS4_SHARE_DENY_READ)
193*4882a593Smuzhiyun 		accmode |= NFSD_MAY_WRITE;
194*4882a593Smuzhiyun 
195*4882a593Smuzhiyun 	status = fh_verify(rqstp, current_fh, S_IFREG, accmode);
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	return status;
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
nfsd_check_obj_isreg(struct svc_fh * fh)200*4882a593Smuzhiyun static __be32 nfsd_check_obj_isreg(struct svc_fh *fh)
201*4882a593Smuzhiyun {
202*4882a593Smuzhiyun 	umode_t mode = d_inode(fh->fh_dentry)->i_mode;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	if (S_ISREG(mode))
205*4882a593Smuzhiyun 		return nfs_ok;
206*4882a593Smuzhiyun 	if (S_ISDIR(mode))
207*4882a593Smuzhiyun 		return nfserr_isdir;
208*4882a593Smuzhiyun 	/*
209*4882a593Smuzhiyun 	 * Using err_symlink as our catch-all case may look odd; but
210*4882a593Smuzhiyun 	 * there's no other obvious error for this case in 4.0, and we
211*4882a593Smuzhiyun 	 * happen to know that it will cause the linux v4 client to do
212*4882a593Smuzhiyun 	 * the right thing on attempts to open something other than a
213*4882a593Smuzhiyun 	 * regular file.
214*4882a593Smuzhiyun 	 */
215*4882a593Smuzhiyun 	return nfserr_symlink;
216*4882a593Smuzhiyun }
217*4882a593Smuzhiyun 
nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state * cstate,struct nfsd4_open * open,struct svc_fh * resfh)218*4882a593Smuzhiyun static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh *resfh)
219*4882a593Smuzhiyun {
220*4882a593Smuzhiyun 	if (nfsd4_has_session(cstate))
221*4882a593Smuzhiyun 		return;
222*4882a593Smuzhiyun 	fh_copy_shallow(&open->op_openowner->oo_owner.so_replay.rp_openfh,
223*4882a593Smuzhiyun 			&resfh->fh_handle);
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun static __be32
do_open_lookup(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,struct nfsd4_open * open,struct svc_fh ** resfh)227*4882a593Smuzhiyun do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh **resfh)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun 	struct svc_fh *current_fh = &cstate->current_fh;
230*4882a593Smuzhiyun 	int accmode;
231*4882a593Smuzhiyun 	__be32 status;
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 	*resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
234*4882a593Smuzhiyun 	if (!*resfh)
235*4882a593Smuzhiyun 		return nfserr_jukebox;
236*4882a593Smuzhiyun 	fh_init(*resfh, NFS4_FHSIZE);
237*4882a593Smuzhiyun 	open->op_truncate = false;
238*4882a593Smuzhiyun 
239*4882a593Smuzhiyun 	if (open->op_create) {
240*4882a593Smuzhiyun 		/* FIXME: check session persistence and pnfs flags.
241*4882a593Smuzhiyun 		 * The nfsv4.1 spec requires the following semantics:
242*4882a593Smuzhiyun 		 *
243*4882a593Smuzhiyun 		 * Persistent   | pNFS   | Server REQUIRED | Client Allowed
244*4882a593Smuzhiyun 		 * Reply Cache  | server |                 |
245*4882a593Smuzhiyun 		 * -------------+--------+-----------------+--------------------
246*4882a593Smuzhiyun 		 * no           | no     | EXCLUSIVE4_1    | EXCLUSIVE4_1
247*4882a593Smuzhiyun 		 *              |        |                 | (SHOULD)
248*4882a593Smuzhiyun 		 *              |        | and EXCLUSIVE4  | or EXCLUSIVE4
249*4882a593Smuzhiyun 		 *              |        |                 | (SHOULD NOT)
250*4882a593Smuzhiyun 		 * no           | yes    | EXCLUSIVE4_1    | EXCLUSIVE4_1
251*4882a593Smuzhiyun 		 * yes          | no     | GUARDED4        | GUARDED4
252*4882a593Smuzhiyun 		 * yes          | yes    | GUARDED4        | GUARDED4
253*4882a593Smuzhiyun 		 */
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 		/*
256*4882a593Smuzhiyun 		 * Note: create modes (UNCHECKED,GUARDED...) are the same
257*4882a593Smuzhiyun 		 * in NFSv4 as in v3 except EXCLUSIVE4_1.
258*4882a593Smuzhiyun 		 */
259*4882a593Smuzhiyun 		current->fs->umask = open->op_umask;
260*4882a593Smuzhiyun 		status = do_nfsd_create(rqstp, current_fh, open->op_fname.data,
261*4882a593Smuzhiyun 					open->op_fname.len, &open->op_iattr,
262*4882a593Smuzhiyun 					*resfh, open->op_createmode,
263*4882a593Smuzhiyun 					(u32 *)open->op_verf.data,
264*4882a593Smuzhiyun 					&open->op_truncate, &open->op_created);
265*4882a593Smuzhiyun 		current->fs->umask = 0;
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 		if (!status && open->op_label.len)
268*4882a593Smuzhiyun 			nfsd4_security_inode_setsecctx(*resfh, &open->op_label, open->op_bmval);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 		/*
271*4882a593Smuzhiyun 		 * Following rfc 3530 14.2.16, and rfc 5661 18.16.4
272*4882a593Smuzhiyun 		 * use the returned bitmask to indicate which attributes
273*4882a593Smuzhiyun 		 * we used to store the verifier:
274*4882a593Smuzhiyun 		 */
275*4882a593Smuzhiyun 		if (nfsd_create_is_exclusive(open->op_createmode) && status == 0)
276*4882a593Smuzhiyun 			open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS |
277*4882a593Smuzhiyun 						FATTR4_WORD1_TIME_MODIFY);
278*4882a593Smuzhiyun 	} else
279*4882a593Smuzhiyun 		/*
280*4882a593Smuzhiyun 		 * Note this may exit with the parent still locked.
281*4882a593Smuzhiyun 		 * We will hold the lock until nfsd4_open's final
282*4882a593Smuzhiyun 		 * lookup, to prevent renames or unlinks until we've had
283*4882a593Smuzhiyun 		 * a chance to an acquire a delegation if appropriate.
284*4882a593Smuzhiyun 		 */
285*4882a593Smuzhiyun 		status = nfsd_lookup(rqstp, current_fh,
286*4882a593Smuzhiyun 				     open->op_fname.data, open->op_fname.len, *resfh);
287*4882a593Smuzhiyun 	if (status)
288*4882a593Smuzhiyun 		goto out;
289*4882a593Smuzhiyun 	status = nfsd_check_obj_isreg(*resfh);
290*4882a593Smuzhiyun 	if (status)
291*4882a593Smuzhiyun 		goto out;
292*4882a593Smuzhiyun 
293*4882a593Smuzhiyun 	if (is_create_with_attrs(open) && open->op_acl != NULL)
294*4882a593Smuzhiyun 		do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	nfsd4_set_open_owner_reply_cache(cstate, open, *resfh);
297*4882a593Smuzhiyun 	accmode = NFSD_MAY_NOP;
298*4882a593Smuzhiyun 	if (open->op_created ||
299*4882a593Smuzhiyun 			open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
300*4882a593Smuzhiyun 		accmode |= NFSD_MAY_OWNER_OVERRIDE;
301*4882a593Smuzhiyun 	status = do_open_permission(rqstp, *resfh, open, accmode);
302*4882a593Smuzhiyun 	set_change_info(&open->op_cinfo, current_fh);
303*4882a593Smuzhiyun out:
304*4882a593Smuzhiyun 	return status;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
307*4882a593Smuzhiyun static __be32
do_open_fhandle(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,struct nfsd4_open * open)308*4882a593Smuzhiyun do_open_fhandle(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	struct svc_fh *current_fh = &cstate->current_fh;
311*4882a593Smuzhiyun 	__be32 status;
312*4882a593Smuzhiyun 	int accmode = 0;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	/* We don't know the target directory, and therefore can not
315*4882a593Smuzhiyun 	* set the change info
316*4882a593Smuzhiyun 	*/
317*4882a593Smuzhiyun 
318*4882a593Smuzhiyun 	memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	nfsd4_set_open_owner_reply_cache(cstate, open, current_fh);
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 	open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
323*4882a593Smuzhiyun 		(open->op_iattr.ia_size == 0);
324*4882a593Smuzhiyun 	/*
325*4882a593Smuzhiyun 	 * In the delegation case, the client is telling us about an
326*4882a593Smuzhiyun 	 * open that it *already* performed locally, some time ago.  We
327*4882a593Smuzhiyun 	 * should let it succeed now if possible.
328*4882a593Smuzhiyun 	 *
329*4882a593Smuzhiyun 	 * In the case of a CLAIM_FH open, on the other hand, the client
330*4882a593Smuzhiyun 	 * may be counting on us to enforce permissions (the Linux 4.1
331*4882a593Smuzhiyun 	 * client uses this for normal opens, for example).
332*4882a593Smuzhiyun 	 */
333*4882a593Smuzhiyun 	if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEG_CUR_FH)
334*4882a593Smuzhiyun 		accmode = NFSD_MAY_OWNER_OVERRIDE;
335*4882a593Smuzhiyun 
336*4882a593Smuzhiyun 	status = do_open_permission(rqstp, current_fh, open, accmode);
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 	return status;
339*4882a593Smuzhiyun }
340*4882a593Smuzhiyun 
341*4882a593Smuzhiyun static void
copy_clientid(clientid_t * clid,struct nfsd4_session * session)342*4882a593Smuzhiyun copy_clientid(clientid_t *clid, struct nfsd4_session *session)
343*4882a593Smuzhiyun {
344*4882a593Smuzhiyun 	struct nfsd4_sessionid *sid =
345*4882a593Smuzhiyun 			(struct nfsd4_sessionid *)session->se_sessionid.data;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	clid->cl_boot = sid->clientid.cl_boot;
348*4882a593Smuzhiyun 	clid->cl_id = sid->clientid.cl_id;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun static __be32
nfsd4_open(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)352*4882a593Smuzhiyun nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
353*4882a593Smuzhiyun 	   union nfsd4_op_u *u)
354*4882a593Smuzhiyun {
355*4882a593Smuzhiyun 	struct nfsd4_open *open = &u->open;
356*4882a593Smuzhiyun 	__be32 status;
357*4882a593Smuzhiyun 	struct svc_fh *resfh = NULL;
358*4882a593Smuzhiyun 	struct net *net = SVC_NET(rqstp);
359*4882a593Smuzhiyun 	struct nfsd_net *nn = net_generic(net, nfsd_net_id);
360*4882a593Smuzhiyun 	bool reclaim = false;
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun 	dprintk("NFSD: nfsd4_open filename %.*s op_openowner %p\n",
363*4882a593Smuzhiyun 		(int)open->op_fname.len, open->op_fname.data,
364*4882a593Smuzhiyun 		open->op_openowner);
365*4882a593Smuzhiyun 
366*4882a593Smuzhiyun 	/* This check required by spec. */
367*4882a593Smuzhiyun 	if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
368*4882a593Smuzhiyun 		return nfserr_inval;
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	open->op_created = false;
371*4882a593Smuzhiyun 	/*
372*4882a593Smuzhiyun 	 * RFC5661 18.51.3
373*4882a593Smuzhiyun 	 * Before RECLAIM_COMPLETE done, server should deny new lock
374*4882a593Smuzhiyun 	 */
375*4882a593Smuzhiyun 	if (nfsd4_has_session(cstate) &&
376*4882a593Smuzhiyun 	    !test_bit(NFSD4_CLIENT_RECLAIM_COMPLETE,
377*4882a593Smuzhiyun 		      &cstate->session->se_client->cl_flags) &&
378*4882a593Smuzhiyun 	    open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
379*4882a593Smuzhiyun 		return nfserr_grace;
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	if (nfsd4_has_session(cstate))
382*4882a593Smuzhiyun 		copy_clientid(&open->op_clientid, cstate->session);
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	/* check seqid for replay. set nfs4_owner */
385*4882a593Smuzhiyun 	status = nfsd4_process_open1(cstate, open, nn);
386*4882a593Smuzhiyun 	if (status == nfserr_replay_me) {
387*4882a593Smuzhiyun 		struct nfs4_replay *rp = &open->op_openowner->oo_owner.so_replay;
388*4882a593Smuzhiyun 		fh_put(&cstate->current_fh);
389*4882a593Smuzhiyun 		fh_copy_shallow(&cstate->current_fh.fh_handle,
390*4882a593Smuzhiyun 				&rp->rp_openfh);
391*4882a593Smuzhiyun 		status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
392*4882a593Smuzhiyun 		if (status)
393*4882a593Smuzhiyun 			dprintk("nfsd4_open: replay failed"
394*4882a593Smuzhiyun 				" restoring previous filehandle\n");
395*4882a593Smuzhiyun 		else
396*4882a593Smuzhiyun 			status = nfserr_replay_me;
397*4882a593Smuzhiyun 	}
398*4882a593Smuzhiyun 	if (status)
399*4882a593Smuzhiyun 		goto out;
400*4882a593Smuzhiyun 	if (open->op_xdr_error) {
401*4882a593Smuzhiyun 		status = open->op_xdr_error;
402*4882a593Smuzhiyun 		goto out;
403*4882a593Smuzhiyun 	}
404*4882a593Smuzhiyun 
405*4882a593Smuzhiyun 	status = nfsd4_check_open_attributes(rqstp, cstate, open);
406*4882a593Smuzhiyun 	if (status)
407*4882a593Smuzhiyun 		goto out;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 	/* Openowner is now set, so sequence id will get bumped.  Now we need
410*4882a593Smuzhiyun 	 * these checks before we do any creates: */
411*4882a593Smuzhiyun 	status = nfserr_grace;
412*4882a593Smuzhiyun 	if (opens_in_grace(net) && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
413*4882a593Smuzhiyun 		goto out;
414*4882a593Smuzhiyun 	status = nfserr_no_grace;
415*4882a593Smuzhiyun 	if (!opens_in_grace(net) && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
416*4882a593Smuzhiyun 		goto out;
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	switch (open->op_claim_type) {
419*4882a593Smuzhiyun 		case NFS4_OPEN_CLAIM_DELEGATE_CUR:
420*4882a593Smuzhiyun 		case NFS4_OPEN_CLAIM_NULL:
421*4882a593Smuzhiyun 			status = do_open_lookup(rqstp, cstate, open, &resfh);
422*4882a593Smuzhiyun 			if (status)
423*4882a593Smuzhiyun 				goto out;
424*4882a593Smuzhiyun 			break;
425*4882a593Smuzhiyun 		case NFS4_OPEN_CLAIM_PREVIOUS:
426*4882a593Smuzhiyun 			status = nfs4_check_open_reclaim(&open->op_clientid,
427*4882a593Smuzhiyun 							 cstate, nn);
428*4882a593Smuzhiyun 			if (status)
429*4882a593Smuzhiyun 				goto out;
430*4882a593Smuzhiyun 			open->op_openowner->oo_flags |= NFS4_OO_CONFIRMED;
431*4882a593Smuzhiyun 			reclaim = true;
432*4882a593Smuzhiyun 			fallthrough;
433*4882a593Smuzhiyun 		case NFS4_OPEN_CLAIM_FH:
434*4882a593Smuzhiyun 		case NFS4_OPEN_CLAIM_DELEG_CUR_FH:
435*4882a593Smuzhiyun 			status = do_open_fhandle(rqstp, cstate, open);
436*4882a593Smuzhiyun 			if (status)
437*4882a593Smuzhiyun 				goto out;
438*4882a593Smuzhiyun 			resfh = &cstate->current_fh;
439*4882a593Smuzhiyun 			break;
440*4882a593Smuzhiyun 		case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
441*4882a593Smuzhiyun              	case NFS4_OPEN_CLAIM_DELEGATE_PREV:
442*4882a593Smuzhiyun 			dprintk("NFSD: unsupported OPEN claim type %d\n",
443*4882a593Smuzhiyun 				open->op_claim_type);
444*4882a593Smuzhiyun 			status = nfserr_notsupp;
445*4882a593Smuzhiyun 			goto out;
446*4882a593Smuzhiyun 		default:
447*4882a593Smuzhiyun 			dprintk("NFSD: Invalid OPEN claim type %d\n",
448*4882a593Smuzhiyun 				open->op_claim_type);
449*4882a593Smuzhiyun 			status = nfserr_inval;
450*4882a593Smuzhiyun 			goto out;
451*4882a593Smuzhiyun 	}
452*4882a593Smuzhiyun 	/*
453*4882a593Smuzhiyun 	 * nfsd4_process_open2() does the actual opening of the file.  If
454*4882a593Smuzhiyun 	 * successful, it (1) truncates the file if open->op_truncate was
455*4882a593Smuzhiyun 	 * set, (2) sets open->op_stateid, (3) sets open->op_delegation.
456*4882a593Smuzhiyun 	 */
457*4882a593Smuzhiyun 	status = nfsd4_process_open2(rqstp, resfh, open);
458*4882a593Smuzhiyun 	WARN(status && open->op_created,
459*4882a593Smuzhiyun 	     "nfsd4_process_open2 failed to open newly-created file! status=%u\n",
460*4882a593Smuzhiyun 	     be32_to_cpu(status));
461*4882a593Smuzhiyun 	if (reclaim && !status)
462*4882a593Smuzhiyun 		nn->somebody_reclaimed = true;
463*4882a593Smuzhiyun out:
464*4882a593Smuzhiyun 	if (resfh && resfh != &cstate->current_fh) {
465*4882a593Smuzhiyun 		fh_dup2(&cstate->current_fh, resfh);
466*4882a593Smuzhiyun 		fh_put(resfh);
467*4882a593Smuzhiyun 		kfree(resfh);
468*4882a593Smuzhiyun 	}
469*4882a593Smuzhiyun 	nfsd4_cleanup_open_state(cstate, open);
470*4882a593Smuzhiyun 	nfsd4_bump_seqid(cstate, status);
471*4882a593Smuzhiyun 	return status;
472*4882a593Smuzhiyun }
473*4882a593Smuzhiyun 
474*4882a593Smuzhiyun /*
475*4882a593Smuzhiyun  * OPEN is the only seqid-mutating operation whose decoding can fail
476*4882a593Smuzhiyun  * with a seqid-mutating error (specifically, decoding of user names in
477*4882a593Smuzhiyun  * the attributes).  Therefore we have to do some processing to look up
478*4882a593Smuzhiyun  * the stateowner so that we can bump the seqid.
479*4882a593Smuzhiyun  */
nfsd4_open_omfg(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,struct nfsd4_op * op)480*4882a593Smuzhiyun static __be32 nfsd4_open_omfg(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_op *op)
481*4882a593Smuzhiyun {
482*4882a593Smuzhiyun 	struct nfsd4_open *open = &op->u.open;
483*4882a593Smuzhiyun 
484*4882a593Smuzhiyun 	if (!seqid_mutating_err(ntohl(op->status)))
485*4882a593Smuzhiyun 		return op->status;
486*4882a593Smuzhiyun 	if (nfsd4_has_session(cstate))
487*4882a593Smuzhiyun 		return op->status;
488*4882a593Smuzhiyun 	open->op_xdr_error = op->status;
489*4882a593Smuzhiyun 	return nfsd4_open(rqstp, cstate, &op->u);
490*4882a593Smuzhiyun }
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun /*
493*4882a593Smuzhiyun  * filehandle-manipulating ops.
494*4882a593Smuzhiyun  */
495*4882a593Smuzhiyun static __be32
nfsd4_getfh(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)496*4882a593Smuzhiyun nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
497*4882a593Smuzhiyun 	    union nfsd4_op_u *u)
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun 	u->getfh = &cstate->current_fh;
500*4882a593Smuzhiyun 	return nfs_ok;
501*4882a593Smuzhiyun }
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun static __be32
nfsd4_putfh(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)504*4882a593Smuzhiyun nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
505*4882a593Smuzhiyun 	    union nfsd4_op_u *u)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	struct nfsd4_putfh *putfh = &u->putfh;
508*4882a593Smuzhiyun 	__be32 ret;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	fh_put(&cstate->current_fh);
511*4882a593Smuzhiyun 	cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
512*4882a593Smuzhiyun 	memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
513*4882a593Smuzhiyun 	       putfh->pf_fhlen);
514*4882a593Smuzhiyun 	ret = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_BYPASS_GSS);
515*4882a593Smuzhiyun #ifdef CONFIG_NFSD_V4_2_INTER_SSC
516*4882a593Smuzhiyun 	if (ret == nfserr_stale && putfh->no_verify) {
517*4882a593Smuzhiyun 		SET_FH_FLAG(&cstate->current_fh, NFSD4_FH_FOREIGN);
518*4882a593Smuzhiyun 		ret = 0;
519*4882a593Smuzhiyun 	}
520*4882a593Smuzhiyun #endif
521*4882a593Smuzhiyun 	return ret;
522*4882a593Smuzhiyun }
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun static __be32
nfsd4_putrootfh(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)525*4882a593Smuzhiyun nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
526*4882a593Smuzhiyun 		union nfsd4_op_u *u)
527*4882a593Smuzhiyun {
528*4882a593Smuzhiyun 	__be32 status;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	fh_put(&cstate->current_fh);
531*4882a593Smuzhiyun 	status = exp_pseudoroot(rqstp, &cstate->current_fh);
532*4882a593Smuzhiyun 	return status;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun 
535*4882a593Smuzhiyun static __be32
nfsd4_restorefh(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)536*4882a593Smuzhiyun nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
537*4882a593Smuzhiyun 		union nfsd4_op_u *u)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	if (!cstate->save_fh.fh_dentry)
540*4882a593Smuzhiyun 		return nfserr_restorefh;
541*4882a593Smuzhiyun 
542*4882a593Smuzhiyun 	fh_dup2(&cstate->current_fh, &cstate->save_fh);
543*4882a593Smuzhiyun 	if (HAS_CSTATE_FLAG(cstate, SAVED_STATE_ID_FLAG)) {
544*4882a593Smuzhiyun 		memcpy(&cstate->current_stateid, &cstate->save_stateid, sizeof(stateid_t));
545*4882a593Smuzhiyun 		SET_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG);
546*4882a593Smuzhiyun 	}
547*4882a593Smuzhiyun 	return nfs_ok;
548*4882a593Smuzhiyun }
549*4882a593Smuzhiyun 
550*4882a593Smuzhiyun static __be32
nfsd4_savefh(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)551*4882a593Smuzhiyun nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
552*4882a593Smuzhiyun 	     union nfsd4_op_u *u)
553*4882a593Smuzhiyun {
554*4882a593Smuzhiyun 	fh_dup2(&cstate->save_fh, &cstate->current_fh);
555*4882a593Smuzhiyun 	if (HAS_CSTATE_FLAG(cstate, CURRENT_STATE_ID_FLAG)) {
556*4882a593Smuzhiyun 		memcpy(&cstate->save_stateid, &cstate->current_stateid, sizeof(stateid_t));
557*4882a593Smuzhiyun 		SET_CSTATE_FLAG(cstate, SAVED_STATE_ID_FLAG);
558*4882a593Smuzhiyun 	}
559*4882a593Smuzhiyun 	return nfs_ok;
560*4882a593Smuzhiyun }
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun /*
563*4882a593Smuzhiyun  * misc nfsv4 ops
564*4882a593Smuzhiyun  */
565*4882a593Smuzhiyun static __be32
nfsd4_access(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)566*4882a593Smuzhiyun nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
567*4882a593Smuzhiyun 	     union nfsd4_op_u *u)
568*4882a593Smuzhiyun {
569*4882a593Smuzhiyun 	struct nfsd4_access *access = &u->access;
570*4882a593Smuzhiyun 	u32 access_full;
571*4882a593Smuzhiyun 
572*4882a593Smuzhiyun 	access_full = NFS3_ACCESS_FULL;
573*4882a593Smuzhiyun 	if (cstate->minorversion >= 2)
574*4882a593Smuzhiyun 		access_full |= NFS4_ACCESS_XALIST | NFS4_ACCESS_XAREAD |
575*4882a593Smuzhiyun 			       NFS4_ACCESS_XAWRITE;
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	if (access->ac_req_access & ~access_full)
578*4882a593Smuzhiyun 		return nfserr_inval;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	access->ac_resp_access = access->ac_req_access;
581*4882a593Smuzhiyun 	return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access,
582*4882a593Smuzhiyun 			   &access->ac_supported);
583*4882a593Smuzhiyun }
584*4882a593Smuzhiyun 
gen_boot_verifier(nfs4_verifier * verifier,struct net * net)585*4882a593Smuzhiyun static void gen_boot_verifier(nfs4_verifier *verifier, struct net *net)
586*4882a593Smuzhiyun {
587*4882a593Smuzhiyun 	__be32 *verf = (__be32 *)verifier->data;
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun 	BUILD_BUG_ON(2*sizeof(*verf) != sizeof(verifier->data));
590*4882a593Smuzhiyun 
591*4882a593Smuzhiyun 	nfsd_copy_boot_verifier(verf, net_generic(net, nfsd_net_id));
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun static __be32
nfsd4_commit(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)595*4882a593Smuzhiyun nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
596*4882a593Smuzhiyun 	     union nfsd4_op_u *u)
597*4882a593Smuzhiyun {
598*4882a593Smuzhiyun 	struct nfsd4_commit *commit = &u->commit;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	return nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
601*4882a593Smuzhiyun 			     commit->co_count,
602*4882a593Smuzhiyun 			     (__be32 *)commit->co_verf.data);
603*4882a593Smuzhiyun }
604*4882a593Smuzhiyun 
605*4882a593Smuzhiyun static __be32
nfsd4_create(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)606*4882a593Smuzhiyun nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
607*4882a593Smuzhiyun 	     union nfsd4_op_u *u)
608*4882a593Smuzhiyun {
609*4882a593Smuzhiyun 	struct nfsd4_create *create = &u->create;
610*4882a593Smuzhiyun 	struct svc_fh resfh;
611*4882a593Smuzhiyun 	__be32 status;
612*4882a593Smuzhiyun 	dev_t rdev;
613*4882a593Smuzhiyun 
614*4882a593Smuzhiyun 	fh_init(&resfh, NFS4_FHSIZE);
615*4882a593Smuzhiyun 
616*4882a593Smuzhiyun 	status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_NOP);
617*4882a593Smuzhiyun 	if (status)
618*4882a593Smuzhiyun 		return status;
619*4882a593Smuzhiyun 
620*4882a593Smuzhiyun 	status = check_attr_support(rqstp, cstate, create->cr_bmval,
621*4882a593Smuzhiyun 				    nfsd_attrmask);
622*4882a593Smuzhiyun 	if (status)
623*4882a593Smuzhiyun 		return status;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	current->fs->umask = create->cr_umask;
626*4882a593Smuzhiyun 	switch (create->cr_type) {
627*4882a593Smuzhiyun 	case NF4LNK:
628*4882a593Smuzhiyun 		status = nfsd_symlink(rqstp, &cstate->current_fh,
629*4882a593Smuzhiyun 				      create->cr_name, create->cr_namelen,
630*4882a593Smuzhiyun 				      create->cr_data, &resfh);
631*4882a593Smuzhiyun 		break;
632*4882a593Smuzhiyun 
633*4882a593Smuzhiyun 	case NF4BLK:
634*4882a593Smuzhiyun 		status = nfserr_inval;
635*4882a593Smuzhiyun 		rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
636*4882a593Smuzhiyun 		if (MAJOR(rdev) != create->cr_specdata1 ||
637*4882a593Smuzhiyun 		    MINOR(rdev) != create->cr_specdata2)
638*4882a593Smuzhiyun 			goto out_umask;
639*4882a593Smuzhiyun 		status = nfsd_create(rqstp, &cstate->current_fh,
640*4882a593Smuzhiyun 				     create->cr_name, create->cr_namelen,
641*4882a593Smuzhiyun 				     &create->cr_iattr, S_IFBLK, rdev, &resfh);
642*4882a593Smuzhiyun 		break;
643*4882a593Smuzhiyun 
644*4882a593Smuzhiyun 	case NF4CHR:
645*4882a593Smuzhiyun 		status = nfserr_inval;
646*4882a593Smuzhiyun 		rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
647*4882a593Smuzhiyun 		if (MAJOR(rdev) != create->cr_specdata1 ||
648*4882a593Smuzhiyun 		    MINOR(rdev) != create->cr_specdata2)
649*4882a593Smuzhiyun 			goto out_umask;
650*4882a593Smuzhiyun 		status = nfsd_create(rqstp, &cstate->current_fh,
651*4882a593Smuzhiyun 				     create->cr_name, create->cr_namelen,
652*4882a593Smuzhiyun 				     &create->cr_iattr,S_IFCHR, rdev, &resfh);
653*4882a593Smuzhiyun 		break;
654*4882a593Smuzhiyun 
655*4882a593Smuzhiyun 	case NF4SOCK:
656*4882a593Smuzhiyun 		status = nfsd_create(rqstp, &cstate->current_fh,
657*4882a593Smuzhiyun 				     create->cr_name, create->cr_namelen,
658*4882a593Smuzhiyun 				     &create->cr_iattr, S_IFSOCK, 0, &resfh);
659*4882a593Smuzhiyun 		break;
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 	case NF4FIFO:
662*4882a593Smuzhiyun 		status = nfsd_create(rqstp, &cstate->current_fh,
663*4882a593Smuzhiyun 				     create->cr_name, create->cr_namelen,
664*4882a593Smuzhiyun 				     &create->cr_iattr, S_IFIFO, 0, &resfh);
665*4882a593Smuzhiyun 		break;
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 	case NF4DIR:
668*4882a593Smuzhiyun 		create->cr_iattr.ia_valid &= ~ATTR_SIZE;
669*4882a593Smuzhiyun 		status = nfsd_create(rqstp, &cstate->current_fh,
670*4882a593Smuzhiyun 				     create->cr_name, create->cr_namelen,
671*4882a593Smuzhiyun 				     &create->cr_iattr, S_IFDIR, 0, &resfh);
672*4882a593Smuzhiyun 		break;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	default:
675*4882a593Smuzhiyun 		status = nfserr_badtype;
676*4882a593Smuzhiyun 	}
677*4882a593Smuzhiyun 
678*4882a593Smuzhiyun 	if (status)
679*4882a593Smuzhiyun 		goto out;
680*4882a593Smuzhiyun 
681*4882a593Smuzhiyun 	if (create->cr_label.len)
682*4882a593Smuzhiyun 		nfsd4_security_inode_setsecctx(&resfh, &create->cr_label, create->cr_bmval);
683*4882a593Smuzhiyun 
684*4882a593Smuzhiyun 	if (create->cr_acl != NULL)
685*4882a593Smuzhiyun 		do_set_nfs4_acl(rqstp, &resfh, create->cr_acl,
686*4882a593Smuzhiyun 				create->cr_bmval);
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	fh_unlock(&cstate->current_fh);
689*4882a593Smuzhiyun 	set_change_info(&create->cr_cinfo, &cstate->current_fh);
690*4882a593Smuzhiyun 	fh_dup2(&cstate->current_fh, &resfh);
691*4882a593Smuzhiyun out:
692*4882a593Smuzhiyun 	fh_put(&resfh);
693*4882a593Smuzhiyun out_umask:
694*4882a593Smuzhiyun 	current->fs->umask = 0;
695*4882a593Smuzhiyun 	return status;
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun 
698*4882a593Smuzhiyun static __be32
nfsd4_getattr(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)699*4882a593Smuzhiyun nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
700*4882a593Smuzhiyun 	      union nfsd4_op_u *u)
701*4882a593Smuzhiyun {
702*4882a593Smuzhiyun 	struct nfsd4_getattr *getattr = &u->getattr;
703*4882a593Smuzhiyun 	__be32 status;
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 	status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
706*4882a593Smuzhiyun 	if (status)
707*4882a593Smuzhiyun 		return status;
708*4882a593Smuzhiyun 
709*4882a593Smuzhiyun 	if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
710*4882a593Smuzhiyun 		return nfserr_inval;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	getattr->ga_bmval[0] &= nfsd_suppattrs[cstate->minorversion][0];
713*4882a593Smuzhiyun 	getattr->ga_bmval[1] &= nfsd_suppattrs[cstate->minorversion][1];
714*4882a593Smuzhiyun 	getattr->ga_bmval[2] &= nfsd_suppattrs[cstate->minorversion][2];
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	getattr->ga_fhp = &cstate->current_fh;
717*4882a593Smuzhiyun 	return nfs_ok;
718*4882a593Smuzhiyun }
719*4882a593Smuzhiyun 
720*4882a593Smuzhiyun static __be32
nfsd4_link(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)721*4882a593Smuzhiyun nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
722*4882a593Smuzhiyun 	   union nfsd4_op_u *u)
723*4882a593Smuzhiyun {
724*4882a593Smuzhiyun 	struct nfsd4_link *link = &u->link;
725*4882a593Smuzhiyun 	__be32 status;
726*4882a593Smuzhiyun 
727*4882a593Smuzhiyun 	status = nfsd_link(rqstp, &cstate->current_fh,
728*4882a593Smuzhiyun 			   link->li_name, link->li_namelen, &cstate->save_fh);
729*4882a593Smuzhiyun 	if (!status)
730*4882a593Smuzhiyun 		set_change_info(&link->li_cinfo, &cstate->current_fh);
731*4882a593Smuzhiyun 	return status;
732*4882a593Smuzhiyun }
733*4882a593Smuzhiyun 
nfsd4_do_lookupp(struct svc_rqst * rqstp,struct svc_fh * fh)734*4882a593Smuzhiyun static __be32 nfsd4_do_lookupp(struct svc_rqst *rqstp, struct svc_fh *fh)
735*4882a593Smuzhiyun {
736*4882a593Smuzhiyun 	struct svc_fh tmp_fh;
737*4882a593Smuzhiyun 	__be32 ret;
738*4882a593Smuzhiyun 
739*4882a593Smuzhiyun 	fh_init(&tmp_fh, NFS4_FHSIZE);
740*4882a593Smuzhiyun 	ret = exp_pseudoroot(rqstp, &tmp_fh);
741*4882a593Smuzhiyun 	if (ret)
742*4882a593Smuzhiyun 		return ret;
743*4882a593Smuzhiyun 	if (tmp_fh.fh_dentry == fh->fh_dentry) {
744*4882a593Smuzhiyun 		fh_put(&tmp_fh);
745*4882a593Smuzhiyun 		return nfserr_noent;
746*4882a593Smuzhiyun 	}
747*4882a593Smuzhiyun 	fh_put(&tmp_fh);
748*4882a593Smuzhiyun 	return nfsd_lookup(rqstp, fh, "..", 2, fh);
749*4882a593Smuzhiyun }
750*4882a593Smuzhiyun 
751*4882a593Smuzhiyun static __be32
nfsd4_lookupp(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)752*4882a593Smuzhiyun nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
753*4882a593Smuzhiyun 	      union nfsd4_op_u *u)
754*4882a593Smuzhiyun {
755*4882a593Smuzhiyun 	return nfsd4_do_lookupp(rqstp, &cstate->current_fh);
756*4882a593Smuzhiyun }
757*4882a593Smuzhiyun 
758*4882a593Smuzhiyun static __be32
nfsd4_lookup(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)759*4882a593Smuzhiyun nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
760*4882a593Smuzhiyun 	     union nfsd4_op_u *u)
761*4882a593Smuzhiyun {
762*4882a593Smuzhiyun 	return nfsd_lookup(rqstp, &cstate->current_fh,
763*4882a593Smuzhiyun 			   u->lookup.lo_name, u->lookup.lo_len,
764*4882a593Smuzhiyun 			   &cstate->current_fh);
765*4882a593Smuzhiyun }
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun static __be32
nfsd4_read(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)768*4882a593Smuzhiyun nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
769*4882a593Smuzhiyun 	   union nfsd4_op_u *u)
770*4882a593Smuzhiyun {
771*4882a593Smuzhiyun 	struct nfsd4_read *read = &u->read;
772*4882a593Smuzhiyun 	__be32 status;
773*4882a593Smuzhiyun 
774*4882a593Smuzhiyun 	read->rd_nf = NULL;
775*4882a593Smuzhiyun 	if (read->rd_offset >= OFFSET_MAX)
776*4882a593Smuzhiyun 		return nfserr_inval;
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 	trace_nfsd_read_start(rqstp, &cstate->current_fh,
779*4882a593Smuzhiyun 			      read->rd_offset, read->rd_length);
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 	/*
782*4882a593Smuzhiyun 	 * If we do a zero copy read, then a client will see read data
783*4882a593Smuzhiyun 	 * that reflects the state of the file *after* performing the
784*4882a593Smuzhiyun 	 * following compound.
785*4882a593Smuzhiyun 	 *
786*4882a593Smuzhiyun 	 * To ensure proper ordering, we therefore turn off zero copy if
787*4882a593Smuzhiyun 	 * the client wants us to do more in this compound:
788*4882a593Smuzhiyun 	 */
789*4882a593Smuzhiyun 	if (!nfsd4_last_compound_op(rqstp))
790*4882a593Smuzhiyun 		clear_bit(RQ_SPLICE_OK, &rqstp->rq_flags);
791*4882a593Smuzhiyun 
792*4882a593Smuzhiyun 	/* check stateid */
793*4882a593Smuzhiyun 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
794*4882a593Smuzhiyun 					&read->rd_stateid, RD_STATE,
795*4882a593Smuzhiyun 					&read->rd_nf, NULL);
796*4882a593Smuzhiyun 	if (status) {
797*4882a593Smuzhiyun 		dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
798*4882a593Smuzhiyun 		goto out;
799*4882a593Smuzhiyun 	}
800*4882a593Smuzhiyun 	status = nfs_ok;
801*4882a593Smuzhiyun out:
802*4882a593Smuzhiyun 	read->rd_rqstp = rqstp;
803*4882a593Smuzhiyun 	read->rd_fhp = &cstate->current_fh;
804*4882a593Smuzhiyun 	return status;
805*4882a593Smuzhiyun }
806*4882a593Smuzhiyun 
807*4882a593Smuzhiyun 
808*4882a593Smuzhiyun static void
nfsd4_read_release(union nfsd4_op_u * u)809*4882a593Smuzhiyun nfsd4_read_release(union nfsd4_op_u *u)
810*4882a593Smuzhiyun {
811*4882a593Smuzhiyun 	if (u->read.rd_nf)
812*4882a593Smuzhiyun 		nfsd_file_put(u->read.rd_nf);
813*4882a593Smuzhiyun 	trace_nfsd_read_done(u->read.rd_rqstp, u->read.rd_fhp,
814*4882a593Smuzhiyun 			     u->read.rd_offset, u->read.rd_length);
815*4882a593Smuzhiyun }
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun static __be32
nfsd4_readdir(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)818*4882a593Smuzhiyun nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
819*4882a593Smuzhiyun 	      union nfsd4_op_u *u)
820*4882a593Smuzhiyun {
821*4882a593Smuzhiyun 	struct nfsd4_readdir *readdir = &u->readdir;
822*4882a593Smuzhiyun 	u64 cookie = readdir->rd_cookie;
823*4882a593Smuzhiyun 	static const nfs4_verifier zeroverf;
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 	/* no need to check permission - this will be done in nfsd_readdir() */
826*4882a593Smuzhiyun 
827*4882a593Smuzhiyun 	if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
828*4882a593Smuzhiyun 		return nfserr_inval;
829*4882a593Smuzhiyun 
830*4882a593Smuzhiyun 	readdir->rd_bmval[0] &= nfsd_suppattrs[cstate->minorversion][0];
831*4882a593Smuzhiyun 	readdir->rd_bmval[1] &= nfsd_suppattrs[cstate->minorversion][1];
832*4882a593Smuzhiyun 	readdir->rd_bmval[2] &= nfsd_suppattrs[cstate->minorversion][2];
833*4882a593Smuzhiyun 
834*4882a593Smuzhiyun 	if ((cookie == 1) || (cookie == 2) ||
835*4882a593Smuzhiyun 	    (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
836*4882a593Smuzhiyun 		return nfserr_bad_cookie;
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 	readdir->rd_rqstp = rqstp;
839*4882a593Smuzhiyun 	readdir->rd_fhp = &cstate->current_fh;
840*4882a593Smuzhiyun 	return nfs_ok;
841*4882a593Smuzhiyun }
842*4882a593Smuzhiyun 
843*4882a593Smuzhiyun static __be32
nfsd4_readlink(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)844*4882a593Smuzhiyun nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
845*4882a593Smuzhiyun 	       union nfsd4_op_u *u)
846*4882a593Smuzhiyun {
847*4882a593Smuzhiyun 	u->readlink.rl_rqstp = rqstp;
848*4882a593Smuzhiyun 	u->readlink.rl_fhp = &cstate->current_fh;
849*4882a593Smuzhiyun 	return nfs_ok;
850*4882a593Smuzhiyun }
851*4882a593Smuzhiyun 
852*4882a593Smuzhiyun static __be32
nfsd4_remove(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)853*4882a593Smuzhiyun nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
854*4882a593Smuzhiyun 	     union nfsd4_op_u *u)
855*4882a593Smuzhiyun {
856*4882a593Smuzhiyun 	struct nfsd4_remove *remove = &u->remove;
857*4882a593Smuzhiyun 	__be32 status;
858*4882a593Smuzhiyun 
859*4882a593Smuzhiyun 	if (opens_in_grace(SVC_NET(rqstp)))
860*4882a593Smuzhiyun 		return nfserr_grace;
861*4882a593Smuzhiyun 	status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
862*4882a593Smuzhiyun 			     remove->rm_name, remove->rm_namelen);
863*4882a593Smuzhiyun 	if (!status) {
864*4882a593Smuzhiyun 		fh_unlock(&cstate->current_fh);
865*4882a593Smuzhiyun 		set_change_info(&remove->rm_cinfo, &cstate->current_fh);
866*4882a593Smuzhiyun 	}
867*4882a593Smuzhiyun 	return status;
868*4882a593Smuzhiyun }
869*4882a593Smuzhiyun 
870*4882a593Smuzhiyun static __be32
nfsd4_rename(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)871*4882a593Smuzhiyun nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
872*4882a593Smuzhiyun 	     union nfsd4_op_u *u)
873*4882a593Smuzhiyun {
874*4882a593Smuzhiyun 	struct nfsd4_rename *rename = &u->rename;
875*4882a593Smuzhiyun 	__be32 status;
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun 	if (opens_in_grace(SVC_NET(rqstp)))
878*4882a593Smuzhiyun 		return nfserr_grace;
879*4882a593Smuzhiyun 	status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
880*4882a593Smuzhiyun 			     rename->rn_snamelen, &cstate->current_fh,
881*4882a593Smuzhiyun 			     rename->rn_tname, rename->rn_tnamelen);
882*4882a593Smuzhiyun 	if (status)
883*4882a593Smuzhiyun 		return status;
884*4882a593Smuzhiyun 	set_change_info(&rename->rn_sinfo, &cstate->current_fh);
885*4882a593Smuzhiyun 	set_change_info(&rename->rn_tinfo, &cstate->save_fh);
886*4882a593Smuzhiyun 	return nfs_ok;
887*4882a593Smuzhiyun }
888*4882a593Smuzhiyun 
889*4882a593Smuzhiyun static __be32
nfsd4_secinfo(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)890*4882a593Smuzhiyun nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
891*4882a593Smuzhiyun 	      union nfsd4_op_u *u)
892*4882a593Smuzhiyun {
893*4882a593Smuzhiyun 	struct nfsd4_secinfo *secinfo = &u->secinfo;
894*4882a593Smuzhiyun 	struct svc_export *exp;
895*4882a593Smuzhiyun 	struct dentry *dentry;
896*4882a593Smuzhiyun 	__be32 err;
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun 	err = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, NFSD_MAY_EXEC);
899*4882a593Smuzhiyun 	if (err)
900*4882a593Smuzhiyun 		return err;
901*4882a593Smuzhiyun 	err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
902*4882a593Smuzhiyun 				    secinfo->si_name, secinfo->si_namelen,
903*4882a593Smuzhiyun 				    &exp, &dentry);
904*4882a593Smuzhiyun 	if (err)
905*4882a593Smuzhiyun 		return err;
906*4882a593Smuzhiyun 	fh_unlock(&cstate->current_fh);
907*4882a593Smuzhiyun 	if (d_really_is_negative(dentry)) {
908*4882a593Smuzhiyun 		exp_put(exp);
909*4882a593Smuzhiyun 		err = nfserr_noent;
910*4882a593Smuzhiyun 	} else
911*4882a593Smuzhiyun 		secinfo->si_exp = exp;
912*4882a593Smuzhiyun 	dput(dentry);
913*4882a593Smuzhiyun 	if (cstate->minorversion)
914*4882a593Smuzhiyun 		/* See rfc 5661 section 2.6.3.1.1.8 */
915*4882a593Smuzhiyun 		fh_put(&cstate->current_fh);
916*4882a593Smuzhiyun 	return err;
917*4882a593Smuzhiyun }
918*4882a593Smuzhiyun 
919*4882a593Smuzhiyun static __be32
nfsd4_secinfo_no_name(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)920*4882a593Smuzhiyun nfsd4_secinfo_no_name(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
921*4882a593Smuzhiyun 		union nfsd4_op_u *u)
922*4882a593Smuzhiyun {
923*4882a593Smuzhiyun 	__be32 err;
924*4882a593Smuzhiyun 
925*4882a593Smuzhiyun 	switch (u->secinfo_no_name.sin_style) {
926*4882a593Smuzhiyun 	case NFS4_SECINFO_STYLE4_CURRENT_FH:
927*4882a593Smuzhiyun 		break;
928*4882a593Smuzhiyun 	case NFS4_SECINFO_STYLE4_PARENT:
929*4882a593Smuzhiyun 		err = nfsd4_do_lookupp(rqstp, &cstate->current_fh);
930*4882a593Smuzhiyun 		if (err)
931*4882a593Smuzhiyun 			return err;
932*4882a593Smuzhiyun 		break;
933*4882a593Smuzhiyun 	default:
934*4882a593Smuzhiyun 		return nfserr_inval;
935*4882a593Smuzhiyun 	}
936*4882a593Smuzhiyun 
937*4882a593Smuzhiyun 	u->secinfo_no_name.sin_exp = exp_get(cstate->current_fh.fh_export);
938*4882a593Smuzhiyun 	fh_put(&cstate->current_fh);
939*4882a593Smuzhiyun 	return nfs_ok;
940*4882a593Smuzhiyun }
941*4882a593Smuzhiyun 
942*4882a593Smuzhiyun static void
nfsd4_secinfo_release(union nfsd4_op_u * u)943*4882a593Smuzhiyun nfsd4_secinfo_release(union nfsd4_op_u *u)
944*4882a593Smuzhiyun {
945*4882a593Smuzhiyun 	if (u->secinfo.si_exp)
946*4882a593Smuzhiyun 		exp_put(u->secinfo.si_exp);
947*4882a593Smuzhiyun }
948*4882a593Smuzhiyun 
949*4882a593Smuzhiyun static void
nfsd4_secinfo_no_name_release(union nfsd4_op_u * u)950*4882a593Smuzhiyun nfsd4_secinfo_no_name_release(union nfsd4_op_u *u)
951*4882a593Smuzhiyun {
952*4882a593Smuzhiyun 	if (u->secinfo_no_name.sin_exp)
953*4882a593Smuzhiyun 		exp_put(u->secinfo_no_name.sin_exp);
954*4882a593Smuzhiyun }
955*4882a593Smuzhiyun 
956*4882a593Smuzhiyun static __be32
nfsd4_setattr(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)957*4882a593Smuzhiyun nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
958*4882a593Smuzhiyun 	      union nfsd4_op_u *u)
959*4882a593Smuzhiyun {
960*4882a593Smuzhiyun 	struct nfsd4_setattr *setattr = &u->setattr;
961*4882a593Smuzhiyun 	__be32 status = nfs_ok;
962*4882a593Smuzhiyun 	int err;
963*4882a593Smuzhiyun 
964*4882a593Smuzhiyun 	if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
965*4882a593Smuzhiyun 		status = nfs4_preprocess_stateid_op(rqstp, cstate,
966*4882a593Smuzhiyun 				&cstate->current_fh, &setattr->sa_stateid,
967*4882a593Smuzhiyun 				WR_STATE, NULL, NULL);
968*4882a593Smuzhiyun 		if (status) {
969*4882a593Smuzhiyun 			dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
970*4882a593Smuzhiyun 			return status;
971*4882a593Smuzhiyun 		}
972*4882a593Smuzhiyun 	}
973*4882a593Smuzhiyun 	err = fh_want_write(&cstate->current_fh);
974*4882a593Smuzhiyun 	if (err)
975*4882a593Smuzhiyun 		return nfserrno(err);
976*4882a593Smuzhiyun 	status = nfs_ok;
977*4882a593Smuzhiyun 
978*4882a593Smuzhiyun 	status = check_attr_support(rqstp, cstate, setattr->sa_bmval,
979*4882a593Smuzhiyun 				    nfsd_attrmask);
980*4882a593Smuzhiyun 	if (status)
981*4882a593Smuzhiyun 		goto out;
982*4882a593Smuzhiyun 
983*4882a593Smuzhiyun 	if (setattr->sa_acl != NULL)
984*4882a593Smuzhiyun 		status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
985*4882a593Smuzhiyun 					    setattr->sa_acl);
986*4882a593Smuzhiyun 	if (status)
987*4882a593Smuzhiyun 		goto out;
988*4882a593Smuzhiyun 	if (setattr->sa_label.len)
989*4882a593Smuzhiyun 		status = nfsd4_set_nfs4_label(rqstp, &cstate->current_fh,
990*4882a593Smuzhiyun 				&setattr->sa_label);
991*4882a593Smuzhiyun 	if (status)
992*4882a593Smuzhiyun 		goto out;
993*4882a593Smuzhiyun 	status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
994*4882a593Smuzhiyun 				0, (time64_t)0);
995*4882a593Smuzhiyun out:
996*4882a593Smuzhiyun 	fh_drop_write(&cstate->current_fh);
997*4882a593Smuzhiyun 	return status;
998*4882a593Smuzhiyun }
999*4882a593Smuzhiyun 
1000*4882a593Smuzhiyun static __be32
nfsd4_write(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1001*4882a593Smuzhiyun nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1002*4882a593Smuzhiyun 	    union nfsd4_op_u *u)
1003*4882a593Smuzhiyun {
1004*4882a593Smuzhiyun 	struct nfsd4_write *write = &u->write;
1005*4882a593Smuzhiyun 	stateid_t *stateid = &write->wr_stateid;
1006*4882a593Smuzhiyun 	struct nfsd_file *nf = NULL;
1007*4882a593Smuzhiyun 	__be32 status = nfs_ok;
1008*4882a593Smuzhiyun 	unsigned long cnt;
1009*4882a593Smuzhiyun 	int nvecs;
1010*4882a593Smuzhiyun 
1011*4882a593Smuzhiyun 	if (write->wr_offset > (u64)OFFSET_MAX ||
1012*4882a593Smuzhiyun 	    write->wr_offset + write->wr_buflen > (u64)OFFSET_MAX)
1013*4882a593Smuzhiyun 		return nfserr_fbig;
1014*4882a593Smuzhiyun 
1015*4882a593Smuzhiyun 	cnt = write->wr_buflen;
1016*4882a593Smuzhiyun 	trace_nfsd_write_start(rqstp, &cstate->current_fh,
1017*4882a593Smuzhiyun 			       write->wr_offset, cnt);
1018*4882a593Smuzhiyun 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
1019*4882a593Smuzhiyun 						stateid, WR_STATE, &nf, NULL);
1020*4882a593Smuzhiyun 	if (status) {
1021*4882a593Smuzhiyun 		dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
1022*4882a593Smuzhiyun 		return status;
1023*4882a593Smuzhiyun 	}
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun 	write->wr_how_written = write->wr_stable_how;
1026*4882a593Smuzhiyun 
1027*4882a593Smuzhiyun 	nvecs = svc_fill_write_vector(rqstp, write->wr_pagelist,
1028*4882a593Smuzhiyun 				      &write->wr_head, write->wr_buflen);
1029*4882a593Smuzhiyun 	WARN_ON_ONCE(nvecs > ARRAY_SIZE(rqstp->rq_vec));
1030*4882a593Smuzhiyun 
1031*4882a593Smuzhiyun 	status = nfsd_vfs_write(rqstp, &cstate->current_fh, nf,
1032*4882a593Smuzhiyun 				write->wr_offset, rqstp->rq_vec, nvecs, &cnt,
1033*4882a593Smuzhiyun 				write->wr_how_written,
1034*4882a593Smuzhiyun 				(__be32 *)write->wr_verifier.data);
1035*4882a593Smuzhiyun 	nfsd_file_put(nf);
1036*4882a593Smuzhiyun 
1037*4882a593Smuzhiyun 	write->wr_bytes_written = cnt;
1038*4882a593Smuzhiyun 	trace_nfsd_write_done(rqstp, &cstate->current_fh,
1039*4882a593Smuzhiyun 			      write->wr_offset, cnt);
1040*4882a593Smuzhiyun 	return status;
1041*4882a593Smuzhiyun }
1042*4882a593Smuzhiyun 
1043*4882a593Smuzhiyun static __be32
nfsd4_verify_copy(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,stateid_t * src_stateid,struct nfsd_file ** src,stateid_t * dst_stateid,struct nfsd_file ** dst)1044*4882a593Smuzhiyun nfsd4_verify_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1045*4882a593Smuzhiyun 		  stateid_t *src_stateid, struct nfsd_file **src,
1046*4882a593Smuzhiyun 		  stateid_t *dst_stateid, struct nfsd_file **dst)
1047*4882a593Smuzhiyun {
1048*4882a593Smuzhiyun 	__be32 status;
1049*4882a593Smuzhiyun 
1050*4882a593Smuzhiyun 	if (!cstate->save_fh.fh_dentry)
1051*4882a593Smuzhiyun 		return nfserr_nofilehandle;
1052*4882a593Smuzhiyun 
1053*4882a593Smuzhiyun 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->save_fh,
1054*4882a593Smuzhiyun 					    src_stateid, RD_STATE, src, NULL);
1055*4882a593Smuzhiyun 	if (status) {
1056*4882a593Smuzhiyun 		dprintk("NFSD: %s: couldn't process src stateid!\n", __func__);
1057*4882a593Smuzhiyun 		goto out;
1058*4882a593Smuzhiyun 	}
1059*4882a593Smuzhiyun 
1060*4882a593Smuzhiyun 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
1061*4882a593Smuzhiyun 					    dst_stateid, WR_STATE, dst, NULL);
1062*4882a593Smuzhiyun 	if (status) {
1063*4882a593Smuzhiyun 		dprintk("NFSD: %s: couldn't process dst stateid!\n", __func__);
1064*4882a593Smuzhiyun 		goto out_put_src;
1065*4882a593Smuzhiyun 	}
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun 	/* fix up for NFS-specific error code */
1068*4882a593Smuzhiyun 	if (!S_ISREG(file_inode((*src)->nf_file)->i_mode) ||
1069*4882a593Smuzhiyun 	    !S_ISREG(file_inode((*dst)->nf_file)->i_mode)) {
1070*4882a593Smuzhiyun 		status = nfserr_wrong_type;
1071*4882a593Smuzhiyun 		goto out_put_dst;
1072*4882a593Smuzhiyun 	}
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun out:
1075*4882a593Smuzhiyun 	return status;
1076*4882a593Smuzhiyun out_put_dst:
1077*4882a593Smuzhiyun 	nfsd_file_put(*dst);
1078*4882a593Smuzhiyun out_put_src:
1079*4882a593Smuzhiyun 	nfsd_file_put(*src);
1080*4882a593Smuzhiyun 	goto out;
1081*4882a593Smuzhiyun }
1082*4882a593Smuzhiyun 
1083*4882a593Smuzhiyun static __be32
nfsd4_clone(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1084*4882a593Smuzhiyun nfsd4_clone(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1085*4882a593Smuzhiyun 		union nfsd4_op_u *u)
1086*4882a593Smuzhiyun {
1087*4882a593Smuzhiyun 	struct nfsd4_clone *clone = &u->clone;
1088*4882a593Smuzhiyun 	struct nfsd_file *src, *dst;
1089*4882a593Smuzhiyun 	__be32 status;
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun 	status = nfsd4_verify_copy(rqstp, cstate, &clone->cl_src_stateid, &src,
1092*4882a593Smuzhiyun 				   &clone->cl_dst_stateid, &dst);
1093*4882a593Smuzhiyun 	if (status)
1094*4882a593Smuzhiyun 		goto out;
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 	status = nfsd4_clone_file_range(src, clone->cl_src_pos,
1097*4882a593Smuzhiyun 			dst, clone->cl_dst_pos, clone->cl_count,
1098*4882a593Smuzhiyun 			EX_ISSYNC(cstate->current_fh.fh_export));
1099*4882a593Smuzhiyun 
1100*4882a593Smuzhiyun 	nfsd_file_put(dst);
1101*4882a593Smuzhiyun 	nfsd_file_put(src);
1102*4882a593Smuzhiyun out:
1103*4882a593Smuzhiyun 	return status;
1104*4882a593Smuzhiyun }
1105*4882a593Smuzhiyun 
nfs4_put_copy(struct nfsd4_copy * copy)1106*4882a593Smuzhiyun void nfs4_put_copy(struct nfsd4_copy *copy)
1107*4882a593Smuzhiyun {
1108*4882a593Smuzhiyun 	if (!refcount_dec_and_test(&copy->refcount))
1109*4882a593Smuzhiyun 		return;
1110*4882a593Smuzhiyun 	kfree(copy);
1111*4882a593Smuzhiyun }
1112*4882a593Smuzhiyun 
1113*4882a593Smuzhiyun static bool
check_and_set_stop_copy(struct nfsd4_copy * copy)1114*4882a593Smuzhiyun check_and_set_stop_copy(struct nfsd4_copy *copy)
1115*4882a593Smuzhiyun {
1116*4882a593Smuzhiyun 	bool value;
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	spin_lock(&copy->cp_clp->async_lock);
1119*4882a593Smuzhiyun 	value = copy->stopped;
1120*4882a593Smuzhiyun 	if (!copy->stopped)
1121*4882a593Smuzhiyun 		copy->stopped = true;
1122*4882a593Smuzhiyun 	spin_unlock(&copy->cp_clp->async_lock);
1123*4882a593Smuzhiyun 	return value;
1124*4882a593Smuzhiyun }
1125*4882a593Smuzhiyun 
nfsd4_stop_copy(struct nfsd4_copy * copy)1126*4882a593Smuzhiyun static void nfsd4_stop_copy(struct nfsd4_copy *copy)
1127*4882a593Smuzhiyun {
1128*4882a593Smuzhiyun 	/* only 1 thread should stop the copy */
1129*4882a593Smuzhiyun 	if (!check_and_set_stop_copy(copy))
1130*4882a593Smuzhiyun 		kthread_stop(copy->copy_task);
1131*4882a593Smuzhiyun 	nfs4_put_copy(copy);
1132*4882a593Smuzhiyun }
1133*4882a593Smuzhiyun 
nfsd4_get_copy(struct nfs4_client * clp)1134*4882a593Smuzhiyun static struct nfsd4_copy *nfsd4_get_copy(struct nfs4_client *clp)
1135*4882a593Smuzhiyun {
1136*4882a593Smuzhiyun 	struct nfsd4_copy *copy = NULL;
1137*4882a593Smuzhiyun 
1138*4882a593Smuzhiyun 	spin_lock(&clp->async_lock);
1139*4882a593Smuzhiyun 	if (!list_empty(&clp->async_copies)) {
1140*4882a593Smuzhiyun 		copy = list_first_entry(&clp->async_copies, struct nfsd4_copy,
1141*4882a593Smuzhiyun 					copies);
1142*4882a593Smuzhiyun 		refcount_inc(&copy->refcount);
1143*4882a593Smuzhiyun 	}
1144*4882a593Smuzhiyun 	spin_unlock(&clp->async_lock);
1145*4882a593Smuzhiyun 	return copy;
1146*4882a593Smuzhiyun }
1147*4882a593Smuzhiyun 
nfsd4_shutdown_copy(struct nfs4_client * clp)1148*4882a593Smuzhiyun void nfsd4_shutdown_copy(struct nfs4_client *clp)
1149*4882a593Smuzhiyun {
1150*4882a593Smuzhiyun 	struct nfsd4_copy *copy;
1151*4882a593Smuzhiyun 
1152*4882a593Smuzhiyun 	while ((copy = nfsd4_get_copy(clp)) != NULL)
1153*4882a593Smuzhiyun 		nfsd4_stop_copy(copy);
1154*4882a593Smuzhiyun }
1155*4882a593Smuzhiyun #ifdef CONFIG_NFSD_V4_2_INTER_SSC
1156*4882a593Smuzhiyun 
1157*4882a593Smuzhiyun extern struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
1158*4882a593Smuzhiyun 				   struct nfs_fh *src_fh,
1159*4882a593Smuzhiyun 				   nfs4_stateid *stateid);
1160*4882a593Smuzhiyun extern void nfs42_ssc_close(struct file *filep);
1161*4882a593Smuzhiyun 
1162*4882a593Smuzhiyun extern void nfs_sb_deactive(struct super_block *sb);
1163*4882a593Smuzhiyun 
1164*4882a593Smuzhiyun #define NFSD42_INTERSSC_MOUNTOPS "vers=4.2,addr=%s,sec=sys"
1165*4882a593Smuzhiyun 
1166*4882a593Smuzhiyun /*
1167*4882a593Smuzhiyun  * Support one copy source server for now.
1168*4882a593Smuzhiyun  */
1169*4882a593Smuzhiyun static __be32
nfsd4_interssc_connect(struct nl4_server * nss,struct svc_rqst * rqstp,struct vfsmount ** mount)1170*4882a593Smuzhiyun nfsd4_interssc_connect(struct nl4_server *nss, struct svc_rqst *rqstp,
1171*4882a593Smuzhiyun 		       struct vfsmount **mount)
1172*4882a593Smuzhiyun {
1173*4882a593Smuzhiyun 	struct file_system_type *type;
1174*4882a593Smuzhiyun 	struct vfsmount *ss_mnt;
1175*4882a593Smuzhiyun 	struct nfs42_netaddr *naddr;
1176*4882a593Smuzhiyun 	struct sockaddr_storage tmp_addr;
1177*4882a593Smuzhiyun 	size_t tmp_addrlen, match_netid_len = 3;
1178*4882a593Smuzhiyun 	char *startsep = "", *endsep = "", *match_netid = "tcp";
1179*4882a593Smuzhiyun 	char *ipaddr, *dev_name, *raw_data;
1180*4882a593Smuzhiyun 	int len, raw_len;
1181*4882a593Smuzhiyun 	__be32 status = nfserr_inval;
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun 	naddr = &nss->u.nl4_addr;
1184*4882a593Smuzhiyun 	tmp_addrlen = rpc_uaddr2sockaddr(SVC_NET(rqstp), naddr->addr,
1185*4882a593Smuzhiyun 					 naddr->addr_len,
1186*4882a593Smuzhiyun 					 (struct sockaddr *)&tmp_addr,
1187*4882a593Smuzhiyun 					 sizeof(tmp_addr));
1188*4882a593Smuzhiyun 	if (tmp_addrlen == 0)
1189*4882a593Smuzhiyun 		goto out_err;
1190*4882a593Smuzhiyun 
1191*4882a593Smuzhiyun 	if (tmp_addr.ss_family == AF_INET6) {
1192*4882a593Smuzhiyun 		startsep = "[";
1193*4882a593Smuzhiyun 		endsep = "]";
1194*4882a593Smuzhiyun 		match_netid = "tcp6";
1195*4882a593Smuzhiyun 		match_netid_len = 4;
1196*4882a593Smuzhiyun 	}
1197*4882a593Smuzhiyun 
1198*4882a593Smuzhiyun 	if (naddr->netid_len != match_netid_len ||
1199*4882a593Smuzhiyun 		strncmp(naddr->netid, match_netid, naddr->netid_len))
1200*4882a593Smuzhiyun 		goto out_err;
1201*4882a593Smuzhiyun 
1202*4882a593Smuzhiyun 	/* Construct the raw data for the vfs_kern_mount call */
1203*4882a593Smuzhiyun 	len = RPC_MAX_ADDRBUFLEN + 1;
1204*4882a593Smuzhiyun 	ipaddr = kzalloc(len, GFP_KERNEL);
1205*4882a593Smuzhiyun 	if (!ipaddr)
1206*4882a593Smuzhiyun 		goto out_err;
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	rpc_ntop((struct sockaddr *)&tmp_addr, ipaddr, len);
1209*4882a593Smuzhiyun 
1210*4882a593Smuzhiyun 	/* 2 for ipv6 endsep and startsep. 3 for ":/" and trailing '/0'*/
1211*4882a593Smuzhiyun 
1212*4882a593Smuzhiyun 	raw_len = strlen(NFSD42_INTERSSC_MOUNTOPS) + strlen(ipaddr);
1213*4882a593Smuzhiyun 	raw_data = kzalloc(raw_len, GFP_KERNEL);
1214*4882a593Smuzhiyun 	if (!raw_data)
1215*4882a593Smuzhiyun 		goto out_free_ipaddr;
1216*4882a593Smuzhiyun 
1217*4882a593Smuzhiyun 	snprintf(raw_data, raw_len, NFSD42_INTERSSC_MOUNTOPS, ipaddr);
1218*4882a593Smuzhiyun 
1219*4882a593Smuzhiyun 	status = nfserr_nodev;
1220*4882a593Smuzhiyun 	type = get_fs_type("nfs");
1221*4882a593Smuzhiyun 	if (!type)
1222*4882a593Smuzhiyun 		goto out_free_rawdata;
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	/* Set the server:<export> for the vfs_kern_mount call */
1225*4882a593Smuzhiyun 	dev_name = kzalloc(len + 5, GFP_KERNEL);
1226*4882a593Smuzhiyun 	if (!dev_name)
1227*4882a593Smuzhiyun 		goto out_free_rawdata;
1228*4882a593Smuzhiyun 	snprintf(dev_name, len + 5, "%s%s%s:/", startsep, ipaddr, endsep);
1229*4882a593Smuzhiyun 
1230*4882a593Smuzhiyun 	/* Use an 'internal' mount: SB_KERNMOUNT -> MNT_INTERNAL */
1231*4882a593Smuzhiyun 	ss_mnt = vfs_kern_mount(type, SB_KERNMOUNT, dev_name, raw_data);
1232*4882a593Smuzhiyun 	module_put(type->owner);
1233*4882a593Smuzhiyun 	if (IS_ERR(ss_mnt))
1234*4882a593Smuzhiyun 		goto out_free_devname;
1235*4882a593Smuzhiyun 
1236*4882a593Smuzhiyun 	status = 0;
1237*4882a593Smuzhiyun 	*mount = ss_mnt;
1238*4882a593Smuzhiyun 
1239*4882a593Smuzhiyun out_free_devname:
1240*4882a593Smuzhiyun 	kfree(dev_name);
1241*4882a593Smuzhiyun out_free_rawdata:
1242*4882a593Smuzhiyun 	kfree(raw_data);
1243*4882a593Smuzhiyun out_free_ipaddr:
1244*4882a593Smuzhiyun 	kfree(ipaddr);
1245*4882a593Smuzhiyun out_err:
1246*4882a593Smuzhiyun 	return status;
1247*4882a593Smuzhiyun }
1248*4882a593Smuzhiyun 
1249*4882a593Smuzhiyun static void
nfsd4_interssc_disconnect(struct vfsmount * ss_mnt)1250*4882a593Smuzhiyun nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
1251*4882a593Smuzhiyun {
1252*4882a593Smuzhiyun 	nfs_do_sb_deactive(ss_mnt->mnt_sb);
1253*4882a593Smuzhiyun 	mntput(ss_mnt);
1254*4882a593Smuzhiyun }
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun /*
1257*4882a593Smuzhiyun  * Verify COPY destination stateid.
1258*4882a593Smuzhiyun  *
1259*4882a593Smuzhiyun  * Connect to the source server with NFSv4.1.
1260*4882a593Smuzhiyun  * Create the source struct file for nfsd_copy_range.
1261*4882a593Smuzhiyun  * Called with COPY cstate:
1262*4882a593Smuzhiyun  *    SAVED_FH: source filehandle
1263*4882a593Smuzhiyun  *    CURRENT_FH: destination filehandle
1264*4882a593Smuzhiyun  */
1265*4882a593Smuzhiyun static __be32
nfsd4_setup_inter_ssc(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,struct nfsd4_copy * copy,struct vfsmount ** mount)1266*4882a593Smuzhiyun nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
1267*4882a593Smuzhiyun 		      struct nfsd4_compound_state *cstate,
1268*4882a593Smuzhiyun 		      struct nfsd4_copy *copy, struct vfsmount **mount)
1269*4882a593Smuzhiyun {
1270*4882a593Smuzhiyun 	struct svc_fh *s_fh = NULL;
1271*4882a593Smuzhiyun 	stateid_t *s_stid = &copy->cp_src_stateid;
1272*4882a593Smuzhiyun 	__be32 status = nfserr_inval;
1273*4882a593Smuzhiyun 
1274*4882a593Smuzhiyun 	/* Verify the destination stateid and set dst struct file*/
1275*4882a593Smuzhiyun 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
1276*4882a593Smuzhiyun 					    &copy->cp_dst_stateid,
1277*4882a593Smuzhiyun 					    WR_STATE, &copy->nf_dst, NULL);
1278*4882a593Smuzhiyun 	if (status)
1279*4882a593Smuzhiyun 		goto out;
1280*4882a593Smuzhiyun 
1281*4882a593Smuzhiyun 	status = nfsd4_interssc_connect(&copy->cp_src, rqstp, mount);
1282*4882a593Smuzhiyun 	if (status)
1283*4882a593Smuzhiyun 		goto out;
1284*4882a593Smuzhiyun 
1285*4882a593Smuzhiyun 	s_fh = &cstate->save_fh;
1286*4882a593Smuzhiyun 
1287*4882a593Smuzhiyun 	copy->c_fh.size = s_fh->fh_handle.fh_size;
1288*4882a593Smuzhiyun 	memcpy(copy->c_fh.data, &s_fh->fh_handle.fh_base, copy->c_fh.size);
1289*4882a593Smuzhiyun 	copy->stateid.seqid = cpu_to_be32(s_stid->si_generation);
1290*4882a593Smuzhiyun 	memcpy(copy->stateid.other, (void *)&s_stid->si_opaque,
1291*4882a593Smuzhiyun 	       sizeof(stateid_opaque_t));
1292*4882a593Smuzhiyun 
1293*4882a593Smuzhiyun 	status = 0;
1294*4882a593Smuzhiyun out:
1295*4882a593Smuzhiyun 	return status;
1296*4882a593Smuzhiyun }
1297*4882a593Smuzhiyun 
1298*4882a593Smuzhiyun static void
nfsd4_cleanup_inter_ssc(struct vfsmount * ss_mnt,struct nfsd_file * src,struct nfsd_file * dst)1299*4882a593Smuzhiyun nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
1300*4882a593Smuzhiyun 			struct nfsd_file *dst)
1301*4882a593Smuzhiyun {
1302*4882a593Smuzhiyun 	nfs42_ssc_close(src->nf_file);
1303*4882a593Smuzhiyun 	fput(src->nf_file);
1304*4882a593Smuzhiyun 	nfsd_file_put(dst);
1305*4882a593Smuzhiyun 	mntput(ss_mnt);
1306*4882a593Smuzhiyun }
1307*4882a593Smuzhiyun 
1308*4882a593Smuzhiyun #else /* CONFIG_NFSD_V4_2_INTER_SSC */
1309*4882a593Smuzhiyun 
1310*4882a593Smuzhiyun static __be32
nfsd4_setup_inter_ssc(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,struct nfsd4_copy * copy,struct vfsmount ** mount)1311*4882a593Smuzhiyun nfsd4_setup_inter_ssc(struct svc_rqst *rqstp,
1312*4882a593Smuzhiyun 		      struct nfsd4_compound_state *cstate,
1313*4882a593Smuzhiyun 		      struct nfsd4_copy *copy,
1314*4882a593Smuzhiyun 		      struct vfsmount **mount)
1315*4882a593Smuzhiyun {
1316*4882a593Smuzhiyun 	*mount = NULL;
1317*4882a593Smuzhiyun 	return nfserr_inval;
1318*4882a593Smuzhiyun }
1319*4882a593Smuzhiyun 
1320*4882a593Smuzhiyun static void
nfsd4_cleanup_inter_ssc(struct vfsmount * ss_mnt,struct nfsd_file * src,struct nfsd_file * dst)1321*4882a593Smuzhiyun nfsd4_cleanup_inter_ssc(struct vfsmount *ss_mnt, struct nfsd_file *src,
1322*4882a593Smuzhiyun 			struct nfsd_file *dst)
1323*4882a593Smuzhiyun {
1324*4882a593Smuzhiyun }
1325*4882a593Smuzhiyun 
1326*4882a593Smuzhiyun static void
nfsd4_interssc_disconnect(struct vfsmount * ss_mnt)1327*4882a593Smuzhiyun nfsd4_interssc_disconnect(struct vfsmount *ss_mnt)
1328*4882a593Smuzhiyun {
1329*4882a593Smuzhiyun }
1330*4882a593Smuzhiyun 
nfs42_ssc_open(struct vfsmount * ss_mnt,struct nfs_fh * src_fh,nfs4_stateid * stateid)1331*4882a593Smuzhiyun static struct file *nfs42_ssc_open(struct vfsmount *ss_mnt,
1332*4882a593Smuzhiyun 				   struct nfs_fh *src_fh,
1333*4882a593Smuzhiyun 				   nfs4_stateid *stateid)
1334*4882a593Smuzhiyun {
1335*4882a593Smuzhiyun 	return NULL;
1336*4882a593Smuzhiyun }
1337*4882a593Smuzhiyun #endif /* CONFIG_NFSD_V4_2_INTER_SSC */
1338*4882a593Smuzhiyun 
1339*4882a593Smuzhiyun static __be32
nfsd4_setup_intra_ssc(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,struct nfsd4_copy * copy)1340*4882a593Smuzhiyun nfsd4_setup_intra_ssc(struct svc_rqst *rqstp,
1341*4882a593Smuzhiyun 		      struct nfsd4_compound_state *cstate,
1342*4882a593Smuzhiyun 		      struct nfsd4_copy *copy)
1343*4882a593Smuzhiyun {
1344*4882a593Smuzhiyun 	return nfsd4_verify_copy(rqstp, cstate, &copy->cp_src_stateid,
1345*4882a593Smuzhiyun 				 &copy->nf_src, &copy->cp_dst_stateid,
1346*4882a593Smuzhiyun 				 &copy->nf_dst);
1347*4882a593Smuzhiyun }
1348*4882a593Smuzhiyun 
1349*4882a593Smuzhiyun static void
nfsd4_cleanup_intra_ssc(struct nfsd_file * src,struct nfsd_file * dst)1350*4882a593Smuzhiyun nfsd4_cleanup_intra_ssc(struct nfsd_file *src, struct nfsd_file *dst)
1351*4882a593Smuzhiyun {
1352*4882a593Smuzhiyun 	nfsd_file_put(src);
1353*4882a593Smuzhiyun 	nfsd_file_put(dst);
1354*4882a593Smuzhiyun }
1355*4882a593Smuzhiyun 
nfsd4_cb_offload_release(struct nfsd4_callback * cb)1356*4882a593Smuzhiyun static void nfsd4_cb_offload_release(struct nfsd4_callback *cb)
1357*4882a593Smuzhiyun {
1358*4882a593Smuzhiyun 	struct nfsd4_copy *copy = container_of(cb, struct nfsd4_copy, cp_cb);
1359*4882a593Smuzhiyun 
1360*4882a593Smuzhiyun 	nfs4_put_copy(copy);
1361*4882a593Smuzhiyun }
1362*4882a593Smuzhiyun 
nfsd4_cb_offload_done(struct nfsd4_callback * cb,struct rpc_task * task)1363*4882a593Smuzhiyun static int nfsd4_cb_offload_done(struct nfsd4_callback *cb,
1364*4882a593Smuzhiyun 				 struct rpc_task *task)
1365*4882a593Smuzhiyun {
1366*4882a593Smuzhiyun 	return 1;
1367*4882a593Smuzhiyun }
1368*4882a593Smuzhiyun 
1369*4882a593Smuzhiyun static const struct nfsd4_callback_ops nfsd4_cb_offload_ops = {
1370*4882a593Smuzhiyun 	.release = nfsd4_cb_offload_release,
1371*4882a593Smuzhiyun 	.done = nfsd4_cb_offload_done
1372*4882a593Smuzhiyun };
1373*4882a593Smuzhiyun 
nfsd4_init_copy_res(struct nfsd4_copy * copy,bool sync)1374*4882a593Smuzhiyun static void nfsd4_init_copy_res(struct nfsd4_copy *copy, bool sync)
1375*4882a593Smuzhiyun {
1376*4882a593Smuzhiyun 	copy->cp_res.wr_stable_how = NFS_UNSTABLE;
1377*4882a593Smuzhiyun 	copy->cp_synchronous = sync;
1378*4882a593Smuzhiyun 	gen_boot_verifier(&copy->cp_res.wr_verifier, copy->cp_clp->net);
1379*4882a593Smuzhiyun }
1380*4882a593Smuzhiyun 
_nfsd_copy_file_range(struct nfsd4_copy * copy)1381*4882a593Smuzhiyun static ssize_t _nfsd_copy_file_range(struct nfsd4_copy *copy)
1382*4882a593Smuzhiyun {
1383*4882a593Smuzhiyun 	struct file *dst = copy->nf_dst->nf_file;
1384*4882a593Smuzhiyun 	struct file *src = copy->nf_src->nf_file;
1385*4882a593Smuzhiyun 	ssize_t bytes_copied = 0;
1386*4882a593Smuzhiyun 	size_t bytes_total = copy->cp_count;
1387*4882a593Smuzhiyun 	u64 src_pos = copy->cp_src_pos;
1388*4882a593Smuzhiyun 	u64 dst_pos = copy->cp_dst_pos;
1389*4882a593Smuzhiyun 
1390*4882a593Smuzhiyun 	do {
1391*4882a593Smuzhiyun 		if (kthread_should_stop())
1392*4882a593Smuzhiyun 			break;
1393*4882a593Smuzhiyun 		bytes_copied = nfsd_copy_file_range(src, src_pos, dst, dst_pos,
1394*4882a593Smuzhiyun 						    bytes_total);
1395*4882a593Smuzhiyun 		if (bytes_copied <= 0)
1396*4882a593Smuzhiyun 			break;
1397*4882a593Smuzhiyun 		bytes_total -= bytes_copied;
1398*4882a593Smuzhiyun 		copy->cp_res.wr_bytes_written += bytes_copied;
1399*4882a593Smuzhiyun 		src_pos += bytes_copied;
1400*4882a593Smuzhiyun 		dst_pos += bytes_copied;
1401*4882a593Smuzhiyun 	} while (bytes_total > 0 && !copy->cp_synchronous);
1402*4882a593Smuzhiyun 	return bytes_copied;
1403*4882a593Smuzhiyun }
1404*4882a593Smuzhiyun 
nfsd4_do_copy(struct nfsd4_copy * copy,bool sync)1405*4882a593Smuzhiyun static __be32 nfsd4_do_copy(struct nfsd4_copy *copy, bool sync)
1406*4882a593Smuzhiyun {
1407*4882a593Smuzhiyun 	__be32 status;
1408*4882a593Smuzhiyun 	ssize_t bytes;
1409*4882a593Smuzhiyun 
1410*4882a593Smuzhiyun 	bytes = _nfsd_copy_file_range(copy);
1411*4882a593Smuzhiyun 	/* for async copy, we ignore the error, client can always retry
1412*4882a593Smuzhiyun 	 * to get the error
1413*4882a593Smuzhiyun 	 */
1414*4882a593Smuzhiyun 	if (bytes < 0 && !copy->cp_res.wr_bytes_written)
1415*4882a593Smuzhiyun 		status = nfserrno(bytes);
1416*4882a593Smuzhiyun 	else {
1417*4882a593Smuzhiyun 		nfsd4_init_copy_res(copy, sync);
1418*4882a593Smuzhiyun 		status = nfs_ok;
1419*4882a593Smuzhiyun 	}
1420*4882a593Smuzhiyun 
1421*4882a593Smuzhiyun 	if (!copy->cp_intra) /* Inter server SSC */
1422*4882a593Smuzhiyun 		nfsd4_cleanup_inter_ssc(copy->ss_mnt, copy->nf_src,
1423*4882a593Smuzhiyun 					copy->nf_dst);
1424*4882a593Smuzhiyun 	else
1425*4882a593Smuzhiyun 		nfsd4_cleanup_intra_ssc(copy->nf_src, copy->nf_dst);
1426*4882a593Smuzhiyun 
1427*4882a593Smuzhiyun 	return status;
1428*4882a593Smuzhiyun }
1429*4882a593Smuzhiyun 
dup_copy_fields(struct nfsd4_copy * src,struct nfsd4_copy * dst)1430*4882a593Smuzhiyun static void dup_copy_fields(struct nfsd4_copy *src, struct nfsd4_copy *dst)
1431*4882a593Smuzhiyun {
1432*4882a593Smuzhiyun 	dst->cp_src_pos = src->cp_src_pos;
1433*4882a593Smuzhiyun 	dst->cp_dst_pos = src->cp_dst_pos;
1434*4882a593Smuzhiyun 	dst->cp_count = src->cp_count;
1435*4882a593Smuzhiyun 	dst->cp_synchronous = src->cp_synchronous;
1436*4882a593Smuzhiyun 	memcpy(&dst->cp_res, &src->cp_res, sizeof(src->cp_res));
1437*4882a593Smuzhiyun 	memcpy(&dst->fh, &src->fh, sizeof(src->fh));
1438*4882a593Smuzhiyun 	dst->cp_clp = src->cp_clp;
1439*4882a593Smuzhiyun 	dst->nf_dst = nfsd_file_get(src->nf_dst);
1440*4882a593Smuzhiyun 	dst->cp_intra = src->cp_intra;
1441*4882a593Smuzhiyun 	if (src->cp_intra) /* for inter, file_src doesn't exist yet */
1442*4882a593Smuzhiyun 		dst->nf_src = nfsd_file_get(src->nf_src);
1443*4882a593Smuzhiyun 
1444*4882a593Smuzhiyun 	memcpy(&dst->cp_stateid, &src->cp_stateid, sizeof(src->cp_stateid));
1445*4882a593Smuzhiyun 	memcpy(&dst->cp_src, &src->cp_src, sizeof(struct nl4_server));
1446*4882a593Smuzhiyun 	memcpy(&dst->stateid, &src->stateid, sizeof(src->stateid));
1447*4882a593Smuzhiyun 	memcpy(&dst->c_fh, &src->c_fh, sizeof(src->c_fh));
1448*4882a593Smuzhiyun 	dst->ss_mnt = src->ss_mnt;
1449*4882a593Smuzhiyun }
1450*4882a593Smuzhiyun 
cleanup_async_copy(struct nfsd4_copy * copy)1451*4882a593Smuzhiyun static void cleanup_async_copy(struct nfsd4_copy *copy)
1452*4882a593Smuzhiyun {
1453*4882a593Smuzhiyun 	nfs4_free_copy_state(copy);
1454*4882a593Smuzhiyun 	nfsd_file_put(copy->nf_dst);
1455*4882a593Smuzhiyun 	if (copy->cp_intra)
1456*4882a593Smuzhiyun 		nfsd_file_put(copy->nf_src);
1457*4882a593Smuzhiyun 	spin_lock(&copy->cp_clp->async_lock);
1458*4882a593Smuzhiyun 	list_del(&copy->copies);
1459*4882a593Smuzhiyun 	spin_unlock(&copy->cp_clp->async_lock);
1460*4882a593Smuzhiyun 	nfs4_put_copy(copy);
1461*4882a593Smuzhiyun }
1462*4882a593Smuzhiyun 
nfsd4_do_async_copy(void * data)1463*4882a593Smuzhiyun static int nfsd4_do_async_copy(void *data)
1464*4882a593Smuzhiyun {
1465*4882a593Smuzhiyun 	struct nfsd4_copy *copy = (struct nfsd4_copy *)data;
1466*4882a593Smuzhiyun 	struct nfsd4_copy *cb_copy;
1467*4882a593Smuzhiyun 
1468*4882a593Smuzhiyun 	if (!copy->cp_intra) { /* Inter server SSC */
1469*4882a593Smuzhiyun 		copy->nf_src = kzalloc(sizeof(struct nfsd_file), GFP_KERNEL);
1470*4882a593Smuzhiyun 		if (!copy->nf_src) {
1471*4882a593Smuzhiyun 			copy->nfserr = nfserr_serverfault;
1472*4882a593Smuzhiyun 			nfsd4_interssc_disconnect(copy->ss_mnt);
1473*4882a593Smuzhiyun 			goto do_callback;
1474*4882a593Smuzhiyun 		}
1475*4882a593Smuzhiyun 		copy->nf_src->nf_file = nfs42_ssc_open(copy->ss_mnt, &copy->c_fh,
1476*4882a593Smuzhiyun 					      &copy->stateid);
1477*4882a593Smuzhiyun 		if (IS_ERR(copy->nf_src->nf_file)) {
1478*4882a593Smuzhiyun 			copy->nfserr = nfserr_offload_denied;
1479*4882a593Smuzhiyun 			nfsd4_interssc_disconnect(copy->ss_mnt);
1480*4882a593Smuzhiyun 			goto do_callback;
1481*4882a593Smuzhiyun 		}
1482*4882a593Smuzhiyun 	}
1483*4882a593Smuzhiyun 
1484*4882a593Smuzhiyun 	copy->nfserr = nfsd4_do_copy(copy, 0);
1485*4882a593Smuzhiyun do_callback:
1486*4882a593Smuzhiyun 	cb_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
1487*4882a593Smuzhiyun 	if (!cb_copy)
1488*4882a593Smuzhiyun 		goto out;
1489*4882a593Smuzhiyun 	refcount_set(&cb_copy->refcount, 1);
1490*4882a593Smuzhiyun 	memcpy(&cb_copy->cp_res, &copy->cp_res, sizeof(copy->cp_res));
1491*4882a593Smuzhiyun 	cb_copy->cp_clp = copy->cp_clp;
1492*4882a593Smuzhiyun 	cb_copy->nfserr = copy->nfserr;
1493*4882a593Smuzhiyun 	memcpy(&cb_copy->fh, &copy->fh, sizeof(copy->fh));
1494*4882a593Smuzhiyun 	nfsd4_init_cb(&cb_copy->cp_cb, cb_copy->cp_clp,
1495*4882a593Smuzhiyun 			&nfsd4_cb_offload_ops, NFSPROC4_CLNT_CB_OFFLOAD);
1496*4882a593Smuzhiyun 	nfsd4_run_cb(&cb_copy->cp_cb);
1497*4882a593Smuzhiyun out:
1498*4882a593Smuzhiyun 	if (!copy->cp_intra)
1499*4882a593Smuzhiyun 		kfree(copy->nf_src);
1500*4882a593Smuzhiyun 	cleanup_async_copy(copy);
1501*4882a593Smuzhiyun 	return 0;
1502*4882a593Smuzhiyun }
1503*4882a593Smuzhiyun 
1504*4882a593Smuzhiyun static __be32
nfsd4_copy(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1505*4882a593Smuzhiyun nfsd4_copy(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1506*4882a593Smuzhiyun 		union nfsd4_op_u *u)
1507*4882a593Smuzhiyun {
1508*4882a593Smuzhiyun 	struct nfsd4_copy *copy = &u->copy;
1509*4882a593Smuzhiyun 	__be32 status;
1510*4882a593Smuzhiyun 	struct nfsd4_copy *async_copy = NULL;
1511*4882a593Smuzhiyun 
1512*4882a593Smuzhiyun 	if (!copy->cp_intra) { /* Inter server SSC */
1513*4882a593Smuzhiyun 		if (!inter_copy_offload_enable || copy->cp_synchronous) {
1514*4882a593Smuzhiyun 			status = nfserr_notsupp;
1515*4882a593Smuzhiyun 			goto out;
1516*4882a593Smuzhiyun 		}
1517*4882a593Smuzhiyun 		status = nfsd4_setup_inter_ssc(rqstp, cstate, copy,
1518*4882a593Smuzhiyun 				&copy->ss_mnt);
1519*4882a593Smuzhiyun 		if (status)
1520*4882a593Smuzhiyun 			return nfserr_offload_denied;
1521*4882a593Smuzhiyun 	} else {
1522*4882a593Smuzhiyun 		status = nfsd4_setup_intra_ssc(rqstp, cstate, copy);
1523*4882a593Smuzhiyun 		if (status)
1524*4882a593Smuzhiyun 			return status;
1525*4882a593Smuzhiyun 	}
1526*4882a593Smuzhiyun 
1527*4882a593Smuzhiyun 	copy->cp_clp = cstate->clp;
1528*4882a593Smuzhiyun 	memcpy(&copy->fh, &cstate->current_fh.fh_handle,
1529*4882a593Smuzhiyun 		sizeof(struct knfsd_fh));
1530*4882a593Smuzhiyun 	if (!copy->cp_synchronous) {
1531*4882a593Smuzhiyun 		struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1532*4882a593Smuzhiyun 
1533*4882a593Smuzhiyun 		status = nfserrno(-ENOMEM);
1534*4882a593Smuzhiyun 		async_copy = kzalloc(sizeof(struct nfsd4_copy), GFP_KERNEL);
1535*4882a593Smuzhiyun 		if (!async_copy)
1536*4882a593Smuzhiyun 			goto out_err;
1537*4882a593Smuzhiyun 		if (!nfs4_init_copy_state(nn, copy))
1538*4882a593Smuzhiyun 			goto out_err;
1539*4882a593Smuzhiyun 		refcount_set(&async_copy->refcount, 1);
1540*4882a593Smuzhiyun 		memcpy(&copy->cp_res.cb_stateid, &copy->cp_stateid.stid,
1541*4882a593Smuzhiyun 			sizeof(copy->cp_res.cb_stateid));
1542*4882a593Smuzhiyun 		dup_copy_fields(copy, async_copy);
1543*4882a593Smuzhiyun 		async_copy->copy_task = kthread_create(nfsd4_do_async_copy,
1544*4882a593Smuzhiyun 				async_copy, "%s", "copy thread");
1545*4882a593Smuzhiyun 		if (IS_ERR(async_copy->copy_task))
1546*4882a593Smuzhiyun 			goto out_err;
1547*4882a593Smuzhiyun 		spin_lock(&async_copy->cp_clp->async_lock);
1548*4882a593Smuzhiyun 		list_add(&async_copy->copies,
1549*4882a593Smuzhiyun 				&async_copy->cp_clp->async_copies);
1550*4882a593Smuzhiyun 		spin_unlock(&async_copy->cp_clp->async_lock);
1551*4882a593Smuzhiyun 		wake_up_process(async_copy->copy_task);
1552*4882a593Smuzhiyun 		status = nfs_ok;
1553*4882a593Smuzhiyun 	} else {
1554*4882a593Smuzhiyun 		status = nfsd4_do_copy(copy, 1);
1555*4882a593Smuzhiyun 	}
1556*4882a593Smuzhiyun out:
1557*4882a593Smuzhiyun 	return status;
1558*4882a593Smuzhiyun out_err:
1559*4882a593Smuzhiyun 	if (async_copy)
1560*4882a593Smuzhiyun 		cleanup_async_copy(async_copy);
1561*4882a593Smuzhiyun 	status = nfserrno(-ENOMEM);
1562*4882a593Smuzhiyun 	if (!copy->cp_intra)
1563*4882a593Smuzhiyun 		nfsd4_interssc_disconnect(copy->ss_mnt);
1564*4882a593Smuzhiyun 	goto out;
1565*4882a593Smuzhiyun }
1566*4882a593Smuzhiyun 
1567*4882a593Smuzhiyun struct nfsd4_copy *
find_async_copy(struct nfs4_client * clp,stateid_t * stateid)1568*4882a593Smuzhiyun find_async_copy(struct nfs4_client *clp, stateid_t *stateid)
1569*4882a593Smuzhiyun {
1570*4882a593Smuzhiyun 	struct nfsd4_copy *copy;
1571*4882a593Smuzhiyun 
1572*4882a593Smuzhiyun 	spin_lock(&clp->async_lock);
1573*4882a593Smuzhiyun 	list_for_each_entry(copy, &clp->async_copies, copies) {
1574*4882a593Smuzhiyun 		if (memcmp(&copy->cp_stateid.stid, stateid, NFS4_STATEID_SIZE))
1575*4882a593Smuzhiyun 			continue;
1576*4882a593Smuzhiyun 		refcount_inc(&copy->refcount);
1577*4882a593Smuzhiyun 		spin_unlock(&clp->async_lock);
1578*4882a593Smuzhiyun 		return copy;
1579*4882a593Smuzhiyun 	}
1580*4882a593Smuzhiyun 	spin_unlock(&clp->async_lock);
1581*4882a593Smuzhiyun 	return NULL;
1582*4882a593Smuzhiyun }
1583*4882a593Smuzhiyun 
1584*4882a593Smuzhiyun static __be32
nfsd4_offload_cancel(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1585*4882a593Smuzhiyun nfsd4_offload_cancel(struct svc_rqst *rqstp,
1586*4882a593Smuzhiyun 		     struct nfsd4_compound_state *cstate,
1587*4882a593Smuzhiyun 		     union nfsd4_op_u *u)
1588*4882a593Smuzhiyun {
1589*4882a593Smuzhiyun 	struct nfsd4_offload_status *os = &u->offload_status;
1590*4882a593Smuzhiyun 	struct nfsd4_copy *copy;
1591*4882a593Smuzhiyun 	struct nfs4_client *clp = cstate->clp;
1592*4882a593Smuzhiyun 
1593*4882a593Smuzhiyun 	copy = find_async_copy(clp, &os->stateid);
1594*4882a593Smuzhiyun 	if (!copy) {
1595*4882a593Smuzhiyun 		struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1596*4882a593Smuzhiyun 
1597*4882a593Smuzhiyun 		return manage_cpntf_state(nn, &os->stateid, clp, NULL);
1598*4882a593Smuzhiyun 	} else
1599*4882a593Smuzhiyun 		nfsd4_stop_copy(copy);
1600*4882a593Smuzhiyun 
1601*4882a593Smuzhiyun 	return nfs_ok;
1602*4882a593Smuzhiyun }
1603*4882a593Smuzhiyun 
1604*4882a593Smuzhiyun static __be32
nfsd4_copy_notify(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1605*4882a593Smuzhiyun nfsd4_copy_notify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1606*4882a593Smuzhiyun 		  union nfsd4_op_u *u)
1607*4882a593Smuzhiyun {
1608*4882a593Smuzhiyun 	struct nfsd4_copy_notify *cn = &u->copy_notify;
1609*4882a593Smuzhiyun 	__be32 status;
1610*4882a593Smuzhiyun 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
1611*4882a593Smuzhiyun 	struct nfs4_stid *stid;
1612*4882a593Smuzhiyun 	struct nfs4_cpntf_state *cps;
1613*4882a593Smuzhiyun 	struct nfs4_client *clp = cstate->clp;
1614*4882a593Smuzhiyun 
1615*4882a593Smuzhiyun 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
1616*4882a593Smuzhiyun 					&cn->cpn_src_stateid, RD_STATE, NULL,
1617*4882a593Smuzhiyun 					&stid);
1618*4882a593Smuzhiyun 	if (status)
1619*4882a593Smuzhiyun 		return status;
1620*4882a593Smuzhiyun 
1621*4882a593Smuzhiyun 	cn->cpn_sec = nn->nfsd4_lease;
1622*4882a593Smuzhiyun 	cn->cpn_nsec = 0;
1623*4882a593Smuzhiyun 
1624*4882a593Smuzhiyun 	status = nfserrno(-ENOMEM);
1625*4882a593Smuzhiyun 	cps = nfs4_alloc_init_cpntf_state(nn, stid);
1626*4882a593Smuzhiyun 	if (!cps)
1627*4882a593Smuzhiyun 		goto out;
1628*4882a593Smuzhiyun 	memcpy(&cn->cpn_cnr_stateid, &cps->cp_stateid.stid, sizeof(stateid_t));
1629*4882a593Smuzhiyun 	memcpy(&cps->cp_p_stateid, &stid->sc_stateid, sizeof(stateid_t));
1630*4882a593Smuzhiyun 	memcpy(&cps->cp_p_clid, &clp->cl_clientid, sizeof(clientid_t));
1631*4882a593Smuzhiyun 
1632*4882a593Smuzhiyun 	/* For now, only return one server address in cpn_src, the
1633*4882a593Smuzhiyun 	 * address used by the client to connect to this server.
1634*4882a593Smuzhiyun 	 */
1635*4882a593Smuzhiyun 	cn->cpn_src.nl4_type = NL4_NETADDR;
1636*4882a593Smuzhiyun 	status = nfsd4_set_netaddr((struct sockaddr *)&rqstp->rq_daddr,
1637*4882a593Smuzhiyun 				 &cn->cpn_src.u.nl4_addr);
1638*4882a593Smuzhiyun 	WARN_ON_ONCE(status);
1639*4882a593Smuzhiyun 	if (status) {
1640*4882a593Smuzhiyun 		nfs4_put_cpntf_state(nn, cps);
1641*4882a593Smuzhiyun 		goto out;
1642*4882a593Smuzhiyun 	}
1643*4882a593Smuzhiyun out:
1644*4882a593Smuzhiyun 	nfs4_put_stid(stid);
1645*4882a593Smuzhiyun 	return status;
1646*4882a593Smuzhiyun }
1647*4882a593Smuzhiyun 
1648*4882a593Smuzhiyun static __be32
nfsd4_fallocate(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,struct nfsd4_fallocate * fallocate,int flags)1649*4882a593Smuzhiyun nfsd4_fallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1650*4882a593Smuzhiyun 		struct nfsd4_fallocate *fallocate, int flags)
1651*4882a593Smuzhiyun {
1652*4882a593Smuzhiyun 	__be32 status;
1653*4882a593Smuzhiyun 	struct nfsd_file *nf;
1654*4882a593Smuzhiyun 
1655*4882a593Smuzhiyun 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
1656*4882a593Smuzhiyun 					    &fallocate->falloc_stateid,
1657*4882a593Smuzhiyun 					    WR_STATE, &nf, NULL);
1658*4882a593Smuzhiyun 	if (status != nfs_ok) {
1659*4882a593Smuzhiyun 		dprintk("NFSD: nfsd4_fallocate: couldn't process stateid!\n");
1660*4882a593Smuzhiyun 		return status;
1661*4882a593Smuzhiyun 	}
1662*4882a593Smuzhiyun 
1663*4882a593Smuzhiyun 	status = nfsd4_vfs_fallocate(rqstp, &cstate->current_fh, nf->nf_file,
1664*4882a593Smuzhiyun 				     fallocate->falloc_offset,
1665*4882a593Smuzhiyun 				     fallocate->falloc_length,
1666*4882a593Smuzhiyun 				     flags);
1667*4882a593Smuzhiyun 	nfsd_file_put(nf);
1668*4882a593Smuzhiyun 	return status;
1669*4882a593Smuzhiyun }
1670*4882a593Smuzhiyun static __be32
nfsd4_offload_status(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1671*4882a593Smuzhiyun nfsd4_offload_status(struct svc_rqst *rqstp,
1672*4882a593Smuzhiyun 		     struct nfsd4_compound_state *cstate,
1673*4882a593Smuzhiyun 		     union nfsd4_op_u *u)
1674*4882a593Smuzhiyun {
1675*4882a593Smuzhiyun 	struct nfsd4_offload_status *os = &u->offload_status;
1676*4882a593Smuzhiyun 	__be32 status = 0;
1677*4882a593Smuzhiyun 	struct nfsd4_copy *copy;
1678*4882a593Smuzhiyun 	struct nfs4_client *clp = cstate->clp;
1679*4882a593Smuzhiyun 
1680*4882a593Smuzhiyun 	copy = find_async_copy(clp, &os->stateid);
1681*4882a593Smuzhiyun 	if (copy) {
1682*4882a593Smuzhiyun 		os->count = copy->cp_res.wr_bytes_written;
1683*4882a593Smuzhiyun 		nfs4_put_copy(copy);
1684*4882a593Smuzhiyun 	} else
1685*4882a593Smuzhiyun 		status = nfserr_bad_stateid;
1686*4882a593Smuzhiyun 
1687*4882a593Smuzhiyun 	return status;
1688*4882a593Smuzhiyun }
1689*4882a593Smuzhiyun 
1690*4882a593Smuzhiyun static __be32
nfsd4_allocate(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1691*4882a593Smuzhiyun nfsd4_allocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1692*4882a593Smuzhiyun 	       union nfsd4_op_u *u)
1693*4882a593Smuzhiyun {
1694*4882a593Smuzhiyun 	return nfsd4_fallocate(rqstp, cstate, &u->allocate, 0);
1695*4882a593Smuzhiyun }
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun static __be32
nfsd4_deallocate(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1698*4882a593Smuzhiyun nfsd4_deallocate(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1699*4882a593Smuzhiyun 		 union nfsd4_op_u *u)
1700*4882a593Smuzhiyun {
1701*4882a593Smuzhiyun 	return nfsd4_fallocate(rqstp, cstate, &u->deallocate,
1702*4882a593Smuzhiyun 			       FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE);
1703*4882a593Smuzhiyun }
1704*4882a593Smuzhiyun 
1705*4882a593Smuzhiyun static __be32
nfsd4_seek(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1706*4882a593Smuzhiyun nfsd4_seek(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1707*4882a593Smuzhiyun 	   union nfsd4_op_u *u)
1708*4882a593Smuzhiyun {
1709*4882a593Smuzhiyun 	struct nfsd4_seek *seek = &u->seek;
1710*4882a593Smuzhiyun 	int whence;
1711*4882a593Smuzhiyun 	__be32 status;
1712*4882a593Smuzhiyun 	struct nfsd_file *nf;
1713*4882a593Smuzhiyun 
1714*4882a593Smuzhiyun 	status = nfs4_preprocess_stateid_op(rqstp, cstate, &cstate->current_fh,
1715*4882a593Smuzhiyun 					    &seek->seek_stateid,
1716*4882a593Smuzhiyun 					    RD_STATE, &nf, NULL);
1717*4882a593Smuzhiyun 	if (status) {
1718*4882a593Smuzhiyun 		dprintk("NFSD: nfsd4_seek: couldn't process stateid!\n");
1719*4882a593Smuzhiyun 		return status;
1720*4882a593Smuzhiyun 	}
1721*4882a593Smuzhiyun 
1722*4882a593Smuzhiyun 	switch (seek->seek_whence) {
1723*4882a593Smuzhiyun 	case NFS4_CONTENT_DATA:
1724*4882a593Smuzhiyun 		whence = SEEK_DATA;
1725*4882a593Smuzhiyun 		break;
1726*4882a593Smuzhiyun 	case NFS4_CONTENT_HOLE:
1727*4882a593Smuzhiyun 		whence = SEEK_HOLE;
1728*4882a593Smuzhiyun 		break;
1729*4882a593Smuzhiyun 	default:
1730*4882a593Smuzhiyun 		status = nfserr_union_notsupp;
1731*4882a593Smuzhiyun 		goto out;
1732*4882a593Smuzhiyun 	}
1733*4882a593Smuzhiyun 
1734*4882a593Smuzhiyun 	/*
1735*4882a593Smuzhiyun 	 * Note:  This call does change file->f_pos, but nothing in NFSD
1736*4882a593Smuzhiyun 	 *        should ever file->f_pos.
1737*4882a593Smuzhiyun 	 */
1738*4882a593Smuzhiyun 	seek->seek_pos = vfs_llseek(nf->nf_file, seek->seek_offset, whence);
1739*4882a593Smuzhiyun 	if (seek->seek_pos < 0)
1740*4882a593Smuzhiyun 		status = nfserrno(seek->seek_pos);
1741*4882a593Smuzhiyun 	else if (seek->seek_pos >= i_size_read(file_inode(nf->nf_file)))
1742*4882a593Smuzhiyun 		seek->seek_eof = true;
1743*4882a593Smuzhiyun 
1744*4882a593Smuzhiyun out:
1745*4882a593Smuzhiyun 	nfsd_file_put(nf);
1746*4882a593Smuzhiyun 	return status;
1747*4882a593Smuzhiyun }
1748*4882a593Smuzhiyun 
1749*4882a593Smuzhiyun /* This routine never returns NFS_OK!  If there are no other errors, it
1750*4882a593Smuzhiyun  * will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the
1751*4882a593Smuzhiyun  * attributes matched.  VERIFY is implemented by mapping NFSERR_SAME
1752*4882a593Smuzhiyun  * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK.
1753*4882a593Smuzhiyun  */
1754*4882a593Smuzhiyun static __be32
_nfsd4_verify(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,struct nfsd4_verify * verify)1755*4882a593Smuzhiyun _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1756*4882a593Smuzhiyun 	     struct nfsd4_verify *verify)
1757*4882a593Smuzhiyun {
1758*4882a593Smuzhiyun 	__be32 *buf, *p;
1759*4882a593Smuzhiyun 	int count;
1760*4882a593Smuzhiyun 	__be32 status;
1761*4882a593Smuzhiyun 
1762*4882a593Smuzhiyun 	status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
1763*4882a593Smuzhiyun 	if (status)
1764*4882a593Smuzhiyun 		return status;
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun 	status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL);
1767*4882a593Smuzhiyun 	if (status)
1768*4882a593Smuzhiyun 		return status;
1769*4882a593Smuzhiyun 
1770*4882a593Smuzhiyun 	if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
1771*4882a593Smuzhiyun 	    || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
1772*4882a593Smuzhiyun 		return nfserr_inval;
1773*4882a593Smuzhiyun 	if (verify->ve_attrlen & 3)
1774*4882a593Smuzhiyun 		return nfserr_inval;
1775*4882a593Smuzhiyun 
1776*4882a593Smuzhiyun 	/* count in words:
1777*4882a593Smuzhiyun 	 *   bitmap_len(1) + bitmap(2) + attr_len(1) = 4
1778*4882a593Smuzhiyun 	 */
1779*4882a593Smuzhiyun 	count = 4 + (verify->ve_attrlen >> 2);
1780*4882a593Smuzhiyun 	buf = kmalloc(count << 2, GFP_KERNEL);
1781*4882a593Smuzhiyun 	if (!buf)
1782*4882a593Smuzhiyun 		return nfserr_jukebox;
1783*4882a593Smuzhiyun 
1784*4882a593Smuzhiyun 	p = buf;
1785*4882a593Smuzhiyun 	status = nfsd4_encode_fattr_to_buf(&p, count, &cstate->current_fh,
1786*4882a593Smuzhiyun 				    cstate->current_fh.fh_export,
1787*4882a593Smuzhiyun 				    cstate->current_fh.fh_dentry,
1788*4882a593Smuzhiyun 				    verify->ve_bmval,
1789*4882a593Smuzhiyun 				    rqstp, 0);
1790*4882a593Smuzhiyun 	/*
1791*4882a593Smuzhiyun 	 * If nfsd4_encode_fattr() ran out of space, assume that's because
1792*4882a593Smuzhiyun 	 * the attributes are longer (hence different) than those given:
1793*4882a593Smuzhiyun 	 */
1794*4882a593Smuzhiyun 	if (status == nfserr_resource)
1795*4882a593Smuzhiyun 		status = nfserr_not_same;
1796*4882a593Smuzhiyun 	if (status)
1797*4882a593Smuzhiyun 		goto out_kfree;
1798*4882a593Smuzhiyun 
1799*4882a593Smuzhiyun 	/* skip bitmap */
1800*4882a593Smuzhiyun 	p = buf + 1 + ntohl(buf[0]);
1801*4882a593Smuzhiyun 	status = nfserr_not_same;
1802*4882a593Smuzhiyun 	if (ntohl(*p++) != verify->ve_attrlen)
1803*4882a593Smuzhiyun 		goto out_kfree;
1804*4882a593Smuzhiyun 	if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen))
1805*4882a593Smuzhiyun 		status = nfserr_same;
1806*4882a593Smuzhiyun 
1807*4882a593Smuzhiyun out_kfree:
1808*4882a593Smuzhiyun 	kfree(buf);
1809*4882a593Smuzhiyun 	return status;
1810*4882a593Smuzhiyun }
1811*4882a593Smuzhiyun 
1812*4882a593Smuzhiyun static __be32
nfsd4_nverify(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1813*4882a593Smuzhiyun nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1814*4882a593Smuzhiyun 	      union nfsd4_op_u *u)
1815*4882a593Smuzhiyun {
1816*4882a593Smuzhiyun 	__be32 status;
1817*4882a593Smuzhiyun 
1818*4882a593Smuzhiyun 	status = _nfsd4_verify(rqstp, cstate, &u->verify);
1819*4882a593Smuzhiyun 	return status == nfserr_not_same ? nfs_ok : status;
1820*4882a593Smuzhiyun }
1821*4882a593Smuzhiyun 
1822*4882a593Smuzhiyun static __be32
nfsd4_verify(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1823*4882a593Smuzhiyun nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
1824*4882a593Smuzhiyun 	     union nfsd4_op_u *u)
1825*4882a593Smuzhiyun {
1826*4882a593Smuzhiyun 	__be32 status;
1827*4882a593Smuzhiyun 
1828*4882a593Smuzhiyun 	status = _nfsd4_verify(rqstp, cstate, &u->nverify);
1829*4882a593Smuzhiyun 	return status == nfserr_same ? nfs_ok : status;
1830*4882a593Smuzhiyun }
1831*4882a593Smuzhiyun 
1832*4882a593Smuzhiyun #ifdef CONFIG_NFSD_PNFS
1833*4882a593Smuzhiyun static const struct nfsd4_layout_ops *
nfsd4_layout_verify(struct svc_export * exp,unsigned int layout_type)1834*4882a593Smuzhiyun nfsd4_layout_verify(struct svc_export *exp, unsigned int layout_type)
1835*4882a593Smuzhiyun {
1836*4882a593Smuzhiyun 	if (!exp->ex_layout_types) {
1837*4882a593Smuzhiyun 		dprintk("%s: export does not support pNFS\n", __func__);
1838*4882a593Smuzhiyun 		return NULL;
1839*4882a593Smuzhiyun 	}
1840*4882a593Smuzhiyun 
1841*4882a593Smuzhiyun 	if (layout_type >= LAYOUT_TYPE_MAX ||
1842*4882a593Smuzhiyun 	    !(exp->ex_layout_types & (1 << layout_type))) {
1843*4882a593Smuzhiyun 		dprintk("%s: layout type %d not supported\n",
1844*4882a593Smuzhiyun 			__func__, layout_type);
1845*4882a593Smuzhiyun 		return NULL;
1846*4882a593Smuzhiyun 	}
1847*4882a593Smuzhiyun 
1848*4882a593Smuzhiyun 	return nfsd4_layout_ops[layout_type];
1849*4882a593Smuzhiyun }
1850*4882a593Smuzhiyun 
1851*4882a593Smuzhiyun static __be32
nfsd4_getdeviceinfo(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1852*4882a593Smuzhiyun nfsd4_getdeviceinfo(struct svc_rqst *rqstp,
1853*4882a593Smuzhiyun 		struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
1854*4882a593Smuzhiyun {
1855*4882a593Smuzhiyun 	struct nfsd4_getdeviceinfo *gdp = &u->getdeviceinfo;
1856*4882a593Smuzhiyun 	const struct nfsd4_layout_ops *ops;
1857*4882a593Smuzhiyun 	struct nfsd4_deviceid_map *map;
1858*4882a593Smuzhiyun 	struct svc_export *exp;
1859*4882a593Smuzhiyun 	__be32 nfserr;
1860*4882a593Smuzhiyun 
1861*4882a593Smuzhiyun 	dprintk("%s: layout_type %u dev_id [0x%llx:0x%x] maxcnt %u\n",
1862*4882a593Smuzhiyun 	       __func__,
1863*4882a593Smuzhiyun 	       gdp->gd_layout_type,
1864*4882a593Smuzhiyun 	       gdp->gd_devid.fsid_idx, gdp->gd_devid.generation,
1865*4882a593Smuzhiyun 	       gdp->gd_maxcount);
1866*4882a593Smuzhiyun 
1867*4882a593Smuzhiyun 	map = nfsd4_find_devid_map(gdp->gd_devid.fsid_idx);
1868*4882a593Smuzhiyun 	if (!map) {
1869*4882a593Smuzhiyun 		dprintk("%s: couldn't find device ID to export mapping!\n",
1870*4882a593Smuzhiyun 			__func__);
1871*4882a593Smuzhiyun 		return nfserr_noent;
1872*4882a593Smuzhiyun 	}
1873*4882a593Smuzhiyun 
1874*4882a593Smuzhiyun 	exp = rqst_exp_find(rqstp, map->fsid_type, map->fsid);
1875*4882a593Smuzhiyun 	if (IS_ERR(exp)) {
1876*4882a593Smuzhiyun 		dprintk("%s: could not find device id\n", __func__);
1877*4882a593Smuzhiyun 		return nfserr_noent;
1878*4882a593Smuzhiyun 	}
1879*4882a593Smuzhiyun 
1880*4882a593Smuzhiyun 	nfserr = nfserr_layoutunavailable;
1881*4882a593Smuzhiyun 	ops = nfsd4_layout_verify(exp, gdp->gd_layout_type);
1882*4882a593Smuzhiyun 	if (!ops)
1883*4882a593Smuzhiyun 		goto out;
1884*4882a593Smuzhiyun 
1885*4882a593Smuzhiyun 	nfserr = nfs_ok;
1886*4882a593Smuzhiyun 	if (gdp->gd_maxcount != 0) {
1887*4882a593Smuzhiyun 		nfserr = ops->proc_getdeviceinfo(exp->ex_path.mnt->mnt_sb,
1888*4882a593Smuzhiyun 				rqstp, cstate->session->se_client, gdp);
1889*4882a593Smuzhiyun 	}
1890*4882a593Smuzhiyun 
1891*4882a593Smuzhiyun 	gdp->gd_notify_types &= ops->notify_types;
1892*4882a593Smuzhiyun out:
1893*4882a593Smuzhiyun 	exp_put(exp);
1894*4882a593Smuzhiyun 	return nfserr;
1895*4882a593Smuzhiyun }
1896*4882a593Smuzhiyun 
1897*4882a593Smuzhiyun static void
nfsd4_getdeviceinfo_release(union nfsd4_op_u * u)1898*4882a593Smuzhiyun nfsd4_getdeviceinfo_release(union nfsd4_op_u *u)
1899*4882a593Smuzhiyun {
1900*4882a593Smuzhiyun 	kfree(u->getdeviceinfo.gd_device);
1901*4882a593Smuzhiyun }
1902*4882a593Smuzhiyun 
1903*4882a593Smuzhiyun static __be32
nfsd4_layoutget(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1904*4882a593Smuzhiyun nfsd4_layoutget(struct svc_rqst *rqstp,
1905*4882a593Smuzhiyun 		struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
1906*4882a593Smuzhiyun {
1907*4882a593Smuzhiyun 	struct nfsd4_layoutget *lgp = &u->layoutget;
1908*4882a593Smuzhiyun 	struct svc_fh *current_fh = &cstate->current_fh;
1909*4882a593Smuzhiyun 	const struct nfsd4_layout_ops *ops;
1910*4882a593Smuzhiyun 	struct nfs4_layout_stateid *ls;
1911*4882a593Smuzhiyun 	__be32 nfserr;
1912*4882a593Smuzhiyun 	int accmode = NFSD_MAY_READ_IF_EXEC;
1913*4882a593Smuzhiyun 
1914*4882a593Smuzhiyun 	switch (lgp->lg_seg.iomode) {
1915*4882a593Smuzhiyun 	case IOMODE_READ:
1916*4882a593Smuzhiyun 		accmode |= NFSD_MAY_READ;
1917*4882a593Smuzhiyun 		break;
1918*4882a593Smuzhiyun 	case IOMODE_RW:
1919*4882a593Smuzhiyun 		accmode |= NFSD_MAY_READ | NFSD_MAY_WRITE;
1920*4882a593Smuzhiyun 		break;
1921*4882a593Smuzhiyun 	default:
1922*4882a593Smuzhiyun 		dprintk("%s: invalid iomode %d\n",
1923*4882a593Smuzhiyun 			__func__, lgp->lg_seg.iomode);
1924*4882a593Smuzhiyun 		nfserr = nfserr_badiomode;
1925*4882a593Smuzhiyun 		goto out;
1926*4882a593Smuzhiyun 	}
1927*4882a593Smuzhiyun 
1928*4882a593Smuzhiyun 	nfserr = fh_verify(rqstp, current_fh, 0, accmode);
1929*4882a593Smuzhiyun 	if (nfserr)
1930*4882a593Smuzhiyun 		goto out;
1931*4882a593Smuzhiyun 
1932*4882a593Smuzhiyun 	nfserr = nfserr_layoutunavailable;
1933*4882a593Smuzhiyun 	ops = nfsd4_layout_verify(current_fh->fh_export, lgp->lg_layout_type);
1934*4882a593Smuzhiyun 	if (!ops)
1935*4882a593Smuzhiyun 		goto out;
1936*4882a593Smuzhiyun 
1937*4882a593Smuzhiyun 	/*
1938*4882a593Smuzhiyun 	 * Verify minlength and range as per RFC5661:
1939*4882a593Smuzhiyun 	 *  o  If loga_length is less than loga_minlength,
1940*4882a593Smuzhiyun 	 *     the metadata server MUST return NFS4ERR_INVAL.
1941*4882a593Smuzhiyun 	 *  o  If the sum of loga_offset and loga_minlength exceeds
1942*4882a593Smuzhiyun 	 *     NFS4_UINT64_MAX, and loga_minlength is not
1943*4882a593Smuzhiyun 	 *     NFS4_UINT64_MAX, the error NFS4ERR_INVAL MUST result.
1944*4882a593Smuzhiyun 	 *  o  If the sum of loga_offset and loga_length exceeds
1945*4882a593Smuzhiyun 	 *     NFS4_UINT64_MAX, and loga_length is not NFS4_UINT64_MAX,
1946*4882a593Smuzhiyun 	 *     the error NFS4ERR_INVAL MUST result.
1947*4882a593Smuzhiyun 	 */
1948*4882a593Smuzhiyun 	nfserr = nfserr_inval;
1949*4882a593Smuzhiyun 	if (lgp->lg_seg.length < lgp->lg_minlength ||
1950*4882a593Smuzhiyun 	    (lgp->lg_minlength != NFS4_MAX_UINT64 &&
1951*4882a593Smuzhiyun 	     lgp->lg_minlength > NFS4_MAX_UINT64 - lgp->lg_seg.offset) ||
1952*4882a593Smuzhiyun 	    (lgp->lg_seg.length != NFS4_MAX_UINT64 &&
1953*4882a593Smuzhiyun 	     lgp->lg_seg.length > NFS4_MAX_UINT64 - lgp->lg_seg.offset))
1954*4882a593Smuzhiyun 		goto out;
1955*4882a593Smuzhiyun 	if (lgp->lg_seg.length == 0)
1956*4882a593Smuzhiyun 		goto out;
1957*4882a593Smuzhiyun 
1958*4882a593Smuzhiyun 	nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lgp->lg_sid,
1959*4882a593Smuzhiyun 						true, lgp->lg_layout_type, &ls);
1960*4882a593Smuzhiyun 	if (nfserr) {
1961*4882a593Smuzhiyun 		trace_nfsd_layout_get_lookup_fail(&lgp->lg_sid);
1962*4882a593Smuzhiyun 		goto out;
1963*4882a593Smuzhiyun 	}
1964*4882a593Smuzhiyun 
1965*4882a593Smuzhiyun 	nfserr = nfserr_recallconflict;
1966*4882a593Smuzhiyun 	if (atomic_read(&ls->ls_stid.sc_file->fi_lo_recalls))
1967*4882a593Smuzhiyun 		goto out_put_stid;
1968*4882a593Smuzhiyun 
1969*4882a593Smuzhiyun 	nfserr = ops->proc_layoutget(d_inode(current_fh->fh_dentry),
1970*4882a593Smuzhiyun 				     current_fh, lgp);
1971*4882a593Smuzhiyun 	if (nfserr)
1972*4882a593Smuzhiyun 		goto out_put_stid;
1973*4882a593Smuzhiyun 
1974*4882a593Smuzhiyun 	nfserr = nfsd4_insert_layout(lgp, ls);
1975*4882a593Smuzhiyun 
1976*4882a593Smuzhiyun out_put_stid:
1977*4882a593Smuzhiyun 	mutex_unlock(&ls->ls_mutex);
1978*4882a593Smuzhiyun 	nfs4_put_stid(&ls->ls_stid);
1979*4882a593Smuzhiyun out:
1980*4882a593Smuzhiyun 	return nfserr;
1981*4882a593Smuzhiyun }
1982*4882a593Smuzhiyun 
1983*4882a593Smuzhiyun static void
nfsd4_layoutget_release(union nfsd4_op_u * u)1984*4882a593Smuzhiyun nfsd4_layoutget_release(union nfsd4_op_u *u)
1985*4882a593Smuzhiyun {
1986*4882a593Smuzhiyun 	kfree(u->layoutget.lg_content);
1987*4882a593Smuzhiyun }
1988*4882a593Smuzhiyun 
1989*4882a593Smuzhiyun static __be32
nfsd4_layoutcommit(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)1990*4882a593Smuzhiyun nfsd4_layoutcommit(struct svc_rqst *rqstp,
1991*4882a593Smuzhiyun 		struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
1992*4882a593Smuzhiyun {
1993*4882a593Smuzhiyun 	struct nfsd4_layoutcommit *lcp = &u->layoutcommit;
1994*4882a593Smuzhiyun 	const struct nfsd4_layout_seg *seg = &lcp->lc_seg;
1995*4882a593Smuzhiyun 	struct svc_fh *current_fh = &cstate->current_fh;
1996*4882a593Smuzhiyun 	const struct nfsd4_layout_ops *ops;
1997*4882a593Smuzhiyun 	loff_t new_size = lcp->lc_last_wr + 1;
1998*4882a593Smuzhiyun 	struct inode *inode;
1999*4882a593Smuzhiyun 	struct nfs4_layout_stateid *ls;
2000*4882a593Smuzhiyun 	__be32 nfserr;
2001*4882a593Smuzhiyun 
2002*4882a593Smuzhiyun 	nfserr = fh_verify(rqstp, current_fh, 0, NFSD_MAY_WRITE);
2003*4882a593Smuzhiyun 	if (nfserr)
2004*4882a593Smuzhiyun 		goto out;
2005*4882a593Smuzhiyun 
2006*4882a593Smuzhiyun 	nfserr = nfserr_layoutunavailable;
2007*4882a593Smuzhiyun 	ops = nfsd4_layout_verify(current_fh->fh_export, lcp->lc_layout_type);
2008*4882a593Smuzhiyun 	if (!ops)
2009*4882a593Smuzhiyun 		goto out;
2010*4882a593Smuzhiyun 	inode = d_inode(current_fh->fh_dentry);
2011*4882a593Smuzhiyun 
2012*4882a593Smuzhiyun 	nfserr = nfserr_inval;
2013*4882a593Smuzhiyun 	if (new_size <= seg->offset) {
2014*4882a593Smuzhiyun 		dprintk("pnfsd: last write before layout segment\n");
2015*4882a593Smuzhiyun 		goto out;
2016*4882a593Smuzhiyun 	}
2017*4882a593Smuzhiyun 	if (new_size > seg->offset + seg->length) {
2018*4882a593Smuzhiyun 		dprintk("pnfsd: last write beyond layout segment\n");
2019*4882a593Smuzhiyun 		goto out;
2020*4882a593Smuzhiyun 	}
2021*4882a593Smuzhiyun 	if (!lcp->lc_newoffset && new_size > i_size_read(inode)) {
2022*4882a593Smuzhiyun 		dprintk("pnfsd: layoutcommit beyond EOF\n");
2023*4882a593Smuzhiyun 		goto out;
2024*4882a593Smuzhiyun 	}
2025*4882a593Smuzhiyun 
2026*4882a593Smuzhiyun 	nfserr = nfsd4_preprocess_layout_stateid(rqstp, cstate, &lcp->lc_sid,
2027*4882a593Smuzhiyun 						false, lcp->lc_layout_type,
2028*4882a593Smuzhiyun 						&ls);
2029*4882a593Smuzhiyun 	if (nfserr) {
2030*4882a593Smuzhiyun 		trace_nfsd_layout_commit_lookup_fail(&lcp->lc_sid);
2031*4882a593Smuzhiyun 		/* fixup error code as per RFC5661 */
2032*4882a593Smuzhiyun 		if (nfserr == nfserr_bad_stateid)
2033*4882a593Smuzhiyun 			nfserr = nfserr_badlayout;
2034*4882a593Smuzhiyun 		goto out;
2035*4882a593Smuzhiyun 	}
2036*4882a593Smuzhiyun 
2037*4882a593Smuzhiyun 	/* LAYOUTCOMMIT does not require any serialization */
2038*4882a593Smuzhiyun 	mutex_unlock(&ls->ls_mutex);
2039*4882a593Smuzhiyun 
2040*4882a593Smuzhiyun 	if (new_size > i_size_read(inode)) {
2041*4882a593Smuzhiyun 		lcp->lc_size_chg = 1;
2042*4882a593Smuzhiyun 		lcp->lc_newsize = new_size;
2043*4882a593Smuzhiyun 	} else {
2044*4882a593Smuzhiyun 		lcp->lc_size_chg = 0;
2045*4882a593Smuzhiyun 	}
2046*4882a593Smuzhiyun 
2047*4882a593Smuzhiyun 	nfserr = ops->proc_layoutcommit(inode, lcp);
2048*4882a593Smuzhiyun 	nfs4_put_stid(&ls->ls_stid);
2049*4882a593Smuzhiyun out:
2050*4882a593Smuzhiyun 	return nfserr;
2051*4882a593Smuzhiyun }
2052*4882a593Smuzhiyun 
2053*4882a593Smuzhiyun static __be32
nfsd4_layoutreturn(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)2054*4882a593Smuzhiyun nfsd4_layoutreturn(struct svc_rqst *rqstp,
2055*4882a593Smuzhiyun 		struct nfsd4_compound_state *cstate, union nfsd4_op_u *u)
2056*4882a593Smuzhiyun {
2057*4882a593Smuzhiyun 	struct nfsd4_layoutreturn *lrp = &u->layoutreturn;
2058*4882a593Smuzhiyun 	struct svc_fh *current_fh = &cstate->current_fh;
2059*4882a593Smuzhiyun 	__be32 nfserr;
2060*4882a593Smuzhiyun 
2061*4882a593Smuzhiyun 	nfserr = fh_verify(rqstp, current_fh, 0, NFSD_MAY_NOP);
2062*4882a593Smuzhiyun 	if (nfserr)
2063*4882a593Smuzhiyun 		goto out;
2064*4882a593Smuzhiyun 
2065*4882a593Smuzhiyun 	nfserr = nfserr_layoutunavailable;
2066*4882a593Smuzhiyun 	if (!nfsd4_layout_verify(current_fh->fh_export, lrp->lr_layout_type))
2067*4882a593Smuzhiyun 		goto out;
2068*4882a593Smuzhiyun 
2069*4882a593Smuzhiyun 	switch (lrp->lr_seg.iomode) {
2070*4882a593Smuzhiyun 	case IOMODE_READ:
2071*4882a593Smuzhiyun 	case IOMODE_RW:
2072*4882a593Smuzhiyun 	case IOMODE_ANY:
2073*4882a593Smuzhiyun 		break;
2074*4882a593Smuzhiyun 	default:
2075*4882a593Smuzhiyun 		dprintk("%s: invalid iomode %d\n", __func__,
2076*4882a593Smuzhiyun 			lrp->lr_seg.iomode);
2077*4882a593Smuzhiyun 		nfserr = nfserr_inval;
2078*4882a593Smuzhiyun 		goto out;
2079*4882a593Smuzhiyun 	}
2080*4882a593Smuzhiyun 
2081*4882a593Smuzhiyun 	switch (lrp->lr_return_type) {
2082*4882a593Smuzhiyun 	case RETURN_FILE:
2083*4882a593Smuzhiyun 		nfserr = nfsd4_return_file_layouts(rqstp, cstate, lrp);
2084*4882a593Smuzhiyun 		break;
2085*4882a593Smuzhiyun 	case RETURN_FSID:
2086*4882a593Smuzhiyun 	case RETURN_ALL:
2087*4882a593Smuzhiyun 		nfserr = nfsd4_return_client_layouts(rqstp, cstate, lrp);
2088*4882a593Smuzhiyun 		break;
2089*4882a593Smuzhiyun 	default:
2090*4882a593Smuzhiyun 		dprintk("%s: invalid return_type %d\n", __func__,
2091*4882a593Smuzhiyun 			lrp->lr_return_type);
2092*4882a593Smuzhiyun 		nfserr = nfserr_inval;
2093*4882a593Smuzhiyun 		break;
2094*4882a593Smuzhiyun 	}
2095*4882a593Smuzhiyun out:
2096*4882a593Smuzhiyun 	return nfserr;
2097*4882a593Smuzhiyun }
2098*4882a593Smuzhiyun #endif /* CONFIG_NFSD_PNFS */
2099*4882a593Smuzhiyun 
2100*4882a593Smuzhiyun static __be32
nfsd4_getxattr(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)2101*4882a593Smuzhiyun nfsd4_getxattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2102*4882a593Smuzhiyun 	       union nfsd4_op_u *u)
2103*4882a593Smuzhiyun {
2104*4882a593Smuzhiyun 	struct nfsd4_getxattr *getxattr = &u->getxattr;
2105*4882a593Smuzhiyun 
2106*4882a593Smuzhiyun 	return nfsd_getxattr(rqstp, &cstate->current_fh,
2107*4882a593Smuzhiyun 			     getxattr->getxa_name, &getxattr->getxa_buf,
2108*4882a593Smuzhiyun 			     &getxattr->getxa_len);
2109*4882a593Smuzhiyun }
2110*4882a593Smuzhiyun 
2111*4882a593Smuzhiyun static __be32
nfsd4_setxattr(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)2112*4882a593Smuzhiyun nfsd4_setxattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2113*4882a593Smuzhiyun 	   union nfsd4_op_u *u)
2114*4882a593Smuzhiyun {
2115*4882a593Smuzhiyun 	struct nfsd4_setxattr *setxattr = &u->setxattr;
2116*4882a593Smuzhiyun 	__be32 ret;
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 	if (opens_in_grace(SVC_NET(rqstp)))
2119*4882a593Smuzhiyun 		return nfserr_grace;
2120*4882a593Smuzhiyun 
2121*4882a593Smuzhiyun 	ret = nfsd_setxattr(rqstp, &cstate->current_fh, setxattr->setxa_name,
2122*4882a593Smuzhiyun 			    setxattr->setxa_buf, setxattr->setxa_len,
2123*4882a593Smuzhiyun 			    setxattr->setxa_flags);
2124*4882a593Smuzhiyun 
2125*4882a593Smuzhiyun 	if (!ret)
2126*4882a593Smuzhiyun 		set_change_info(&setxattr->setxa_cinfo, &cstate->current_fh);
2127*4882a593Smuzhiyun 
2128*4882a593Smuzhiyun 	return ret;
2129*4882a593Smuzhiyun }
2130*4882a593Smuzhiyun 
2131*4882a593Smuzhiyun static __be32
nfsd4_listxattrs(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)2132*4882a593Smuzhiyun nfsd4_listxattrs(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2133*4882a593Smuzhiyun 	   union nfsd4_op_u *u)
2134*4882a593Smuzhiyun {
2135*4882a593Smuzhiyun 	/*
2136*4882a593Smuzhiyun 	 * Get the entire list, then copy out only the user attributes
2137*4882a593Smuzhiyun 	 * in the encode function.
2138*4882a593Smuzhiyun 	 */
2139*4882a593Smuzhiyun 	return nfsd_listxattr(rqstp, &cstate->current_fh,
2140*4882a593Smuzhiyun 			     &u->listxattrs.lsxa_buf, &u->listxattrs.lsxa_len);
2141*4882a593Smuzhiyun }
2142*4882a593Smuzhiyun 
2143*4882a593Smuzhiyun static __be32
nfsd4_removexattr(struct svc_rqst * rqstp,struct nfsd4_compound_state * cstate,union nfsd4_op_u * u)2144*4882a593Smuzhiyun nfsd4_removexattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
2145*4882a593Smuzhiyun 	   union nfsd4_op_u *u)
2146*4882a593Smuzhiyun {
2147*4882a593Smuzhiyun 	struct nfsd4_removexattr *removexattr = &u->removexattr;
2148*4882a593Smuzhiyun 	__be32 ret;
2149*4882a593Smuzhiyun 
2150*4882a593Smuzhiyun 	if (opens_in_grace(SVC_NET(rqstp)))
2151*4882a593Smuzhiyun 		return nfserr_grace;
2152*4882a593Smuzhiyun 
2153*4882a593Smuzhiyun 	ret = nfsd_removexattr(rqstp, &cstate->current_fh,
2154*4882a593Smuzhiyun 	    removexattr->rmxa_name);
2155*4882a593Smuzhiyun 
2156*4882a593Smuzhiyun 	if (!ret)
2157*4882a593Smuzhiyun 		set_change_info(&removexattr->rmxa_cinfo, &cstate->current_fh);
2158*4882a593Smuzhiyun 
2159*4882a593Smuzhiyun 	return ret;
2160*4882a593Smuzhiyun }
2161*4882a593Smuzhiyun 
2162*4882a593Smuzhiyun /*
2163*4882a593Smuzhiyun  * NULL call.
2164*4882a593Smuzhiyun  */
2165*4882a593Smuzhiyun static __be32
nfsd4_proc_null(struct svc_rqst * rqstp)2166*4882a593Smuzhiyun nfsd4_proc_null(struct svc_rqst *rqstp)
2167*4882a593Smuzhiyun {
2168*4882a593Smuzhiyun 	return rpc_success;
2169*4882a593Smuzhiyun }
2170*4882a593Smuzhiyun 
nfsd4_increment_op_stats(u32 opnum)2171*4882a593Smuzhiyun static inline void nfsd4_increment_op_stats(u32 opnum)
2172*4882a593Smuzhiyun {
2173*4882a593Smuzhiyun 	if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP)
2174*4882a593Smuzhiyun 		nfsdstats.nfs4_opcount[opnum]++;
2175*4882a593Smuzhiyun }
2176*4882a593Smuzhiyun 
2177*4882a593Smuzhiyun static const struct nfsd4_operation nfsd4_ops[];
2178*4882a593Smuzhiyun 
2179*4882a593Smuzhiyun static const char *nfsd4_op_name(unsigned opnum);
2180*4882a593Smuzhiyun 
2181*4882a593Smuzhiyun /*
2182*4882a593Smuzhiyun  * Enforce NFSv4.1 COMPOUND ordering rules:
2183*4882a593Smuzhiyun  *
2184*4882a593Smuzhiyun  * Also note, enforced elsewhere:
2185*4882a593Smuzhiyun  *	- SEQUENCE other than as first op results in
2186*4882a593Smuzhiyun  *	  NFS4ERR_SEQUENCE_POS. (Enforced in nfsd4_sequence().)
2187*4882a593Smuzhiyun  *	- BIND_CONN_TO_SESSION must be the only op in its compound.
2188*4882a593Smuzhiyun  *	  (Enforced in nfsd4_bind_conn_to_session().)
2189*4882a593Smuzhiyun  *	- DESTROY_SESSION must be the final operation in a compound, if
2190*4882a593Smuzhiyun  *	  sessionid's in SEQUENCE and DESTROY_SESSION are the same.
2191*4882a593Smuzhiyun  *	  (Enforced in nfsd4_destroy_session().)
2192*4882a593Smuzhiyun  */
nfs41_check_op_ordering(struct nfsd4_compoundargs * args)2193*4882a593Smuzhiyun static __be32 nfs41_check_op_ordering(struct nfsd4_compoundargs *args)
2194*4882a593Smuzhiyun {
2195*4882a593Smuzhiyun 	struct nfsd4_op *first_op = &args->ops[0];
2196*4882a593Smuzhiyun 
2197*4882a593Smuzhiyun 	/* These ordering requirements don't apply to NFSv4.0: */
2198*4882a593Smuzhiyun 	if (args->minorversion == 0)
2199*4882a593Smuzhiyun 		return nfs_ok;
2200*4882a593Smuzhiyun 	/* This is weird, but OK, not our problem: */
2201*4882a593Smuzhiyun 	if (args->opcnt == 0)
2202*4882a593Smuzhiyun 		return nfs_ok;
2203*4882a593Smuzhiyun 	if (first_op->status == nfserr_op_illegal)
2204*4882a593Smuzhiyun 		return nfs_ok;
2205*4882a593Smuzhiyun 	if (!(nfsd4_ops[first_op->opnum].op_flags & ALLOWED_AS_FIRST_OP))
2206*4882a593Smuzhiyun 		return nfserr_op_not_in_session;
2207*4882a593Smuzhiyun 	if (first_op->opnum == OP_SEQUENCE)
2208*4882a593Smuzhiyun 		return nfs_ok;
2209*4882a593Smuzhiyun 	/*
2210*4882a593Smuzhiyun 	 * So first_op is something allowed outside a session, like
2211*4882a593Smuzhiyun 	 * EXCHANGE_ID; but then it has to be the only op in the
2212*4882a593Smuzhiyun 	 * compound:
2213*4882a593Smuzhiyun 	 */
2214*4882a593Smuzhiyun 	if (args->opcnt != 1)
2215*4882a593Smuzhiyun 		return nfserr_not_only_op;
2216*4882a593Smuzhiyun 	return nfs_ok;
2217*4882a593Smuzhiyun }
2218*4882a593Smuzhiyun 
OPDESC(struct nfsd4_op * op)2219*4882a593Smuzhiyun const struct nfsd4_operation *OPDESC(struct nfsd4_op *op)
2220*4882a593Smuzhiyun {
2221*4882a593Smuzhiyun 	return &nfsd4_ops[op->opnum];
2222*4882a593Smuzhiyun }
2223*4882a593Smuzhiyun 
nfsd4_cache_this_op(struct nfsd4_op * op)2224*4882a593Smuzhiyun bool nfsd4_cache_this_op(struct nfsd4_op *op)
2225*4882a593Smuzhiyun {
2226*4882a593Smuzhiyun 	if (op->opnum == OP_ILLEGAL)
2227*4882a593Smuzhiyun 		return false;
2228*4882a593Smuzhiyun 	return OPDESC(op)->op_flags & OP_CACHEME;
2229*4882a593Smuzhiyun }
2230*4882a593Smuzhiyun 
need_wrongsec_check(struct svc_rqst * rqstp)2231*4882a593Smuzhiyun static bool need_wrongsec_check(struct svc_rqst *rqstp)
2232*4882a593Smuzhiyun {
2233*4882a593Smuzhiyun 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
2234*4882a593Smuzhiyun 	struct nfsd4_compoundargs *argp = rqstp->rq_argp;
2235*4882a593Smuzhiyun 	struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
2236*4882a593Smuzhiyun 	struct nfsd4_op *next = &argp->ops[resp->opcnt];
2237*4882a593Smuzhiyun 	const struct nfsd4_operation *thisd = OPDESC(this);
2238*4882a593Smuzhiyun 	const struct nfsd4_operation *nextd;
2239*4882a593Smuzhiyun 
2240*4882a593Smuzhiyun 	/*
2241*4882a593Smuzhiyun 	 * Most ops check wronsec on our own; only the putfh-like ops
2242*4882a593Smuzhiyun 	 * have special rules.
2243*4882a593Smuzhiyun 	 */
2244*4882a593Smuzhiyun 	if (!(thisd->op_flags & OP_IS_PUTFH_LIKE))
2245*4882a593Smuzhiyun 		return false;
2246*4882a593Smuzhiyun 	/*
2247*4882a593Smuzhiyun 	 * rfc 5661 2.6.3.1.1.6: don't bother erroring out a
2248*4882a593Smuzhiyun 	 * put-filehandle operation if we're not going to use the
2249*4882a593Smuzhiyun 	 * result:
2250*4882a593Smuzhiyun 	 */
2251*4882a593Smuzhiyun 	if (argp->opcnt == resp->opcnt)
2252*4882a593Smuzhiyun 		return false;
2253*4882a593Smuzhiyun 	if (next->opnum == OP_ILLEGAL)
2254*4882a593Smuzhiyun 		return false;
2255*4882a593Smuzhiyun 	nextd = OPDESC(next);
2256*4882a593Smuzhiyun 	/*
2257*4882a593Smuzhiyun 	 * Rest of 2.6.3.1.1: certain operations will return WRONGSEC
2258*4882a593Smuzhiyun 	 * errors themselves as necessary; others should check for them
2259*4882a593Smuzhiyun 	 * now:
2260*4882a593Smuzhiyun 	 */
2261*4882a593Smuzhiyun 	return !(nextd->op_flags & OP_HANDLES_WRONGSEC);
2262*4882a593Smuzhiyun }
2263*4882a593Smuzhiyun 
svcxdr_init_encode(struct svc_rqst * rqstp,struct nfsd4_compoundres * resp)2264*4882a593Smuzhiyun static void svcxdr_init_encode(struct svc_rqst *rqstp,
2265*4882a593Smuzhiyun 			       struct nfsd4_compoundres *resp)
2266*4882a593Smuzhiyun {
2267*4882a593Smuzhiyun 	struct xdr_stream *xdr = &resp->xdr;
2268*4882a593Smuzhiyun 	struct xdr_buf *buf = &rqstp->rq_res;
2269*4882a593Smuzhiyun 	struct kvec *head = buf->head;
2270*4882a593Smuzhiyun 
2271*4882a593Smuzhiyun 	xdr->buf = buf;
2272*4882a593Smuzhiyun 	xdr->iov = head;
2273*4882a593Smuzhiyun 	xdr->p   = head->iov_base + head->iov_len;
2274*4882a593Smuzhiyun 	xdr->end = head->iov_base + PAGE_SIZE - rqstp->rq_auth_slack;
2275*4882a593Smuzhiyun 	/* Tail and page_len should be zero at this point: */
2276*4882a593Smuzhiyun 	buf->len = buf->head[0].iov_len;
2277*4882a593Smuzhiyun 	xdr->scratch.iov_len = 0;
2278*4882a593Smuzhiyun 	xdr->page_ptr = buf->pages - 1;
2279*4882a593Smuzhiyun 	buf->buflen = PAGE_SIZE * (1 + rqstp->rq_page_end - buf->pages)
2280*4882a593Smuzhiyun 		- rqstp->rq_auth_slack;
2281*4882a593Smuzhiyun }
2282*4882a593Smuzhiyun 
2283*4882a593Smuzhiyun #ifdef CONFIG_NFSD_V4_2_INTER_SSC
2284*4882a593Smuzhiyun static void
check_if_stalefh_allowed(struct nfsd4_compoundargs * args)2285*4882a593Smuzhiyun check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
2286*4882a593Smuzhiyun {
2287*4882a593Smuzhiyun 	struct nfsd4_op	*op, *current_op = NULL, *saved_op = NULL;
2288*4882a593Smuzhiyun 	struct nfsd4_copy *copy;
2289*4882a593Smuzhiyun 	struct nfsd4_putfh *putfh;
2290*4882a593Smuzhiyun 	int i;
2291*4882a593Smuzhiyun 
2292*4882a593Smuzhiyun 	/* traverse all operation and if it's a COPY compound, mark the
2293*4882a593Smuzhiyun 	 * source filehandle to skip verification
2294*4882a593Smuzhiyun 	 */
2295*4882a593Smuzhiyun 	for (i = 0; i < args->opcnt; i++) {
2296*4882a593Smuzhiyun 		op = &args->ops[i];
2297*4882a593Smuzhiyun 		if (op->opnum == OP_PUTFH)
2298*4882a593Smuzhiyun 			current_op = op;
2299*4882a593Smuzhiyun 		else if (op->opnum == OP_SAVEFH)
2300*4882a593Smuzhiyun 			saved_op = current_op;
2301*4882a593Smuzhiyun 		else if (op->opnum == OP_RESTOREFH)
2302*4882a593Smuzhiyun 			current_op = saved_op;
2303*4882a593Smuzhiyun 		else if (op->opnum == OP_COPY) {
2304*4882a593Smuzhiyun 			copy = (struct nfsd4_copy *)&op->u;
2305*4882a593Smuzhiyun 			if (!saved_op) {
2306*4882a593Smuzhiyun 				op->status = nfserr_nofilehandle;
2307*4882a593Smuzhiyun 				return;
2308*4882a593Smuzhiyun 			}
2309*4882a593Smuzhiyun 			putfh = (struct nfsd4_putfh *)&saved_op->u;
2310*4882a593Smuzhiyun 			if (!copy->cp_intra)
2311*4882a593Smuzhiyun 				putfh->no_verify = true;
2312*4882a593Smuzhiyun 		}
2313*4882a593Smuzhiyun 	}
2314*4882a593Smuzhiyun }
2315*4882a593Smuzhiyun #else
2316*4882a593Smuzhiyun static void
check_if_stalefh_allowed(struct nfsd4_compoundargs * args)2317*4882a593Smuzhiyun check_if_stalefh_allowed(struct nfsd4_compoundargs *args)
2318*4882a593Smuzhiyun {
2319*4882a593Smuzhiyun }
2320*4882a593Smuzhiyun #endif
2321*4882a593Smuzhiyun 
2322*4882a593Smuzhiyun /*
2323*4882a593Smuzhiyun  * COMPOUND call.
2324*4882a593Smuzhiyun  */
2325*4882a593Smuzhiyun static __be32
nfsd4_proc_compound(struct svc_rqst * rqstp)2326*4882a593Smuzhiyun nfsd4_proc_compound(struct svc_rqst *rqstp)
2327*4882a593Smuzhiyun {
2328*4882a593Smuzhiyun 	struct nfsd4_compoundargs *args = rqstp->rq_argp;
2329*4882a593Smuzhiyun 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
2330*4882a593Smuzhiyun 	struct nfsd4_op	*op;
2331*4882a593Smuzhiyun 	struct nfsd4_compound_state *cstate = &resp->cstate;
2332*4882a593Smuzhiyun 	struct svc_fh *current_fh = &cstate->current_fh;
2333*4882a593Smuzhiyun 	struct svc_fh *save_fh = &cstate->save_fh;
2334*4882a593Smuzhiyun 	struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
2335*4882a593Smuzhiyun 	__be32		status;
2336*4882a593Smuzhiyun 
2337*4882a593Smuzhiyun 	svcxdr_init_encode(rqstp, resp);
2338*4882a593Smuzhiyun 	resp->tagp = resp->xdr.p;
2339*4882a593Smuzhiyun 	/* reserve space for: taglen, tag, and opcnt */
2340*4882a593Smuzhiyun 	xdr_reserve_space(&resp->xdr, 8 + args->taglen);
2341*4882a593Smuzhiyun 	resp->taglen = args->taglen;
2342*4882a593Smuzhiyun 	resp->tag = args->tag;
2343*4882a593Smuzhiyun 	resp->rqstp = rqstp;
2344*4882a593Smuzhiyun 	cstate->minorversion = args->minorversion;
2345*4882a593Smuzhiyun 	fh_init(current_fh, NFS4_FHSIZE);
2346*4882a593Smuzhiyun 	fh_init(save_fh, NFS4_FHSIZE);
2347*4882a593Smuzhiyun 	/*
2348*4882a593Smuzhiyun 	 * Don't use the deferral mechanism for NFSv4; compounds make it
2349*4882a593Smuzhiyun 	 * too hard to avoid non-idempotency problems.
2350*4882a593Smuzhiyun 	 */
2351*4882a593Smuzhiyun 	clear_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
2352*4882a593Smuzhiyun 
2353*4882a593Smuzhiyun 	/*
2354*4882a593Smuzhiyun 	 * According to RFC3010, this takes precedence over all other errors.
2355*4882a593Smuzhiyun 	 */
2356*4882a593Smuzhiyun 	status = nfserr_minor_vers_mismatch;
2357*4882a593Smuzhiyun 	if (nfsd_minorversion(nn, args->minorversion, NFSD_TEST) <= 0)
2358*4882a593Smuzhiyun 		goto out;
2359*4882a593Smuzhiyun 	status = nfserr_resource;
2360*4882a593Smuzhiyun 	if (args->opcnt > NFSD_MAX_OPS_PER_COMPOUND)
2361*4882a593Smuzhiyun 		goto out;
2362*4882a593Smuzhiyun 
2363*4882a593Smuzhiyun 	status = nfs41_check_op_ordering(args);
2364*4882a593Smuzhiyun 	if (status) {
2365*4882a593Smuzhiyun 		op = &args->ops[0];
2366*4882a593Smuzhiyun 		op->status = status;
2367*4882a593Smuzhiyun 		resp->opcnt = 1;
2368*4882a593Smuzhiyun 		goto encode_op;
2369*4882a593Smuzhiyun 	}
2370*4882a593Smuzhiyun 	check_if_stalefh_allowed(args);
2371*4882a593Smuzhiyun 
2372*4882a593Smuzhiyun 	rqstp->rq_lease_breaker = (void **)&cstate->clp;
2373*4882a593Smuzhiyun 
2374*4882a593Smuzhiyun 	trace_nfsd_compound(rqstp, args->opcnt);
2375*4882a593Smuzhiyun 	while (!status && resp->opcnt < args->opcnt) {
2376*4882a593Smuzhiyun 		op = &args->ops[resp->opcnt++];
2377*4882a593Smuzhiyun 
2378*4882a593Smuzhiyun 		/*
2379*4882a593Smuzhiyun 		 * The XDR decode routines may have pre-set op->status;
2380*4882a593Smuzhiyun 		 * for example, if there is a miscellaneous XDR error
2381*4882a593Smuzhiyun 		 * it will be set to nfserr_bad_xdr.
2382*4882a593Smuzhiyun 		 */
2383*4882a593Smuzhiyun 		if (op->status) {
2384*4882a593Smuzhiyun 			if (op->opnum == OP_OPEN)
2385*4882a593Smuzhiyun 				op->status = nfsd4_open_omfg(rqstp, cstate, op);
2386*4882a593Smuzhiyun 			goto encode_op;
2387*4882a593Smuzhiyun 		}
2388*4882a593Smuzhiyun 		if (!current_fh->fh_dentry &&
2389*4882a593Smuzhiyun 				!HAS_FH_FLAG(current_fh, NFSD4_FH_FOREIGN)) {
2390*4882a593Smuzhiyun 			if (!(op->opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
2391*4882a593Smuzhiyun 				op->status = nfserr_nofilehandle;
2392*4882a593Smuzhiyun 				goto encode_op;
2393*4882a593Smuzhiyun 			}
2394*4882a593Smuzhiyun 		} else if (current_fh->fh_export &&
2395*4882a593Smuzhiyun 			   current_fh->fh_export->ex_fslocs.migrated &&
2396*4882a593Smuzhiyun 			  !(op->opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
2397*4882a593Smuzhiyun 			op->status = nfserr_moved;
2398*4882a593Smuzhiyun 			goto encode_op;
2399*4882a593Smuzhiyun 		}
2400*4882a593Smuzhiyun 
2401*4882a593Smuzhiyun 		fh_clear_wcc(current_fh);
2402*4882a593Smuzhiyun 
2403*4882a593Smuzhiyun 		/* If op is non-idempotent */
2404*4882a593Smuzhiyun 		if (op->opdesc->op_flags & OP_MODIFIES_SOMETHING) {
2405*4882a593Smuzhiyun 			/*
2406*4882a593Smuzhiyun 			 * Don't execute this op if we couldn't encode a
2407*4882a593Smuzhiyun 			 * succesful reply:
2408*4882a593Smuzhiyun 			 */
2409*4882a593Smuzhiyun 			u32 plen = op->opdesc->op_rsize_bop(rqstp, op);
2410*4882a593Smuzhiyun 			/*
2411*4882a593Smuzhiyun 			 * Plus if there's another operation, make sure
2412*4882a593Smuzhiyun 			 * we'll have space to at least encode an error:
2413*4882a593Smuzhiyun 			 */
2414*4882a593Smuzhiyun 			if (resp->opcnt < args->opcnt)
2415*4882a593Smuzhiyun 				plen += COMPOUND_ERR_SLACK_SPACE;
2416*4882a593Smuzhiyun 			op->status = nfsd4_check_resp_size(resp, plen);
2417*4882a593Smuzhiyun 		}
2418*4882a593Smuzhiyun 
2419*4882a593Smuzhiyun 		if (op->status)
2420*4882a593Smuzhiyun 			goto encode_op;
2421*4882a593Smuzhiyun 
2422*4882a593Smuzhiyun 		if (op->opdesc->op_get_currentstateid)
2423*4882a593Smuzhiyun 			op->opdesc->op_get_currentstateid(cstate, &op->u);
2424*4882a593Smuzhiyun 		op->status = op->opdesc->op_func(rqstp, cstate, &op->u);
2425*4882a593Smuzhiyun 
2426*4882a593Smuzhiyun 		/* Only from SEQUENCE */
2427*4882a593Smuzhiyun 		if (cstate->status == nfserr_replay_cache) {
2428*4882a593Smuzhiyun 			dprintk("%s NFS4.1 replay from cache\n", __func__);
2429*4882a593Smuzhiyun 			status = op->status;
2430*4882a593Smuzhiyun 			goto out;
2431*4882a593Smuzhiyun 		}
2432*4882a593Smuzhiyun 		if (!op->status) {
2433*4882a593Smuzhiyun 			if (op->opdesc->op_set_currentstateid)
2434*4882a593Smuzhiyun 				op->opdesc->op_set_currentstateid(cstate, &op->u);
2435*4882a593Smuzhiyun 
2436*4882a593Smuzhiyun 			if (op->opdesc->op_flags & OP_CLEAR_STATEID)
2437*4882a593Smuzhiyun 				clear_current_stateid(cstate);
2438*4882a593Smuzhiyun 
2439*4882a593Smuzhiyun 			if (current_fh->fh_export &&
2440*4882a593Smuzhiyun 					need_wrongsec_check(rqstp))
2441*4882a593Smuzhiyun 				op->status = check_nfsd_access(current_fh->fh_export, rqstp);
2442*4882a593Smuzhiyun 		}
2443*4882a593Smuzhiyun encode_op:
2444*4882a593Smuzhiyun 		if (op->status == nfserr_replay_me) {
2445*4882a593Smuzhiyun 			op->replay = &cstate->replay_owner->so_replay;
2446*4882a593Smuzhiyun 			nfsd4_encode_replay(&resp->xdr, op);
2447*4882a593Smuzhiyun 			status = op->status = op->replay->rp_status;
2448*4882a593Smuzhiyun 		} else {
2449*4882a593Smuzhiyun 			nfsd4_encode_operation(resp, op);
2450*4882a593Smuzhiyun 			status = op->status;
2451*4882a593Smuzhiyun 		}
2452*4882a593Smuzhiyun 
2453*4882a593Smuzhiyun 		trace_nfsd_compound_status(args->opcnt, resp->opcnt, status,
2454*4882a593Smuzhiyun 					   nfsd4_op_name(op->opnum));
2455*4882a593Smuzhiyun 
2456*4882a593Smuzhiyun 		nfsd4_cstate_clear_replay(cstate);
2457*4882a593Smuzhiyun 		nfsd4_increment_op_stats(op->opnum);
2458*4882a593Smuzhiyun 	}
2459*4882a593Smuzhiyun 
2460*4882a593Smuzhiyun 	fh_put(current_fh);
2461*4882a593Smuzhiyun 	fh_put(save_fh);
2462*4882a593Smuzhiyun 	BUG_ON(cstate->replay_owner);
2463*4882a593Smuzhiyun out:
2464*4882a593Smuzhiyun 	cstate->status = status;
2465*4882a593Smuzhiyun 	/* Reset deferral mechanism for RPC deferrals */
2466*4882a593Smuzhiyun 	set_bit(RQ_USEDEFERRAL, &rqstp->rq_flags);
2467*4882a593Smuzhiyun 	return rpc_success;
2468*4882a593Smuzhiyun }
2469*4882a593Smuzhiyun 
2470*4882a593Smuzhiyun #define op_encode_hdr_size		(2)
2471*4882a593Smuzhiyun #define op_encode_stateid_maxsz		(XDR_QUADLEN(NFS4_STATEID_SIZE))
2472*4882a593Smuzhiyun #define op_encode_verifier_maxsz	(XDR_QUADLEN(NFS4_VERIFIER_SIZE))
2473*4882a593Smuzhiyun #define op_encode_change_info_maxsz	(5)
2474*4882a593Smuzhiyun #define nfs4_fattr_bitmap_maxsz		(4)
2475*4882a593Smuzhiyun 
2476*4882a593Smuzhiyun /* We'll fall back on returning no lockowner if run out of space: */
2477*4882a593Smuzhiyun #define op_encode_lockowner_maxsz	(0)
2478*4882a593Smuzhiyun #define op_encode_lock_denied_maxsz	(8 + op_encode_lockowner_maxsz)
2479*4882a593Smuzhiyun 
2480*4882a593Smuzhiyun #define nfs4_owner_maxsz		(1 + XDR_QUADLEN(IDMAP_NAMESZ))
2481*4882a593Smuzhiyun 
2482*4882a593Smuzhiyun #define op_encode_ace_maxsz		(3 + nfs4_owner_maxsz)
2483*4882a593Smuzhiyun #define op_encode_delegation_maxsz	(1 + op_encode_stateid_maxsz + 1 + \
2484*4882a593Smuzhiyun 					 op_encode_ace_maxsz)
2485*4882a593Smuzhiyun 
2486*4882a593Smuzhiyun #define op_encode_channel_attrs_maxsz	(6 + 1 + 1)
2487*4882a593Smuzhiyun 
nfsd4_only_status_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2488*4882a593Smuzhiyun static inline u32 nfsd4_only_status_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2489*4882a593Smuzhiyun {
2490*4882a593Smuzhiyun 	return (op_encode_hdr_size) * sizeof(__be32);
2491*4882a593Smuzhiyun }
2492*4882a593Smuzhiyun 
nfsd4_status_stateid_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2493*4882a593Smuzhiyun static inline u32 nfsd4_status_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2494*4882a593Smuzhiyun {
2495*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_stateid_maxsz)* sizeof(__be32);
2496*4882a593Smuzhiyun }
2497*4882a593Smuzhiyun 
nfsd4_access_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2498*4882a593Smuzhiyun static inline u32 nfsd4_access_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2499*4882a593Smuzhiyun {
2500*4882a593Smuzhiyun 	/* ac_supported, ac_resp_access */
2501*4882a593Smuzhiyun 	return (op_encode_hdr_size + 2)* sizeof(__be32);
2502*4882a593Smuzhiyun }
2503*4882a593Smuzhiyun 
nfsd4_commit_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2504*4882a593Smuzhiyun static inline u32 nfsd4_commit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2505*4882a593Smuzhiyun {
2506*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_verifier_maxsz) * sizeof(__be32);
2507*4882a593Smuzhiyun }
2508*4882a593Smuzhiyun 
nfsd4_create_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2509*4882a593Smuzhiyun static inline u32 nfsd4_create_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2510*4882a593Smuzhiyun {
2511*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_change_info_maxsz
2512*4882a593Smuzhiyun 		+ nfs4_fattr_bitmap_maxsz) * sizeof(__be32);
2513*4882a593Smuzhiyun }
2514*4882a593Smuzhiyun 
2515*4882a593Smuzhiyun /*
2516*4882a593Smuzhiyun  * Note since this is an idempotent operation we won't insist on failing
2517*4882a593Smuzhiyun  * the op prematurely if the estimate is too large.  We may turn off splice
2518*4882a593Smuzhiyun  * reads unnecessarily.
2519*4882a593Smuzhiyun  */
nfsd4_getattr_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2520*4882a593Smuzhiyun static inline u32 nfsd4_getattr_rsize(struct svc_rqst *rqstp,
2521*4882a593Smuzhiyun 				      struct nfsd4_op *op)
2522*4882a593Smuzhiyun {
2523*4882a593Smuzhiyun 	u32 *bmap = op->u.getattr.ga_bmval;
2524*4882a593Smuzhiyun 	u32 bmap0 = bmap[0], bmap1 = bmap[1], bmap2 = bmap[2];
2525*4882a593Smuzhiyun 	u32 ret = 0;
2526*4882a593Smuzhiyun 
2527*4882a593Smuzhiyun 	if (bmap0 & FATTR4_WORD0_ACL)
2528*4882a593Smuzhiyun 		return svc_max_payload(rqstp);
2529*4882a593Smuzhiyun 	if (bmap0 & FATTR4_WORD0_FS_LOCATIONS)
2530*4882a593Smuzhiyun 		return svc_max_payload(rqstp);
2531*4882a593Smuzhiyun 
2532*4882a593Smuzhiyun 	if (bmap1 & FATTR4_WORD1_OWNER) {
2533*4882a593Smuzhiyun 		ret += IDMAP_NAMESZ + 4;
2534*4882a593Smuzhiyun 		bmap1 &= ~FATTR4_WORD1_OWNER;
2535*4882a593Smuzhiyun 	}
2536*4882a593Smuzhiyun 	if (bmap1 & FATTR4_WORD1_OWNER_GROUP) {
2537*4882a593Smuzhiyun 		ret += IDMAP_NAMESZ + 4;
2538*4882a593Smuzhiyun 		bmap1 &= ~FATTR4_WORD1_OWNER_GROUP;
2539*4882a593Smuzhiyun 	}
2540*4882a593Smuzhiyun 	if (bmap0 & FATTR4_WORD0_FILEHANDLE) {
2541*4882a593Smuzhiyun 		ret += NFS4_FHSIZE + 4;
2542*4882a593Smuzhiyun 		bmap0 &= ~FATTR4_WORD0_FILEHANDLE;
2543*4882a593Smuzhiyun 	}
2544*4882a593Smuzhiyun 	if (bmap2 & FATTR4_WORD2_SECURITY_LABEL) {
2545*4882a593Smuzhiyun 		ret += NFS4_MAXLABELLEN + 12;
2546*4882a593Smuzhiyun 		bmap2 &= ~FATTR4_WORD2_SECURITY_LABEL;
2547*4882a593Smuzhiyun 	}
2548*4882a593Smuzhiyun 	/*
2549*4882a593Smuzhiyun 	 * Largest of remaining attributes are 16 bytes (e.g.,
2550*4882a593Smuzhiyun 	 * supported_attributes)
2551*4882a593Smuzhiyun 	 */
2552*4882a593Smuzhiyun 	ret += 16 * (hweight32(bmap0) + hweight32(bmap1) + hweight32(bmap2));
2553*4882a593Smuzhiyun 	/* bitmask, length */
2554*4882a593Smuzhiyun 	ret += 20;
2555*4882a593Smuzhiyun 	return ret;
2556*4882a593Smuzhiyun }
2557*4882a593Smuzhiyun 
nfsd4_getfh_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2558*4882a593Smuzhiyun static inline u32 nfsd4_getfh_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2559*4882a593Smuzhiyun {
2560*4882a593Smuzhiyun 	return (op_encode_hdr_size + 1) * sizeof(__be32) + NFS4_FHSIZE;
2561*4882a593Smuzhiyun }
2562*4882a593Smuzhiyun 
nfsd4_link_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2563*4882a593Smuzhiyun static inline u32 nfsd4_link_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2564*4882a593Smuzhiyun {
2565*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_change_info_maxsz)
2566*4882a593Smuzhiyun 		* sizeof(__be32);
2567*4882a593Smuzhiyun }
2568*4882a593Smuzhiyun 
nfsd4_lock_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2569*4882a593Smuzhiyun static inline u32 nfsd4_lock_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2570*4882a593Smuzhiyun {
2571*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_lock_denied_maxsz)
2572*4882a593Smuzhiyun 		* sizeof(__be32);
2573*4882a593Smuzhiyun }
2574*4882a593Smuzhiyun 
nfsd4_open_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2575*4882a593Smuzhiyun static inline u32 nfsd4_open_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2576*4882a593Smuzhiyun {
2577*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_stateid_maxsz
2578*4882a593Smuzhiyun 		+ op_encode_change_info_maxsz + 1
2579*4882a593Smuzhiyun 		+ nfs4_fattr_bitmap_maxsz
2580*4882a593Smuzhiyun 		+ op_encode_delegation_maxsz) * sizeof(__be32);
2581*4882a593Smuzhiyun }
2582*4882a593Smuzhiyun 
nfsd4_read_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2583*4882a593Smuzhiyun static inline u32 nfsd4_read_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2584*4882a593Smuzhiyun {
2585*4882a593Smuzhiyun 	u32 maxcount = 0, rlen = 0;
2586*4882a593Smuzhiyun 
2587*4882a593Smuzhiyun 	maxcount = svc_max_payload(rqstp);
2588*4882a593Smuzhiyun 	rlen = min(op->u.read.rd_length, maxcount);
2589*4882a593Smuzhiyun 
2590*4882a593Smuzhiyun 	return (op_encode_hdr_size + 2 + XDR_QUADLEN(rlen)) * sizeof(__be32);
2591*4882a593Smuzhiyun }
2592*4882a593Smuzhiyun 
nfsd4_read_plus_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2593*4882a593Smuzhiyun static inline u32 nfsd4_read_plus_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2594*4882a593Smuzhiyun {
2595*4882a593Smuzhiyun 	u32 maxcount = svc_max_payload(rqstp);
2596*4882a593Smuzhiyun 	u32 rlen = min(op->u.read.rd_length, maxcount);
2597*4882a593Smuzhiyun 	/*
2598*4882a593Smuzhiyun 	 * If we detect that the file changed during hole encoding, then we
2599*4882a593Smuzhiyun 	 * recover by encoding the remaining reply as data. This means we need
2600*4882a593Smuzhiyun 	 * to set aside enough room to encode two data segments.
2601*4882a593Smuzhiyun 	 */
2602*4882a593Smuzhiyun 	u32 seg_len = 2 * (1 + 2 + 1);
2603*4882a593Smuzhiyun 
2604*4882a593Smuzhiyun 	return (op_encode_hdr_size + 2 + seg_len + XDR_QUADLEN(rlen)) * sizeof(__be32);
2605*4882a593Smuzhiyun }
2606*4882a593Smuzhiyun 
nfsd4_readdir_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2607*4882a593Smuzhiyun static inline u32 nfsd4_readdir_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2608*4882a593Smuzhiyun {
2609*4882a593Smuzhiyun 	u32 maxcount = 0, rlen = 0;
2610*4882a593Smuzhiyun 
2611*4882a593Smuzhiyun 	maxcount = svc_max_payload(rqstp);
2612*4882a593Smuzhiyun 	rlen = min(op->u.readdir.rd_maxcount, maxcount);
2613*4882a593Smuzhiyun 
2614*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_verifier_maxsz +
2615*4882a593Smuzhiyun 		XDR_QUADLEN(rlen)) * sizeof(__be32);
2616*4882a593Smuzhiyun }
2617*4882a593Smuzhiyun 
nfsd4_readlink_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2618*4882a593Smuzhiyun static inline u32 nfsd4_readlink_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2619*4882a593Smuzhiyun {
2620*4882a593Smuzhiyun 	return (op_encode_hdr_size + 1) * sizeof(__be32) + PAGE_SIZE;
2621*4882a593Smuzhiyun }
2622*4882a593Smuzhiyun 
nfsd4_remove_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2623*4882a593Smuzhiyun static inline u32 nfsd4_remove_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2624*4882a593Smuzhiyun {
2625*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_change_info_maxsz)
2626*4882a593Smuzhiyun 		* sizeof(__be32);
2627*4882a593Smuzhiyun }
2628*4882a593Smuzhiyun 
nfsd4_rename_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2629*4882a593Smuzhiyun static inline u32 nfsd4_rename_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2630*4882a593Smuzhiyun {
2631*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_change_info_maxsz
2632*4882a593Smuzhiyun 		+ op_encode_change_info_maxsz) * sizeof(__be32);
2633*4882a593Smuzhiyun }
2634*4882a593Smuzhiyun 
nfsd4_sequence_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2635*4882a593Smuzhiyun static inline u32 nfsd4_sequence_rsize(struct svc_rqst *rqstp,
2636*4882a593Smuzhiyun 				       struct nfsd4_op *op)
2637*4882a593Smuzhiyun {
2638*4882a593Smuzhiyun 	return (op_encode_hdr_size
2639*4882a593Smuzhiyun 		+ XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + 5) * sizeof(__be32);
2640*4882a593Smuzhiyun }
2641*4882a593Smuzhiyun 
nfsd4_test_stateid_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2642*4882a593Smuzhiyun static inline u32 nfsd4_test_stateid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2643*4882a593Smuzhiyun {
2644*4882a593Smuzhiyun 	return (op_encode_hdr_size + 1 + op->u.test_stateid.ts_num_ids)
2645*4882a593Smuzhiyun 		* sizeof(__be32);
2646*4882a593Smuzhiyun }
2647*4882a593Smuzhiyun 
nfsd4_setattr_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2648*4882a593Smuzhiyun static inline u32 nfsd4_setattr_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2649*4882a593Smuzhiyun {
2650*4882a593Smuzhiyun 	return (op_encode_hdr_size + nfs4_fattr_bitmap_maxsz) * sizeof(__be32);
2651*4882a593Smuzhiyun }
2652*4882a593Smuzhiyun 
nfsd4_secinfo_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2653*4882a593Smuzhiyun static inline u32 nfsd4_secinfo_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2654*4882a593Smuzhiyun {
2655*4882a593Smuzhiyun 	return (op_encode_hdr_size + RPC_AUTH_MAXFLAVOR *
2656*4882a593Smuzhiyun 		(4 + XDR_QUADLEN(GSS_OID_MAX_LEN))) * sizeof(__be32);
2657*4882a593Smuzhiyun }
2658*4882a593Smuzhiyun 
nfsd4_setclientid_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2659*4882a593Smuzhiyun static inline u32 nfsd4_setclientid_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2660*4882a593Smuzhiyun {
2661*4882a593Smuzhiyun 	return (op_encode_hdr_size + 2 + XDR_QUADLEN(NFS4_VERIFIER_SIZE)) *
2662*4882a593Smuzhiyun 								sizeof(__be32);
2663*4882a593Smuzhiyun }
2664*4882a593Smuzhiyun 
nfsd4_write_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2665*4882a593Smuzhiyun static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2666*4882a593Smuzhiyun {
2667*4882a593Smuzhiyun 	return (op_encode_hdr_size + 2 + op_encode_verifier_maxsz) * sizeof(__be32);
2668*4882a593Smuzhiyun }
2669*4882a593Smuzhiyun 
nfsd4_exchange_id_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2670*4882a593Smuzhiyun static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2671*4882a593Smuzhiyun {
2672*4882a593Smuzhiyun 	return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\
2673*4882a593Smuzhiyun 		1 + 1 + /* eir_flags, spr_how */\
2674*4882a593Smuzhiyun 		4 + /* spo_must_enforce & _allow with bitmap */\
2675*4882a593Smuzhiyun 		2 + /*eir_server_owner.so_minor_id */\
2676*4882a593Smuzhiyun 		/* eir_server_owner.so_major_id<> */\
2677*4882a593Smuzhiyun 		XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\
2678*4882a593Smuzhiyun 		/* eir_server_scope<> */\
2679*4882a593Smuzhiyun 		XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\
2680*4882a593Smuzhiyun 		1 + /* eir_server_impl_id array length */\
2681*4882a593Smuzhiyun 		0 /* ignored eir_server_impl_id contents */) * sizeof(__be32);
2682*4882a593Smuzhiyun }
2683*4882a593Smuzhiyun 
nfsd4_bind_conn_to_session_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2684*4882a593Smuzhiyun static inline u32 nfsd4_bind_conn_to_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2685*4882a593Smuzhiyun {
2686*4882a593Smuzhiyun 	return (op_encode_hdr_size + \
2687*4882a593Smuzhiyun 		XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* bctsr_sessid */\
2688*4882a593Smuzhiyun 		2 /* bctsr_dir, use_conn_in_rdma_mode */) * sizeof(__be32);
2689*4882a593Smuzhiyun }
2690*4882a593Smuzhiyun 
nfsd4_create_session_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2691*4882a593Smuzhiyun static inline u32 nfsd4_create_session_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2692*4882a593Smuzhiyun {
2693*4882a593Smuzhiyun 	return (op_encode_hdr_size + \
2694*4882a593Smuzhiyun 		XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + /* sessionid */\
2695*4882a593Smuzhiyun 		2 + /* csr_sequence, csr_flags */\
2696*4882a593Smuzhiyun 		op_encode_channel_attrs_maxsz + \
2697*4882a593Smuzhiyun 		op_encode_channel_attrs_maxsz) * sizeof(__be32);
2698*4882a593Smuzhiyun }
2699*4882a593Smuzhiyun 
nfsd4_copy_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2700*4882a593Smuzhiyun static inline u32 nfsd4_copy_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2701*4882a593Smuzhiyun {
2702*4882a593Smuzhiyun 	return (op_encode_hdr_size +
2703*4882a593Smuzhiyun 		1 /* wr_callback */ +
2704*4882a593Smuzhiyun 		op_encode_stateid_maxsz /* wr_callback */ +
2705*4882a593Smuzhiyun 		2 /* wr_count */ +
2706*4882a593Smuzhiyun 		1 /* wr_committed */ +
2707*4882a593Smuzhiyun 		op_encode_verifier_maxsz +
2708*4882a593Smuzhiyun 		1 /* cr_consecutive */ +
2709*4882a593Smuzhiyun 		1 /* cr_synchronous */) * sizeof(__be32);
2710*4882a593Smuzhiyun }
2711*4882a593Smuzhiyun 
nfsd4_offload_status_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2712*4882a593Smuzhiyun static inline u32 nfsd4_offload_status_rsize(struct svc_rqst *rqstp,
2713*4882a593Smuzhiyun 					     struct nfsd4_op *op)
2714*4882a593Smuzhiyun {
2715*4882a593Smuzhiyun 	return (op_encode_hdr_size +
2716*4882a593Smuzhiyun 		2 /* osr_count */ +
2717*4882a593Smuzhiyun 		1 /* osr_complete<1> optional 0 for now */) * sizeof(__be32);
2718*4882a593Smuzhiyun }
2719*4882a593Smuzhiyun 
nfsd4_copy_notify_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2720*4882a593Smuzhiyun static inline u32 nfsd4_copy_notify_rsize(struct svc_rqst *rqstp,
2721*4882a593Smuzhiyun 					struct nfsd4_op *op)
2722*4882a593Smuzhiyun {
2723*4882a593Smuzhiyun 	return (op_encode_hdr_size +
2724*4882a593Smuzhiyun 		3 /* cnr_lease_time */ +
2725*4882a593Smuzhiyun 		1 /* We support one cnr_source_server */ +
2726*4882a593Smuzhiyun 		1 /* cnr_stateid seq */ +
2727*4882a593Smuzhiyun 		op_encode_stateid_maxsz /* cnr_stateid */ +
2728*4882a593Smuzhiyun 		1 /* num cnr_source_server*/ +
2729*4882a593Smuzhiyun 		1 /* nl4_type */ +
2730*4882a593Smuzhiyun 		1 /* nl4 size */ +
2731*4882a593Smuzhiyun 		XDR_QUADLEN(NFS4_OPAQUE_LIMIT) /*nl4_loc + nl4_loc_sz */)
2732*4882a593Smuzhiyun 		* sizeof(__be32);
2733*4882a593Smuzhiyun }
2734*4882a593Smuzhiyun 
2735*4882a593Smuzhiyun #ifdef CONFIG_NFSD_PNFS
nfsd4_getdeviceinfo_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2736*4882a593Smuzhiyun static inline u32 nfsd4_getdeviceinfo_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2737*4882a593Smuzhiyun {
2738*4882a593Smuzhiyun 	u32 maxcount = 0, rlen = 0;
2739*4882a593Smuzhiyun 
2740*4882a593Smuzhiyun 	maxcount = svc_max_payload(rqstp);
2741*4882a593Smuzhiyun 	rlen = min(op->u.getdeviceinfo.gd_maxcount, maxcount);
2742*4882a593Smuzhiyun 
2743*4882a593Smuzhiyun 	return (op_encode_hdr_size +
2744*4882a593Smuzhiyun 		1 /* gd_layout_type*/ +
2745*4882a593Smuzhiyun 		XDR_QUADLEN(rlen) +
2746*4882a593Smuzhiyun 		2 /* gd_notify_types */) * sizeof(__be32);
2747*4882a593Smuzhiyun }
2748*4882a593Smuzhiyun 
2749*4882a593Smuzhiyun /*
2750*4882a593Smuzhiyun  * At this stage we don't really know what layout driver will handle the request,
2751*4882a593Smuzhiyun  * so we need to define an arbitrary upper bound here.
2752*4882a593Smuzhiyun  */
2753*4882a593Smuzhiyun #define MAX_LAYOUT_SIZE		128
nfsd4_layoutget_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2754*4882a593Smuzhiyun static inline u32 nfsd4_layoutget_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2755*4882a593Smuzhiyun {
2756*4882a593Smuzhiyun 	return (op_encode_hdr_size +
2757*4882a593Smuzhiyun 		1 /* logr_return_on_close */ +
2758*4882a593Smuzhiyun 		op_encode_stateid_maxsz +
2759*4882a593Smuzhiyun 		1 /* nr of layouts */ +
2760*4882a593Smuzhiyun 		MAX_LAYOUT_SIZE) * sizeof(__be32);
2761*4882a593Smuzhiyun }
2762*4882a593Smuzhiyun 
nfsd4_layoutcommit_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2763*4882a593Smuzhiyun static inline u32 nfsd4_layoutcommit_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2764*4882a593Smuzhiyun {
2765*4882a593Smuzhiyun 	return (op_encode_hdr_size +
2766*4882a593Smuzhiyun 		1 /* locr_newsize */ +
2767*4882a593Smuzhiyun 		2 /* ns_size */) * sizeof(__be32);
2768*4882a593Smuzhiyun }
2769*4882a593Smuzhiyun 
nfsd4_layoutreturn_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2770*4882a593Smuzhiyun static inline u32 nfsd4_layoutreturn_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2771*4882a593Smuzhiyun {
2772*4882a593Smuzhiyun 	return (op_encode_hdr_size +
2773*4882a593Smuzhiyun 		1 /* lrs_stateid */ +
2774*4882a593Smuzhiyun 		op_encode_stateid_maxsz) * sizeof(__be32);
2775*4882a593Smuzhiyun }
2776*4882a593Smuzhiyun #endif /* CONFIG_NFSD_PNFS */
2777*4882a593Smuzhiyun 
2778*4882a593Smuzhiyun 
nfsd4_seek_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2779*4882a593Smuzhiyun static inline u32 nfsd4_seek_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
2780*4882a593Smuzhiyun {
2781*4882a593Smuzhiyun 	return (op_encode_hdr_size + 3) * sizeof(__be32);
2782*4882a593Smuzhiyun }
2783*4882a593Smuzhiyun 
nfsd4_getxattr_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2784*4882a593Smuzhiyun static inline u32 nfsd4_getxattr_rsize(struct svc_rqst *rqstp,
2785*4882a593Smuzhiyun 				       struct nfsd4_op *op)
2786*4882a593Smuzhiyun {
2787*4882a593Smuzhiyun 	u32 maxcount, rlen;
2788*4882a593Smuzhiyun 
2789*4882a593Smuzhiyun 	maxcount = svc_max_payload(rqstp);
2790*4882a593Smuzhiyun 	rlen = min_t(u32, XATTR_SIZE_MAX, maxcount);
2791*4882a593Smuzhiyun 
2792*4882a593Smuzhiyun 	return (op_encode_hdr_size + 1 + XDR_QUADLEN(rlen)) * sizeof(__be32);
2793*4882a593Smuzhiyun }
2794*4882a593Smuzhiyun 
nfsd4_setxattr_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2795*4882a593Smuzhiyun static inline u32 nfsd4_setxattr_rsize(struct svc_rqst *rqstp,
2796*4882a593Smuzhiyun 				       struct nfsd4_op *op)
2797*4882a593Smuzhiyun {
2798*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_change_info_maxsz)
2799*4882a593Smuzhiyun 		* sizeof(__be32);
2800*4882a593Smuzhiyun }
nfsd4_listxattrs_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2801*4882a593Smuzhiyun static inline u32 nfsd4_listxattrs_rsize(struct svc_rqst *rqstp,
2802*4882a593Smuzhiyun 					 struct nfsd4_op *op)
2803*4882a593Smuzhiyun {
2804*4882a593Smuzhiyun 	u32 maxcount, rlen;
2805*4882a593Smuzhiyun 
2806*4882a593Smuzhiyun 	maxcount = svc_max_payload(rqstp);
2807*4882a593Smuzhiyun 	rlen = min(op->u.listxattrs.lsxa_maxcount, maxcount);
2808*4882a593Smuzhiyun 
2809*4882a593Smuzhiyun 	return (op_encode_hdr_size + 4 + XDR_QUADLEN(rlen)) * sizeof(__be32);
2810*4882a593Smuzhiyun }
2811*4882a593Smuzhiyun 
nfsd4_removexattr_rsize(struct svc_rqst * rqstp,struct nfsd4_op * op)2812*4882a593Smuzhiyun static inline u32 nfsd4_removexattr_rsize(struct svc_rqst *rqstp,
2813*4882a593Smuzhiyun 					  struct nfsd4_op *op)
2814*4882a593Smuzhiyun {
2815*4882a593Smuzhiyun 	return (op_encode_hdr_size + op_encode_change_info_maxsz)
2816*4882a593Smuzhiyun 		* sizeof(__be32);
2817*4882a593Smuzhiyun }
2818*4882a593Smuzhiyun 
2819*4882a593Smuzhiyun 
2820*4882a593Smuzhiyun static const struct nfsd4_operation nfsd4_ops[] = {
2821*4882a593Smuzhiyun 	[OP_ACCESS] = {
2822*4882a593Smuzhiyun 		.op_func = nfsd4_access,
2823*4882a593Smuzhiyun 		.op_name = "OP_ACCESS",
2824*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_access_rsize,
2825*4882a593Smuzhiyun 	},
2826*4882a593Smuzhiyun 	[OP_CLOSE] = {
2827*4882a593Smuzhiyun 		.op_func = nfsd4_close,
2828*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
2829*4882a593Smuzhiyun 		.op_name = "OP_CLOSE",
2830*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_status_stateid_rsize,
2831*4882a593Smuzhiyun 		.op_get_currentstateid = nfsd4_get_closestateid,
2832*4882a593Smuzhiyun 		.op_set_currentstateid = nfsd4_set_closestateid,
2833*4882a593Smuzhiyun 	},
2834*4882a593Smuzhiyun 	[OP_COMMIT] = {
2835*4882a593Smuzhiyun 		.op_func = nfsd4_commit,
2836*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
2837*4882a593Smuzhiyun 		.op_name = "OP_COMMIT",
2838*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_commit_rsize,
2839*4882a593Smuzhiyun 	},
2840*4882a593Smuzhiyun 	[OP_CREATE] = {
2841*4882a593Smuzhiyun 		.op_func = nfsd4_create,
2842*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME | OP_CLEAR_STATEID,
2843*4882a593Smuzhiyun 		.op_name = "OP_CREATE",
2844*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_create_rsize,
2845*4882a593Smuzhiyun 	},
2846*4882a593Smuzhiyun 	[OP_DELEGRETURN] = {
2847*4882a593Smuzhiyun 		.op_func = nfsd4_delegreturn,
2848*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
2849*4882a593Smuzhiyun 		.op_name = "OP_DELEGRETURN",
2850*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
2851*4882a593Smuzhiyun 		.op_get_currentstateid = nfsd4_get_delegreturnstateid,
2852*4882a593Smuzhiyun 	},
2853*4882a593Smuzhiyun 	[OP_GETATTR] = {
2854*4882a593Smuzhiyun 		.op_func = nfsd4_getattr,
2855*4882a593Smuzhiyun 		.op_flags = ALLOWED_ON_ABSENT_FS,
2856*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_getattr_rsize,
2857*4882a593Smuzhiyun 		.op_name = "OP_GETATTR",
2858*4882a593Smuzhiyun 	},
2859*4882a593Smuzhiyun 	[OP_GETFH] = {
2860*4882a593Smuzhiyun 		.op_func = nfsd4_getfh,
2861*4882a593Smuzhiyun 		.op_name = "OP_GETFH",
2862*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_getfh_rsize,
2863*4882a593Smuzhiyun 	},
2864*4882a593Smuzhiyun 	[OP_LINK] = {
2865*4882a593Smuzhiyun 		.op_func = nfsd4_link,
2866*4882a593Smuzhiyun 		.op_flags = ALLOWED_ON_ABSENT_FS | OP_MODIFIES_SOMETHING
2867*4882a593Smuzhiyun 				| OP_CACHEME,
2868*4882a593Smuzhiyun 		.op_name = "OP_LINK",
2869*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_link_rsize,
2870*4882a593Smuzhiyun 	},
2871*4882a593Smuzhiyun 	[OP_LOCK] = {
2872*4882a593Smuzhiyun 		.op_func = nfsd4_lock,
2873*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING |
2874*4882a593Smuzhiyun 				OP_NONTRIVIAL_ERROR_ENCODE,
2875*4882a593Smuzhiyun 		.op_name = "OP_LOCK",
2876*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_lock_rsize,
2877*4882a593Smuzhiyun 		.op_set_currentstateid = nfsd4_set_lockstateid,
2878*4882a593Smuzhiyun 	},
2879*4882a593Smuzhiyun 	[OP_LOCKT] = {
2880*4882a593Smuzhiyun 		.op_func = nfsd4_lockt,
2881*4882a593Smuzhiyun 		.op_flags = OP_NONTRIVIAL_ERROR_ENCODE,
2882*4882a593Smuzhiyun 		.op_name = "OP_LOCKT",
2883*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_lock_rsize,
2884*4882a593Smuzhiyun 	},
2885*4882a593Smuzhiyun 	[OP_LOCKU] = {
2886*4882a593Smuzhiyun 		.op_func = nfsd4_locku,
2887*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
2888*4882a593Smuzhiyun 		.op_name = "OP_LOCKU",
2889*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_status_stateid_rsize,
2890*4882a593Smuzhiyun 		.op_get_currentstateid = nfsd4_get_lockustateid,
2891*4882a593Smuzhiyun 	},
2892*4882a593Smuzhiyun 	[OP_LOOKUP] = {
2893*4882a593Smuzhiyun 		.op_func = nfsd4_lookup,
2894*4882a593Smuzhiyun 		.op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
2895*4882a593Smuzhiyun 		.op_name = "OP_LOOKUP",
2896*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
2897*4882a593Smuzhiyun 	},
2898*4882a593Smuzhiyun 	[OP_LOOKUPP] = {
2899*4882a593Smuzhiyun 		.op_func = nfsd4_lookupp,
2900*4882a593Smuzhiyun 		.op_flags = OP_HANDLES_WRONGSEC | OP_CLEAR_STATEID,
2901*4882a593Smuzhiyun 		.op_name = "OP_LOOKUPP",
2902*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
2903*4882a593Smuzhiyun 	},
2904*4882a593Smuzhiyun 	[OP_NVERIFY] = {
2905*4882a593Smuzhiyun 		.op_func = nfsd4_nverify,
2906*4882a593Smuzhiyun 		.op_name = "OP_NVERIFY",
2907*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
2908*4882a593Smuzhiyun 	},
2909*4882a593Smuzhiyun 	[OP_OPEN] = {
2910*4882a593Smuzhiyun 		.op_func = nfsd4_open,
2911*4882a593Smuzhiyun 		.op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
2912*4882a593Smuzhiyun 		.op_name = "OP_OPEN",
2913*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_open_rsize,
2914*4882a593Smuzhiyun 		.op_set_currentstateid = nfsd4_set_openstateid,
2915*4882a593Smuzhiyun 	},
2916*4882a593Smuzhiyun 	[OP_OPEN_CONFIRM] = {
2917*4882a593Smuzhiyun 		.op_func = nfsd4_open_confirm,
2918*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
2919*4882a593Smuzhiyun 		.op_name = "OP_OPEN_CONFIRM",
2920*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_status_stateid_rsize,
2921*4882a593Smuzhiyun 	},
2922*4882a593Smuzhiyun 	[OP_OPEN_DOWNGRADE] = {
2923*4882a593Smuzhiyun 		.op_func = nfsd4_open_downgrade,
2924*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
2925*4882a593Smuzhiyun 		.op_name = "OP_OPEN_DOWNGRADE",
2926*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_status_stateid_rsize,
2927*4882a593Smuzhiyun 		.op_get_currentstateid = nfsd4_get_opendowngradestateid,
2928*4882a593Smuzhiyun 		.op_set_currentstateid = nfsd4_set_opendowngradestateid,
2929*4882a593Smuzhiyun 	},
2930*4882a593Smuzhiyun 	[OP_PUTFH] = {
2931*4882a593Smuzhiyun 		.op_func = nfsd4_putfh,
2932*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
2933*4882a593Smuzhiyun 				| OP_IS_PUTFH_LIKE | OP_CLEAR_STATEID,
2934*4882a593Smuzhiyun 		.op_name = "OP_PUTFH",
2935*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
2936*4882a593Smuzhiyun 	},
2937*4882a593Smuzhiyun 	[OP_PUTPUBFH] = {
2938*4882a593Smuzhiyun 		.op_func = nfsd4_putrootfh,
2939*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
2940*4882a593Smuzhiyun 				| OP_IS_PUTFH_LIKE | OP_CLEAR_STATEID,
2941*4882a593Smuzhiyun 		.op_name = "OP_PUTPUBFH",
2942*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
2943*4882a593Smuzhiyun 	},
2944*4882a593Smuzhiyun 	[OP_PUTROOTFH] = {
2945*4882a593Smuzhiyun 		.op_func = nfsd4_putrootfh,
2946*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
2947*4882a593Smuzhiyun 				| OP_IS_PUTFH_LIKE | OP_CLEAR_STATEID,
2948*4882a593Smuzhiyun 		.op_name = "OP_PUTROOTFH",
2949*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
2950*4882a593Smuzhiyun 	},
2951*4882a593Smuzhiyun 	[OP_READ] = {
2952*4882a593Smuzhiyun 		.op_func = nfsd4_read,
2953*4882a593Smuzhiyun 		.op_release = nfsd4_read_release,
2954*4882a593Smuzhiyun 		.op_name = "OP_READ",
2955*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_read_rsize,
2956*4882a593Smuzhiyun 		.op_get_currentstateid = nfsd4_get_readstateid,
2957*4882a593Smuzhiyun 	},
2958*4882a593Smuzhiyun 	[OP_READDIR] = {
2959*4882a593Smuzhiyun 		.op_func = nfsd4_readdir,
2960*4882a593Smuzhiyun 		.op_name = "OP_READDIR",
2961*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_readdir_rsize,
2962*4882a593Smuzhiyun 	},
2963*4882a593Smuzhiyun 	[OP_READLINK] = {
2964*4882a593Smuzhiyun 		.op_func = nfsd4_readlink,
2965*4882a593Smuzhiyun 		.op_name = "OP_READLINK",
2966*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_readlink_rsize,
2967*4882a593Smuzhiyun 	},
2968*4882a593Smuzhiyun 	[OP_REMOVE] = {
2969*4882a593Smuzhiyun 		.op_func = nfsd4_remove,
2970*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
2971*4882a593Smuzhiyun 		.op_name = "OP_REMOVE",
2972*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_remove_rsize,
2973*4882a593Smuzhiyun 	},
2974*4882a593Smuzhiyun 	[OP_RENAME] = {
2975*4882a593Smuzhiyun 		.op_func = nfsd4_rename,
2976*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
2977*4882a593Smuzhiyun 		.op_name = "OP_RENAME",
2978*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_rename_rsize,
2979*4882a593Smuzhiyun 	},
2980*4882a593Smuzhiyun 	[OP_RENEW] = {
2981*4882a593Smuzhiyun 		.op_func = nfsd4_renew,
2982*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
2983*4882a593Smuzhiyun 				| OP_MODIFIES_SOMETHING,
2984*4882a593Smuzhiyun 		.op_name = "OP_RENEW",
2985*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
2986*4882a593Smuzhiyun 
2987*4882a593Smuzhiyun 	},
2988*4882a593Smuzhiyun 	[OP_RESTOREFH] = {
2989*4882a593Smuzhiyun 		.op_func = nfsd4_restorefh,
2990*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
2991*4882a593Smuzhiyun 				| OP_IS_PUTFH_LIKE | OP_MODIFIES_SOMETHING,
2992*4882a593Smuzhiyun 		.op_name = "OP_RESTOREFH",
2993*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
2994*4882a593Smuzhiyun 	},
2995*4882a593Smuzhiyun 	[OP_SAVEFH] = {
2996*4882a593Smuzhiyun 		.op_func = nfsd4_savefh,
2997*4882a593Smuzhiyun 		.op_flags = OP_HANDLES_WRONGSEC | OP_MODIFIES_SOMETHING,
2998*4882a593Smuzhiyun 		.op_name = "OP_SAVEFH",
2999*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3000*4882a593Smuzhiyun 	},
3001*4882a593Smuzhiyun 	[OP_SECINFO] = {
3002*4882a593Smuzhiyun 		.op_func = nfsd4_secinfo,
3003*4882a593Smuzhiyun 		.op_release = nfsd4_secinfo_release,
3004*4882a593Smuzhiyun 		.op_flags = OP_HANDLES_WRONGSEC,
3005*4882a593Smuzhiyun 		.op_name = "OP_SECINFO",
3006*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_secinfo_rsize,
3007*4882a593Smuzhiyun 	},
3008*4882a593Smuzhiyun 	[OP_SETATTR] = {
3009*4882a593Smuzhiyun 		.op_func = nfsd4_setattr,
3010*4882a593Smuzhiyun 		.op_name = "OP_SETATTR",
3011*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME
3012*4882a593Smuzhiyun 				| OP_NONTRIVIAL_ERROR_ENCODE,
3013*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_setattr_rsize,
3014*4882a593Smuzhiyun 		.op_get_currentstateid = nfsd4_get_setattrstateid,
3015*4882a593Smuzhiyun 	},
3016*4882a593Smuzhiyun 	[OP_SETCLIENTID] = {
3017*4882a593Smuzhiyun 		.op_func = nfsd4_setclientid,
3018*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
3019*4882a593Smuzhiyun 				| OP_MODIFIES_SOMETHING | OP_CACHEME
3020*4882a593Smuzhiyun 				| OP_NONTRIVIAL_ERROR_ENCODE,
3021*4882a593Smuzhiyun 		.op_name = "OP_SETCLIENTID",
3022*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_setclientid_rsize,
3023*4882a593Smuzhiyun 	},
3024*4882a593Smuzhiyun 	[OP_SETCLIENTID_CONFIRM] = {
3025*4882a593Smuzhiyun 		.op_func = nfsd4_setclientid_confirm,
3026*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
3027*4882a593Smuzhiyun 				| OP_MODIFIES_SOMETHING | OP_CACHEME,
3028*4882a593Smuzhiyun 		.op_name = "OP_SETCLIENTID_CONFIRM",
3029*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3030*4882a593Smuzhiyun 	},
3031*4882a593Smuzhiyun 	[OP_VERIFY] = {
3032*4882a593Smuzhiyun 		.op_func = nfsd4_verify,
3033*4882a593Smuzhiyun 		.op_name = "OP_VERIFY",
3034*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3035*4882a593Smuzhiyun 	},
3036*4882a593Smuzhiyun 	[OP_WRITE] = {
3037*4882a593Smuzhiyun 		.op_func = nfsd4_write,
3038*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
3039*4882a593Smuzhiyun 		.op_name = "OP_WRITE",
3040*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_write_rsize,
3041*4882a593Smuzhiyun 		.op_get_currentstateid = nfsd4_get_writestateid,
3042*4882a593Smuzhiyun 	},
3043*4882a593Smuzhiyun 	[OP_RELEASE_LOCKOWNER] = {
3044*4882a593Smuzhiyun 		.op_func = nfsd4_release_lockowner,
3045*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS
3046*4882a593Smuzhiyun 				| OP_MODIFIES_SOMETHING,
3047*4882a593Smuzhiyun 		.op_name = "OP_RELEASE_LOCKOWNER",
3048*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3049*4882a593Smuzhiyun 	},
3050*4882a593Smuzhiyun 
3051*4882a593Smuzhiyun 	/* NFSv4.1 operations */
3052*4882a593Smuzhiyun 	[OP_EXCHANGE_ID] = {
3053*4882a593Smuzhiyun 		.op_func = nfsd4_exchange_id,
3054*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
3055*4882a593Smuzhiyun 				| OP_MODIFIES_SOMETHING,
3056*4882a593Smuzhiyun 		.op_name = "OP_EXCHANGE_ID",
3057*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_exchange_id_rsize,
3058*4882a593Smuzhiyun 	},
3059*4882a593Smuzhiyun 	[OP_BACKCHANNEL_CTL] = {
3060*4882a593Smuzhiyun 		.op_func = nfsd4_backchannel_ctl,
3061*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
3062*4882a593Smuzhiyun 		.op_name = "OP_BACKCHANNEL_CTL",
3063*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3064*4882a593Smuzhiyun 	},
3065*4882a593Smuzhiyun 	[OP_BIND_CONN_TO_SESSION] = {
3066*4882a593Smuzhiyun 		.op_func = nfsd4_bind_conn_to_session,
3067*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
3068*4882a593Smuzhiyun 				| OP_MODIFIES_SOMETHING,
3069*4882a593Smuzhiyun 		.op_name = "OP_BIND_CONN_TO_SESSION",
3070*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_bind_conn_to_session_rsize,
3071*4882a593Smuzhiyun 	},
3072*4882a593Smuzhiyun 	[OP_CREATE_SESSION] = {
3073*4882a593Smuzhiyun 		.op_func = nfsd4_create_session,
3074*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
3075*4882a593Smuzhiyun 				| OP_MODIFIES_SOMETHING,
3076*4882a593Smuzhiyun 		.op_name = "OP_CREATE_SESSION",
3077*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_create_session_rsize,
3078*4882a593Smuzhiyun 	},
3079*4882a593Smuzhiyun 	[OP_DESTROY_SESSION] = {
3080*4882a593Smuzhiyun 		.op_func = nfsd4_destroy_session,
3081*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
3082*4882a593Smuzhiyun 				| OP_MODIFIES_SOMETHING,
3083*4882a593Smuzhiyun 		.op_name = "OP_DESTROY_SESSION",
3084*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3085*4882a593Smuzhiyun 	},
3086*4882a593Smuzhiyun 	[OP_SEQUENCE] = {
3087*4882a593Smuzhiyun 		.op_func = nfsd4_sequence,
3088*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
3089*4882a593Smuzhiyun 		.op_name = "OP_SEQUENCE",
3090*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_sequence_rsize,
3091*4882a593Smuzhiyun 	},
3092*4882a593Smuzhiyun 	[OP_DESTROY_CLIENTID] = {
3093*4882a593Smuzhiyun 		.op_func = nfsd4_destroy_clientid,
3094*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP
3095*4882a593Smuzhiyun 				| OP_MODIFIES_SOMETHING,
3096*4882a593Smuzhiyun 		.op_name = "OP_DESTROY_CLIENTID",
3097*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3098*4882a593Smuzhiyun 	},
3099*4882a593Smuzhiyun 	[OP_RECLAIM_COMPLETE] = {
3100*4882a593Smuzhiyun 		.op_func = nfsd4_reclaim_complete,
3101*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
3102*4882a593Smuzhiyun 		.op_name = "OP_RECLAIM_COMPLETE",
3103*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3104*4882a593Smuzhiyun 	},
3105*4882a593Smuzhiyun 	[OP_SECINFO_NO_NAME] = {
3106*4882a593Smuzhiyun 		.op_func = nfsd4_secinfo_no_name,
3107*4882a593Smuzhiyun 		.op_release = nfsd4_secinfo_no_name_release,
3108*4882a593Smuzhiyun 		.op_flags = OP_HANDLES_WRONGSEC,
3109*4882a593Smuzhiyun 		.op_name = "OP_SECINFO_NO_NAME",
3110*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_secinfo_rsize,
3111*4882a593Smuzhiyun 	},
3112*4882a593Smuzhiyun 	[OP_TEST_STATEID] = {
3113*4882a593Smuzhiyun 		.op_func = nfsd4_test_stateid,
3114*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH,
3115*4882a593Smuzhiyun 		.op_name = "OP_TEST_STATEID",
3116*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_test_stateid_rsize,
3117*4882a593Smuzhiyun 	},
3118*4882a593Smuzhiyun 	[OP_FREE_STATEID] = {
3119*4882a593Smuzhiyun 		.op_func = nfsd4_free_stateid,
3120*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH | OP_MODIFIES_SOMETHING,
3121*4882a593Smuzhiyun 		.op_name = "OP_FREE_STATEID",
3122*4882a593Smuzhiyun 		.op_get_currentstateid = nfsd4_get_freestateid,
3123*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3124*4882a593Smuzhiyun 	},
3125*4882a593Smuzhiyun #ifdef CONFIG_NFSD_PNFS
3126*4882a593Smuzhiyun 	[OP_GETDEVICEINFO] = {
3127*4882a593Smuzhiyun 		.op_func = nfsd4_getdeviceinfo,
3128*4882a593Smuzhiyun 		.op_release = nfsd4_getdeviceinfo_release,
3129*4882a593Smuzhiyun 		.op_flags = ALLOWED_WITHOUT_FH,
3130*4882a593Smuzhiyun 		.op_name = "OP_GETDEVICEINFO",
3131*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_getdeviceinfo_rsize,
3132*4882a593Smuzhiyun 	},
3133*4882a593Smuzhiyun 	[OP_LAYOUTGET] = {
3134*4882a593Smuzhiyun 		.op_func = nfsd4_layoutget,
3135*4882a593Smuzhiyun 		.op_release = nfsd4_layoutget_release,
3136*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
3137*4882a593Smuzhiyun 		.op_name = "OP_LAYOUTGET",
3138*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_layoutget_rsize,
3139*4882a593Smuzhiyun 	},
3140*4882a593Smuzhiyun 	[OP_LAYOUTCOMMIT] = {
3141*4882a593Smuzhiyun 		.op_func = nfsd4_layoutcommit,
3142*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
3143*4882a593Smuzhiyun 		.op_name = "OP_LAYOUTCOMMIT",
3144*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_layoutcommit_rsize,
3145*4882a593Smuzhiyun 	},
3146*4882a593Smuzhiyun 	[OP_LAYOUTRETURN] = {
3147*4882a593Smuzhiyun 		.op_func = nfsd4_layoutreturn,
3148*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
3149*4882a593Smuzhiyun 		.op_name = "OP_LAYOUTRETURN",
3150*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_layoutreturn_rsize,
3151*4882a593Smuzhiyun 	},
3152*4882a593Smuzhiyun #endif /* CONFIG_NFSD_PNFS */
3153*4882a593Smuzhiyun 
3154*4882a593Smuzhiyun 	/* NFSv4.2 operations */
3155*4882a593Smuzhiyun 	[OP_ALLOCATE] = {
3156*4882a593Smuzhiyun 		.op_func = nfsd4_allocate,
3157*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
3158*4882a593Smuzhiyun 		.op_name = "OP_ALLOCATE",
3159*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3160*4882a593Smuzhiyun 	},
3161*4882a593Smuzhiyun 	[OP_DEALLOCATE] = {
3162*4882a593Smuzhiyun 		.op_func = nfsd4_deallocate,
3163*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
3164*4882a593Smuzhiyun 		.op_name = "OP_DEALLOCATE",
3165*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3166*4882a593Smuzhiyun 	},
3167*4882a593Smuzhiyun 	[OP_CLONE] = {
3168*4882a593Smuzhiyun 		.op_func = nfsd4_clone,
3169*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
3170*4882a593Smuzhiyun 		.op_name = "OP_CLONE",
3171*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3172*4882a593Smuzhiyun 	},
3173*4882a593Smuzhiyun 	[OP_COPY] = {
3174*4882a593Smuzhiyun 		.op_func = nfsd4_copy,
3175*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
3176*4882a593Smuzhiyun 		.op_name = "OP_COPY",
3177*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_copy_rsize,
3178*4882a593Smuzhiyun 	},
3179*4882a593Smuzhiyun 	[OP_READ_PLUS] = {
3180*4882a593Smuzhiyun 		.op_func = nfsd4_read,
3181*4882a593Smuzhiyun 		.op_release = nfsd4_read_release,
3182*4882a593Smuzhiyun 		.op_name = "OP_READ_PLUS",
3183*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_read_plus_rsize,
3184*4882a593Smuzhiyun 		.op_get_currentstateid = nfsd4_get_readstateid,
3185*4882a593Smuzhiyun 	},
3186*4882a593Smuzhiyun 	[OP_SEEK] = {
3187*4882a593Smuzhiyun 		.op_func = nfsd4_seek,
3188*4882a593Smuzhiyun 		.op_name = "OP_SEEK",
3189*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_seek_rsize,
3190*4882a593Smuzhiyun 	},
3191*4882a593Smuzhiyun 	[OP_OFFLOAD_STATUS] = {
3192*4882a593Smuzhiyun 		.op_func = nfsd4_offload_status,
3193*4882a593Smuzhiyun 		.op_name = "OP_OFFLOAD_STATUS",
3194*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_offload_status_rsize,
3195*4882a593Smuzhiyun 	},
3196*4882a593Smuzhiyun 	[OP_OFFLOAD_CANCEL] = {
3197*4882a593Smuzhiyun 		.op_func = nfsd4_offload_cancel,
3198*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
3199*4882a593Smuzhiyun 		.op_name = "OP_OFFLOAD_CANCEL",
3200*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_only_status_rsize,
3201*4882a593Smuzhiyun 	},
3202*4882a593Smuzhiyun 	[OP_COPY_NOTIFY] = {
3203*4882a593Smuzhiyun 		.op_func = nfsd4_copy_notify,
3204*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING,
3205*4882a593Smuzhiyun 		.op_name = "OP_COPY_NOTIFY",
3206*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_copy_notify_rsize,
3207*4882a593Smuzhiyun 	},
3208*4882a593Smuzhiyun 	[OP_GETXATTR] = {
3209*4882a593Smuzhiyun 		.op_func = nfsd4_getxattr,
3210*4882a593Smuzhiyun 		.op_name = "OP_GETXATTR",
3211*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_getxattr_rsize,
3212*4882a593Smuzhiyun 	},
3213*4882a593Smuzhiyun 	[OP_SETXATTR] = {
3214*4882a593Smuzhiyun 		.op_func = nfsd4_setxattr,
3215*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
3216*4882a593Smuzhiyun 		.op_name = "OP_SETXATTR",
3217*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_setxattr_rsize,
3218*4882a593Smuzhiyun 	},
3219*4882a593Smuzhiyun 	[OP_LISTXATTRS] = {
3220*4882a593Smuzhiyun 		.op_func = nfsd4_listxattrs,
3221*4882a593Smuzhiyun 		.op_name = "OP_LISTXATTRS",
3222*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_listxattrs_rsize,
3223*4882a593Smuzhiyun 	},
3224*4882a593Smuzhiyun 	[OP_REMOVEXATTR] = {
3225*4882a593Smuzhiyun 		.op_func = nfsd4_removexattr,
3226*4882a593Smuzhiyun 		.op_flags = OP_MODIFIES_SOMETHING | OP_CACHEME,
3227*4882a593Smuzhiyun 		.op_name = "OP_REMOVEXATTR",
3228*4882a593Smuzhiyun 		.op_rsize_bop = nfsd4_removexattr_rsize,
3229*4882a593Smuzhiyun 	},
3230*4882a593Smuzhiyun };
3231*4882a593Smuzhiyun 
3232*4882a593Smuzhiyun /**
3233*4882a593Smuzhiyun  * nfsd4_spo_must_allow - Determine if the compound op contains an
3234*4882a593Smuzhiyun  * operation that is allowed to be sent with machine credentials
3235*4882a593Smuzhiyun  *
3236*4882a593Smuzhiyun  * @rqstp: a pointer to the struct svc_rqst
3237*4882a593Smuzhiyun  *
3238*4882a593Smuzhiyun  * Checks to see if the compound contains a spo_must_allow op
3239*4882a593Smuzhiyun  * and confirms that it was sent with the proper machine creds.
3240*4882a593Smuzhiyun  */
3241*4882a593Smuzhiyun 
nfsd4_spo_must_allow(struct svc_rqst * rqstp)3242*4882a593Smuzhiyun bool nfsd4_spo_must_allow(struct svc_rqst *rqstp)
3243*4882a593Smuzhiyun {
3244*4882a593Smuzhiyun 	struct nfsd4_compoundres *resp = rqstp->rq_resp;
3245*4882a593Smuzhiyun 	struct nfsd4_compoundargs *argp = rqstp->rq_argp;
3246*4882a593Smuzhiyun 	struct nfsd4_op *this = &argp->ops[resp->opcnt - 1];
3247*4882a593Smuzhiyun 	struct nfsd4_compound_state *cstate = &resp->cstate;
3248*4882a593Smuzhiyun 	struct nfs4_op_map *allow = &cstate->clp->cl_spo_must_allow;
3249*4882a593Smuzhiyun 	u32 opiter;
3250*4882a593Smuzhiyun 
3251*4882a593Smuzhiyun 	if (!cstate->minorversion)
3252*4882a593Smuzhiyun 		return false;
3253*4882a593Smuzhiyun 
3254*4882a593Smuzhiyun 	if (cstate->spo_must_allowed)
3255*4882a593Smuzhiyun 		return true;
3256*4882a593Smuzhiyun 
3257*4882a593Smuzhiyun 	opiter = resp->opcnt;
3258*4882a593Smuzhiyun 	while (opiter < argp->opcnt) {
3259*4882a593Smuzhiyun 		this = &argp->ops[opiter++];
3260*4882a593Smuzhiyun 		if (test_bit(this->opnum, allow->u.longs) &&
3261*4882a593Smuzhiyun 			cstate->clp->cl_mach_cred &&
3262*4882a593Smuzhiyun 			nfsd4_mach_creds_match(cstate->clp, rqstp)) {
3263*4882a593Smuzhiyun 			cstate->spo_must_allowed = true;
3264*4882a593Smuzhiyun 			return true;
3265*4882a593Smuzhiyun 		}
3266*4882a593Smuzhiyun 	}
3267*4882a593Smuzhiyun 	cstate->spo_must_allowed = false;
3268*4882a593Smuzhiyun 	return false;
3269*4882a593Smuzhiyun }
3270*4882a593Smuzhiyun 
nfsd4_max_reply(struct svc_rqst * rqstp,struct nfsd4_op * op)3271*4882a593Smuzhiyun int nfsd4_max_reply(struct svc_rqst *rqstp, struct nfsd4_op *op)
3272*4882a593Smuzhiyun {
3273*4882a593Smuzhiyun 	if (op->opnum == OP_ILLEGAL || op->status == nfserr_notsupp)
3274*4882a593Smuzhiyun 		return op_encode_hdr_size * sizeof(__be32);
3275*4882a593Smuzhiyun 
3276*4882a593Smuzhiyun 	BUG_ON(OPDESC(op)->op_rsize_bop == NULL);
3277*4882a593Smuzhiyun 	return OPDESC(op)->op_rsize_bop(rqstp, op);
3278*4882a593Smuzhiyun }
3279*4882a593Smuzhiyun 
warn_on_nonidempotent_op(struct nfsd4_op * op)3280*4882a593Smuzhiyun void warn_on_nonidempotent_op(struct nfsd4_op *op)
3281*4882a593Smuzhiyun {
3282*4882a593Smuzhiyun 	if (OPDESC(op)->op_flags & OP_MODIFIES_SOMETHING) {
3283*4882a593Smuzhiyun 		pr_err("unable to encode reply to nonidempotent op %d (%s)\n",
3284*4882a593Smuzhiyun 			op->opnum, nfsd4_op_name(op->opnum));
3285*4882a593Smuzhiyun 		WARN_ON_ONCE(1);
3286*4882a593Smuzhiyun 	}
3287*4882a593Smuzhiyun }
3288*4882a593Smuzhiyun 
nfsd4_op_name(unsigned opnum)3289*4882a593Smuzhiyun static const char *nfsd4_op_name(unsigned opnum)
3290*4882a593Smuzhiyun {
3291*4882a593Smuzhiyun 	if (opnum < ARRAY_SIZE(nfsd4_ops))
3292*4882a593Smuzhiyun 		return nfsd4_ops[opnum].op_name;
3293*4882a593Smuzhiyun 	return "unknown_operation";
3294*4882a593Smuzhiyun }
3295*4882a593Smuzhiyun 
3296*4882a593Smuzhiyun #define nfsd4_voidres			nfsd4_voidargs
3297*4882a593Smuzhiyun struct nfsd4_voidargs { int dummy; };
3298*4882a593Smuzhiyun 
3299*4882a593Smuzhiyun static const struct svc_procedure nfsd_procedures4[2] = {
3300*4882a593Smuzhiyun 	[NFSPROC4_NULL] = {
3301*4882a593Smuzhiyun 		.pc_func = nfsd4_proc_null,
3302*4882a593Smuzhiyun 		.pc_decode = nfs4svc_decode_voidarg,
3303*4882a593Smuzhiyun 		.pc_encode = nfs4svc_encode_voidres,
3304*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd4_voidargs),
3305*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd4_voidres),
3306*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
3307*4882a593Smuzhiyun 		.pc_xdrressize = 1,
3308*4882a593Smuzhiyun 	},
3309*4882a593Smuzhiyun 	[NFSPROC4_COMPOUND] = {
3310*4882a593Smuzhiyun 		.pc_func = nfsd4_proc_compound,
3311*4882a593Smuzhiyun 		.pc_decode = nfs4svc_decode_compoundargs,
3312*4882a593Smuzhiyun 		.pc_encode = nfs4svc_encode_compoundres,
3313*4882a593Smuzhiyun 		.pc_argsize = sizeof(struct nfsd4_compoundargs),
3314*4882a593Smuzhiyun 		.pc_ressize = sizeof(struct nfsd4_compoundres),
3315*4882a593Smuzhiyun 		.pc_release = nfsd4_release_compoundargs,
3316*4882a593Smuzhiyun 		.pc_cachetype = RC_NOCACHE,
3317*4882a593Smuzhiyun 		.pc_xdrressize = NFSD_BUFSIZE/4,
3318*4882a593Smuzhiyun 	},
3319*4882a593Smuzhiyun };
3320*4882a593Smuzhiyun 
3321*4882a593Smuzhiyun static unsigned int nfsd_count3[ARRAY_SIZE(nfsd_procedures4)];
3322*4882a593Smuzhiyun const struct svc_version nfsd_version4 = {
3323*4882a593Smuzhiyun 	.vs_vers		= 4,
3324*4882a593Smuzhiyun 	.vs_nproc		= 2,
3325*4882a593Smuzhiyun 	.vs_proc		= nfsd_procedures4,
3326*4882a593Smuzhiyun 	.vs_count		= nfsd_count3,
3327*4882a593Smuzhiyun 	.vs_dispatch		= nfsd_dispatch,
3328*4882a593Smuzhiyun 	.vs_xdrsize		= NFS4_SVC_XDRSIZE,
3329*4882a593Smuzhiyun 	.vs_rpcb_optnl		= true,
3330*4882a593Smuzhiyun 	.vs_need_cong_ctrl	= true,
3331*4882a593Smuzhiyun };
3332*4882a593Smuzhiyun 
3333*4882a593Smuzhiyun /*
3334*4882a593Smuzhiyun  * Local variables:
3335*4882a593Smuzhiyun  *  c-basic-offset: 8
3336*4882a593Smuzhiyun  * End:
3337*4882a593Smuzhiyun  */
3338