nfs4proc.c 36.8 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/*
 *  fs/nfsd/nfs4proc.c
 *
 *  Server-side procedures for NFSv4.
 *
 *  Copyright (c) 2002 The Regents of the University of Michigan.
 *  All rights reserved.
 *
 *  Kendrick Smith <kmsmith@umich.edu>
 *  Andy Adamson   <andros@umich.edu>
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the University nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <linux/param.h>
#include <linux/major.h>
#include <linux/slab.h>
41
#include <linux/file.h>
L
Linus Torvalds 已提交
42 43 44 45 46 47 48 49

#include <linux/sunrpc/svc.h>
#include <linux/nfsd/nfsd.h>
#include <linux/nfsd/cache.h>
#include <linux/nfs4.h>
#include <linux/nfsd/state.h>
#include <linux/nfsd/xdr4.h>
#include <linux/nfs4_acl.h>
A
Andy Adamson 已提交
50
#include <linux/sunrpc/gss_api.h>
L
Linus Torvalds 已提交
51 52 53

#define NFSDDBG_FACILITY		NFSDDBG_PROC

54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
static u32 nfsd_attrmask[] = {
	NFSD_WRITEABLE_ATTRS_WORD0,
	NFSD_WRITEABLE_ATTRS_WORD1,
	NFSD_WRITEABLE_ATTRS_WORD2
};

static u32 nfsd41_ex_attrmask[] = {
	NFSD_SUPPATTR_EXCLCREAT_WORD0,
	NFSD_SUPPATTR_EXCLCREAT_WORD1,
	NFSD_SUPPATTR_EXCLCREAT_WORD2
};

static __be32
check_attr_support(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		   u32 *bmval, u32 *writable)
{
	struct dentry *dentry = cstate->current_fh.fh_dentry;
	struct svc_export *exp = cstate->current_fh.fh_export;

	/*
	 * Check about attributes are supported by the NFSv4 server or not.
	 * According to spec, unsupported attributes return ERR_ATTRNOTSUPP.
	 */
	if ((bmval[0] & ~nfsd_suppattrs0(cstate->minorversion)) ||
	    (bmval[1] & ~nfsd_suppattrs1(cstate->minorversion)) ||
	    (bmval[2] & ~nfsd_suppattrs2(cstate->minorversion)))
		return nfserr_attrnotsupp;

	/*
	 * Check FATTR4_WORD0_ACL & FATTR4_WORD0_FS_LOCATIONS can be supported
	 * in current environment or not.
	 */
	if (bmval[0] & FATTR4_WORD0_ACL) {
		if (!IS_POSIXACL(dentry->d_inode))
			return nfserr_attrnotsupp;
	}
	if (bmval[0] & FATTR4_WORD0_FS_LOCATIONS) {
		if (exp->ex_fslocs.locations == NULL)
			return nfserr_attrnotsupp;
	}

	/*
	 * According to spec, read-only attributes return ERR_INVAL.
	 */
	if (writable) {
		if ((bmval[0] & ~writable[0]) || (bmval[1] & ~writable[1]) ||
		    (bmval[2] & ~writable[2]))
			return nfserr_inval;
	}

	return nfs_ok;
}

static __be32
nfsd4_check_open_attributes(struct svc_rqst *rqstp,
	struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
{
	__be32 status = nfs_ok;

	if (open->op_create == NFS4_OPEN_CREATE) {
		if (open->op_createmode == NFS4_CREATE_UNCHECKED
		    || open->op_createmode == NFS4_CREATE_GUARDED)
			status = check_attr_support(rqstp, cstate,
					open->op_bmval, nfsd_attrmask);
		else if (open->op_createmode == NFS4_CREATE_EXCLUSIVE4_1)
			status = check_attr_support(rqstp, cstate,
					open->op_bmval, nfsd41_ex_attrmask);
	}

	return status;
}

L
Linus Torvalds 已提交
126 127 128 129 130 131 132 133 134 135
static inline void
fh_dup2(struct svc_fh *dst, struct svc_fh *src)
{
	fh_put(dst);
	dget(src->fh_dentry);
	if (src->fh_export)
		cache_get(&src->fh_export->h);
	*dst = *src;
}

136
static __be32
137
do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode)
L
Linus Torvalds 已提交
138
{
139
	__be32 status;
L
Linus Torvalds 已提交
140 141 142 143 144 145

	if (open->op_truncate &&
		!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
		return nfserr_inval;

	if (open->op_share_access & NFS4_SHARE_ACCESS_READ)
M
Miklos Szeredi 已提交
146
		accmode |= NFSD_MAY_READ;
147
	if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
M
Miklos Szeredi 已提交
148
		accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC);
149
	if (open->op_share_deny & NFS4_SHARE_DENY_WRITE)
M
Miklos Szeredi 已提交
150
		accmode |= NFSD_MAY_WRITE;
L
Linus Torvalds 已提交
151 152 153 154 155 156

	status = fh_verify(rqstp, current_fh, S_IFREG, accmode);

	return status;
}

157
static __be32
L
Linus Torvalds 已提交
158 159 160
do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
	struct svc_fh resfh;
161
	__be32 status;
162
	int created = 0;
L
Linus Torvalds 已提交
163 164 165 166 167

	fh_init(&resfh, NFS4_FHSIZE);
	open->op_truncate = 0;

	if (open->op_create) {
B
Benny Halevy 已提交
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182
		/* FIXME: check session persistence and pnfs flags.
		 * The nfsv4.1 spec requires the following semantics:
		 *
		 * Persistent   | pNFS   | Server REQUIRED | Client Allowed
		 * Reply Cache  | server |                 |
		 * -------------+--------+-----------------+--------------------
		 * no           | no     | EXCLUSIVE4_1    | EXCLUSIVE4_1
		 *              |        |                 | (SHOULD)
		 *              |        | and EXCLUSIVE4  | or EXCLUSIVE4
		 *              |        |                 | (SHOULD NOT)
		 * no           | yes    | EXCLUSIVE4_1    | EXCLUSIVE4_1
		 * yes          | no     | GUARDED4        | GUARDED4
		 * yes          | yes    | GUARDED4        | GUARDED4
		 */

L
Linus Torvalds 已提交
183 184 185 186 187 188 189
		/*
		 * Note: create modes (UNCHECKED,GUARDED...) are the same
		 * in NFSv4 as in v3.
		 */
		status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data,
					open->op_fname.len, &open->op_iattr,
					&resfh, open->op_createmode,
190 191 192
					(u32 *)open->op_verf.data,
					&open->op_truncate, &created);

193 194 195 196
		/*
		 * Following rfc 3530 14.2.16, use the returned bitmask
		 * to indicate which attributes we used to store the
		 * verifier:
197 198
		 */
		if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0)
199
			open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS |
200
						FATTR4_WORD1_TIME_MODIFY);
201
	} else {
L
Linus Torvalds 已提交
202 203 204 205
		status = nfsd_lookup(rqstp, current_fh,
				     open->op_fname.data, open->op_fname.len, &resfh);
		fh_unlock(current_fh);
	}
206 207
	if (status)
		goto out;
L
Linus Torvalds 已提交
208

209
	set_change_info(&open->op_cinfo, current_fh);
J
J. Bruce Fields 已提交
210
	fh_dup2(current_fh, &resfh);
L
Linus Torvalds 已提交
211

212
	/* set reply cache */
213 214
	fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
			&resfh.fh_handle);
215
	if (!created)
M
Miklos Szeredi 已提交
216 217
		status = do_open_permission(rqstp, current_fh, open,
					    NFSD_MAY_NOP);
L
Linus Torvalds 已提交
218

219
out:
L
Linus Torvalds 已提交
220 221 222 223
	fh_put(&resfh);
	return status;
}

224
static __be32
L
Linus Torvalds 已提交
225 226
do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
227
	__be32 status;
L
Linus Torvalds 已提交
228 229 230 231 232 233 234 235 236 237 238 239

	/* Only reclaims from previously confirmed clients are valid */
	if ((status = nfs4_check_open_reclaim(&open->op_clientid)))
		return status;

	/* We don't know the target directory, and therefore can not
	* set the change info
	*/

	memset(&open->op_cinfo, 0, sizeof(struct nfsd4_change_info));

	/* set replay cache */
240 241
	fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
			&current_fh->fh_handle);
L
Linus Torvalds 已提交
242 243 244 245

	open->op_truncate = (open->op_iattr.ia_valid & ATTR_SIZE) &&
		(open->op_iattr.ia_size == 0);

M
Miklos Szeredi 已提交
246 247
	status = do_open_permission(rqstp, current_fh, open,
				    NFSD_MAY_OWNER_OVERRIDE);
L
Linus Torvalds 已提交
248 249 250 251

	return status;
}

A
Andy Adamson 已提交
252 253 254 255 256 257 258 259 260
static void
copy_clientid(clientid_t *clid, struct nfsd4_session *session)
{
	struct nfsd4_sessionid *sid =
			(struct nfsd4_sessionid *)session->se_sessionid.data;

	clid->cl_boot = sid->clientid.cl_boot;
	clid->cl_id = sid->clientid.cl_id;
}
L
Linus Torvalds 已提交
261

262
static __be32
263
nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
264
	   struct nfsd4_open *open)
L
Linus Torvalds 已提交
265
{
266
	__be32 status;
A
Andy Adamson 已提交
267 268
	struct nfsd4_compoundres *resp;

L
Linus Torvalds 已提交
269 270 271 272 273 274 275 276
	dprintk("NFSD: nfsd4_open filename %.*s op_stateowner %p\n",
		(int)open->op_fname.len, open->op_fname.data,
		open->op_stateowner);

	/* This check required by spec. */
	if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
		return nfserr_inval;

A
Andy Adamson 已提交
277 278 279
	if (nfsd4_has_session(cstate))
		copy_clientid(&open->op_clientid, cstate->session);

L
Linus Torvalds 已提交
280 281 282
	nfs4_lock_state();

	/* check seqid for replay. set nfs4_owner */
A
Andy Adamson 已提交
283 284
	resp = rqstp->rq_resp;
	status = nfsd4_process_open1(&resp->cstate, open);
A
Al Viro 已提交
285
	if (status == nfserr_replay_me) {
L
Linus Torvalds 已提交
286
		struct nfs4_replay *rp = &open->op_stateowner->so_replay;
287
		fh_put(&cstate->current_fh);
288 289
		fh_copy_shallow(&cstate->current_fh.fh_handle,
				&rp->rp_openfh);
M
Miklos Szeredi 已提交
290
		status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
291 292 293 294
		if (status)
			dprintk("nfsd4_open: replay failed"
				" restoring previous filehandle\n");
		else
A
Al Viro 已提交
295
			status = nfserr_replay_me;
L
Linus Torvalds 已提交
296 297 298
	}
	if (status)
		goto out;
299

300 301 302 303
	status = nfsd4_check_open_attributes(rqstp, cstate, open);
	if (status)
		goto out;

304 305
	/* Openowner is now set, so sequence id will get bumped.  Now we need
	 * these checks before we do any creates: */
306
	status = nfserr_grace;
307
	if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
308 309
		goto out;
	status = nfserr_no_grace;
310
	if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
311
		goto out;
312

L
Linus Torvalds 已提交
313
	switch (open->op_claim_type) {
314
		case NFS4_OPEN_CLAIM_DELEGATE_CUR:
L
Linus Torvalds 已提交
315 316 317 318 319 320 321
		case NFS4_OPEN_CLAIM_NULL:
			/*
			 * (1) set CURRENT_FH to the file being opened,
			 * creating it if necessary, (2) set open->op_cinfo,
			 * (3) set open->op_truncate if the file is to be
			 * truncated after opening, (4) do permission checking.
			 */
322 323
			status = do_open_lookup(rqstp, &cstate->current_fh,
						open);
L
Linus Torvalds 已提交
324 325 326 327
			if (status)
				goto out;
			break;
		case NFS4_OPEN_CLAIM_PREVIOUS:
328
			open->op_stateowner->so_confirmed = 1;
L
Linus Torvalds 已提交
329 330 331 332 333 334
			/*
			 * The CURRENT_FH is already set to the file being
			 * opened.  (1) set open->op_cinfo, (2) set
			 * open->op_truncate if the file is to be truncated
			 * after opening, (3) do permission checking.
			*/
335 336
			status = do_open_fhandle(rqstp, &cstate->current_fh,
						 open);
L
Linus Torvalds 已提交
337 338 339 340
			if (status)
				goto out;
			break;
             	case NFS4_OPEN_CLAIM_DELEGATE_PREV:
341
			open->op_stateowner->so_confirmed = 1;
342
			dprintk("NFSD: unsupported OPEN claim type %d\n",
L
Linus Torvalds 已提交
343 344 345 346
				open->op_claim_type);
			status = nfserr_notsupp;
			goto out;
		default:
347
			dprintk("NFSD: Invalid OPEN claim type %d\n",
L
Linus Torvalds 已提交
348 349 350 351 352 353 354 355 356
				open->op_claim_type);
			status = nfserr_inval;
			goto out;
	}
	/*
	 * nfsd4_process_open2() does the actual opening of the file.  If
	 * successful, it (1) truncates the file if open->op_truncate was
	 * set, (2) sets open->op_stateid, (3) sets open->op_delegation.
	 */
357
	status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
L
Linus Torvalds 已提交
358
out:
N
Neil Brown 已提交
359
	if (open->op_stateowner) {
L
Linus Torvalds 已提交
360
		nfs4_get_stateowner(open->op_stateowner);
361
		cstate->replay_owner = open->op_stateowner;
N
Neil Brown 已提交
362
	}
L
Linus Torvalds 已提交
363 364 365 366 367 368 369
	nfs4_unlock_state();
	return status;
}

/*
 * filehandle-manipulating ops.
 */
370
static __be32
371 372
nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    struct svc_fh **getfh)
L
Linus Torvalds 已提交
373
{
374
	if (!cstate->current_fh.fh_dentry)
L
Linus Torvalds 已提交
375 376
		return nfserr_nofilehandle;

377
	*getfh = &cstate->current_fh;
L
Linus Torvalds 已提交
378 379 380
	return nfs_ok;
}

381
static __be32
382 383
nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    struct nfsd4_putfh *putfh)
L
Linus Torvalds 已提交
384
{
385 386 387 388
	fh_put(&cstate->current_fh);
	cstate->current_fh.fh_handle.fh_size = putfh->pf_fhlen;
	memcpy(&cstate->current_fh.fh_handle.fh_base, putfh->pf_fhval,
	       putfh->pf_fhlen);
M
Miklos Szeredi 已提交
389
	return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
390 391
}

392
static __be32
393 394
nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		void *arg)
L
Linus Torvalds 已提交
395
{
396
	__be32 status;
L
Linus Torvalds 已提交
397

398
	fh_put(&cstate->current_fh);
399
	status = exp_pseudoroot(rqstp, &cstate->current_fh);
L
Linus Torvalds 已提交
400 401 402
	return status;
}

403
static __be32
404 405
nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		void *arg)
L
Linus Torvalds 已提交
406
{
407
	if (!cstate->save_fh.fh_dentry)
L
Linus Torvalds 已提交
408 409
		return nfserr_restorefh;

410
	fh_dup2(&cstate->current_fh, &cstate->save_fh);
L
Linus Torvalds 已提交
411 412 413
	return nfs_ok;
}

414
static __be32
415 416
nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     void *arg)
L
Linus Torvalds 已提交
417
{
418
	if (!cstate->current_fh.fh_dentry)
L
Linus Torvalds 已提交
419 420
		return nfserr_nofilehandle;

421
	fh_dup2(&cstate->save_fh, &cstate->current_fh);
L
Linus Torvalds 已提交
422 423 424 425 426 427
	return nfs_ok;
}

/*
 * misc nfsv4 ops
 */
428
static __be32
429 430
nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_access *access)
L
Linus Torvalds 已提交
431 432 433 434 435
{
	if (access->ac_req_access & ~NFS3_ACCESS_FULL)
		return nfserr_inval;

	access->ac_resp_access = access->ac_req_access;
436 437
	return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access,
			   &access->ac_supported);
L
Linus Torvalds 已提交
438 439
}

440
static __be32
441 442
nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_commit *commit)
L
Linus Torvalds 已提交
443
{
444
	__be32 status;
L
Linus Torvalds 已提交
445 446 447 448 449

	u32 *p = (u32 *)commit->co_verf.data;
	*p++ = nfssvc_boot.tv_sec;
	*p++ = nfssvc_boot.tv_usec;

450 451
	status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
			     commit->co_count);
L
Linus Torvalds 已提交
452 453 454 455 456
	if (status == nfserr_symlink)
		status = nfserr_inval;
	return status;
}

457
static __be32
458 459
nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_create *create)
L
Linus Torvalds 已提交
460 461
{
	struct svc_fh resfh;
462
	__be32 status;
L
Linus Torvalds 已提交
463 464 465 466
	dev_t rdev;

	fh_init(&resfh, NFS4_FHSIZE);

M
Miklos Szeredi 已提交
467 468
	status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
			   NFSD_MAY_CREATE);
L
Linus Torvalds 已提交
469 470 471 472 473
	if (status == nfserr_symlink)
		status = nfserr_notdir;
	if (status)
		return status;

474 475 476 477 478
	status = check_attr_support(rqstp, cstate, create->cr_bmval,
				    nfsd_attrmask);
	if (status)
		return status;

L
Linus Torvalds 已提交
479 480 481 482 483 484 485 486 487 488 489
	switch (create->cr_type) {
	case NF4LNK:
		/* ugh! we have to null-terminate the linktext, or
		 * vfs_symlink() will choke.  it is always safe to
		 * null-terminate by brute force, since at worst we
		 * will overwrite the first byte of the create namelen
		 * in the XDR buffer, which has already been extracted
		 * during XDR decode.
		 */
		create->cr_linkname[create->cr_linklen] = 0;

490 491 492 493
		status = nfsd_symlink(rqstp, &cstate->current_fh,
				      create->cr_name, create->cr_namelen,
				      create->cr_linkname, create->cr_linklen,
				      &resfh, &create->cr_iattr);
L
Linus Torvalds 已提交
494 495 496 497 498 499 500
		break;

	case NF4BLK:
		rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
		if (MAJOR(rdev) != create->cr_specdata1 ||
		    MINOR(rdev) != create->cr_specdata2)
			return nfserr_inval;
501 502 503
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFBLK, rdev, &resfh);
L
Linus Torvalds 已提交
504 505 506 507 508 509 510
		break;

	case NF4CHR:
		rdev = MKDEV(create->cr_specdata1, create->cr_specdata2);
		if (MAJOR(rdev) != create->cr_specdata1 ||
		    MINOR(rdev) != create->cr_specdata2)
			return nfserr_inval;
511 512 513
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr,S_IFCHR, rdev, &resfh);
L
Linus Torvalds 已提交
514 515 516
		break;

	case NF4SOCK:
517 518 519
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFSOCK, 0, &resfh);
L
Linus Torvalds 已提交
520 521 522
		break;

	case NF4FIFO:
523 524 525
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFIFO, 0, &resfh);
L
Linus Torvalds 已提交
526 527 528 529
		break;

	case NF4DIR:
		create->cr_iattr.ia_valid &= ~ATTR_SIZE;
530 531 532
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFDIR, 0, &resfh);
L
Linus Torvalds 已提交
533 534 535 536 537 538 539
		break;

	default:
		status = nfserr_badtype;
	}

	if (!status) {
540 541 542
		fh_unlock(&cstate->current_fh);
		set_change_info(&create->cr_cinfo, &cstate->current_fh);
		fh_dup2(&cstate->current_fh, &resfh);
L
Linus Torvalds 已提交
543 544 545 546 547 548
	}

	fh_put(&resfh);
	return status;
}

549
static __be32
550 551
nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_getattr *getattr)
L
Linus Torvalds 已提交
552
{
553
	__be32 status;
L
Linus Torvalds 已提交
554

M
Miklos Szeredi 已提交
555
	status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
556 557 558 559 560 561
	if (status)
		return status;

	if (getattr->ga_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
		return nfserr_inval;

562 563 564
	getattr->ga_bmval[0] &= nfsd_suppattrs0(cstate->minorversion);
	getattr->ga_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
	getattr->ga_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
L
Linus Torvalds 已提交
565

566
	getattr->ga_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
567 568 569
	return nfs_ok;
}

570
static __be32
571 572
nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	   struct nfsd4_link *link)
L
Linus Torvalds 已提交
573
{
574
	__be32 status = nfserr_nofilehandle;
L
Linus Torvalds 已提交
575

576
	if (!cstate->save_fh.fh_dentry)
L
Linus Torvalds 已提交
577
		return status;
578 579
	status = nfsd_link(rqstp, &cstate->current_fh,
			   link->li_name, link->li_namelen, &cstate->save_fh);
L
Linus Torvalds 已提交
580
	if (!status)
581
		set_change_info(&link->li_cinfo, &cstate->current_fh);
L
Linus Torvalds 已提交
582 583 584
	return status;
}

585
static __be32
586 587
nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      void *arg)
L
Linus Torvalds 已提交
588 589
{
	struct svc_fh tmp_fh;
590
	__be32 ret;
L
Linus Torvalds 已提交
591 592

	fh_init(&tmp_fh, NFS4_FHSIZE);
593 594
	ret = exp_pseudoroot(rqstp, &tmp_fh);
	if (ret)
L
Linus Torvalds 已提交
595
		return ret;
596
	if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
L
Linus Torvalds 已提交
597 598 599 600
		fh_put(&tmp_fh);
		return nfserr_noent;
	}
	fh_put(&tmp_fh);
601 602
	return nfsd_lookup(rqstp, &cstate->current_fh,
			   "..", 2, &cstate->current_fh);
L
Linus Torvalds 已提交
603 604
}

605
static __be32
606 607
nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_lookup *lookup)
L
Linus Torvalds 已提交
608
{
609 610 611
	return nfsd_lookup(rqstp, &cstate->current_fh,
			   lookup->lo_name, lookup->lo_len,
			   &cstate->current_fh);
L
Linus Torvalds 已提交
612 613
}

614
static __be32
615 616
nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	   struct nfsd4_read *read)
L
Linus Torvalds 已提交
617
{
618
	__be32 status;
L
Linus Torvalds 已提交
619 620 621

	/* no need to check permission - this will be done in nfsd_read() */

622
	read->rd_filp = NULL;
L
Linus Torvalds 已提交
623 624 625 626 627
	if (read->rd_offset >= OFFSET_MAX)
		return nfserr_inval;

	nfs4_lock_state();
	/* check stateid */
628 629
	if ((status = nfs4_preprocess_stateid_op(cstate, &read->rd_stateid,
						 RD_STATE, &read->rd_filp))) {
L
Linus Torvalds 已提交
630 631 632
		dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
		goto out;
	}
633 634
	if (read->rd_filp)
		get_file(read->rd_filp);
L
Linus Torvalds 已提交
635 636 637 638
	status = nfs_ok;
out:
	nfs4_unlock_state();
	read->rd_rqstp = rqstp;
639
	read->rd_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
640 641 642
	return status;
}

643
static __be32
644 645
nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_readdir *readdir)
L
Linus Torvalds 已提交
646 647 648 649 650 651 652 653 654
{
	u64 cookie = readdir->rd_cookie;
	static const nfs4_verifier zeroverf;

	/* no need to check permission - this will be done in nfsd_readdir() */

	if (readdir->rd_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1)
		return nfserr_inval;

655 656 657
	readdir->rd_bmval[0] &= nfsd_suppattrs0(cstate->minorversion);
	readdir->rd_bmval[1] &= nfsd_suppattrs1(cstate->minorversion);
	readdir->rd_bmval[2] &= nfsd_suppattrs2(cstate->minorversion);
L
Linus Torvalds 已提交
658 659 660 661 662 663

	if ((cookie > ~(u32)0) || (cookie == 1) || (cookie == 2) ||
	    (cookie == 0 && memcmp(readdir->rd_verf.data, zeroverf.data, NFS4_VERIFIER_SIZE)))
		return nfserr_bad_cookie;

	readdir->rd_rqstp = rqstp;
664
	readdir->rd_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
665 666 667
	return nfs_ok;
}

668
static __be32
669 670
nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	       struct nfsd4_readlink *readlink)
L
Linus Torvalds 已提交
671 672
{
	readlink->rl_rqstp = rqstp;
673
	readlink->rl_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
674 675 676
	return nfs_ok;
}

677
static __be32
678 679
nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_remove *remove)
L
Linus Torvalds 已提交
680
{
681
	__be32 status;
L
Linus Torvalds 已提交
682

683
	if (locks_in_grace())
684
		return nfserr_grace;
685 686
	status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
			     remove->rm_name, remove->rm_namelen);
L
Linus Torvalds 已提交
687 688 689
	if (status == nfserr_symlink)
		return nfserr_notdir;
	if (!status) {
690 691
		fh_unlock(&cstate->current_fh);
		set_change_info(&remove->rm_cinfo, &cstate->current_fh);
L
Linus Torvalds 已提交
692 693 694 695
	}
	return status;
}

696
static __be32
697 698
nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_rename *rename)
L
Linus Torvalds 已提交
699
{
700
	__be32 status = nfserr_nofilehandle;
L
Linus Torvalds 已提交
701

702
	if (!cstate->save_fh.fh_dentry)
L
Linus Torvalds 已提交
703
		return status;
704
	if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
705 706
					& NFSEXP_NOSUBTREECHECK))
		return nfserr_grace;
707 708
	status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
			     rename->rn_snamelen, &cstate->current_fh,
L
Linus Torvalds 已提交
709 710 711 712 713 714 715
			     rename->rn_tname, rename->rn_tnamelen);

	/* the underlying filesystem returns different error's than required
	 * by NFSv4. both save_fh and current_fh have been verified.. */
	if (status == nfserr_isdir)
		status = nfserr_exist;
	else if ((status == nfserr_notdir) &&
716 717
                  (S_ISDIR(cstate->save_fh.fh_dentry->d_inode->i_mode) &&
                   S_ISDIR(cstate->current_fh.fh_dentry->d_inode->i_mode)))
L
Linus Torvalds 已提交
718 719 720 721 722
		status = nfserr_exist;
	else if (status == nfserr_symlink)
		status = nfserr_notdir;

	if (!status) {
723 724
		set_change_info(&rename->rn_sinfo, &cstate->current_fh);
		set_change_info(&rename->rn_tinfo, &cstate->save_fh);
L
Linus Torvalds 已提交
725 726 727 728
	}
	return status;
}

A
Andy Adamson 已提交
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
static __be32
nfsd4_secinfo(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_secinfo *secinfo)
{
	struct svc_fh resfh;
	struct svc_export *exp;
	struct dentry *dentry;
	__be32 err;

	fh_init(&resfh, NFS4_FHSIZE);
	err = nfsd_lookup_dentry(rqstp, &cstate->current_fh,
				    secinfo->si_name, secinfo->si_namelen,
				    &exp, &dentry);
	if (err)
		return err;
	if (dentry->d_inode == NULL) {
		exp_put(exp);
		err = nfserr_noent;
	} else
		secinfo->si_exp = exp;
	dput(dentry);
	return err;
}

753
static __be32
754 755
nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_setattr *setattr)
L
Linus Torvalds 已提交
756
{
757
	__be32 status = nfs_ok;
L
Linus Torvalds 已提交
758 759 760

	if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
		nfs4_lock_state();
761
		status = nfs4_preprocess_stateid_op(cstate,
762
			&setattr->sa_stateid, WR_STATE, NULL);
L
Linus Torvalds 已提交
763
		nfs4_unlock_state();
764
		if (status) {
765
			dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
766 767
			return status;
		}
L
Linus Torvalds 已提交
768
	}
769 770 771
	status = mnt_want_write(cstate->current_fh.fh_export->ex_path.mnt);
	if (status)
		return status;
L
Linus Torvalds 已提交
772
	status = nfs_ok;
773 774 775 776 777 778

	status = check_attr_support(rqstp, cstate, setattr->sa_bmval,
				    nfsd_attrmask);
	if (status)
		goto out;

L
Linus Torvalds 已提交
779
	if (setattr->sa_acl != NULL)
780 781
		status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
					    setattr->sa_acl);
L
Linus Torvalds 已提交
782
	if (status)
783
		goto out;
784
	status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
L
Linus Torvalds 已提交
785
				0, (time_t)0);
786 787
out:
	mnt_drop_write(cstate->current_fh.fh_export->ex_path.mnt);
L
Linus Torvalds 已提交
788 789 790
	return status;
}

791
static __be32
792 793
nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    struct nfsd4_write *write)
L
Linus Torvalds 已提交
794 795 796 797
{
	stateid_t *stateid = &write->wr_stateid;
	struct file *filp = NULL;
	u32 *p;
798
	__be32 status = nfs_ok;
799
	unsigned long cnt;
L
Linus Torvalds 已提交
800 801 802 803 804 805 806

	/* no need to check permission - this will be done in nfsd_write() */

	if (write->wr_offset >= OFFSET_MAX)
		return nfserr_inval;

	nfs4_lock_state();
807
	status = nfs4_preprocess_stateid_op(cstate, stateid, WR_STATE, &filp);
808 809
	if (filp)
		get_file(filp);
L
Linus Torvalds 已提交
810 811
	nfs4_unlock_state();

812 813 814 815 816
	if (status) {
		dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
		return status;
	}

817
	cnt = write->wr_buflen;
L
Linus Torvalds 已提交
818 819 820 821 822
	write->wr_how_written = write->wr_stable_how;
	p = (u32 *)write->wr_verifier.data;
	*p++ = nfssvc_boot.tv_sec;
	*p++ = nfssvc_boot.tv_usec;

823 824
	status =  nfsd_write(rqstp, &cstate->current_fh, filp,
			     write->wr_offset, rqstp->rq_vec, write->wr_vlen,
825
			     &cnt, &write->wr_how_written);
826 827
	if (filp)
		fput(filp);
L
Linus Torvalds 已提交
828

829 830
	write->wr_bytes_written = cnt;

L
Linus Torvalds 已提交
831 832 833 834 835 836 837 838 839 840
	if (status == nfserr_symlink)
		status = nfserr_inval;
	return status;
}

/* This routine never returns NFS_OK!  If there are no other errors, it
 * will return NFSERR_SAME or NFSERR_NOT_SAME depending on whether the
 * attributes matched.  VERIFY is implemented by mapping NFSERR_SAME
 * to NFS_OK after the call; NVERIFY by mapping NFSERR_NOT_SAME to NFS_OK.
 */
841
static __be32
842
_nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
843
	     struct nfsd4_verify *verify)
L
Linus Torvalds 已提交
844
{
A
Al Viro 已提交
845
	__be32 *buf, *p;
L
Linus Torvalds 已提交
846
	int count;
847
	__be32 status;
L
Linus Torvalds 已提交
848

M
Miklos Szeredi 已提交
849
	status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
850 851 852
	if (status)
		return status;

853 854 855 856
	status = check_attr_support(rqstp, cstate, verify->ve_bmval, NULL);
	if (status)
		return status;

L
Linus Torvalds 已提交
857 858 859 860 861 862 863 864 865 866 867 868 869 870
	if ((verify->ve_bmval[0] & FATTR4_WORD0_RDATTR_ERROR)
	    || (verify->ve_bmval[1] & NFSD_WRITEONLY_ATTRS_WORD1))
		return nfserr_inval;
	if (verify->ve_attrlen & 3)
		return nfserr_inval;

	/* count in words:
	 *   bitmap_len(1) + bitmap(2) + attr_len(1) = 4
	 */
	count = 4 + (verify->ve_attrlen >> 2);
	buf = kmalloc(count << 2, GFP_KERNEL);
	if (!buf)
		return nfserr_resource;

871 872 873
	status = nfsd4_encode_fattr(&cstate->current_fh,
				    cstate->current_fh.fh_export,
				    cstate->current_fh.fh_dentry, buf,
L
Linus Torvalds 已提交
874
				    &count, verify->ve_bmval,
875
				    rqstp, 0);
L
Linus Torvalds 已提交
876 877 878 879 880 881 882

	/* this means that nfsd4_encode_fattr() ran out of space */
	if (status == nfserr_resource && count == 0)
		status = nfserr_not_same;
	if (status)
		goto out_kfree;

883 884
	/* skip bitmap */
	p = buf + 1 + ntohl(buf[0]);
L
Linus Torvalds 已提交
885 886 887 888 889 890 891 892 893 894 895
	status = nfserr_not_same;
	if (ntohl(*p++) != verify->ve_attrlen)
		goto out_kfree;
	if (!memcmp(p, verify->ve_attrval, verify->ve_attrlen))
		status = nfserr_same;

out_kfree:
	kfree(buf);
	return status;
}

896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915
static __be32
nfsd4_nverify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_verify *verify)
{
	__be32 status;

	status = _nfsd4_verify(rqstp, cstate, verify);
	return status == nfserr_not_same ? nfs_ok : status;
}

static __be32
nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_verify *verify)
{
	__be32 status;

	status = _nfsd4_verify(rqstp, cstate, verify);
	return status == nfserr_same ? nfs_ok : status;
}

L
Linus Torvalds 已提交
916 917 918
/*
 * NULL call.
 */
A
Al Viro 已提交
919
static __be32
L
Linus Torvalds 已提交
920 921 922 923 924
nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
	return nfs_ok;
}

925 926 927 928 929 930
static inline void nfsd4_increment_op_stats(u32 opnum)
{
	if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP)
		nfsdstats.nfs4_opcount[opnum]++;
}

931 932
typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
			      void *);
933 934 935 936 937
enum nfsd4_op_flags {
	ALLOWED_WITHOUT_FH = 1 << 0,	/* No current filehandle required */
	ALLOWED_ON_ABSENT_FS = 2 << 0,	/* ops processed on absent fs */
	ALLOWED_AS_FIRST_OP = 3 << 0,	/* ops reqired first in compound */
};
938 939 940 941

struct nfsd4_operation {
	nfsd4op_func op_func;
	u32 op_flags;
B
Benny Halevy 已提交
942
	char *op_name;
943 944 945 946
};

static struct nfsd4_operation nfsd4_ops[];

A
Adrian Bunk 已提交
947
static const char *nfsd4_op_name(unsigned opnum);
B
Benny Halevy 已提交
948

949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
/*
 * This is a replay of a compound for which no cache entry pages
 * were used. Encode the sequence operation, and if cachethis is FALSE
 * encode the uncache rep error on the next operation.
 */
static __be32
nfsd4_enc_uncached_replay(struct nfsd4_compoundargs *args,
			 struct nfsd4_compoundres *resp)
{
	struct nfsd4_op *op;

	dprintk("--> %s resp->opcnt %d ce_cachethis %u \n", __func__,
		resp->opcnt, resp->cstate.slot->sl_cache_entry.ce_cachethis);

	/* Encode the replayed sequence operation */
	BUG_ON(resp->opcnt != 1);
	op = &args->ops[resp->opcnt - 1];
	nfsd4_encode_operation(resp, op);

	/*return nfserr_retry_uncached_rep in next operation. */
	if (resp->cstate.slot->sl_cache_entry.ce_cachethis == 0) {
		op = &args->ops[resp->opcnt++];
		op->status = nfserr_retry_uncached_rep;
		nfsd4_encode_operation(resp, op);
	}
	return op->status;
}

977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993
/*
 * Enforce NFSv4.1 COMPOUND ordering rules.
 *
 * TODO:
 * - enforce NFS4ERR_NOT_ONLY_OP,
 * - DESTROY_SESSION MUST be the final operation in the COMPOUND request.
 */
static bool nfs41_op_ordering_ok(struct nfsd4_compoundargs *args)
{
	if (args->minorversion && args->opcnt > 0) {
		struct nfsd4_op *op = &args->ops[0];
		return (op->status == nfserr_op_illegal) ||
		       (nfsd4_ops[op->opnum].op_flags & ALLOWED_AS_FIRST_OP);
	}
	return true;
}

L
Linus Torvalds 已提交
994 995 996
/*
 * COMPOUND call.
 */
A
Al Viro 已提交
997
static __be32
L
Linus Torvalds 已提交
998 999 1000 1001 1002
nfsd4_proc_compound(struct svc_rqst *rqstp,
		    struct nfsd4_compoundargs *args,
		    struct nfsd4_compoundres *resp)
{
	struct nfsd4_op	*op;
1003
	struct nfsd4_operation *opdesc;
1004
	struct nfsd4_compound_state *cstate = &resp->cstate;
1005
	int		slack_bytes;
1006
	__be32		status;
L
Linus Torvalds 已提交
1007 1008

	resp->xbuf = &rqstp->rq_res;
1009 1010
	resp->p = rqstp->rq_res.head[0].iov_base +
						rqstp->rq_res.head[0].iov_len;
L
Linus Torvalds 已提交
1011 1012 1013 1014 1015 1016 1017 1018
	resp->tagp = resp->p;
	/* reserve space for: taglen, tag, and opcnt */
	resp->p += 2 + XDR_QUADLEN(args->taglen);
	resp->end = rqstp->rq_res.head[0].iov_base + PAGE_SIZE;
	resp->taglen = args->taglen;
	resp->tag = args->tag;
	resp->opcnt = 0;
	resp->rqstp = rqstp;
A
Andy Adamson 已提交
1019
	resp->cstate.minorversion = args->minorversion;
1020 1021 1022
	resp->cstate.replay_owner = NULL;
	fh_init(&resp->cstate.current_fh, NFS4_FHSIZE);
	fh_init(&resp->cstate.save_fh, NFS4_FHSIZE);
1023 1024
	/* Use the deferral mechanism only for NFSv4.0 compounds */
	rqstp->rq_usedeferral = (args->minorversion == 0);
L
Linus Torvalds 已提交
1025 1026 1027 1028 1029

	/*
	 * According to RFC3010, this takes precedence over all other errors.
	 */
	status = nfserr_minor_vers_mismatch;
1030
	if (args->minorversion > nfsd_supported_minorversion)
L
Linus Torvalds 已提交
1031 1032
		goto out;

1033 1034 1035 1036 1037 1038
	if (!nfs41_op_ordering_ok(args)) {
		op = &args->ops[0];
		op->status = nfserr_sequence_pos;
		goto encode_op;
	}

L
Linus Torvalds 已提交
1039 1040 1041 1042
	status = nfs_ok;
	while (!status && resp->opcnt < args->opcnt) {
		op = &args->ops[resp->opcnt++];

B
Benny Halevy 已提交
1043 1044 1045
		dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
			resp->opcnt, args->opcnt, op->opnum,
			nfsd4_op_name(op->opnum));
L
Linus Torvalds 已提交
1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058
		/*
		 * The XDR decode routines may have pre-set op->status;
		 * for example, if there is a miscellaneous XDR error
		 * it will be set to nfserr_bad_xdr.
		 */
		if (op->status)
			goto encode_op;

		/* We must be able to encode a successful response to
		 * this operation, with enough room left over to encode a
		 * failed response to the next operation.  If we don't
		 * have enough room, fail with ERR_RESOURCE.
		 */
1059 1060 1061 1062
		slack_bytes = (char *)resp->end - (char *)resp->p;
		if (slack_bytes < COMPOUND_SLACK_SPACE
				+ COMPOUND_ERR_SLACK_SPACE) {
			BUG_ON(slack_bytes < COMPOUND_ERR_SLACK_SPACE);
L
Linus Torvalds 已提交
1063 1064 1065 1066
			op->status = nfserr_resource;
			goto encode_op;
		}

1067 1068
		opdesc = &nfsd4_ops[op->opnum];

1069
		if (!cstate->current_fh.fh_dentry) {
1070
			if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
1071 1072 1073
				op->status = nfserr_nofilehandle;
				goto encode_op;
			}
1074 1075
		} else if (cstate->current_fh.fh_export->ex_fslocs.migrated &&
			  !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
1076
			op->status = nfserr_moved;
L
Linus Torvalds 已提交
1077 1078
			goto encode_op;
		}
1079 1080 1081 1082

		if (opdesc->op_func)
			op->status = opdesc->op_func(rqstp, cstate, &op->u);
		else
L
Linus Torvalds 已提交
1083 1084 1085
			BUG_ON(op->status == nfs_ok);

encode_op:
A
Andy Adamson 已提交
1086 1087 1088
		/* Only from SEQUENCE or CREATE_SESSION */
		if (resp->cstate.status == nfserr_replay_cache) {
			dprintk("%s NFS4.1 replay from cache\n", __func__);
1089 1090 1091 1092
			if (nfsd4_not_cached(resp))
				status = nfsd4_enc_uncached_replay(args, resp);
			else
				status = op->status;
A
Andy Adamson 已提交
1093 1094
			goto out;
		}
A
Al Viro 已提交
1095
		if (op->status == nfserr_replay_me) {
1096
			op->replay = &cstate->replay_owner->so_replay;
L
Linus Torvalds 已提交
1097 1098 1099 1100 1101 1102
			nfsd4_encode_replay(resp, op);
			status = op->status = op->replay->rp_status;
		} else {
			nfsd4_encode_operation(resp, op);
			status = op->status;
		}
1103 1104 1105 1106 1107

		dprintk("nfsv4 compound op %p opcnt %d #%d: %d: status %d\n",
			args->ops, args->opcnt, resp->opcnt, op->opnum,
			be32_to_cpu(status));

1108 1109 1110
		if (cstate->replay_owner) {
			nfs4_put_stateowner(cstate->replay_owner);
			cstate->replay_owner = NULL;
L
Linus Torvalds 已提交
1111
		}
1112 1113 1114
		/* XXX Ugh, we need to get rid of this kind of special case: */
		if (op->opnum == OP_READ && op->u.read.rd_filp)
			fput(op->u.read.rd_filp);
1115 1116

		nfsd4_increment_op_stats(op->opnum);
L
Linus Torvalds 已提交
1117
	}
1118 1119 1120 1121
	if (!rqstp->rq_usedeferral && status == nfserr_dropit) {
		dprintk("%s Dropit - send NFS4ERR_DELAY\n", __func__);
		status = nfserr_jukebox;
	}
L
Linus Torvalds 已提交
1122

A
Andy Adamson 已提交
1123
	resp->cstate.status = status;
1124 1125 1126
	fh_put(&resp->cstate.current_fh);
	fh_put(&resp->cstate.save_fh);
	BUG_ON(resp->cstate.replay_owner);
L
Linus Torvalds 已提交
1127 1128
out:
	nfsd4_release_compoundargs(args);
1129 1130
	/* Reset deferral mechanism for RPC deferrals */
	rqstp->rq_usedeferral = 1;
1131
	dprintk("nfsv4 compound returned %d\n", ntohl(status));
L
Linus Torvalds 已提交
1132 1133 1134
	return status;
}

B
Benny Halevy 已提交
1135
static struct nfsd4_operation nfsd4_ops[] = {
1136 1137
	[OP_ACCESS] = {
		.op_func = (nfsd4op_func)nfsd4_access,
B
Benny Halevy 已提交
1138
		.op_name = "OP_ACCESS",
1139 1140 1141
	},
	[OP_CLOSE] = {
		.op_func = (nfsd4op_func)nfsd4_close,
B
Benny Halevy 已提交
1142
		.op_name = "OP_CLOSE",
1143 1144 1145
	},
	[OP_COMMIT] = {
		.op_func = (nfsd4op_func)nfsd4_commit,
B
Benny Halevy 已提交
1146
		.op_name = "OP_COMMIT",
1147 1148 1149
	},
	[OP_CREATE] = {
		.op_func = (nfsd4op_func)nfsd4_create,
B
Benny Halevy 已提交
1150
		.op_name = "OP_CREATE",
1151 1152 1153
	},
	[OP_DELEGRETURN] = {
		.op_func = (nfsd4op_func)nfsd4_delegreturn,
B
Benny Halevy 已提交
1154
		.op_name = "OP_DELEGRETURN",
1155 1156 1157
	},
	[OP_GETATTR] = {
		.op_func = (nfsd4op_func)nfsd4_getattr,
1158
		.op_flags = ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1159
		.op_name = "OP_GETATTR",
1160 1161 1162
	},
	[OP_GETFH] = {
		.op_func = (nfsd4op_func)nfsd4_getfh,
B
Benny Halevy 已提交
1163
		.op_name = "OP_GETFH",
1164 1165 1166
	},
	[OP_LINK] = {
		.op_func = (nfsd4op_func)nfsd4_link,
B
Benny Halevy 已提交
1167
		.op_name = "OP_LINK",
1168 1169 1170
	},
	[OP_LOCK] = {
		.op_func = (nfsd4op_func)nfsd4_lock,
B
Benny Halevy 已提交
1171
		.op_name = "OP_LOCK",
1172 1173 1174
	},
	[OP_LOCKT] = {
		.op_func = (nfsd4op_func)nfsd4_lockt,
B
Benny Halevy 已提交
1175
		.op_name = "OP_LOCKT",
1176 1177 1178
	},
	[OP_LOCKU] = {
		.op_func = (nfsd4op_func)nfsd4_locku,
B
Benny Halevy 已提交
1179
		.op_name = "OP_LOCKU",
1180 1181 1182
	},
	[OP_LOOKUP] = {
		.op_func = (nfsd4op_func)nfsd4_lookup,
B
Benny Halevy 已提交
1183
		.op_name = "OP_LOOKUP",
1184 1185 1186
	},
	[OP_LOOKUPP] = {
		.op_func = (nfsd4op_func)nfsd4_lookupp,
B
Benny Halevy 已提交
1187
		.op_name = "OP_LOOKUPP",
1188 1189 1190
	},
	[OP_NVERIFY] = {
		.op_func = (nfsd4op_func)nfsd4_nverify,
B
Benny Halevy 已提交
1191
		.op_name = "OP_NVERIFY",
1192 1193 1194
	},
	[OP_OPEN] = {
		.op_func = (nfsd4op_func)nfsd4_open,
B
Benny Halevy 已提交
1195
		.op_name = "OP_OPEN",
1196 1197 1198
	},
	[OP_OPEN_CONFIRM] = {
		.op_func = (nfsd4op_func)nfsd4_open_confirm,
B
Benny Halevy 已提交
1199
		.op_name = "OP_OPEN_CONFIRM",
1200 1201 1202
	},
	[OP_OPEN_DOWNGRADE] = {
		.op_func = (nfsd4op_func)nfsd4_open_downgrade,
B
Benny Halevy 已提交
1203
		.op_name = "OP_OPEN_DOWNGRADE",
1204 1205 1206
	},
	[OP_PUTFH] = {
		.op_func = (nfsd4op_func)nfsd4_putfh,
1207
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1208
		.op_name = "OP_PUTFH",
1209
	},
1210
	[OP_PUTPUBFH] = {
1211
		.op_func = (nfsd4op_func)nfsd4_putrootfh,
1212
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1213
		.op_name = "OP_PUTPUBFH",
1214
	},
1215 1216
	[OP_PUTROOTFH] = {
		.op_func = (nfsd4op_func)nfsd4_putrootfh,
1217
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1218
		.op_name = "OP_PUTROOTFH",
1219 1220 1221
	},
	[OP_READ] = {
		.op_func = (nfsd4op_func)nfsd4_read,
B
Benny Halevy 已提交
1222
		.op_name = "OP_READ",
1223 1224 1225
	},
	[OP_READDIR] = {
		.op_func = (nfsd4op_func)nfsd4_readdir,
B
Benny Halevy 已提交
1226
		.op_name = "OP_READDIR",
1227 1228 1229
	},
	[OP_READLINK] = {
		.op_func = (nfsd4op_func)nfsd4_readlink,
B
Benny Halevy 已提交
1230
		.op_name = "OP_READLINK",
1231 1232 1233
	},
	[OP_REMOVE] = {
		.op_func = (nfsd4op_func)nfsd4_remove,
B
Benny Halevy 已提交
1234
		.op_name = "OP_REMOVE",
1235 1236
	},
	[OP_RENAME] = {
B
Benny Halevy 已提交
1237
		.op_name = "OP_RENAME",
1238 1239 1240 1241
		.op_func = (nfsd4op_func)nfsd4_rename,
	},
	[OP_RENEW] = {
		.op_func = (nfsd4op_func)nfsd4_renew,
1242
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1243
		.op_name = "OP_RENEW",
1244 1245 1246
	},
	[OP_RESTOREFH] = {
		.op_func = (nfsd4op_func)nfsd4_restorefh,
1247
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1248
		.op_name = "OP_RESTOREFH",
1249 1250 1251
	},
	[OP_SAVEFH] = {
		.op_func = (nfsd4op_func)nfsd4_savefh,
B
Benny Halevy 已提交
1252
		.op_name = "OP_SAVEFH",
1253
	},
A
Andy Adamson 已提交
1254 1255
	[OP_SECINFO] = {
		.op_func = (nfsd4op_func)nfsd4_secinfo,
B
Benny Halevy 已提交
1256
		.op_name = "OP_SECINFO",
A
Andy Adamson 已提交
1257
	},
1258 1259
	[OP_SETATTR] = {
		.op_func = (nfsd4op_func)nfsd4_setattr,
B
Benny Halevy 已提交
1260
		.op_name = "OP_SETATTR",
1261 1262 1263
	},
	[OP_SETCLIENTID] = {
		.op_func = (nfsd4op_func)nfsd4_setclientid,
1264
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1265
		.op_name = "OP_SETCLIENTID",
1266 1267 1268
	},
	[OP_SETCLIENTID_CONFIRM] = {
		.op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
1269
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1270
		.op_name = "OP_SETCLIENTID_CONFIRM",
1271 1272 1273
	},
	[OP_VERIFY] = {
		.op_func = (nfsd4op_func)nfsd4_verify,
B
Benny Halevy 已提交
1274
		.op_name = "OP_VERIFY",
1275 1276 1277
	},
	[OP_WRITE] = {
		.op_func = (nfsd4op_func)nfsd4_write,
B
Benny Halevy 已提交
1278
		.op_name = "OP_WRITE",
1279 1280 1281
	},
	[OP_RELEASE_LOCKOWNER] = {
		.op_func = (nfsd4op_func)nfsd4_release_lockowner,
1282
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1283
		.op_name = "OP_RELEASE_LOCKOWNER",
1284
	},
A
Andy Adamson 已提交
1285 1286 1287 1288

	/* NFSv4.1 operations */
	[OP_EXCHANGE_ID] = {
		.op_func = (nfsd4op_func)nfsd4_exchange_id,
1289
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
A
Andy Adamson 已提交
1290 1291 1292 1293
		.op_name = "OP_EXCHANGE_ID",
	},
	[OP_CREATE_SESSION] = {
		.op_func = (nfsd4op_func)nfsd4_create_session,
1294
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
A
Andy Adamson 已提交
1295 1296 1297 1298
		.op_name = "OP_CREATE_SESSION",
	},
	[OP_DESTROY_SESSION] = {
		.op_func = (nfsd4op_func)nfsd4_destroy_session,
1299
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
A
Andy Adamson 已提交
1300 1301 1302 1303
		.op_name = "OP_DESTROY_SESSION",
	},
	[OP_SEQUENCE] = {
		.op_func = (nfsd4op_func)nfsd4_sequence,
1304
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_AS_FIRST_OP,
A
Andy Adamson 已提交
1305 1306
		.op_name = "OP_SEQUENCE",
	},
1307 1308
};

A
Adrian Bunk 已提交
1309
static const char *nfsd4_op_name(unsigned opnum)
B
Benny Halevy 已提交
1310 1311 1312 1313 1314 1315
{
	if (opnum < ARRAY_SIZE(nfsd4_ops))
		return nfsd4_ops[opnum].op_name;
	return "unknown_operation";
}

L
Linus Torvalds 已提交
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
#define nfs4svc_decode_voidargs		NULL
#define nfs4svc_release_void		NULL
#define nfsd4_voidres			nfsd4_voidargs
#define nfs4svc_release_compound	NULL
struct nfsd4_voidargs { int dummy; };

#define PROC(name, argt, rest, relt, cache, respsize)	\
 { (svc_procfunc) nfsd4_proc_##name,		\
   (kxdrproc_t) nfs4svc_decode_##argt##args,	\
   (kxdrproc_t) nfs4svc_encode_##rest##res,	\
   (kxdrproc_t) nfs4svc_release_##relt,		\
   sizeof(struct nfsd4_##argt##args),		\
   sizeof(struct nfsd4_##rest##res),		\
   0,						\
   cache,					\
   respsize,					\
 }

/*
 * TODO: At the present time, the NFSv4 server does not do XID caching
 * of requests.  Implementing XID caching would not be a serious problem,
 * although it would require a mild change in interfaces since one
 * doesn't know whether an NFSv4 request is idempotent until after the
 * XDR decode.  However, XID caching totally confuses pynfs (Peter
 * Astrand's regression testsuite for NFSv4 servers), which reuses
 * XID's liberally, so I've left it unimplemented until pynfs generates
 * better XID's.
 */
static struct svc_procedure		nfsd_procedures4[2] = {
  PROC(null,	 void,		void,		void,	  RC_NOCACHE, 1),
1346
  PROC(compound, compound,	compound,	compound, RC_NOCACHE, NFSD_BUFSIZE/4)
L
Linus Torvalds 已提交
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361
};

struct svc_version	nfsd_version4 = {
		.vs_vers	= 4,
		.vs_nproc	= 2,
		.vs_proc	= nfsd_procedures4,
		.vs_dispatch	= nfsd_dispatch,
		.vs_xdrsize	= NFS4_SVC_XDRSIZE,
};

/*
 * Local variables:
 *  c-basic-offset: 8
 * End:
 */