nfs4proc.c 29.7 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)
74
		accmode |= MAY_READ;
75
	if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
L
Linus Torvalds 已提交
76
		accmode |= (MAY_WRITE | MAY_TRUNC);
77 78
	if (open->op_share_deny & NFS4_SHARE_DENY_WRITE)
		accmode |= 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 106 107 108 109 110 111
					(u32 *)open->op_verf.data,
					&open->op_truncate, &created);

		/* If we ever decide to use different attrs to store the
		 * verifier in nfsd_create_v3, then we'll need to change this
		 */
		if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0)
			open->op_bmval[1] |= (FATTR4_WORD1_TIME_ACCESS |
						FATTR4_WORD1_TIME_MODIFY);
112
	} else {
L
Linus Torvalds 已提交
113 114 115 116
		status = nfsd_lookup(rqstp, current_fh,
				     open->op_fname.data, open->op_fname.len, &resfh);
		fh_unlock(current_fh);
	}
117 118
	if (status)
		goto out;
L
Linus Torvalds 已提交
119

120
	set_change_info(&open->op_cinfo, current_fh);
L
Linus Torvalds 已提交
121

122 123 124 125 126
	/* 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 已提交
127

128 129
	if (!created)
		status = do_open_permission(rqstp, current_fh, open, MAY_NOP);
L
Linus Torvalds 已提交
130

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

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

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

160
	status = do_open_permission(rqstp, current_fh, open, 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 186 187
		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 已提交
188
				rp->rp_openfh_len);
189
		status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP);
L
Linus Torvalds 已提交
190 191 192 193
		if (status)
			dprintk("nfsd4_open: replay failed"
				" restoring previous filehandle\n");
		else
A
Al Viro 已提交
194
			status = nfserr_replay_me;
L
Linus Torvalds 已提交
195 196 197
	}
	if (status)
		goto out;
198 199 200

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

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

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

276
	*getfh = &cstate->current_fh;
L
Linus Torvalds 已提交
277 278 279
	return nfs_ok;
}

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

291
static __be32
292 293
nfsd4_putrootfh(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		void *arg)
L
Linus Torvalds 已提交
294
{
295
	__be32 status;
L
Linus Torvalds 已提交
296

297
	fh_put(&cstate->current_fh);
298
	status = exp_pseudoroot(rqstp, &cstate->current_fh);
L
Linus Torvalds 已提交
299 300 301
	return status;
}

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

309
	fh_dup2(&cstate->current_fh, &cstate->save_fh);
L
Linus Torvalds 已提交
310 311 312
	return nfs_ok;
}

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

320
	fh_dup2(&cstate->save_fh, &cstate->current_fh);
L
Linus Torvalds 已提交
321 322 323 324 325 326
	return nfs_ok;
}

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

	access->ac_resp_access = access->ac_req_access;
335 336
	return nfsd_access(rqstp, &cstate->current_fh, &access->ac_resp_access,
			   &access->ac_supported);
L
Linus Torvalds 已提交
337 338
}

339
static __be32
340 341
nfsd4_commit(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_commit *commit)
L
Linus Torvalds 已提交
342
{
343
	__be32 status;
L
Linus Torvalds 已提交
344 345 346 347 348

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

349 350
	status = nfsd_commit(rqstp, &cstate->current_fh, commit->co_offset,
			     commit->co_count);
L
Linus Torvalds 已提交
351 352 353 354 355
	if (status == nfserr_symlink)
		status = nfserr_inval;
	return status;
}

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

	fh_init(&resfh, NFS4_FHSIZE);

366
	status = fh_verify(rqstp, &cstate->current_fh, S_IFDIR, MAY_CREATE);
L
Linus Torvalds 已提交
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382
	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;

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

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

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

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

	default:
		status = nfserr_badtype;
	}

	if (!status) {
433 434 435
		fh_unlock(&cstate->current_fh);
		set_change_info(&create->cr_cinfo, &cstate->current_fh);
		fh_dup2(&cstate->current_fh, &resfh);
L
Linus Torvalds 已提交
436 437 438 439 440 441
	}

	fh_put(&resfh);
	return status;
}

442
static __be32
443 444
nfsd4_getattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_getattr *getattr)
L
Linus Torvalds 已提交
445
{
446
	__be32 status;
L
Linus Torvalds 已提交
447

448
	status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP);
L
Linus Torvalds 已提交
449 450 451 452 453 454 455 456 457
	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;

458
	getattr->ga_fhp = &cstate->current_fh;
L
Linus Torvalds 已提交
459 460 461
	return nfs_ok;
}

462
static __be32
463 464
nfsd4_link(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	   struct nfsd4_link *link)
L
Linus Torvalds 已提交
465
{
466
	__be32 status = nfserr_nofilehandle;
L
Linus Torvalds 已提交
467

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

477
static __be32
478 479
nfsd4_lookupp(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      void *arg)
L
Linus Torvalds 已提交
480 481
{
	struct svc_fh tmp_fh;
482
	__be32 ret;
L
Linus Torvalds 已提交
483 484

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

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

506
static __be32
507 508
nfsd4_read(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	   struct nfsd4_read *read)
L
Linus Torvalds 已提交
509
{
510
	__be32 status;
L
Linus Torvalds 已提交
511 512 513

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

514
	read->rd_filp = NULL;
L
Linus Torvalds 已提交
515 516 517 518 519
	if (read->rd_offset >= OFFSET_MAX)
		return nfserr_inval;

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

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

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

569
static __be32
570 571
nfsd4_remove(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_remove *remove)
L
Linus Torvalds 已提交
572
{
573
	__be32 status;
L
Linus Torvalds 已提交
574

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

588
static __be32
589 590
nfsd4_rename(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	     struct nfsd4_rename *rename)
L
Linus Torvalds 已提交
591
{
592
	__be32 status = nfserr_nofilehandle;
L
Linus Torvalds 已提交
593

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

	if (!status) {
615 616
		set_change_info(&rename->rn_sinfo, &cstate->current_fh);
		set_change_info(&rename->rn_tinfo, &cstate->save_fh);
L
Linus Torvalds 已提交
617 618 619 620
	}
	return status;
}

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

645
static __be32
646 647
nfsd4_setattr(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	      struct nfsd4_setattr *setattr)
L
Linus Torvalds 已提交
648
{
649
	__be32 status = nfs_ok;
L
Linus Torvalds 已提交
650 651 652

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

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

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

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

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

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

L
Linus Torvalds 已提交
698 699 700 701 702 703
	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;

704 705 706
	status =  nfsd_write(rqstp, &cstate->current_fh, filp,
			     write->wr_offset, rqstp->rq_vec, write->wr_vlen,
			     write->wr_buflen, &write->wr_how_written);
707 708
	if (filp)
		fput(filp);
L
Linus Torvalds 已提交
709 710 711 712 713 714 715 716 717 718 719

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

728
	status = fh_verify(rqstp, &cstate->current_fh, 0, MAY_NOP);
L
Linus Torvalds 已提交
729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
	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;

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

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

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

802 803 804 805 806 807
static inline void nfsd4_increment_op_stats(u32 opnum)
{
	if (opnum >= FIRST_NFS4_OP && opnum <= LAST_NFS4_OP)
		nfsdstats.nfs4_opcount[opnum]++;
}

808 809 810 811 812 813
static void cstate_free(struct nfsd4_compound_state *cstate)
{
	if (cstate == NULL)
		return;
	fh_put(&cstate->current_fh);
	fh_put(&cstate->save_fh);
814
	BUG_ON(cstate->replay_owner);
815 816 817 818 819 820 821 822 823 824 825 826
	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);
827
	cstate->replay_owner = NULL;
828 829
	return cstate;
}
L
Linus Torvalds 已提交
830

831 832 833 834 835 836
typedef __be32(*nfsd4op_func)(struct svc_rqst *, struct nfsd4_compound_state *,
			      void *);

struct nfsd4_operation {
	nfsd4op_func op_func;
	u32 op_flags;
837 838
/* Most ops require a valid current filehandle; a few don't: */
#define ALLOWED_WITHOUT_FH 1
839
/* GETATTR and ops not listed as returning NFS4ERR_MOVED: */
840
#define ALLOWED_ON_ABSENT_FS 2
841 842 843 844
};

static struct nfsd4_operation nfsd4_ops[];

L
Linus Torvalds 已提交
845 846 847
/*
 * COMPOUND call.
 */
A
Al Viro 已提交
848
static __be32
L
Linus Torvalds 已提交
849 850 851 852 853
nfsd4_proc_compound(struct svc_rqst *rqstp,
		    struct nfsd4_compoundargs *args,
		    struct nfsd4_compoundres *resp)
{
	struct nfsd4_op	*op;
854
	struct nfsd4_operation *opdesc;
855
	struct nfsd4_compound_state *cstate = NULL;
856
	int		slack_bytes;
857
	__be32		status;
L
Linus Torvalds 已提交
858 859

	status = nfserr_resource;
860 861
	cstate = cstate_alloc();
	if (cstate == NULL)
L
Linus Torvalds 已提交
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885
		goto out;

	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;

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

886 887
		dprintk("nfsv4 compound op #%d: %d\n", resp->opcnt, op->opnum);

L
Linus Torvalds 已提交
888 889 890 891 892 893 894 895 896 897 898 899 900
		/*
		 * 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.
		 */
901 902 903 904
		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 已提交
905 906 907 908
			op->status = nfserr_resource;
			goto encode_op;
		}

909 910
		opdesc = &nfsd4_ops[op->opnum];

911
		if (!cstate->current_fh.fh_dentry) {
912
			if (!(opdesc->op_flags & ALLOWED_WITHOUT_FH)) {
913 914 915
				op->status = nfserr_nofilehandle;
				goto encode_op;
			}
916 917
		} else if (cstate->current_fh.fh_export->ex_fslocs.migrated &&
			  !(opdesc->op_flags & ALLOWED_ON_ABSENT_FS)) {
918
			op->status = nfserr_moved;
L
Linus Torvalds 已提交
919 920
			goto encode_op;
		}
921 922 923 924

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

encode_op:
A
Al Viro 已提交
928
		if (op->status == nfserr_replay_me) {
929
			op->replay = &cstate->replay_owner->so_replay;
L
Linus Torvalds 已提交
930 931 932 933 934 935
			nfsd4_encode_replay(resp, op);
			status = op->status = op->replay->rp_status;
		} else {
			nfsd4_encode_operation(resp, op);
			status = op->status;
		}
936 937 938
		if (cstate->replay_owner) {
			nfs4_put_stateowner(cstate->replay_owner);
			cstate->replay_owner = NULL;
L
Linus Torvalds 已提交
939
		}
940 941 942
		/* 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);
943 944

		nfsd4_increment_op_stats(op->opnum);
L
Linus Torvalds 已提交
945 946 947 948
	}

out:
	nfsd4_release_compoundargs(args);
949
	cstate_free(cstate);
L
Linus Torvalds 已提交
950 951 952
	return status;
}

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

L
Linus Torvalds 已提交
1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099
#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),
1100
  PROC(compound, compound,	compound,	compound, RC_NOCACHE, NFSD_BUFSIZE/4)
L
Linus Torvalds 已提交
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115
};

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