nfs4proc.c 31.3 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);
L
Linus Torvalds 已提交
123

124 125 126 127 128
	/* set reply cache */
	fh_dup2(current_fh, &resfh);
	open->op_stateowner->so_replay.rp_openfh_len = resfh.fh_handle.fh_size;
	memcpy(open->op_stateowner->so_replay.rp_openfh,
			&resfh.fh_handle.fh_base, resfh.fh_handle.fh_size);
L
Linus Torvalds 已提交
129

130
	if (!created)
M
Miklos Szeredi 已提交
131 132
		status = do_open_permission(rqstp, current_fh, open,
					    NFSD_MAY_NOP);
L
Linus Torvalds 已提交
133

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

139
static __be32
L
Linus Torvalds 已提交
140 141
do_open_fhandle(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
142
	__be32 status;
L
Linus Torvalds 已提交
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

	/* 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 */
	open->op_stateowner->so_replay.rp_openfh_len = current_fh->fh_handle.fh_size;
	memcpy(open->op_stateowner->so_replay.rp_openfh,
		&current_fh->fh_handle.fh_base,
		current_fh->fh_handle.fh_size);

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

M
Miklos Szeredi 已提交
163 164
	status = do_open_permission(rqstp, current_fh, open,
				    NFSD_MAY_OWNER_OVERRIDE);
L
Linus Torvalds 已提交
165 166 167 168 169

	return status;
}


170
static __be32
171
nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
172
	   struct nfsd4_open *open)
L
Linus Torvalds 已提交
173
{
174
	__be32 status;
L
Linus Torvalds 已提交
175 176 177 178 179 180 181 182 183 184 185 186
	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 已提交
187
	if (status == nfserr_replay_me) {
L
Linus Torvalds 已提交
188
		struct nfs4_replay *rp = &open->op_stateowner->so_replay;
189 190 191
		fh_put(&cstate->current_fh);
		cstate->current_fh.fh_handle.fh_size = rp->rp_openfh_len;
		memcpy(&cstate->current_fh.fh_handle.fh_base, rp->rp_openfh,
L
Linus Torvalds 已提交
192
				rp->rp_openfh_len);
M
Miklos Szeredi 已提交
193
		status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
194 195 196 197
		if (status)
			dprintk("nfsd4_open: replay failed"
				" restoring previous filehandle\n");
		else
A
Al Viro 已提交
198
			status = nfserr_replay_me;
L
Linus Torvalds 已提交
199 200 201
	}
	if (status)
		goto out;
202 203 204

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

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

/*
 * filehandle-manipulating ops.
 */
273
static __be32
274 275
nfsd4_getfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    struct svc_fh **getfh)
L
Linus Torvalds 已提交
276
{
277
	if (!cstate->current_fh.fh_dentry)
L
Linus Torvalds 已提交
278 279
		return nfserr_nofilehandle;

280
	*getfh = &cstate->current_fh;
L
Linus Torvalds 已提交
281 282 283
	return nfs_ok;
}

284
static __be32
285 286
nfsd4_putfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    struct nfsd4_putfh *putfh)
L
Linus Torvalds 已提交
287
{
288 289 290 291
	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 已提交
292
	return fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
293 294
}

295
static __be32
296 297
nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		void *arg)
L
Linus Torvalds 已提交
298
{
299
	__be32 status;
L
Linus Torvalds 已提交
300

301
	fh_put(&cstate->current_fh);
302
	status = exp_pseudoroot(rqstp, &cstate->current_fh);
L
Linus Torvalds 已提交
303 304 305
	return status;
}

306
static __be32
307 308
nfsd4_restorefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		void *arg)
L
Linus Torvalds 已提交
309
{
310
	if (!cstate->save_fh.fh_dentry)
L
Linus Torvalds 已提交
311 312
		return nfserr_restorefh;

313
	fh_dup2(&cstate->current_fh, &cstate->save_fh);
L
Linus Torvalds 已提交
314 315 316
	return nfs_ok;
}

317
static __be32
318 319
nfsd4_savefh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     void *arg)
L
Linus Torvalds 已提交
320
{
321
	if (!cstate->current_fh.fh_dentry)
L
Linus Torvalds 已提交
322 323
		return nfserr_nofilehandle;

324
	fh_dup2(&cstate->save_fh, &cstate->current_fh);
L
Linus Torvalds 已提交
325 326 327 328 329 330
	return nfs_ok;
}

/*
 * misc nfsv4 ops
 */
331
static __be32
332 333
nfsd4_access(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_access *access)
L
Linus Torvalds 已提交
334 335 336 337 338
{
	if (access->ac_req_access & ~NFS3_ACCESS_FULL)
		return nfserr_inval;

	access->ac_resp_access = access->ac_req_access;
339 340
	return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access,
			   &access->ac_supported);
L
Linus Torvalds 已提交
341 342
}

343
static __be32
344 345
nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_commit *commit)
L
Linus Torvalds 已提交
346
{
347
	__be32 status;
L
Linus Torvalds 已提交
348 349 350 351 352

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

353 354
	status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
			     commit->co_count);
L
Linus Torvalds 已提交
355 356 357 358 359
	if (status == nfserr_symlink)
		status = nfserr_inval;
	return status;
}

360
static __be32
361 362
nfsd4_create(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_create *create)
L
Linus Torvalds 已提交
363 364
{
	struct svc_fh resfh;
365
	__be32 status;
L
Linus Torvalds 已提交
366 367 368 369
	dev_t rdev;

	fh_init(&resfh, NFS4_FHSIZE);

M
Miklos Szeredi 已提交
370 371
	status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR,
			   NFSD_MAY_CREATE);
L
Linus Torvalds 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
	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;

388 389 390 391
		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 已提交
392 393 394 395 396 397 398
		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;
399 400 401
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFBLK, rdev, &resfh);
L
Linus Torvalds 已提交
402 403 404 405 406 407 408
		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;
409 410 411
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr,S_IFCHR, rdev, &resfh);
L
Linus Torvalds 已提交
412 413 414
		break;

	case NF4SOCK:
415 416 417
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFSOCK, 0, &resfh);
L
Linus Torvalds 已提交
418 419 420
		break;

	case NF4FIFO:
421 422 423
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFIFO, 0, &resfh);
L
Linus Torvalds 已提交
424 425 426 427
		break;

	case NF4DIR:
		create->cr_iattr.ia_valid &= ~ATTR_SIZE;
428 429 430
		status = nfsd_create(rqstp, &cstate->current_fh,
				     create->cr_name, create->cr_namelen,
				     &create->cr_iattr, S_IFDIR, 0, &resfh);
L
Linus Torvalds 已提交
431 432 433 434 435 436 437
		break;

	default:
		status = nfserr_badtype;
	}

	if (!status) {
438 439 440
		fh_unlock(&cstate->current_fh);
		set_change_info(&create->cr_cinfo, &cstate->current_fh);
		fh_dup2(&cstate->current_fh, &resfh);
L
Linus Torvalds 已提交
441 442 443 444 445 446
	}

	fh_put(&resfh);
	return status;
}

447
static __be32
448 449
nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_getattr *getattr)
L
Linus Torvalds 已提交
450
{
451
	__be32 status;
L
Linus Torvalds 已提交
452

M
Miklos Szeredi 已提交
453
	status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
454 455 456 457 458 459 460 461 462
	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;

463
	getattr->ga_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
464 465 466
	return nfs_ok;
}

467
static __be32
468 469
nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	   struct nfsd4_link *link)
L
Linus Torvalds 已提交
470
{
471
	__be32 status = nfserr_nofilehandle;
L
Linus Torvalds 已提交
472

473
	if (!cstate->save_fh.fh_dentry)
L
Linus Torvalds 已提交
474
		return status;
475 476
	status = nfsd_link(rqstp, &cstate->current_fh,
			   link->li_name, link->li_namelen, &cstate->save_fh);
L
Linus Torvalds 已提交
477
	if (!status)
478
		set_change_info(&link->li_cinfo, &cstate->current_fh);
L
Linus Torvalds 已提交
479 480 481
	return status;
}

482
static __be32
483 484
nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      void *arg)
L
Linus Torvalds 已提交
485 486
{
	struct svc_fh tmp_fh;
487
	__be32 ret;
L
Linus Torvalds 已提交
488 489

	fh_init(&tmp_fh, NFS4_FHSIZE);
490 491
	ret = exp_pseudoroot(rqstp, &tmp_fh);
	if (ret)
L
Linus Torvalds 已提交
492
		return ret;
493
	if (tmp_fh.fh_dentry == cstate->current_fh.fh_dentry) {
L
Linus Torvalds 已提交
494 495 496 497
		fh_put(&tmp_fh);
		return nfserr_noent;
	}
	fh_put(&tmp_fh);
498 499
	return nfsd_lookup(rqstp, &cstate->current_fh,
			   "..", 2, &cstate->current_fh);
L
Linus Torvalds 已提交
500 501
}

502
static __be32
503 504
nfsd4_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_lookup *lookup)
L
Linus Torvalds 已提交
505
{
506 507 508
	return nfsd_lookup(rqstp, &cstate->current_fh,
			   lookup->lo_name, lookup->lo_len,
			   &cstate->current_fh);
L
Linus Torvalds 已提交
509 510
}

511
static __be32
512 513
nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	   struct nfsd4_read *read)
L
Linus Torvalds 已提交
514
{
515
	__be32 status;
L
Linus Torvalds 已提交
516 517 518

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

519
	read->rd_filp = NULL;
L
Linus Torvalds 已提交
520 521 522 523 524
	if (read->rd_offset >= OFFSET_MAX)
		return nfserr_inval;

	nfs4_lock_state();
	/* check stateid */
525 526
	if ((status = nfs4_preprocess_stateid_op(&cstate->current_fh,
				&read->rd_stateid,
527
				CHECK_FH | RD_STATE, &read->rd_filp))) {
L
Linus Torvalds 已提交
528 529 530
		dprintk("NFSD: nfsd4_read: couldn't process stateid!\n");
		goto out;
	}
531 532
	if (read->rd_filp)
		get_file(read->rd_filp);
L
Linus Torvalds 已提交
533 534 535 536
	status = nfs_ok;
out:
	nfs4_unlock_state();
	read->rd_rqstp = rqstp;
537
	read->rd_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
538 539 540
	return status;
}

541
static __be32
542 543
nfsd4_readdir(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_readdir *readdir)
L
Linus Torvalds 已提交
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
{
	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;
561
	readdir->rd_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
562 563 564
	return nfs_ok;
}

565
static __be32
566 567
nfsd4_readlink(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	       struct nfsd4_readlink *readlink)
L
Linus Torvalds 已提交
568 569
{
	readlink->rl_rqstp = rqstp;
570
	readlink->rl_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
571 572 573
	return nfs_ok;
}

574
static __be32
575 576
nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_remove *remove)
L
Linus Torvalds 已提交
577
{
578
	__be32 status;
L
Linus Torvalds 已提交
579

580
	if (locks_in_grace())
581
		return nfserr_grace;
582 583
	status = nfsd_unlink(rqstp, &cstate->current_fh, 0,
			     remove->rm_name, remove->rm_namelen);
L
Linus Torvalds 已提交
584 585 586
	if (status == nfserr_symlink)
		return nfserr_notdir;
	if (!status) {
587 588
		fh_unlock(&cstate->current_fh);
		set_change_info(&remove->rm_cinfo, &cstate->current_fh);
L
Linus Torvalds 已提交
589 590 591 592
	}
	return status;
}

593
static __be32
594 595
nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_rename *rename)
L
Linus Torvalds 已提交
596
{
597
	__be32 status = nfserr_nofilehandle;
L
Linus Torvalds 已提交
598

599
	if (!cstate->save_fh.fh_dentry)
L
Linus Torvalds 已提交
600
		return status;
601
	if (locks_in_grace() && !(cstate->save_fh.fh_export->ex_flags
602 603
					& NFSEXP_NOSUBTREECHECK))
		return nfserr_grace;
604 605
	status = nfsd_rename(rqstp, &cstate->save_fh, rename->rn_sname,
			     rename->rn_snamelen, &cstate->current_fh,
L
Linus Torvalds 已提交
606 607 608 609 610 611 612
			     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) &&
613 614
                  (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 已提交
615 616 617 618 619
		status = nfserr_exist;
	else if (status == nfserr_symlink)
		status = nfserr_notdir;

	if (!status) {
620 621
		set_change_info(&rename->rn_sinfo, &cstate->current_fh);
		set_change_info(&rename->rn_tinfo, &cstate->save_fh);
L
Linus Torvalds 已提交
622 623 624 625
	}
	return status;
}

A
Andy Adamson 已提交
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
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;
}

650
static __be32
651 652
nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_setattr *setattr)
L
Linus Torvalds 已提交
653
{
654
	__be32 status = nfs_ok;
L
Linus Torvalds 已提交
655 656 657

	if (setattr->sa_iattr.ia_valid & ATTR_SIZE) {
		nfs4_lock_state();
658
		status = nfs4_preprocess_stateid_op(&cstate->current_fh,
659
			&setattr->sa_stateid, CHECK_FH | WR_STATE, NULL);
L
Linus Torvalds 已提交
660
		nfs4_unlock_state();
661
		if (status) {
662
			dprintk("NFSD: nfsd4_setattr: couldn't process stateid!\n");
663 664
			return status;
		}
L
Linus Torvalds 已提交
665
	}
666 667 668
	status = mnt_want_write(cstate->current_fh.fh_export->ex_path.mnt);
	if (status)
		return status;
L
Linus Torvalds 已提交
669 670
	status = nfs_ok;
	if (setattr->sa_acl != NULL)
671 672
		status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
					    setattr->sa_acl);
L
Linus Torvalds 已提交
673
	if (status)
674
		goto out;
675
	status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
L
Linus Torvalds 已提交
676
				0, (time_t)0);
677 678
out:
	mnt_drop_write(cstate->current_fh.fh_export->ex_path.mnt);
L
Linus Torvalds 已提交
679 680 681
	return status;
}

682
static __be32
683 684
nfsd4_write(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    struct nfsd4_write *write)
L
Linus Torvalds 已提交
685 686 687 688
{
	stateid_t *stateid = &write->wr_stateid;
	struct file *filp = NULL;
	u32 *p;
689
	__be32 status = nfs_ok;
L
Linus Torvalds 已提交
690 691 692 693 694 695 696

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

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

	nfs4_lock_state();
697
	status = nfs4_preprocess_stateid_op(&cstate->current_fh, stateid,
698
					CHECK_FH | WR_STATE, &filp);
699 700
	if (filp)
		get_file(filp);
L
Linus Torvalds 已提交
701 702
	nfs4_unlock_state();

703 704 705 706 707
	if (status) {
		dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
		return status;
	}

L
Linus Torvalds 已提交
708 709 710 711 712 713
	write->wr_bytes_written = write->wr_buflen;
	write->wr_how_written = write->wr_stable_how;
	p = (u32 *)write->wr_verifier.data;
	*p++ = nfssvc_boot.tv_sec;
	*p++ = nfssvc_boot.tv_usec;

714 715 716
	status =  nfsd_write(rqstp, &cstate->current_fh, filp,
			     write->wr_offset, rqstp->rq_vec, write->wr_vlen,
			     write->wr_buflen, &write->wr_how_written);
717 718
	if (filp)
		fput(filp);
L
Linus Torvalds 已提交
719 720 721 722 723 724 725 726 727 728 729

	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.
 */
730
static __be32
731
_nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
732
	     struct nfsd4_verify *verify)
L
Linus Torvalds 已提交
733
{
A
Al Viro 已提交
734
	__be32 *buf, *p;
L
Linus Torvalds 已提交
735
	int count;
736
	__be32 status;
L
Linus Torvalds 已提交
737

M
Miklos Szeredi 已提交
738
	status = fh_verify(rqstp, &cstate->current_fh, 0, NFSD_MAY_NOP);
L
Linus Torvalds 已提交
739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758
	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;

759 760 761
	status = nfsd4_encode_fattr(&cstate->current_fh,
				    cstate->current_fh.fh_export,
				    cstate->current_fh.fh_dentry, buf,
L
Linus Torvalds 已提交
762
				    &count, verify->ve_bmval,
763
				    rqstp, 0);
L
Linus Torvalds 已提交
764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782

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

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

812 813 814 815 816 817
static inline void nfsd4_increment_op_stats(u32 opnum)
{
	if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP)
		nfsdstats.nfs4_opcount[opnum]++;
}

818 819 820 821 822 823
static void cstate_free(struct nfsd4_compound_state *cstate)
{
	if (cstate == NULL)
		return;
	fh_put(&cstate->current_fh);
	fh_put(&cstate->save_fh);
824
	BUG_ON(cstate->replay_owner);
825 826 827 828 829 830 831 832 833 834 835 836
	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);
837
	cstate->replay_owner = NULL;
838 839
	return cstate;
}
L
Linus Torvalds 已提交
840

841 842 843 844 845 846
typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
			      void *);

struct nfsd4_operation {
	nfsd4op_func op_func;
	u32 op_flags;
847 848
/* Most ops require a valid current filehandle; a few don't: */
#define ALLOWED_WITHOUT_FH 1
849
/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */
850
#define ALLOWED_ON_ABSENT_FS 2
B
Benny Halevy 已提交
851
	char *op_name;
852 853 854 855
};

static struct nfsd4_operation nfsd4_ops[];

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

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

	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;

890 891 892 893 894
	status = nfserr_resource;
	cstate = cstate_alloc();
	if (cstate == NULL)
		goto out;

L
Linus Torvalds 已提交
895 896 897 898
	status = nfs_ok;
	while (!status && resp->opcnt < args->opcnt) {
		op = &args->ops[resp->opcnt++];

B
Benny Halevy 已提交
899 900 901
		dprintk("nfsv4 compound op #%d/%d: %d (%s)\n",
			resp->opcnt, args->opcnt, op->opnum,
			nfsd4_op_name(op->opnum));
902

L
Linus Torvalds 已提交
903 904 905 906 907 908 909 910 911 912 913 914 915
		/*
		 * 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.
		 */
916 917 918 919
		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 已提交
920 921 922 923
			op->status = nfserr_resource;
			goto encode_op;
		}

924 925
		opdesc = &nfsd4_ops[op->opnum];

926
		if (!cstate->current_fh.fh_dentry) {
927
			if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
928 929 930
				op->status = nfserr_nofilehandle;
				goto encode_op;
			}
931 932
		} else if (cstate->current_fh.fh_export->ex_fslocs.migrated &&
			  !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
933
			op->status = nfserr_moved;
L
Linus Torvalds 已提交
934 935
			goto encode_op;
		}
936 937 938 939

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

encode_op:
A
Al Viro 已提交
943
		if (op->status == nfserr_replay_me) {
944
			op->replay = &cstate->replay_owner->so_replay;
L
Linus Torvalds 已提交
945 946 947 948 949 950
			nfsd4_encode_replay(resp, op);
			status = op->status = op->replay->rp_status;
		} else {
			nfsd4_encode_operation(resp, op);
			status = op->status;
		}
951 952 953 954 955

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

956 957 958
		if (cstate->replay_owner) {
			nfs4_put_stateowner(cstate->replay_owner);
			cstate->replay_owner = NULL;
L
Linus Torvalds 已提交
959
		}
960 961 962
		/* 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);
963 964

		nfsd4_increment_op_stats(op->opnum);
L
Linus Torvalds 已提交
965 966
	}

967
	cstate_free(cstate);
L
Linus Torvalds 已提交
968 969
out:
	nfsd4_release_compoundargs(args);
970
	dprintk("nfsv4 compound returned %d\n", ntohl(status));
L
Linus Torvalds 已提交
971 972 973
	return status;
}

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

A
Adrian Bunk 已提交
1126
static const char *nfsd4_op_name(unsigned opnum)
B
Benny Halevy 已提交
1127 1128 1129 1130 1131 1132
{
	if (opnum < ARRAY_SIZE(nfsd4_ops))
		return nfsd4_ops[opnum].op_name;
	return "unknown_operation";
}

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

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