nfs4proc.c 31.0 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 54 55 56 57 58 59 60 61 62 63

#define NFSDDBG_FACILITY		NFSDDBG_PROC

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;
}

64
static __be32
65
do_open_permission(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open, int accmode)
L
Linus Torvalds 已提交
66
{
67
	__be32 status;
L
Linus Torvalds 已提交
68 69 70 71 72 73

	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 已提交
74
		accmode |= NFSD_MAY_READ;
75
	if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
M
Miklos Szeredi 已提交
76
		accmode |= (NFSD_MAY_WRITE | NFSD_MAY_TRUNC);
77
	if (open->op_share_deny & NFS4_SHARE_DENY_WRITE)
M
Miklos Szeredi 已提交
78
		accmode |= NFSD_MAY_WRITE;
L
Linus Torvalds 已提交
79 80 81 82 83 84

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

	return status;
}

85
static __be32
L
Linus Torvalds 已提交
86 87 88
do_open_lookup(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
	struct svc_fh resfh;
89
	__be32 status;
90
	int created = 0;
L
Linus Torvalds 已提交
91 92 93 94 95 96 97 98 99 100 101 102

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

	if (open->op_create) {
		/*
		 * 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,
103 104 105
					(u32 *)open->op_verf.data,
					&open->op_truncate, &created);

106 107 108 109
		/*
		 * Following rfc 3530 14.2.16, use the returned bitmask
		 * to indicate which attributes we used to store the
		 * verifier:
110 111
		 */
		if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0)
112
			open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS |
113
						FATTR4_WORD1_TIME_MODIFY);
114
	} else {
L
Linus Torvalds 已提交
115 116 117 118
		status = nfsd_lookup(rqstp, current_fh,
				     open->op_fname.data, open->op_fname.len, &resfh);
		fh_unlock(current_fh);
	}
119 120
	if (status)
		goto out;
L
Linus Torvalds 已提交
121

122
	set_change_info(&open->op_cinfo, current_fh);
J
J. Bruce Fields 已提交
123
	fh_dup2(current_fh, &resfh);
L
Linus Torvalds 已提交
124

125
	/* set reply cache */
126 127
	fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
			&resfh.fh_handle);
128
	if (!created)
M
Miklos Szeredi 已提交
129 130
		status = do_open_permission(rqstp, current_fh, open,
					    NFSD_MAY_NOP);
L
Linus Torvalds 已提交
131

132
out:
L
Linus Torvalds 已提交
133 134 135 136
	fh_put(&resfh);
	return status;
}

137
static __be32
L
Linus Torvalds 已提交
138 139
do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
140
	__be32 status;
L
Linus Torvalds 已提交
141 142 143 144 145 146 147 148 149 150 151 152

	/* 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 */
153 154
	fh_copy_shallow(&open->op_stateowner->so_replay.rp_openfh,
			&current_fh->fh_handle);
L
Linus Torvalds 已提交
155 156 157 158

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

M
Miklos Szeredi 已提交
159 160
	status = do_open_permission(rqstp, current_fh, open,
				    NFSD_MAY_OWNER_OVERRIDE);
L
Linus Torvalds 已提交
161 162 163 164 165

	return status;
}


166
static __be32
167
nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
168
	   struct nfsd4_open *open)
L
Linus Torvalds 已提交
169
{
170
	__be32 status;
L
Linus Torvalds 已提交
171 172 173 174 175 176 177 178 179 180 181 182
	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;

	nfs4_lock_state();

	/* check seqid for replay. set nfs4_owner */
	status = nfsd4_process_open1(open);
A
Al Viro 已提交
183
	if (status == nfserr_replay_me) {
L
Linus Torvalds 已提交
184
		struct nfs4_replay *rp = &open->op_stateowner->so_replay;
185
		fh_put(&cstate->current_fh);
186 187
		fh_copy_shallow(&cstate->current_fh.fh_handle,
				&rp->rp_openfh);
M
Miklos Szeredi 已提交
188
		status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
189 190 191 192
		if (status)
			dprintk("nfsd4_open: replay failed"
				" restoring previous filehandle\n");
		else
A
Al Viro 已提交
193
			status = nfserr_replay_me;
L
Linus Torvalds 已提交
194 195 196
	}
	if (status)
		goto out;
197 198 199

	/* Openowner is now set, so sequence id will get bumped.  Now we need
	 * these checks before we do any creates: */
200
	status = nfserr_grace;
201
	if (locks_in_grace() && open->op_claim_type != NFS4_OPEN_CLAIM_PREVIOUS)
202 203
		goto out;
	status = nfserr_no_grace;
204
	if (!locks_in_grace() && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
205
		goto out;
206

L
Linus Torvalds 已提交
207
	switch (open->op_claim_type) {
208
		case NFS4_OPEN_CLAIM_DELEGATE_CUR:
L
Linus Torvalds 已提交
209 210 211 212 213 214 215
		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.
			 */
216 217
			status = do_open_lookup(rqstp, &cstate->current_fh,
						open);
L
Linus Torvalds 已提交
218 219 220 221
			if (status)
				goto out;
			break;
		case NFS4_OPEN_CLAIM_PREVIOUS:
222
			open->op_stateowner->so_confirmed = 1;
L
Linus Torvalds 已提交
223 224 225 226 227 228
			/*
			 * 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.
			*/
229 230
			status = do_open_fhandle(rqstp, &cstate->current_fh,
						 open);
L
Linus Torvalds 已提交
231 232 233 234
			if (status)
				goto out;
			break;
             	case NFS4_OPEN_CLAIM_DELEGATE_PREV:
235
			open->op_stateowner->so_confirmed = 1;
236
			dprintk("NFSD: unsupported OPEN claim type %d\n",
L
Linus Torvalds 已提交
237 238 239 240
				open->op_claim_type);
			status = nfserr_notsupp;
			goto out;
		default:
241
			dprintk("NFSD: Invalid OPEN claim type %d\n",
L
Linus Torvalds 已提交
242 243 244 245 246 247 248 249 250
				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.
	 */
251
	status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
L
Linus Torvalds 已提交
252
out:
N
Neil Brown 已提交
253
	if (open->op_stateowner) {
L
Linus Torvalds 已提交
254
		nfs4_get_stateowner(open->op_stateowner);
255
		cstate->replay_owner = open->op_stateowner;
N
Neil Brown 已提交
256
	}
L
Linus Torvalds 已提交
257 258 259 260 261 262 263
	nfs4_unlock_state();
	return status;
}

/*
 * filehandle-manipulating ops.
 */
264
static __be32
265 266
nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    struct svc_fh **getfh)
L
Linus Torvalds 已提交
267
{
268
	if (!cstate->current_fh.fh_dentry)
L
Linus Torvalds 已提交
269 270
		return nfserr_nofilehandle;

271
	*getfh = &cstate->current_fh;
L
Linus Torvalds 已提交
272 273 274
	return nfs_ok;
}

275
static __be32
276 277
nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    struct nfsd4_putfh *putfh)
L
Linus Torvalds 已提交
278
{
279 280 281 282
	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 已提交
283
	return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
284 285
}

286
static __be32
287 288
nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		void *arg)
L
Linus Torvalds 已提交
289
{
290
	__be32 status;
L
Linus Torvalds 已提交
291

292
	fh_put(&cstate->current_fh);
293
	status = exp_pseudoroot(rqstp, &cstate->current_fh);
L
Linus Torvalds 已提交
294 295 296
	return status;
}

297
static __be32
298 299
nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		void *arg)
L
Linus Torvalds 已提交
300
{
301
	if (!cstate->save_fh.fh_dentry)
L
Linus Torvalds 已提交
302 303
		return nfserr_restorefh;

304
	fh_dup2(&cstate->current_fh, &cstate->save_fh);
L
Linus Torvalds 已提交
305 306 307
	return nfs_ok;
}

308
static __be32
309 310
nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     void *arg)
L
Linus Torvalds 已提交
311
{
312
	if (!cstate->current_fh.fh_dentry)
L
Linus Torvalds 已提交
313 314
		return nfserr_nofilehandle;

315
	fh_dup2(&cstate->save_fh, &cstate->current_fh);
L
Linus Torvalds 已提交
316 317 318 319 320 321
	return nfs_ok;
}

/*
 * misc nfsv4 ops
 */
322
static __be32
323 324
nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_access *access)
L
Linus Torvalds 已提交
325 326 327 328 329
{
	if (access->ac_req_access & ~NFS3_ACCESS_FULL)
		return nfserr_inval;

	access->ac_resp_access = access->ac_req_access;
330 331
	return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access,
			   &access->ac_supported);
L
Linus Torvalds 已提交
332 333
}

334
static __be32
335 336
nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_commit *commit)
L
Linus Torvalds 已提交
337
{
338
	__be32 status;
L
Linus Torvalds 已提交
339 340 341 342 343

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

344 345
	status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
			     commit->co_count);
L
Linus Torvalds 已提交
346 347 348 349 350
	if (status == nfserr_symlink)
		status = nfserr_inval;
	return status;
}

351
static __be32
352 353
nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_create *create)
L
Linus Torvalds 已提交
354 355
{
	struct svc_fh resfh;
356
	__be32 status;
L
Linus Torvalds 已提交
357 358 359 360
	dev_t rdev;

	fh_init(&resfh, NFS4_FHSIZE);

M
Miklos Szeredi 已提交
361 362
	status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
			   NFSD_MAY_CREATE);
L
Linus Torvalds 已提交
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378
	if (status == nfserr_symlink)
		status = nfserr_notdir;
	if (status)
		return status;

	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;

379 380 381 382
		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 已提交
383 384 385 386 387 388 389
		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;
390 391 392
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFBLK, rdev, &resfh);
L
Linus Torvalds 已提交
393 394 395 396 397 398 399
		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;
400 401 402
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr,S_IFCHR, rdev, &resfh);
L
Linus Torvalds 已提交
403 404 405
		break;

	case NF4SOCK:
406 407 408
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFSOCK, 0, &resfh);
L
Linus Torvalds 已提交
409 410 411
		break;

	case NF4FIFO:
412 413 414
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFIFO, 0, &resfh);
L
Linus Torvalds 已提交
415 416 417 418
		break;

	case NF4DIR:
		create->cr_iattr.ia_valid &= ~ATTR_SIZE;
419 420 421
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFDIR, 0, &resfh);
L
Linus Torvalds 已提交
422 423 424 425 426 427 428
		break;

	default:
		status = nfserr_badtype;
	}

	if (!status) {
429 430 431
		fh_unlock(&cstate->current_fh);
		set_change_info(&create->cr_cinfo, &cstate->current_fh);
		fh_dup2(&cstate->current_fh, &resfh);
L
Linus Torvalds 已提交
432 433 434 435 436 437
	}

	fh_put(&resfh);
	return status;
}

438
static __be32
439 440
nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_getattr *getattr)
L
Linus Torvalds 已提交
441
{
442
	__be32 status;
L
Linus Torvalds 已提交
443

M
Miklos Szeredi 已提交
444
	status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
445 446 447 448 449 450 451 452 453
	if (status)
		return status;

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

	getattr->ga_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
	getattr->ga_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;

454
	getattr->ga_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
455 456 457
	return nfs_ok;
}

458
static __be32
459 460
nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	   struct nfsd4_link *link)
L
Linus Torvalds 已提交
461
{
462
	__be32 status = nfserr_nofilehandle;
L
Linus Torvalds 已提交
463

464
	if (!cstate->save_fh.fh_dentry)
L
Linus Torvalds 已提交
465
		return status;
466 467
	status = nfsd_link(rqstp, &cstate->current_fh,
			   link->li_name, link->li_namelen, &cstate->save_fh);
L
Linus Torvalds 已提交
468
	if (!status)
469
		set_change_info(&link->li_cinfo, &cstate->current_fh);
L
Linus Torvalds 已提交
470 471 472
	return status;
}

473
static __be32
474 475
nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      void *arg)
L
Linus Torvalds 已提交
476 477
{
	struct svc_fh tmp_fh;
478
	__be32 ret;
L
Linus Torvalds 已提交
479 480

	fh_init(&tmp_fh, NFS4_FHSIZE);
481 482
	ret = exp_pseudoroot(rqstp, &tmp_fh);
	if (ret)
L
Linus Torvalds 已提交
483
		return ret;
484
	if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
L
Linus Torvalds 已提交
485 486 487 488
		fh_put(&tmp_fh);
		return nfserr_noent;
	}
	fh_put(&tmp_fh);
489 490
	return nfsd_lookup(rqstp, &cstate->current_fh,
			   "..", 2, &cstate->current_fh);
L
Linus Torvalds 已提交
491 492
}

493
static __be32
494 495
nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_lookup *lookup)
L
Linus Torvalds 已提交
496
{
497 498 499
	return nfsd_lookup(rqstp, &cstate->current_fh,
			   lookup->lo_name, lookup->lo_len,
			   &cstate->current_fh);
L
Linus Torvalds 已提交
500 501
}

502
static __be32
503 504
nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	   struct nfsd4_read *read)
L
Linus Torvalds 已提交
505
{
506
	__be32 status;
L
Linus Torvalds 已提交
507 508 509

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

510
	read->rd_filp = NULL;
L
Linus Torvalds 已提交
511 512 513 514 515
	if (read->rd_offset >= OFFSET_MAX)
		return nfserr_inval;

	nfs4_lock_state();
	/* check stateid */
516 517
	if ((status = nfs4_preprocess_stateid_op(&cstate->current_fh,
				&read->rd_stateid,
518
				RD_STATE, &read->rd_filp))) {
L
Linus Torvalds 已提交
519 520 521
		dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
		goto out;
	}
522 523
	if (read->rd_filp)
		get_file(read->rd_filp);
L
Linus Torvalds 已提交
524 525 526 527
	status = nfs_ok;
out:
	nfs4_unlock_state();
	read->rd_rqstp = rqstp;
528
	read->rd_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
529 530 531
	return status;
}

532
static __be32
533 534
nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_readdir *readdir)
L
Linus Torvalds 已提交
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551
{
	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;

	readdir->rd_bmval[0] &= NFSD_SUPPORTED_ATTRS_WORD0;
	readdir->rd_bmval[1] &= NFSD_SUPPORTED_ATTRS_WORD1;

	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;
552
	readdir->rd_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
553 554 555
	return nfs_ok;
}

556
static __be32
557 558
nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	       struct nfsd4_readlink *readlink)
L
Linus Torvalds 已提交
559 560
{
	readlink->rl_rqstp = rqstp;
561
	readlink->rl_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
562 563 564
	return nfs_ok;
}

565
static __be32
566 567
nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_remove *remove)
L
Linus Torvalds 已提交
568
{
569
	__be32 status;
L
Linus Torvalds 已提交
570

571
	if (locks_in_grace())
572
		return nfserr_grace;
573 574
	status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
			     remove->rm_name, remove->rm_namelen);
L
Linus Torvalds 已提交
575 576 577
	if (status == nfserr_symlink)
		return nfserr_notdir;
	if (!status) {
578 579
		fh_unlock(&cstate->current_fh);
		set_change_info(&remove->rm_cinfo, &cstate->current_fh);
L
Linus Torvalds 已提交
580 581 582 583
	}
	return status;
}

584
static __be32
585 586
nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_rename *rename)
L
Linus Torvalds 已提交
587
{
588
	__be32 status = nfserr_nofilehandle;
L
Linus Torvalds 已提交
589

590
	if (!cstate->save_fh.fh_dentry)
L
Linus Torvalds 已提交
591
		return status;
592
	if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
593 594
					& NFSEXP_NOSUBTREECHECK))
		return nfserr_grace;
595 596
	status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
			     rename->rn_snamelen, &cstate->current_fh,
L
Linus Torvalds 已提交
597 598 599 600 601 602 603
			     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) &&
604 605
                  (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 已提交
606 607 608 609 610
		status = nfserr_exist;
	else if (status == nfserr_symlink)
		status = nfserr_notdir;

	if (!status) {
611 612
		set_change_info(&rename->rn_sinfo, &cstate->current_fh);
		set_change_info(&rename->rn_tinfo, &cstate->save_fh);
L
Linus Torvalds 已提交
613 614 615 616
	}
	return status;
}

A
Andy Adamson 已提交
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
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;
}

641
static __be32
642 643
nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_setattr *setattr)
L
Linus Torvalds 已提交
644
{
645
	__be32 status = nfs_ok;
L
Linus Torvalds 已提交
646 647 648

	if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
		nfs4_lock_state();
649
		status = nfs4_preprocess_stateid_op(&cstate->current_fh,
650
			&setattr->sa_stateid, WR_STATE, NULL);
L
Linus Torvalds 已提交
651
		nfs4_unlock_state();
652
		if (status) {
653
			dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
654 655
			return status;
		}
L
Linus Torvalds 已提交
656
	}
657 658 659
	status = mnt_want_write(cstate->current_fh.fh_export->ex_path.mnt);
	if (status)
		return status;
L
Linus Torvalds 已提交
660 661
	status = nfs_ok;
	if (setattr->sa_acl != NULL)
662 663
		status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
					    setattr->sa_acl);
L
Linus Torvalds 已提交
664
	if (status)
665
		goto out;
666
	status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
L
Linus Torvalds 已提交
667
				0, (time_t)0);
668 669
out:
	mnt_drop_write(cstate->current_fh.fh_export->ex_path.mnt);
L
Linus Torvalds 已提交
670 671 672
	return status;
}

673
static __be32
674 675
nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    struct nfsd4_write *write)
L
Linus Torvalds 已提交
676 677 678 679
{
	stateid_t *stateid = &write->wr_stateid;
	struct file *filp = NULL;
	u32 *p;
680
	__be32 status = nfs_ok;
681
	unsigned long cnt;
L
Linus Torvalds 已提交
682 683 684 685 686 687 688

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

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

	nfs4_lock_state();
689
	status = nfs4_preprocess_stateid_op(&cstate->current_fh, stateid,
690
					WR_STATE, &filp);
691 692
	if (filp)
		get_file(filp);
L
Linus Torvalds 已提交
693 694
	nfs4_unlock_state();

695 696 697 698 699
	if (status) {
		dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
		return status;
	}

700
	cnt = write->wr_buflen;
L
Linus Torvalds 已提交
701 702 703 704 705
	write->wr_how_written = write->wr_stable_how;
	p = (u32 *)write->wr_verifier.data;
	*p++ = nfssvc_boot.tv_sec;
	*p++ = nfssvc_boot.tv_usec;

706 707
	status =  nfsd_write(rqstp, &cstate->current_fh, filp,
			     write->wr_offset, rqstp->rq_vec, write->wr_vlen,
708
			     &cnt, &write->wr_how_written);
709 710
	if (filp)
		fput(filp);
L
Linus Torvalds 已提交
711

712 713
	write->wr_bytes_written = cnt;

L
Linus Torvalds 已提交
714 715 716 717 718 719 720 721 722 723
	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.
 */
724
static __be32
725
_nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
726
	     struct nfsd4_verify *verify)
L
Linus Torvalds 已提交
727
{
A
Al Viro 已提交
728
	__be32 *buf, *p;
L
Linus Torvalds 已提交
729
	int count;
730
	__be32 status;
L
Linus Torvalds 已提交
731

M
Miklos Szeredi 已提交
732
	status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752
	if (status)
		return status;

	if ((verify->ve_bmval[0] & ~NFSD_SUPPORTED_ATTRS_WORD0)
	    || (verify->ve_bmval[1] & ~NFSD_SUPPORTED_ATTRS_WORD1))
		return nfserr_attrnotsupp;
	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;

753 754 755
	status = nfsd4_encode_fattr(&cstate->current_fh,
				    cstate->current_fh.fh_export,
				    cstate->current_fh.fh_dentry, buf,
L
Linus Torvalds 已提交
756
				    &count, verify->ve_bmval,
757
				    rqstp, 0);
L
Linus Torvalds 已提交
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776

	/* 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;

	p = buf + 3;
	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;
}

777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796
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 已提交
797 798 799
/*
 * NULL call.
 */
A
Al Viro 已提交
800
static __be32
L
Linus Torvalds 已提交
801 802 803 804 805
nfsd4_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
{
	return nfs_ok;
}

806 807 808 809 810 811
static inline void nfsd4_increment_op_stats(u32 opnum)
{
	if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP)
		nfsdstats.nfs4_opcount[opnum]++;
}

812 813 814 815 816 817
static void cstate_free(struct nfsd4_compound_state *cstate)
{
	if (cstate == NULL)
		return;
	fh_put(&cstate->current_fh);
	fh_put(&cstate->save_fh);
818
	BUG_ON(cstate->replay_owner);
819 820 821 822 823 824 825 826 827 828 829 830
	kfree(cstate);
}

static struct nfsd4_compound_state *cstate_alloc(void)
{
	struct nfsd4_compound_state *cstate;

	cstate = kmalloc(sizeof(struct nfsd4_compound_state), GFP_KERNEL);
	if (cstate == NULL)
		return NULL;
	fh_init(&cstate->current_fh, NFS4_FHSIZE);
	fh_init(&cstate->save_fh, NFS4_FHSIZE);
831
	cstate->replay_owner = NULL;
832 833
	return cstate;
}
L
Linus Torvalds 已提交
834

835 836 837 838 839 840
typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
			      void *);

struct nfsd4_operation {
	nfsd4op_func op_func;
	u32 op_flags;
841 842
/* Most ops require a valid current filehandle; a few don't: */
#define ALLOWED_WITHOUT_FH 1
843
/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */
844
#define ALLOWED_ON_ABSENT_FS 2
B
Benny Halevy 已提交
845
	char *op_name;
846 847 848 849
};

static struct nfsd4_operation nfsd4_ops[];

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

L
Linus Torvalds 已提交
852 853 854
/*
 * COMPOUND call.
 */
A
Al Viro 已提交
855
static __be32
L
Linus Torvalds 已提交
856 857 858 859 860
nfsd4_proc_compound(struct svc_rqst *rqstp,
		    struct nfsd4_compoundargs *args,
		    struct nfsd4_compoundres *resp)
{
	struct nfsd4_op	*op;
861
	struct nfsd4_operation *opdesc;
862
	struct nfsd4_compound_state *cstate = NULL;
863
	int		slack_bytes;
864
	__be32		status;
L
Linus Torvalds 已提交
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883

	resp->xbuf = &rqstp->rq_res;
	resp->p = rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len;
	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;

	/*
	 * According to RFC3010, this takes precedence over all other errors.
	 */
	status = nfserr_minor_vers_mismatch;
	if (args->minorversion > NFSD_SUPPORTED_MINOR_VERSION)
		goto out;

884 885 886 887 888
	status = nfserr_resource;
	cstate = cstate_alloc();
	if (cstate == NULL)
		goto out;

L
Linus Torvalds 已提交
889 890 891 892
	status = nfs_ok;
	while (!status && resp->opcnt < args->opcnt) {
		op = &args->ops[resp->opcnt++];

B
Benny Halevy 已提交
893 894 895
		dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
			resp->opcnt, args->opcnt, op->opnum,
			nfsd4_op_name(op->opnum));
896

L
Linus Torvalds 已提交
897 898 899 900 901 902 903 904 905 906 907 908 909
		/*
		 * 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.
		 */
910 911 912 913
		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 已提交
914 915 916 917
			op->status = nfserr_resource;
			goto encode_op;
		}

918 919
		opdesc = &nfsd4_ops[op->opnum];

920
		if (!cstate->current_fh.fh_dentry) {
921
			if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
922 923 924
				op->status = nfserr_nofilehandle;
				goto encode_op;
			}
925 926
		} else if (cstate->current_fh.fh_export->ex_fslocs.migrated &&
			  !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
927
			op->status = nfserr_moved;
L
Linus Torvalds 已提交
928 929
			goto encode_op;
		}
930 931 932 933

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

encode_op:
A
Al Viro 已提交
937
		if (op->status == nfserr_replay_me) {
938
			op->replay = &cstate->replay_owner->so_replay;
L
Linus Torvalds 已提交
939 940 941 942 943 944
			nfsd4_encode_replay(resp, op);
			status = op->status = op->replay->rp_status;
		} else {
			nfsd4_encode_operation(resp, op);
			status = op->status;
		}
945 946 947 948 949

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

950 951 952
		if (cstate->replay_owner) {
			nfs4_put_stateowner(cstate->replay_owner);
			cstate->replay_owner = NULL;
L
Linus Torvalds 已提交
953
		}
954 955 956
		/* 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);
957 958

		nfsd4_increment_op_stats(op->opnum);
L
Linus Torvalds 已提交
959 960
	}

961
	cstate_free(cstate);
L
Linus Torvalds 已提交
962 963
out:
	nfsd4_release_compoundargs(args);
964
	dprintk("nfsv4 compound returned %d\n", ntohl(status));
L
Linus Torvalds 已提交
965 966 967
	return status;
}

968 969 970
static struct nfsd4_operation nfsd4_ops[OP_RELEASE_LOCKOWNER+1] = {
	[OP_ACCESS] = {
		.op_func = (nfsd4op_func)nfsd4_access,
B
Benny Halevy 已提交
971
		.op_name = "OP_ACCESS",
972 973 974
	},
	[OP_CLOSE] = {
		.op_func = (nfsd4op_func)nfsd4_close,
B
Benny Halevy 已提交
975
		.op_name = "OP_CLOSE",
976 977 978
	},
	[OP_COMMIT] = {
		.op_func = (nfsd4op_func)nfsd4_commit,
B
Benny Halevy 已提交
979
		.op_name = "OP_COMMIT",
980 981 982
	},
	[OP_CREATE] = {
		.op_func = (nfsd4op_func)nfsd4_create,
B
Benny Halevy 已提交
983
		.op_name = "OP_CREATE",
984 985 986
	},
	[OP_DELEGRETURN] = {
		.op_func = (nfsd4op_func)nfsd4_delegreturn,
B
Benny Halevy 已提交
987
		.op_name = "OP_DELEGRETURN",
988 989 990
	},
	[OP_GETATTR] = {
		.op_func = (nfsd4op_func)nfsd4_getattr,
991
		.op_flags = ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
992
		.op_name = "OP_GETATTR",
993 994 995
	},
	[OP_GETFH] = {
		.op_func = (nfsd4op_func)nfsd4_getfh,
B
Benny Halevy 已提交
996
		.op_name = "OP_GETFH",
997 998 999
	},
	[OP_LINK] = {
		.op_func = (nfsd4op_func)nfsd4_link,
B
Benny Halevy 已提交
1000
		.op_name = "OP_LINK",
1001 1002 1003
	},
	[OP_LOCK] = {
		.op_func = (nfsd4op_func)nfsd4_lock,
B
Benny Halevy 已提交
1004
		.op_name = "OP_LOCK",
1005 1006 1007
	},
	[OP_LOCKT] = {
		.op_func = (nfsd4op_func)nfsd4_lockt,
B
Benny Halevy 已提交
1008
		.op_name = "OP_LOCKT",
1009 1010 1011
	},
	[OP_LOCKU] = {
		.op_func = (nfsd4op_func)nfsd4_locku,
B
Benny Halevy 已提交
1012
		.op_name = "OP_LOCKU",
1013 1014 1015
	},
	[OP_LOOKUP] = {
		.op_func = (nfsd4op_func)nfsd4_lookup,
B
Benny Halevy 已提交
1016
		.op_name = "OP_LOOKUP",
1017 1018 1019
	},
	[OP_LOOKUPP] = {
		.op_func = (nfsd4op_func)nfsd4_lookupp,
B
Benny Halevy 已提交
1020
		.op_name = "OP_LOOKUPP",
1021 1022 1023
	},
	[OP_NVERIFY] = {
		.op_func = (nfsd4op_func)nfsd4_nverify,
B
Benny Halevy 已提交
1024
		.op_name = "OP_NVERIFY",
1025 1026 1027
	},
	[OP_OPEN] = {
		.op_func = (nfsd4op_func)nfsd4_open,
B
Benny Halevy 已提交
1028
		.op_name = "OP_OPEN",
1029 1030 1031
	},
	[OP_OPEN_CONFIRM] = {
		.op_func = (nfsd4op_func)nfsd4_open_confirm,
B
Benny Halevy 已提交
1032
		.op_name = "OP_OPEN_CONFIRM",
1033 1034 1035
	},
	[OP_OPEN_DOWNGRADE] = {
		.op_func = (nfsd4op_func)nfsd4_open_downgrade,
B
Benny Halevy 已提交
1036
		.op_name = "OP_OPEN_DOWNGRADE",
1037 1038 1039
	},
	[OP_PUTFH] = {
		.op_func = (nfsd4op_func)nfsd4_putfh,
1040
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1041
		.op_name = "OP_PUTFH",
1042
	},
1043
	[OP_PUTPUBFH] = {
1044
		.op_func = (nfsd4op_func)nfsd4_putrootfh,
1045
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1046
		.op_name = "OP_PUTPUBFH",
1047
	},
1048 1049
	[OP_PUTROOTFH] = {
		.op_func = (nfsd4op_func)nfsd4_putrootfh,
1050
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1051
		.op_name = "OP_PUTROOTFH",
1052 1053 1054
	},
	[OP_READ] = {
		.op_func = (nfsd4op_func)nfsd4_read,
B
Benny Halevy 已提交
1055
		.op_name = "OP_READ",
1056 1057 1058
	},
	[OP_READDIR] = {
		.op_func = (nfsd4op_func)nfsd4_readdir,
B
Benny Halevy 已提交
1059
		.op_name = "OP_READDIR",
1060 1061 1062
	},
	[OP_READLINK] = {
		.op_func = (nfsd4op_func)nfsd4_readlink,
B
Benny Halevy 已提交
1063
		.op_name = "OP_READLINK",
1064 1065 1066
	},
	[OP_REMOVE] = {
		.op_func = (nfsd4op_func)nfsd4_remove,
B
Benny Halevy 已提交
1067
		.op_name = "OP_REMOVE",
1068 1069
	},
	[OP_RENAME] = {
B
Benny Halevy 已提交
1070
		.op_name = "OP_RENAME",
1071 1072 1073 1074
		.op_func = (nfsd4op_func)nfsd4_rename,
	},
	[OP_RENEW] = {
		.op_func = (nfsd4op_func)nfsd4_renew,
1075
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1076
		.op_name = "OP_RENEW",
1077 1078 1079
	},
	[OP_RESTOREFH] = {
		.op_func = (nfsd4op_func)nfsd4_restorefh,
1080
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1081
		.op_name = "OP_RESTOREFH",
1082 1083 1084
	},
	[OP_SAVEFH] = {
		.op_func = (nfsd4op_func)nfsd4_savefh,
B
Benny Halevy 已提交
1085
		.op_name = "OP_SAVEFH",
1086
	},
A
Andy Adamson 已提交
1087 1088
	[OP_SECINFO] = {
		.op_func = (nfsd4op_func)nfsd4_secinfo,
B
Benny Halevy 已提交
1089
		.op_name = "OP_SECINFO",
A
Andy Adamson 已提交
1090
	},
1091 1092
	[OP_SETATTR] = {
		.op_func = (nfsd4op_func)nfsd4_setattr,
B
Benny Halevy 已提交
1093
		.op_name = "OP_SETATTR",
1094 1095 1096
	},
	[OP_SETCLIENTID] = {
		.op_func = (nfsd4op_func)nfsd4_setclientid,
1097
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1098
		.op_name = "OP_SETCLIENTID",
1099 1100 1101
	},
	[OP_SETCLIENTID_CONFIRM] = {
		.op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
1102
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1103
		.op_name = "OP_SETCLIENTID_CONFIRM",
1104 1105 1106
	},
	[OP_VERIFY] = {
		.op_func = (nfsd4op_func)nfsd4_verify,
B
Benny Halevy 已提交
1107
		.op_name = "OP_VERIFY",
1108 1109 1110
	},
	[OP_WRITE] = {
		.op_func = (nfsd4op_func)nfsd4_write,
B
Benny Halevy 已提交
1111
		.op_name = "OP_WRITE",
1112 1113 1114
	},
	[OP_RELEASE_LOCKOWNER] = {
		.op_func = (nfsd4op_func)nfsd4_release_lockowner,
1115
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
B
Benny Halevy 已提交
1116
		.op_name = "OP_RELEASE_LOCKOWNER",
1117 1118 1119
	},
};

A
Adrian Bunk 已提交
1120
static const char *nfsd4_op_name(unsigned opnum)
B
Benny Halevy 已提交
1121 1122 1123 1124 1125 1126
{
	if (opnum < ARRAY_SIZE(nfsd4_ops))
		return nfsd4_ops[opnum].op_name;
	return "unknown_operation";
}

L
Linus Torvalds 已提交
1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156
#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),
1157
  PROC(compound, compound,	compound,	compound, RC_NOCACHE, NFSD_BUFSIZE/4)
L
Linus Torvalds 已提交
1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172
};

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:
 */