nfs4proc.c 30.6 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
typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
			      void *);

struct nfsd4_operation {
	nfsd4op_func op_func;
	u32 op_flags;
818 819
/* Most ops require a valid current filehandle; a few don't: */
#define ALLOWED_WITHOUT_FH 1
820
/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */
821
#define ALLOWED_ON_ABSENT_FS 2
B
Benny Halevy 已提交
822
	char *op_name;
823 824 825 826
};

static struct nfsd4_operation nfsd4_ops[];

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

L
Linus Torvalds 已提交
829 830 831
/*
 * COMPOUND call.
 */
A
Al Viro 已提交
832
static __be32
L
Linus Torvalds 已提交
833 834 835 836 837
nfsd4_proc_compound(struct svc_rqst *rqstp,
		    struct nfsd4_compoundargs *args,
		    struct nfsd4_compoundres *resp)
{
	struct nfsd4_op	*op;
838
	struct nfsd4_operation *opdesc;
839
	struct nfsd4_compound_state *cstate = &resp->cstate;
840
	int		slack_bytes;
841
	__be32		status;
L
Linus Torvalds 已提交
842 843

	resp->xbuf = &rqstp->rq_res;
844 845
	resp->p = rqstp->rq_res.head[0].iov_base +
						rqstp->rq_res.head[0].iov_len;
L
Linus Torvalds 已提交
846 847 848 849 850 851 852 853
	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;
854 855 856
	resp->cstate.replay_owner = NULL;
	fh_init(&resp->cstate.current_fh, NFS4_FHSIZE);
	fh_init(&resp->cstate.save_fh, NFS4_FHSIZE);
L
Linus Torvalds 已提交
857 858 859 860 861 862 863 864 865 866 867 868

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

	status = nfs_ok;
	while (!status && resp->opcnt < args->opcnt) {
		op = &args->ops[resp->opcnt++];

B
Benny Halevy 已提交
869 870 871
		dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
			resp->opcnt, args->opcnt, op->opnum,
			nfsd4_op_name(op->opnum));
872

L
Linus Torvalds 已提交
873 874 875 876 877 878 879 880 881 882 883 884 885
		/*
		 * 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.
		 */
886 887 888 889
		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 已提交
890 891 892 893
			op->status = nfserr_resource;
			goto encode_op;
		}

894 895
		opdesc = &nfsd4_ops[op->opnum];

896
		if (!cstate->current_fh.fh_dentry) {
897
			if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
898 899 900
				op->status = nfserr_nofilehandle;
				goto encode_op;
			}
901 902
		} else if (cstate->current_fh.fh_export->ex_fslocs.migrated &&
			  !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
903
			op->status = nfserr_moved;
L
Linus Torvalds 已提交
904 905
			goto encode_op;
		}
906 907 908 909

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

encode_op:
A
Al Viro 已提交
913
		if (op->status == nfserr_replay_me) {
914
			op->replay = &cstate->replay_owner->so_replay;
L
Linus Torvalds 已提交
915 916 917 918 919 920
			nfsd4_encode_replay(resp, op);
			status = op->status = op->replay->rp_status;
		} else {
			nfsd4_encode_operation(resp, op);
			status = op->status;
		}
921 922 923 924 925

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

926 927 928
		if (cstate->replay_owner) {
			nfs4_put_stateowner(cstate->replay_owner);
			cstate->replay_owner = NULL;
L
Linus Torvalds 已提交
929
		}
930 931 932
		/* 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);
933 934

		nfsd4_increment_op_stats(op->opnum);
L
Linus Torvalds 已提交
935 936
	}

937 938 939
	fh_put(&resp->cstate.current_fh);
	fh_put(&resp->cstate.save_fh);
	BUG_ON(resp->cstate.replay_owner);
L
Linus Torvalds 已提交
940 941
out:
	nfsd4_release_compoundargs(args);
942
	dprintk("nfsv4 compound returned %d\n", ntohl(status));
L
Linus Torvalds 已提交
943 944 945
	return status;
}

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

A
Adrian Bunk 已提交
1098
static const char *nfsd4_op_name(unsigned opnum)
B
Benny Halevy 已提交
1099 1100 1101 1102 1103 1104
{
	if (opnum < ARRAY_SIZE(nfsd4_ops))
		return nfsd4_ops[opnum].op_name;
	return "unknown_operation";
}

L
Linus Torvalds 已提交
1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134
#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),
1135
  PROC(compound, compound,	compound,	compound, RC_NOCACHE, NFSD_BUFSIZE/4)
L
Linus Torvalds 已提交
1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
};

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