nfs4proc.c 29.9 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 663
	status = mnt_want_write(cstate->current_fh.fh_export->ex_path.mnt);
	if (status)
		return status;
L
Linus Torvalds 已提交
664 665
	status = nfs_ok;
	if (setattr->sa_acl != NULL)
666 667
		status = nfsd4_set_nfs4_acl(rqstp, &cstate->current_fh,
					    setattr->sa_acl);
L
Linus Torvalds 已提交
668
	if (status)
669
		goto out;
670
	status = nfsd_setattr(rqstp, &cstate->current_fh, &setattr->sa_iattr,
L
Linus Torvalds 已提交
671
				0, (time_t)0);
672 673
out:
	mnt_drop_write(cstate->current_fh.fh_export->ex_path.mnt);
L
Linus Torvalds 已提交
674 675 676
	return status;
}

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

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

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

	nfs4_lock_state();
692
	status = nfs4_preprocess_stateid_op(&cstate->current_fh, stateid,
693
					CHECK_FH | WR_STATE, &filp);
694 695
	if (filp)
		get_file(filp);
L
Linus Torvalds 已提交
696 697
	nfs4_unlock_state();

698 699 700 701 702
	if (status) {
		dprintk("NFSD: nfsd4_write: couldn't process stateid!\n");
		return status;
	}

L
Linus Torvalds 已提交
703 704 705 706 707 708
	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;

709 710 711
	status =  nfsd_write(rqstp, &cstate->current_fh, filp,
			     write->wr_offset, rqstp->rq_vec, write->wr_vlen,
			     write->wr_buflen, &write->wr_how_written);
712 713
	if (filp)
		fput(filp);
L
Linus Torvalds 已提交
714 715 716 717 718 719 720 721 722 723 724

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

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

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

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

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

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

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

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

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

static struct nfsd4_operation nfsd4_ops[];

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

	status = nfserr_resource;
865 866
	cstate = cstate_alloc();
	if (cstate == NULL)
L
Linus Torvalds 已提交
867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890
		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++];

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

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

914 915
		opdesc = &nfsd4_ops[op->opnum];

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

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

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

		nfsd4_increment_op_stats(op->opnum);
L
Linus Torvalds 已提交
950 951 952 953
	}

out:
	nfsd4_release_compoundargs(args);
954
	cstate_free(cstate);
955
	dprintk("nfsv4 compound returned %d\n", ntohl(status));
L
Linus Torvalds 已提交
956 957 958
	return status;
}

959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
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,
977
		.op_flags = ALLOWED_ON_ABSENT_FS,
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 1008 1009 1010 1011 1012 1013
	},
	[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,
1014
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1015
	},
1016 1017
	[OP_PUTPUBFH] = {
		/* unsupported; just for future reference: */
1018
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1019
	},
1020 1021
	[OP_PUTROOTFH] = {
		.op_func = (nfsd4op_func)nfsd4_putrootfh,
1022
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040
	},
	[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,
1041
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1042 1043 1044
	},
	[OP_RESTOREFH] = {
		.op_func = (nfsd4op_func)nfsd4_restorefh,
1045
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1046 1047 1048 1049
	},
	[OP_SAVEFH] = {
		.op_func = (nfsd4op_func)nfsd4_savefh,
	},
A
Andy Adamson 已提交
1050 1051 1052
	[OP_SECINFO] = {
		.op_func = (nfsd4op_func)nfsd4_secinfo,
	},
1053 1054 1055 1056 1057
	[OP_SETATTR] = {
		.op_func = (nfsd4op_func)nfsd4_setattr,
	},
	[OP_SETCLIENTID] = {
		.op_func = (nfsd4op_func)nfsd4_setclientid,
1058
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1059 1060 1061
	},
	[OP_SETCLIENTID_CONFIRM] = {
		.op_func = (nfsd4op_func)nfsd4_setclientid_confirm,
1062
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1063 1064 1065 1066 1067 1068 1069 1070 1071
	},
	[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,
1072
		.op_flags = ALLOWED_WITHOUT_FH | ALLOWED_ON_ABSENT_FS,
1073 1074 1075
	},
};

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

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