nfs4state.c 117.4 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
/*
*  Copyright (c) 2001 The Regents of the University of Michigan.
*  All rights reserved.
*
*  Kendrick Smith <kmsmith@umich.edu>
*  Andy Adamson <kandros@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.
*
*/

35
#include <linux/file.h>
36
#include <linux/fs.h>
37
#include <linux/slab.h>
38
#include <linux/namei.h>
39
#include <linux/swap.h>
40
#include <linux/pagemap.h>
41
#include <linux/sunrpc/svcauth_gss.h>
42
#include <linux/sunrpc/clnt.h>
43
#include "xdr4.h"
44
#include "vfs.h"
L
Linus Torvalds 已提交
45 46 47 48

#define NFSDDBG_FACILITY                NFSDDBG_PROC

/* Globals */
49
time_t nfsd4_lease = 90;     /* default lease time */
50
time_t nfsd4_grace = 90;
51
static time_t boot_time;
L
Linus Torvalds 已提交
52 53 54
static u32 current_ownerid = 1;
static u32 current_fileid = 1;
static u32 current_delegid = 1;
55 56
static stateid_t zerostateid;             /* bits all 0 */
static stateid_t onestateid;              /* bits all 1 */
A
Andy Adamson 已提交
57
static u64 current_sessionid = 1;
58 59 60

#define ZERO_STATEID(stateid) (!memcmp((stateid), &zerostateid, sizeof(stateid_t)))
#define ONE_STATEID(stateid)  (!memcmp((stateid), &onestateid, sizeof(stateid_t)))
L
Linus Torvalds 已提交
61 62

/* forward declarations */
63
static int check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner);
L
Linus Torvalds 已提交
64

65 66 67
/* Locking: */

/* Currently used for almost all code touching nfsv4 state: */
I
Ingo Molnar 已提交
68
static DEFINE_MUTEX(client_mutex);
L
Linus Torvalds 已提交
69

70 71 72 73 74 75 76
/*
 * Currently used for the del_recall_lru and file hash table.  In an
 * effort to decrease the scope of the client_mutex, this spinlock may
 * eventually cover more:
 */
static DEFINE_SPINLOCK(recall_lock);

77 78
static struct kmem_cache *openowner_slab = NULL;
static struct kmem_cache *lockowner_slab = NULL;
79 80 81
static struct kmem_cache *file_slab = NULL;
static struct kmem_cache *stateid_slab = NULL;
static struct kmem_cache *deleg_slab = NULL;
N
NeilBrown 已提交
82

L
Linus Torvalds 已提交
83 84 85
void
nfs4_lock_state(void)
{
I
Ingo Molnar 已提交
86
	mutex_lock(&client_mutex);
L
Linus Torvalds 已提交
87 88 89 90 91
}

void
nfs4_unlock_state(void)
{
I
Ingo Molnar 已提交
92
	mutex_unlock(&client_mutex);
L
Linus Torvalds 已提交
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
}

static inline u32
opaque_hashval(const void *ptr, int nbytes)
{
	unsigned char *cptr = (unsigned char *) ptr;

	u32 x = 0;
	while (nbytes--) {
		x *= 37;
		x += *cptr++;
	}
	return x;
}

static struct list_head del_recall_lru;

110 111 112
static inline void
put_nfs4_file(struct nfs4_file *fi)
{
113 114 115 116 117 118
	if (atomic_dec_and_lock(&fi->fi_ref, &recall_lock)) {
		list_del(&fi->fi_hash);
		spin_unlock(&recall_lock);
		iput(fi->fi_inode);
		kmem_cache_free(file_slab, fi);
	}
119 120 121 122 123
}

static inline void
get_nfs4_file(struct nfs4_file *fi)
{
124
	atomic_inc(&fi->fi_ref);
125 126
}

127
static int num_delegations;
128
unsigned int max_delegations;
129 130 131 132 133

/*
 * Open owner state (share locks)
 */

134 135 136 137
/* hash tables for open owners */
#define OPEN_OWNER_HASH_BITS              8
#define OPEN_OWNER_HASH_SIZE             (1 << OPEN_OWNER_HASH_BITS)
#define OPEN_OWNER_HASH_MASK             (OPEN_OWNER_HASH_SIZE - 1)
138

139
static unsigned int open_ownerid_hashval(const u32 id)
140
{
141
	return id & OPEN_OWNER_HASH_MASK;
142 143
}

144
static unsigned int open_ownerstr_hashval(u32 clientid, struct xdr_netobj *ownername)
145 146 147 148 149
{
	unsigned int ret;

	ret = opaque_hashval(ownername->data, ownername->len);
	ret += clientid;
150
	return ret & OPEN_OWNER_HASH_MASK;
151
}
152

153 154
static struct list_head	open_ownerid_hashtbl[OPEN_OWNER_HASH_SIZE];
static struct list_head	open_ownerstr_hashtbl[OPEN_OWNER_HASH_SIZE];
155 156 157 158

/* hash table for nfs4_file */
#define FILE_HASH_BITS                   8
#define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
S
Shan Wei 已提交
159

160
/* hash table for (open)nfs4_ol_stateid */
161 162 163 164
#define STATEID_HASH_BITS              10
#define STATEID_HASH_SIZE              (1 << STATEID_HASH_BITS)
#define STATEID_HASH_MASK              (STATEID_HASH_SIZE - 1)

165 166 167 168 169 170
static unsigned int file_hashval(struct inode *ino)
{
	/* XXX: why are we hashing on inode pointer, anyway? */
	return hash_ptr(ino, FILE_HASH_BITS);
}

J
J. Bruce Fields 已提交
171
static unsigned int stateid_hashval(stateid_t *s)
172
{
J
J. Bruce Fields 已提交
173
	return opaque_hashval(&s->si_opaque, sizeof(stateid_opaque_t)) & STATEID_HASH_MASK;
174
}
175 176 177 178

static struct list_head file_hashtbl[FILE_HASH_SIZE];
static struct list_head stateid_hashtbl[STATEID_HASH_SIZE];

179
static void __nfs4_file_get_access(struct nfs4_file *fp, int oflag)
180 181 182 183 184
{
	BUG_ON(!(fp->fi_fds[oflag] || fp->fi_fds[O_RDWR]));
	atomic_inc(&fp->fi_access[oflag]);
}

185 186 187 188 189 190 191 192 193 194
static void nfs4_file_get_access(struct nfs4_file *fp, int oflag)
{
	if (oflag == O_RDWR) {
		__nfs4_file_get_access(fp, O_RDONLY);
		__nfs4_file_get_access(fp, O_WRONLY);
	} else
		__nfs4_file_get_access(fp, oflag);
}

static void nfs4_file_put_fd(struct nfs4_file *fp, int oflag)
195 196 197 198 199 200 201
{
	if (fp->fi_fds[oflag]) {
		fput(fp->fi_fds[oflag]);
		fp->fi_fds[oflag] = NULL;
	}
}

202
static void __nfs4_file_put_access(struct nfs4_file *fp, int oflag)
203 204 205 206 207 208 209
{
	if (atomic_dec_and_test(&fp->fi_access[oflag])) {
		nfs4_file_put_fd(fp, O_RDWR);
		nfs4_file_put_fd(fp, oflag);
	}
}

210 211 212 213 214 215 216 217 218
static void nfs4_file_put_access(struct nfs4_file *fp, int oflag)
{
	if (oflag == O_RDWR) {
		__nfs4_file_put_access(fp, O_RDONLY);
		__nfs4_file_put_access(fp, O_WRONLY);
	} else
		__nfs4_file_put_access(fp, oflag);
}

219 220 221 222 223
static inline void hash_stid(struct nfs4_stid *stid)
{
	stateid_t *s = &stid->sc_stateid;
	unsigned int hashval;

J
J. Bruce Fields 已提交
224
	hashval = stateid_hashval(s);
225 226 227
	list_add(&stid->sc_hash, &stateid_hashtbl[hashval]);
}

L
Linus Torvalds 已提交
228
static struct nfs4_delegation *
229
alloc_init_deleg(struct nfs4_client *clp, struct nfs4_ol_stateid *stp, struct svc_fh *current_fh, u32 type)
L
Linus Torvalds 已提交
230 231 232 233 234
{
	struct nfs4_delegation *dp;
	struct nfs4_file *fp = stp->st_file;

	dprintk("NFSD alloc_init_deleg\n");
235 236 237 238 239 240 241
	/*
	 * Major work on the lease subsystem (for example, to support
	 * calbacks on stat) will be required before we can support
	 * write delegations properly.
	 */
	if (type != NFS4_OPEN_DELEGATE_READ)
		return NULL;
242 243
	if (fp->fi_had_conflict)
		return NULL;
244
	if (num_delegations > max_delegations)
245
		return NULL;
N
NeilBrown 已提交
246 247
	dp = kmem_cache_alloc(deleg_slab, GFP_KERNEL);
	if (dp == NULL)
L
Linus Torvalds 已提交
248
		return dp;
249
	num_delegations++;
250 251
	INIT_LIST_HEAD(&dp->dl_perfile);
	INIT_LIST_HEAD(&dp->dl_perclnt);
L
Linus Torvalds 已提交
252 253
	INIT_LIST_HEAD(&dp->dl_recall_lru);
	dp->dl_client = clp;
254
	get_nfs4_file(fp);
L
Linus Torvalds 已提交
255 256
	dp->dl_file = fp;
	dp->dl_type = type;
257
	dp->dl_stid.sc_type = NFS4_DELEG_STID;
258 259 260 261
	dp->dl_stid.sc_stateid.si_boot = boot_time;
	dp->dl_stid.sc_stateid.si_stateownerid = current_delegid++;
	dp->dl_stid.sc_stateid.si_fileid = 0;
	dp->dl_stid.sc_stateid.si_generation = 1;
262
	hash_stid(&dp->dl_stid);
263
	fh_copy_shallow(&dp->dl_fh, &current_fh->fh_handle);
L
Linus Torvalds 已提交
264 265
	dp->dl_time = 0;
	atomic_set(&dp->dl_count, 1);
266
	INIT_WORK(&dp->dl_recall.cb_work, nfsd4_do_callback_rpc);
L
Linus Torvalds 已提交
267 268 269 270 271 272 273 274
	return dp;
}

void
nfs4_put_delegation(struct nfs4_delegation *dp)
{
	if (atomic_dec_and_test(&dp->dl_count)) {
		dprintk("NFSD: freeing dp %p\n",dp);
275
		put_nfs4_file(dp->dl_file);
N
NeilBrown 已提交
276
		kmem_cache_free(deleg_slab, dp);
277
		num_delegations--;
L
Linus Torvalds 已提交
278 279 280
	}
}

281
static void nfs4_put_deleg_lease(struct nfs4_file *fp)
L
Linus Torvalds 已提交
282
{
283 284 285
	if (atomic_dec_and_test(&fp->fi_delegees)) {
		vfs_setlease(fp->fi_deleg_file, F_UNLCK, &fp->fi_lease);
		fp->fi_lease = NULL;
286
		fput(fp->fi_deleg_file);
287 288
		fp->fi_deleg_file = NULL;
	}
L
Linus Torvalds 已提交
289 290 291 292 293 294
}

/* Called under the state lock. */
static void
unhash_delegation(struct nfs4_delegation *dp)
{
295
	list_del_init(&dp->dl_stid.sc_hash);
296
	list_del_init(&dp->dl_perclnt);
L
Linus Torvalds 已提交
297
	spin_lock(&recall_lock);
298
	list_del_init(&dp->dl_perfile);
L
Linus Torvalds 已提交
299 300
	list_del_init(&dp->dl_recall_lru);
	spin_unlock(&recall_lock);
301
	nfs4_put_deleg_lease(dp->dl_file);
L
Linus Torvalds 已提交
302 303 304 305 306 307 308
	nfs4_put_delegation(dp);
}

/* 
 * SETCLIENTID state 
 */

309
/* client_lock protects the client lru list and session hash table */
310 311
static DEFINE_SPINLOCK(client_lock);

L
Linus Torvalds 已提交
312 313 314 315 316
/* Hash tables for nfs4_clientid state */
#define CLIENT_HASH_BITS                 4
#define CLIENT_HASH_SIZE                (1 << CLIENT_HASH_BITS)
#define CLIENT_HASH_MASK                (CLIENT_HASH_SIZE - 1)

317 318 319 320 321 322 323 324 325 326
static unsigned int clientid_hashval(u32 id)
{
	return id & CLIENT_HASH_MASK;
}

static unsigned int clientstr_hashval(const char *name)
{
	return opaque_hashval(name, 8) & CLIENT_HASH_MASK;
}

L
Linus Torvalds 已提交
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
/*
 * reclaim_str_hashtbl[] holds known client info from previous reset/reboot
 * used in reboot/reset lease grace period processing
 *
 * conf_id_hashtbl[], and conf_str_hashtbl[] hold confirmed
 * setclientid_confirmed info. 
 *
 * unconf_str_hastbl[] and unconf_id_hashtbl[] hold unconfirmed 
 * setclientid info.
 *
 * client_lru holds client queue ordered by nfs4_client.cl_time
 * for lease renewal.
 *
 * close_lru holds (open) stateowner queue ordered by nfs4_stateowner.so_time
 * for last close replay.
 */
static struct list_head	reclaim_str_hashtbl[CLIENT_HASH_SIZE];
static int reclaim_str_hashtbl_size = 0;
static struct list_head	conf_id_hashtbl[CLIENT_HASH_SIZE];
static struct list_head	conf_str_hashtbl[CLIENT_HASH_SIZE];
static struct list_head	unconf_str_hashtbl[CLIENT_HASH_SIZE];
static struct list_head	unconf_id_hashtbl[CLIENT_HASH_SIZE];
static struct list_head client_lru;
static struct list_head close_lru;

352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392
/*
 * We store the NONE, READ, WRITE, and BOTH bits separately in the
 * st_{access,deny}_bmap field of the stateid, in order to track not
 * only what share bits are currently in force, but also what
 * combinations of share bits previous opens have used.  This allows us
 * to enforce the recommendation of rfc 3530 14.2.19 that the server
 * return an error if the client attempt to downgrade to a combination
 * of share bits not explicable by closing some of its previous opens.
 *
 * XXX: This enforcement is actually incomplete, since we don't keep
 * track of access/deny bit combinations; so, e.g., we allow:
 *
 *	OPEN allow read, deny write
 *	OPEN allow both, deny none
 *	DOWNGRADE allow read, deny none
 *
 * which we should reject.
 */
static void
set_access(unsigned int *access, unsigned long bmap) {
	int i;

	*access = 0;
	for (i = 1; i < 4; i++) {
		if (test_bit(i, &bmap))
			*access |= i;
	}
}

static void
set_deny(unsigned int *deny, unsigned long bmap) {
	int i;

	*deny = 0;
	for (i = 0; i < 4; i++) {
		if (test_bit(i, &bmap))
			*deny |= i ;
	}
}

static int
393
test_share(struct nfs4_ol_stateid *stp, struct nfsd4_open *open) {
394 395 396 397 398 399 400 401 402 403 404
	unsigned int access, deny;

	set_access(&access, stp->st_access_bmap);
	set_deny(&deny, stp->st_deny_bmap);
	if ((access & open->op_share_deny) || (deny & open->op_share_access))
		return 0;
	return 1;
}

static int nfs4_access_to_omode(u32 access)
{
405
	switch (access & NFS4_SHARE_ACCESS_BOTH) {
406 407 408 409 410 411 412 413 414 415
	case NFS4_SHARE_ACCESS_READ:
		return O_RDONLY;
	case NFS4_SHARE_ACCESS_WRITE:
		return O_WRONLY;
	case NFS4_SHARE_ACCESS_BOTH:
		return O_RDWR;
	}
	BUG();
}

416
static void unhash_generic_stateid(struct nfs4_ol_stateid *stp)
417
{
418
	list_del(&stp->st_stid.sc_hash);
419 420 421 422
	list_del(&stp->st_perfile);
	list_del(&stp->st_perstateowner);
}

423
static void close_generic_stateid(struct nfs4_ol_stateid *stp)
424
{
425
	int i;
J
J. Bruce Fields 已提交
426

427
	if (stp->st_access_bmap) {
428 429 430 431
		for (i = 1; i < 4; i++) {
			if (test_bit(i, &stp->st_access_bmap))
				nfs4_file_put_access(stp->st_file,
						nfs4_access_to_omode(i));
432
			__clear_bit(i, &stp->st_access_bmap);
433
		}
434
	}
O
OGAWA Hirofumi 已提交
435
	put_nfs4_file(stp->st_file);
436 437 438
	stp->st_file = NULL;
}

439
static void free_generic_stateid(struct nfs4_ol_stateid *stp)
440 441
{
	close_generic_stateid(stp);
442 443 444
	kmem_cache_free(stateid_slab, stp);
}

445
static void release_lock_stateid(struct nfs4_ol_stateid *stp)
446 447 448 449 450 451
{
	struct file *file;

	unhash_generic_stateid(stp);
	file = find_any_file(stp->st_file);
	if (file)
452
		locks_remove_posix(file, (fl_owner_t)lockowner(stp->st_stateowner));
453 454 455
	free_generic_stateid(stp);
}

456
static void unhash_lockowner(struct nfs4_lockowner *lo)
457
{
458
	struct nfs4_ol_stateid *stp;
459

460 461 462 463 464
	list_del(&lo->lo_owner.so_idhash);
	list_del(&lo->lo_owner.so_strhash);
	list_del(&lo->lo_perstateid);
	while (!list_empty(&lo->lo_owner.so_stateids)) {
		stp = list_first_entry(&lo->lo_owner.so_stateids,
465
				struct nfs4_ol_stateid, st_perstateowner);
466 467 468 469
		release_lock_stateid(stp);
	}
}

470
static void release_lockowner(struct nfs4_lockowner *lo)
471
{
472 473
	unhash_lockowner(lo);
	nfs4_free_lockowner(lo);
474 475 476
}

static void
477
release_stateid_lockowners(struct nfs4_ol_stateid *open_stp)
478
{
479
	struct nfs4_lockowner *lo;
480 481

	while (!list_empty(&open_stp->st_lockowners)) {
482 483 484
		lo = list_entry(open_stp->st_lockowners.next,
				struct nfs4_lockowner, lo_perstateid);
		release_lockowner(lo);
485 486 487
	}
}

488
static void release_open_stateid(struct nfs4_ol_stateid *stp)
489 490 491 492 493 494
{
	unhash_generic_stateid(stp);
	release_stateid_lockowners(stp);
	free_generic_stateid(stp);
}

495
static void unhash_openowner(struct nfs4_openowner *oo)
496
{
497
	struct nfs4_ol_stateid *stp;
498

499 500 501 502 503
	list_del(&oo->oo_owner.so_idhash);
	list_del(&oo->oo_owner.so_strhash);
	list_del(&oo->oo_perclient);
	while (!list_empty(&oo->oo_owner.so_stateids)) {
		stp = list_first_entry(&oo->oo_owner.so_stateids,
504
				struct nfs4_ol_stateid, st_perstateowner);
505
		release_open_stateid(stp);
506 507 508
	}
}

509
static void release_openowner(struct nfs4_openowner *oo)
510
{
511 512 513
	unhash_openowner(oo);
	list_del(&oo->oo_close_lru);
	nfs4_free_openowner(oo);
514 515
}

M
Marc Eshel 已提交
516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
#define SESSION_HASH_SIZE	512
static struct list_head sessionid_hashtbl[SESSION_HASH_SIZE];

static inline int
hash_sessionid(struct nfs4_sessionid *sessionid)
{
	struct nfsd4_sessionid *sid = (struct nfsd4_sessionid *)sessionid;

	return sid->sequence % SESSION_HASH_SIZE;
}

static inline void
dump_sessionid(const char *fn, struct nfs4_sessionid *sessionid)
{
	u32 *ptr = (u32 *)(&sessionid->data[0]);
	dprintk("%s: %u:%u:%u:%u\n", fn, ptr[0], ptr[1], ptr[2], ptr[3]);
}

A
Andy Adamson 已提交
534 535 536 537 538 539 540 541 542 543 544 545 546
static void
gen_sessionid(struct nfsd4_session *ses)
{
	struct nfs4_client *clp = ses->se_client;
	struct nfsd4_sessionid *sid;

	sid = (struct nfsd4_sessionid *)ses->se_sessionid.data;
	sid->clientid = clp->cl_clientid;
	sid->sequence = current_sessionid++;
	sid->reserved = 0;
}

/*
547 548 549 550 551 552 553 554 555 556 557 558 559
 * The protocol defines ca_maxresponssize_cached to include the size of
 * the rpc header, but all we need to cache is the data starting after
 * the end of the initial SEQUENCE operation--the rest we regenerate
 * each time.  Therefore we can advertise a ca_maxresponssize_cached
 * value that is the number of bytes in our cache plus a few additional
 * bytes.  In order to stay on the safe side, and not promise more than
 * we can cache, those additional bytes must be the minimum possible: 24
 * bytes of rpc header (xid through accept state, with AUTH_NULL
 * verifier), 12 for the compound header (with zero-length tag), and 44
 * for the SEQUENCE op response:
 */
#define NFSD_MIN_HDR_SEQ_SZ  (24 + 12 + 44)

560 561 562 563 564 565 566 567 568
static void
free_session_slots(struct nfsd4_session *ses)
{
	int i;

	for (i = 0; i < ses->se_fchannel.maxreqs; i++)
		kfree(ses->se_slots[i]);
}

569
/*
570 571 572 573 574 575 576 577
 * We don't actually need to cache the rpc and session headers, so we
 * can allocate a little less for each slot:
 */
static inline int slot_bytes(struct nfsd4_channel_attrs *ca)
{
	return ca->maxresp_cached - NFSD_MIN_HDR_SEQ_SZ;
}

578
static int nfsd4_sanitize_slot_size(u32 size)
A
Andy Adamson 已提交
579
{
580 581
	size -= NFSD_MIN_HDR_SEQ_SZ; /* We don't cache the rpc header */
	size = min_t(u32, size, NFSD_SLOT_CACHE_SIZE);
A
Andy Adamson 已提交
582

583 584
	return size;
}
A
Andy Adamson 已提交
585

586 587
/*
 * XXX: If we run out of reserved DRC memory we could (up to a point)
588 589
 * re-negotiate active sessions and reduce their slot usage to make
 * rooom for new connections. For now we just fail the create session.
A
Andy Adamson 已提交
590
 */
591
static int nfsd4_get_drc_mem(int slotsize, u32 num)
A
Andy Adamson 已提交
592
{
593
	int avail;
A
Andy Adamson 已提交
594

595
	num = min_t(u32, num, NFSD_MAX_SLOTS_PER_SESSION);
596

597 598 599 600 601 602
	spin_lock(&nfsd_drc_lock);
	avail = min_t(int, NFSD_MAX_MEM_PER_SESSION,
			nfsd_drc_max_mem - nfsd_drc_mem_used);
	num = min_t(int, num, avail / slotsize);
	nfsd_drc_mem_used += num * slotsize;
	spin_unlock(&nfsd_drc_lock);
A
Andy Adamson 已提交
603

604 605
	return num;
}
A
Andy Adamson 已提交
606

607 608
static void nfsd4_put_drc_mem(int slotsize, int num)
{
609
	spin_lock(&nfsd_drc_lock);
610
	nfsd_drc_mem_used -= slotsize * num;
611
	spin_unlock(&nfsd_drc_lock);
612
}
A
Andy Adamson 已提交
613

614 615 616 617
static struct nfsd4_session *alloc_session(int slotsize, int numslots)
{
	struct nfsd4_session *new;
	int mem, i;
618

619 620 621
	BUILD_BUG_ON(NFSD_MAX_SLOTS_PER_SESSION * sizeof(struct nfsd4_slot *)
			+ sizeof(struct nfsd4_session) > PAGE_SIZE);
	mem = numslots * sizeof(struct nfsd4_slot *);
A
Andy Adamson 已提交
622

623 624 625
	new = kzalloc(sizeof(*new) + mem, GFP_KERNEL);
	if (!new)
		return NULL;
626
	/* allocate each struct nfsd4_slot and data cache in one piece */
627 628 629 630
	for (i = 0; i < numslots; i++) {
		mem = sizeof(struct nfsd4_slot) + slotsize;
		new->se_slots[i] = kzalloc(mem, GFP_KERNEL);
		if (!new->se_slots[i])
631 632
			goto out_free;
	}
633 634 635 636 637 638
	return new;
out_free:
	while (i--)
		kfree(new->se_slots[i]);
	kfree(new);
	return NULL;
A
Andy Adamson 已提交
639 640
}

641
static void init_forechannel_attrs(struct nfsd4_channel_attrs *new, struct nfsd4_channel_attrs *req, int numslots, int slotsize)
A
Andy Adamson 已提交
642
{
643
	u32 maxrpc = nfsd_serv->sv_max_mesg;
A
Andy Adamson 已提交
644

645
	new->maxreqs = numslots;
646 647
	new->maxresp_cached = min_t(u32, req->maxresp_cached,
					slotsize + NFSD_MIN_HDR_SEQ_SZ);
648 649 650 651
	new->maxreq_sz = min_t(u32, req->maxreq_sz, maxrpc);
	new->maxresp_sz = min_t(u32, req->maxresp_sz, maxrpc);
	new->maxops = min_t(u32, req->maxops, NFSD_MAX_OPS_PER_COMPOUND);
}
A
Andy Adamson 已提交
652

653 654 655 656 657
static void free_conn(struct nfsd4_conn *c)
{
	svc_xprt_put(c->cn_xprt);
	kfree(c);
}
A
Andy Adamson 已提交
658

659 660 661 662
static void nfsd4_conn_lost(struct svc_xpt_user *u)
{
	struct nfsd4_conn *c = container_of(u, struct nfsd4_conn, cn_xpt_user);
	struct nfs4_client *clp = c->cn_session->se_client;
A
Andy Adamson 已提交
663

664 665 666 667 668 669
	spin_lock(&clp->cl_lock);
	if (!list_empty(&c->cn_persession)) {
		list_del(&c->cn_persession);
		free_conn(c);
	}
	spin_unlock(&clp->cl_lock);
670
	nfsd4_probe_callback(clp);
671
}
A
Andy Adamson 已提交
672

673
static struct nfsd4_conn *alloc_conn(struct svc_rqst *rqstp, u32 flags)
674 675
{
	struct nfsd4_conn *conn;
A
Andy Adamson 已提交
676

677 678
	conn = kmalloc(sizeof(struct nfsd4_conn), GFP_KERNEL);
	if (!conn)
679
		return NULL;
680 681
	svc_xprt_get(rqstp->rq_xprt);
	conn->cn_xprt = rqstp->rq_xprt;
682
	conn->cn_flags = flags;
683 684 685
	INIT_LIST_HEAD(&conn->cn_xpt_user.list);
	return conn;
}
686

687 688 689 690
static void __nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
{
	conn->cn_session = ses;
	list_add(&conn->cn_persession, &ses->se_conns);
A
Andy Adamson 已提交
691 692
}

693
static void nfsd4_hash_conn(struct nfsd4_conn *conn, struct nfsd4_session *ses)
694
{
695
	struct nfs4_client *clp = ses->se_client;
696

697
	spin_lock(&clp->cl_lock);
698
	__nfsd4_hash_conn(conn, ses);
699
	spin_unlock(&clp->cl_lock);
700 701
}

702
static int nfsd4_register_conn(struct nfsd4_conn *conn)
703
{
704
	conn->cn_xpt_user.callback = nfsd4_conn_lost;
705
	return register_xpt_user(conn->cn_xprt, &conn->cn_xpt_user);
706 707
}

708
static __be32 nfsd4_new_conn(struct svc_rqst *rqstp, struct nfsd4_session *ses, u32 dir)
A
Andy Adamson 已提交
709
{
710
	struct nfsd4_conn *conn;
711
	int ret;
A
Andy Adamson 已提交
712

713
	conn = alloc_conn(rqstp, dir);
714 715 716
	if (!conn)
		return nfserr_jukebox;
	nfsd4_hash_conn(conn, ses);
717 718 719 720
	ret = nfsd4_register_conn(conn);
	if (ret)
		/* oops; xprt is already down: */
		nfsd4_conn_lost(&conn->cn_xpt_user);
721 722
	return nfs_ok;
}
A
Andy Adamson 已提交
723

724 725 726 727 728 729 730 731 732 733 734
static __be32 nfsd4_new_conn_from_crses(struct svc_rqst *rqstp, struct nfsd4_session *ses)
{
	u32 dir = NFS4_CDFC4_FORE;

	if (ses->se_flags & SESSION4_BACK_CHAN)
		dir |= NFS4_CDFC4_BACK;

	return nfsd4_new_conn(rqstp, ses, dir);
}

/* must be called under client_lock */
735
static void nfsd4_del_conns(struct nfsd4_session *s)
736
{
737 738
	struct nfs4_client *clp = s->se_client;
	struct nfsd4_conn *c;
A
Andy Adamson 已提交
739

740 741 742 743 744
	spin_lock(&clp->cl_lock);
	while (!list_empty(&s->se_conns)) {
		c = list_first_entry(&s->se_conns, struct nfsd4_conn, cn_persession);
		list_del_init(&c->cn_persession);
		spin_unlock(&clp->cl_lock);
745

746 747
		unregister_xpt_user(c->cn_xprt, &c->cn_xpt_user);
		free_conn(c);
A
Andy Adamson 已提交
748

749 750 751
		spin_lock(&clp->cl_lock);
	}
	spin_unlock(&clp->cl_lock);
752
}
A
Andy Adamson 已提交
753

754 755 756 757 758 759
void free_session(struct kref *kref)
{
	struct nfsd4_session *ses;
	int mem;

	ses = container_of(kref, struct nfsd4_session, se_ref);
760
	nfsd4_del_conns(ses);
761 762 763 764 765 766 767 768
	spin_lock(&nfsd_drc_lock);
	mem = ses->se_fchannel.maxreqs * slot_bytes(&ses->se_fchannel);
	nfsd_drc_mem_used -= mem;
	spin_unlock(&nfsd_drc_lock);
	free_session_slots(ses);
	kfree(ses);
}

769
static struct nfsd4_session *alloc_init_session(struct svc_rqst *rqstp, struct nfs4_client *clp, struct nfsd4_create_session *cses)
770 771 772 773
{
	struct nfsd4_session *new;
	struct nfsd4_channel_attrs *fchan = &cses->fore_channel;
	int numslots, slotsize;
774
	int status;
775 776 777 778 779 780 781 782 783 784 785
	int idx;

	/*
	 * Note decreasing slot size below client's request may
	 * make it difficult for client to function correctly, whereas
	 * decreasing the number of slots will (just?) affect
	 * performance.  When short on memory we therefore prefer to
	 * decrease number of slots instead of their size.
	 */
	slotsize = nfsd4_sanitize_slot_size(fchan->maxresp_cached);
	numslots = nfsd4_get_drc_mem(slotsize, fchan->maxreqs);
786 787
	if (numslots < 1)
		return NULL;
788 789 790 791

	new = alloc_session(slotsize, numslots);
	if (!new) {
		nfsd4_put_drc_mem(slotsize, fchan->maxreqs);
792
		return NULL;
793
	}
794
	init_forechannel_attrs(&new->se_fchannel, fchan, numslots, slotsize);
795

A
Andy Adamson 已提交
796 797 798
	new->se_client = clp;
	gen_sessionid(new);

799 800
	INIT_LIST_HEAD(&new->se_conns);

801
	new->se_cb_seq_nr = 1;
A
Andy Adamson 已提交
802
	new->se_flags = cses->flags;
803
	new->se_cb_prog = cses->callback_prog;
A
Andy Adamson 已提交
804
	kref_init(&new->se_ref);
805
	idx = hash_sessionid(&new->se_sessionid);
806
	spin_lock(&client_lock);
A
Andy Adamson 已提交
807
	list_add(&new->se_hash, &sessionid_hashtbl[idx]);
808
	spin_lock(&clp->cl_lock);
A
Andy Adamson 已提交
809
	list_add(&new->se_perclnt, &clp->cl_sessions);
810
	spin_unlock(&clp->cl_lock);
811
	spin_unlock(&client_lock);
A
Andy Adamson 已提交
812

813
	status = nfsd4_new_conn_from_crses(rqstp, new);
814
	/* whoops: benny points out, status is ignored! (err, or bogus) */
815 816
	if (status) {
		free_session(&new->se_ref);
817
		return NULL;
818
	}
819
	if (cses->flags & SESSION4_BACK_CHAN) {
820
		struct sockaddr *sa = svc_addr(rqstp);
821 822 823 824 825 826 827
		/*
		 * This is a little silly; with sessions there's no real
		 * use for the callback address.  Use the peer address
		 * as a reasonable default for now, but consider fixing
		 * the rpc client not to require an address in the
		 * future:
		 */
828 829 830
		rpc_copy_addr((struct sockaddr *)&clp->cl_cb_conn.cb_addr, sa);
		clp->cl_cb_conn.cb_addrlen = svc_addr_len(sa);
	}
831
	nfsd4_probe_callback(clp);
832
	return new;
A
Andy Adamson 已提交
833 834
}

835
/* caller must hold client_lock */
M
Marc Eshel 已提交
836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
static struct nfsd4_session *
find_in_sessionid_hashtbl(struct nfs4_sessionid *sessionid)
{
	struct nfsd4_session *elem;
	int idx;

	dump_sessionid(__func__, sessionid);
	idx = hash_sessionid(sessionid);
	/* Search in the appropriate list */
	list_for_each_entry(elem, &sessionid_hashtbl[idx], se_hash) {
		if (!memcmp(elem->se_sessionid.data, sessionid->data,
			    NFS4_MAX_SESSIONID_LEN)) {
			return elem;
		}
	}

	dprintk("%s: session not found\n", __func__);
	return NULL;
}

856
/* caller must hold client_lock */
A
Andy Adamson 已提交
857
static void
M
Marc Eshel 已提交
858
unhash_session(struct nfsd4_session *ses)
A
Andy Adamson 已提交
859 860
{
	list_del(&ses->se_hash);
861
	spin_lock(&ses->se_client->cl_lock);
A
Andy Adamson 已提交
862
	list_del(&ses->se_perclnt);
863
	spin_unlock(&ses->se_client->cl_lock);
M
Marc Eshel 已提交
864 865
}

866
/* must be called under the client_lock */
L
Linus Torvalds 已提交
867
static inline void
868
renew_client_locked(struct nfs4_client *clp)
L
Linus Torvalds 已提交
869
{
B
Benny Halevy 已提交
870 871 872 873 874 875 876 877
	if (is_client_expired(clp)) {
		dprintk("%s: client (clientid %08x/%08x) already expired\n",
			__func__,
			clp->cl_clientid.cl_boot,
			clp->cl_clientid.cl_id);
		return;
	}

L
Linus Torvalds 已提交
878 879 880 881 882 883 884 885 886 887
	/*
	* Move client to the end to the LRU list.
	*/
	dprintk("renewing client (clientid %08x/%08x)\n", 
			clp->cl_clientid.cl_boot, 
			clp->cl_clientid.cl_id);
	list_move_tail(&clp->cl_lru, &client_lru);
	clp->cl_time = get_seconds();
}

888 889 890 891 892 893 894 895
static inline void
renew_client(struct nfs4_client *clp)
{
	spin_lock(&client_lock);
	renew_client_locked(clp);
	spin_unlock(&client_lock);
}

L
Linus Torvalds 已提交
896 897 898 899 900 901
/* SETCLIENTID and SETCLIENTID_CONFIRM Helper functions */
static int
STALE_CLIENTID(clientid_t *clid)
{
	if (clid->cl_boot == boot_time)
		return 0;
A
Andy Adamson 已提交
902 903
	dprintk("NFSD stale clientid (%08x/%08x) boot_time %08lx\n",
		clid->cl_boot, clid->cl_id, boot_time);
L
Linus Torvalds 已提交
904 905 906 907 908 909 910 911
	return 1;
}

/* 
 * XXX Should we use a slab cache ?
 * This type of memory management is somewhat inefficient, but we use it
 * anyway since SETCLIENTID is not a common operation.
 */
912
static struct nfs4_client *alloc_client(struct xdr_netobj name)
L
Linus Torvalds 已提交
913 914 915
{
	struct nfs4_client *clp;

916 917 918 919 920 921 922
	clp = kzalloc(sizeof(struct nfs4_client), GFP_KERNEL);
	if (clp == NULL)
		return NULL;
	clp->cl_name.data = kmalloc(name.len, GFP_KERNEL);
	if (clp->cl_name.data == NULL) {
		kfree(clp);
		return NULL;
L
Linus Torvalds 已提交
923
	}
924 925
	memcpy(clp->cl_name.data, name.data, name.len);
	clp->cl_name.len = name.len;
L
Linus Torvalds 已提交
926 927 928 929 930 931
	return clp;
}

static inline void
free_client(struct nfs4_client *clp)
{
932 933 934 935 936 937 938
	while (!list_empty(&clp->cl_sessions)) {
		struct nfsd4_session *ses;
		ses = list_entry(clp->cl_sessions.next, struct nfsd4_session,
				se_perclnt);
		list_del(&ses->se_perclnt);
		nfsd4_put_session(ses);
	}
L
Linus Torvalds 已提交
939 940
	if (clp->cl_cred.cr_group_info)
		put_group_info(clp->cl_cred.cr_group_info);
941
	kfree(clp->cl_principal);
L
Linus Torvalds 已提交
942 943 944 945
	kfree(clp->cl_name.data);
	kfree(clp);
}

946 947 948 949 950 951 952 953 954 955 956 957 958 959 960
void
release_session_client(struct nfsd4_session *session)
{
	struct nfs4_client *clp = session->se_client;

	if (!atomic_dec_and_lock(&clp->cl_refcount, &client_lock))
		return;
	if (is_client_expired(clp)) {
		free_client(clp);
		session->se_client = NULL;
	} else
		renew_client_locked(clp);
	spin_unlock(&client_lock);
}

B
Benny Halevy 已提交
961 962 963 964
/* must be called under the client_lock */
static inline void
unhash_client_locked(struct nfs4_client *clp)
{
965 966
	struct nfsd4_session *ses;

B
Benny Halevy 已提交
967
	mark_client_expired(clp);
B
Benny Halevy 已提交
968
	list_del(&clp->cl_lru);
969
	spin_lock(&clp->cl_lock);
970 971
	list_for_each_entry(ses, &clp->cl_sessions, se_perclnt)
		list_del_init(&ses->se_hash);
972
	spin_unlock(&clp->cl_lock);
B
Benny Halevy 已提交
973 974
}

L
Linus Torvalds 已提交
975 976 977
static void
expire_client(struct nfs4_client *clp)
{
978
	struct nfs4_openowner *oo;
L
Linus Torvalds 已提交
979 980 981 982 983
	struct nfs4_delegation *dp;
	struct list_head reaplist;

	INIT_LIST_HEAD(&reaplist);
	spin_lock(&recall_lock);
984 985 986
	while (!list_empty(&clp->cl_delegations)) {
		dp = list_entry(clp->cl_delegations.next, struct nfs4_delegation, dl_perclnt);
		list_del_init(&dp->dl_perclnt);
L
Linus Torvalds 已提交
987 988 989 990 991 992 993 994
		list_move(&dp->dl_recall_lru, &reaplist);
	}
	spin_unlock(&recall_lock);
	while (!list_empty(&reaplist)) {
		dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru);
		list_del_init(&dp->dl_recall_lru);
		unhash_delegation(dp);
	}
995
	while (!list_empty(&clp->cl_openowners)) {
996 997
		oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient);
		release_openowner(oo);
L
Linus Torvalds 已提交
998
	}
999
	nfsd4_shutdown_callback(clp);
B
Benny Halevy 已提交
1000 1001
	if (clp->cl_cb_conn.cb_xprt)
		svc_xprt_put(clp->cl_cb_conn.cb_xprt);
1002 1003
	list_del(&clp->cl_idhash);
	list_del(&clp->cl_strhash);
1004
	spin_lock(&client_lock);
B
Benny Halevy 已提交
1005
	unhash_client_locked(clp);
1006 1007
	if (atomic_read(&clp->cl_refcount) == 0)
		free_client(clp);
1008
	spin_unlock(&client_lock);
L
Linus Torvalds 已提交
1009 1010
}

1011 1012 1013 1014
static void copy_verf(struct nfs4_client *target, nfs4_verifier *source)
{
	memcpy(target->cl_verifier.data, source->data,
			sizeof(target->cl_verifier.data));
L
Linus Torvalds 已提交
1015 1016
}

1017 1018
static void copy_clid(struct nfs4_client *target, struct nfs4_client *source)
{
L
Linus Torvalds 已提交
1019 1020 1021 1022
	target->cl_clientid.cl_boot = source->cl_clientid.cl_boot; 
	target->cl_clientid.cl_id = source->cl_clientid.cl_id; 
}

1023 1024
static void copy_cred(struct svc_cred *target, struct svc_cred *source)
{
L
Linus Torvalds 已提交
1025 1026 1027 1028 1029 1030
	target->cr_uid = source->cr_uid;
	target->cr_gid = source->cr_gid;
	target->cr_group_info = source->cr_group_info;
	get_group_info(target->cr_group_info);
}

1031
static int same_name(const char *n1, const char *n2)
1032
{
N
NeilBrown 已提交
1033
	return 0 == memcmp(n1, n2, HEXDIR_LEN);
L
Linus Torvalds 已提交
1034 1035 1036
}

static int
1037 1038 1039
same_verf(nfs4_verifier *v1, nfs4_verifier *v2)
{
	return 0 == memcmp(v1->data, v2->data, sizeof(v1->data));
L
Linus Torvalds 已提交
1040 1041 1042
}

static int
1043 1044 1045
same_clid(clientid_t *cl1, clientid_t *cl2)
{
	return (cl1->cl_boot == cl2->cl_boot) && (cl1->cl_id == cl2->cl_id);
L
Linus Torvalds 已提交
1046 1047 1048 1049
}

/* XXX what about NGROUP */
static int
1050 1051 1052
same_creds(struct svc_cred *cr1, struct svc_cred *cr2)
{
	return cr1->cr_uid == cr2->cr_uid;
L
Linus Torvalds 已提交
1053 1054
}

1055 1056 1057 1058
static void gen_clid(struct nfs4_client *clp)
{
	static u32 current_clientid = 1;

L
Linus Torvalds 已提交
1059 1060 1061 1062
	clp->cl_clientid.cl_boot = boot_time;
	clp->cl_clientid.cl_id = current_clientid++; 
}

1063 1064 1065 1066
static void gen_confirm(struct nfs4_client *clp)
{
	static u32 i;
	u32 *p;
L
Linus Torvalds 已提交
1067 1068

	p = (u32 *)clp->cl_confirm.data;
1069 1070
	*p++ = get_seconds();
	*p++ = i++;
L
Linus Torvalds 已提交
1071 1072
}

1073 1074 1075 1076 1077 1078 1079 1080
static int
same_stateid(stateid_t *id_one, stateid_t *id_two)
{
	if (id_one->si_stateownerid != id_two->si_stateownerid)
		return 0;
	return id_one->si_fileid == id_two->si_fileid;
}

1081
static struct nfs4_stid *find_stateid(stateid_t *t)
1082
{
1083
	struct nfs4_stid *s;
1084 1085
	unsigned int hashval;

J
J. Bruce Fields 已提交
1086
	hashval = stateid_hashval(t);
1087 1088
	list_for_each_entry(s, &stateid_hashtbl[hashval], sc_hash)
		if (same_stateid(&s->sc_stateid, t))
1089
			return s;
J
J. Bruce Fields 已提交
1090 1091 1092
	return NULL;
}

1093
static struct nfs4_ol_stateid *find_ol_stateid(stateid_t *t)
J
J. Bruce Fields 已提交
1094
{
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
	struct nfs4_stid *s;

	s = find_stateid(t);
	if (!s)
		return NULL;
	return openlockstateid(s);
}

static struct nfs4_stid *find_stateid_by_type(stateid_t *t, char typemask)
{
	struct nfs4_stid *s;
J
J. Bruce Fields 已提交
1106 1107 1108 1109

	s = find_stateid(t);
	if (!s)
		return NULL;
1110
	if (typemask & s->sc_type)
1111 1112 1113 1114
		return s;
	return NULL;
}

1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
static struct nfs4_ol_stateid *find_ol_stateid_by_type(stateid_t *t, char typemask)
{
	struct nfs4_stid *s;

	s = find_stateid_by_type(t, typemask);
	if (!s)
		return NULL;
	return openlockstateid(s);
}

1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
static struct nfs4_client *create_client(struct xdr_netobj name, char *recdir,
		struct svc_rqst *rqstp, nfs4_verifier *verf)
{
	struct nfs4_client *clp;
	struct sockaddr *sa = svc_addr(rqstp);
	char *princ;

	clp = alloc_client(name);
	if (clp == NULL)
		return NULL;

1136 1137
	INIT_LIST_HEAD(&clp->cl_sessions);

1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
	princ = svc_gss_principal(rqstp);
	if (princ) {
		clp->cl_principal = kstrdup(princ, GFP_KERNEL);
		if (clp->cl_principal == NULL) {
			free_client(clp);
			return NULL;
		}
	}

	memcpy(clp->cl_recdir, recdir, HEXDIR_LEN);
1148
	atomic_set(&clp->cl_refcount, 0);
1149
	clp->cl_cb_state = NFSD4_CB_UNKNOWN;
1150 1151 1152 1153 1154
	INIT_LIST_HEAD(&clp->cl_idhash);
	INIT_LIST_HEAD(&clp->cl_strhash);
	INIT_LIST_HEAD(&clp->cl_openowners);
	INIT_LIST_HEAD(&clp->cl_delegations);
	INIT_LIST_HEAD(&clp->cl_lru);
1155
	INIT_LIST_HEAD(&clp->cl_callbacks);
1156
	spin_lock_init(&clp->cl_lock);
1157
	INIT_WORK(&clp->cl_cb_null.cb_work, nfsd4_do_callback_rpc);
B
Benny Halevy 已提交
1158
	clp->cl_time = get_seconds();
1159 1160 1161 1162 1163 1164 1165
	clear_bit(0, &clp->cl_cb_slot_busy);
	rpc_init_wait_queue(&clp->cl_cb_waitq, "Backchannel slot table");
	copy_verf(clp, verf);
	rpc_copy_addr((struct sockaddr *) &clp->cl_addr, sa);
	clp->cl_flavor = rqstp->rq_flavor;
	copy_cred(&clp->cl_cred, &rqstp->rq_cred);
	gen_confirm(clp);
1166
	clp->cl_cb_session = NULL;
1167 1168 1169
	return clp;
}

1170 1171
static int check_name(struct xdr_netobj name)
{
L
Linus Torvalds 已提交
1172 1173 1174
	if (name.len == 0) 
		return 0;
	if (name.len > NFS4_OPAQUE_LIMIT) {
1175
		dprintk("NFSD: check_name: name too long(%d)!\n", name.len);
L
Linus Torvalds 已提交
1176 1177 1178 1179 1180
		return 0;
	}
	return 1;
}

1181
static void
L
Linus Torvalds 已提交
1182 1183 1184 1185 1186 1187 1188
add_to_unconfirmed(struct nfs4_client *clp, unsigned int strhashval)
{
	unsigned int idhashval;

	list_add(&clp->cl_strhash, &unconf_str_hashtbl[strhashval]);
	idhashval = clientid_hashval(clp->cl_clientid.cl_id);
	list_add(&clp->cl_idhash, &unconf_id_hashtbl[idhashval]);
1189
	renew_client(clp);
L
Linus Torvalds 已提交
1190 1191
}

1192
static void
L
Linus Torvalds 已提交
1193 1194 1195 1196 1197 1198
move_to_confirmed(struct nfs4_client *clp)
{
	unsigned int idhashval = clientid_hashval(clp->cl_clientid.cl_id);
	unsigned int strhashval;

	dprintk("NFSD: move_to_confirm nfs4_client %p\n", clp);
A
Akinobu Mita 已提交
1199
	list_move(&clp->cl_idhash, &conf_id_hashtbl[idhashval]);
N
NeilBrown 已提交
1200
	strhashval = clientstr_hashval(clp->cl_recdir);
1201
	list_move(&clp->cl_strhash, &conf_str_hashtbl[strhashval]);
L
Linus Torvalds 已提交
1202 1203 1204 1205 1206 1207 1208 1209 1210 1211
	renew_client(clp);
}

static struct nfs4_client *
find_confirmed_client(clientid_t *clid)
{
	struct nfs4_client *clp;
	unsigned int idhashval = clientid_hashval(clid->cl_id);

	list_for_each_entry(clp, &conf_id_hashtbl[idhashval], cl_idhash) {
1212
		if (same_clid(&clp->cl_clientid, clid))
L
Linus Torvalds 已提交
1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224
			return clp;
	}
	return NULL;
}

static struct nfs4_client *
find_unconfirmed_client(clientid_t *clid)
{
	struct nfs4_client *clp;
	unsigned int idhashval = clientid_hashval(clid->cl_id);

	list_for_each_entry(clp, &unconf_id_hashtbl[idhashval], cl_idhash) {
1225
		if (same_clid(&clp->cl_clientid, clid))
L
Linus Torvalds 已提交
1226 1227 1228 1229 1230
			return clp;
	}
	return NULL;
}

1231
static bool clp_used_exchangeid(struct nfs4_client *clp)
1232
{
1233
	return clp->cl_exchange_flags != 0;
1234
} 
1235

1236
static struct nfs4_client *
1237
find_confirmed_client_by_str(const char *dname, unsigned int hashval)
1238 1239 1240 1241
{
	struct nfs4_client *clp;

	list_for_each_entry(clp, &conf_str_hashtbl[hashval], cl_strhash) {
1242
		if (same_name(clp->cl_recdir, dname))
1243 1244 1245 1246 1247 1248
			return clp;
	}
	return NULL;
}

static struct nfs4_client *
1249
find_unconfirmed_client_by_str(const char *dname, unsigned int hashval)
1250 1251 1252 1253
{
	struct nfs4_client *clp;

	list_for_each_entry(clp, &unconf_str_hashtbl[hashval], cl_strhash) {
1254
		if (same_name(clp->cl_recdir, dname))
1255 1256 1257 1258 1259
			return clp;
	}
	return NULL;
}

1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273
static void rpc_svcaddr2sockaddr(struct sockaddr *sa, unsigned short family, union svc_addr_u *svcaddr)
{
	switch (family) {
	case AF_INET:
		((struct sockaddr_in *)sa)->sin_family = AF_INET;
		((struct sockaddr_in *)sa)->sin_addr = svcaddr->addr;
		return;
	case AF_INET6:
		((struct sockaddr_in6 *)sa)->sin6_family = AF_INET6;
		((struct sockaddr_in6 *)sa)->sin6_addr = svcaddr->addr6;
		return;
	}
}

1274
static void
1275
gen_callback(struct nfs4_client *clp, struct nfsd4_setclientid *se, struct svc_rqst *rqstp)
L
Linus Torvalds 已提交
1276
{
1277
	struct nfs4_cb_conn *conn = &clp->cl_cb_conn;
1278 1279
	struct sockaddr	*sa = svc_addr(rqstp);
	u32 scopeid = rpc_get_scope_id(sa);
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
	unsigned short expected_family;

	/* Currently, we only support tcp and tcp6 for the callback channel */
	if (se->se_callback_netid_len == 3 &&
	    !memcmp(se->se_callback_netid_val, "tcp", 3))
		expected_family = AF_INET;
	else if (se->se_callback_netid_len == 4 &&
		 !memcmp(se->se_callback_netid_val, "tcp6", 4))
		expected_family = AF_INET6;
	else
L
Linus Torvalds 已提交
1290 1291
		goto out_err;

1292
	conn->cb_addrlen = rpc_uaddr2sockaddr(se->se_callback_addr_val,
1293
					    se->se_callback_addr_len,
1294 1295
					    (struct sockaddr *)&conn->cb_addr,
					    sizeof(conn->cb_addr));
1296

1297
	if (!conn->cb_addrlen || conn->cb_addr.ss_family != expected_family)
L
Linus Torvalds 已提交
1298
		goto out_err;
1299

1300 1301
	if (conn->cb_addr.ss_family == AF_INET6)
		((struct sockaddr_in6 *)&conn->cb_addr)->sin6_scope_id = scopeid;
1302

1303 1304
	conn->cb_prog = se->se_callback_prog;
	conn->cb_ident = se->se_callback_ident;
1305
	rpc_svcaddr2sockaddr((struct sockaddr *)&conn->cb_saddr, expected_family, &rqstp->rq_daddr);
L
Linus Torvalds 已提交
1306 1307
	return;
out_err:
1308 1309
	conn->cb_addr.ss_family = AF_UNSPEC;
	conn->cb_addrlen = 0;
N
Neil Brown 已提交
1310
	dprintk(KERN_INFO "NFSD: this client (clientid %08x/%08x) "
L
Linus Torvalds 已提交
1311 1312 1313 1314 1315 1316
		"will not receive delegations\n",
		clp->cl_clientid.cl_boot, clp->cl_clientid.cl_id);

	return;
}

1317
/*
1318
 * Cache a reply. nfsd4_check_drc_limit() has bounded the cache size.
1319 1320 1321 1322
 */
void
nfsd4_store_cache_entry(struct nfsd4_compoundres *resp)
{
1323 1324
	struct nfsd4_slot *slot = resp->cstate.slot;
	unsigned int base;
1325

1326
	dprintk("--> %s slot %p\n", __func__, slot);
1327

1328 1329
	slot->sl_opcnt = resp->opcnt;
	slot->sl_status = resp->cstate.status;
1330

1331
	if (nfsd4_not_cached(resp)) {
1332
		slot->sl_datalen = 0;
1333
		return;
1334
	}
1335 1336 1337 1338 1339 1340 1341
	slot->sl_datalen = (char *)resp->p - (char *)resp->cstate.datap;
	base = (char *)resp->cstate.datap -
					(char *)resp->xbuf->head[0].iov_base;
	if (read_bytes_from_xdr_buf(resp->xbuf, base, slot->sl_data,
				    slot->sl_datalen))
		WARN("%s: sessions DRC could not cache compound\n", __func__);
	return;
1342 1343 1344
}

/*
1345 1346 1347 1348
 * Encode the replay sequence operation from the slot values.
 * If cachethis is FALSE encode the uncached rep error on the next
 * operation which sets resp->p and increments resp->opcnt for
 * nfs4svc_encode_compoundres.
1349 1350
 *
 */
1351 1352 1353
static __be32
nfsd4_enc_sequence_replay(struct nfsd4_compoundargs *args,
			  struct nfsd4_compoundres *resp)
1354
{
1355 1356
	struct nfsd4_op *op;
	struct nfsd4_slot *slot = resp->cstate.slot;
1357

1358
	dprintk("--> %s resp->opcnt %d cachethis %u \n", __func__,
1359
		resp->opcnt, resp->cstate.slot->sl_cachethis);
1360

1361 1362 1363
	/* Encode the replayed sequence operation */
	op = &args->ops[resp->opcnt - 1];
	nfsd4_encode_operation(resp, op);
1364

1365
	/* Return nfserr_retry_uncached_rep in next operation. */
1366
	if (args->opcnt > 1 && slot->sl_cachethis == 0) {
1367 1368 1369
		op = &args->ops[resp->opcnt++];
		op->status = nfserr_retry_uncached_rep;
		nfsd4_encode_operation(resp, op);
1370
	}
1371
	return op->status;
1372 1373 1374
}

/*
1375 1376
 * The sequence operation is not cached because we can use the slot and
 * session values.
1377 1378
 */
__be32
1379 1380
nfsd4_replay_cache_entry(struct nfsd4_compoundres *resp,
			 struct nfsd4_sequence *seq)
1381
{
1382
	struct nfsd4_slot *slot = resp->cstate.slot;
1383 1384
	__be32 status;

1385
	dprintk("--> %s slot %p\n", __func__, slot);
1386

1387 1388 1389 1390
	/* Either returns 0 or nfserr_retry_uncached */
	status = nfsd4_enc_sequence_replay(resp->rqstp->rq_argp, resp);
	if (status == nfserr_retry_uncached_rep)
		return status;
1391

1392 1393
	/* The sequence operation has been encoded, cstate->datap set. */
	memcpy(resp->cstate.datap, slot->sl_data, slot->sl_datalen);
1394

1395 1396 1397
	resp->opcnt = slot->sl_opcnt;
	resp->p = resp->cstate.datap + XDR_QUADLEN(slot->sl_datalen);
	status = slot->sl_status;
1398 1399 1400 1401

	return status;
}

A
Andy Adamson 已提交
1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417
/*
 * Set the exchange_id flags returned by the server.
 */
static void
nfsd4_set_ex_flags(struct nfs4_client *new, struct nfsd4_exchange_id *clid)
{
	/* pNFS is not supported */
	new->cl_exchange_flags |= EXCHGID4_FLAG_USE_NON_PNFS;

	/* Referrals are supported, Migration is not. */
	new->cl_exchange_flags |= EXCHGID4_FLAG_SUPP_MOVED_REFER;

	/* set the wire flags to return to client. */
	clid->flags = new->cl_exchange_flags;
}

A
Andy Adamson 已提交
1418 1419 1420 1421 1422
__be32
nfsd4_exchange_id(struct svc_rqst *rqstp,
		  struct nfsd4_compound_state *cstate,
		  struct nfsd4_exchange_id *exid)
{
A
Andy Adamson 已提交
1423 1424 1425 1426
	struct nfs4_client *unconf, *conf, *new;
	int status;
	unsigned int		strhashval;
	char			dname[HEXDIR_LEN];
1427
	char			addr_str[INET6_ADDRSTRLEN];
A
Andy Adamson 已提交
1428
	nfs4_verifier		verf = exid->verifier;
1429
	struct sockaddr		*sa = svc_addr(rqstp);
A
Andy Adamson 已提交
1430

1431
	rpc_ntop(sa, addr_str, sizeof(addr_str));
A
Andy Adamson 已提交
1432
	dprintk("%s rqstp=%p exid=%p clname.len=%u clname.data=%p "
1433
		"ip_addr=%s flags %x, spa_how %d\n",
A
Andy Adamson 已提交
1434
		__func__, rqstp, exid, exid->clname.len, exid->clname.data,
1435
		addr_str, exid->flags, exid->spa_how);
A
Andy Adamson 已提交
1436 1437 1438 1439 1440 1441 1442 1443 1444

	if (!check_name(exid->clname) || (exid->flags & ~EXCHGID4_FLAG_MASK_A))
		return nfserr_inval;

	/* Currently only support SP4_NONE */
	switch (exid->spa_how) {
	case SP4_NONE:
		break;
	case SP4_SSV:
1445
		return nfserr_serverfault;
A
Andy Adamson 已提交
1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461
	default:
		BUG();				/* checked by xdr code */
	case SP4_MACH_CRED:
		return nfserr_serverfault;	/* no excuse :-/ */
	}

	status = nfs4_make_rec_clidname(dname, &exid->clname);

	if (status)
		goto error;

	strhashval = clientstr_hashval(dname);

	nfs4_lock_state();
	status = nfs_ok;

1462
	conf = find_confirmed_client_by_str(dname, strhashval);
A
Andy Adamson 已提交
1463
	if (conf) {
1464 1465 1466 1467
		if (!clp_used_exchangeid(conf)) {
			status = nfserr_clid_inuse; /* XXX: ? */
			goto out;
		}
A
Andy Adamson 已提交
1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
		if (!same_verf(&verf, &conf->cl_verifier)) {
			/* 18.35.4 case 8 */
			if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
				status = nfserr_not_same;
				goto out;
			}
			/* Client reboot: destroy old state */
			expire_client(conf);
			goto out_new;
		}
		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
			/* 18.35.4 case 9 */
			if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
				status = nfserr_perm;
				goto out;
			}
			expire_client(conf);
			goto out_new;
		}
		/*
		 * Set bit when the owner id and verifier map to an already
		 * confirmed client id (18.35.3).
		 */
		exid->flags |= EXCHGID4_FLAG_CONFIRMED_R;

		/*
		 * Falling into 18.35.4 case 2, possible router replay.
		 * Leave confirmed record intact and return same result.
		 */
		copy_verf(conf, &verf);
		new = conf;
		goto out_copy;
1500 1501 1502 1503 1504 1505
	}

	/* 18.35.4 case 7 */
	if (exid->flags & EXCHGID4_FLAG_UPD_CONFIRMED_REC_A) {
		status = nfserr_noent;
		goto out;
A
Andy Adamson 已提交
1506 1507
	}

1508
	unconf  = find_unconfirmed_client_by_str(dname, strhashval);
A
Andy Adamson 已提交
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519
	if (unconf) {
		/*
		 * Possible retry or client restart.  Per 18.35.4 case 4,
		 * a new unconfirmed record should be generated regardless
		 * of whether any properties have changed.
		 */
		expire_client(unconf);
	}

out_new:
	/* Normal case */
1520
	new = create_client(exid->clname, dname, rqstp, &verf);
A
Andy Adamson 已提交
1521
	if (new == NULL) {
1522
		status = nfserr_jukebox;
A
Andy Adamson 已提交
1523 1524 1525 1526 1527 1528 1529 1530 1531
		goto out;
	}

	gen_clid(new);
	add_to_unconfirmed(new, strhashval);
out_copy:
	exid->clientid.cl_boot = new->cl_clientid.cl_boot;
	exid->clientid.cl_id = new->cl_clientid.cl_id;

1532
	exid->seqid = 1;
A
Andy Adamson 已提交
1533 1534 1535
	nfsd4_set_ex_flags(new, exid);

	dprintk("nfsd4_exchange_id seqid %d flags %x\n",
1536
		new->cl_cs_slot.sl_seqid, new->cl_exchange_flags);
A
Andy Adamson 已提交
1537 1538 1539 1540 1541 1542 1543
	status = nfs_ok;

out:
	nfs4_unlock_state();
error:
	dprintk("nfsd4_exchange_id returns %d\n", ntohl(status));
	return status;
A
Andy Adamson 已提交
1544 1545
}

B
Benny Halevy 已提交
1546
static int
1547
check_slot_seqid(u32 seqid, u32 slot_seqid, int slot_inuse)
B
Benny Halevy 已提交
1548
{
1549 1550
	dprintk("%s enter. seqid %d slot_seqid %d\n", __func__, seqid,
		slot_seqid);
B
Benny Halevy 已提交
1551 1552

	/* The slot is in use, and no response has been sent. */
1553 1554
	if (slot_inuse) {
		if (seqid == slot_seqid)
B
Benny Halevy 已提交
1555 1556 1557 1558 1559
			return nfserr_jukebox;
		else
			return nfserr_seq_misordered;
	}
	/* Normal */
1560
	if (likely(seqid == slot_seqid + 1))
B
Benny Halevy 已提交
1561 1562
		return nfs_ok;
	/* Replay */
1563
	if (seqid == slot_seqid)
B
Benny Halevy 已提交
1564 1565
		return nfserr_replay_cache;
	/* Wraparound */
1566
	if (seqid == 1 && (slot_seqid + 1) == 0)
B
Benny Halevy 已提交
1567 1568 1569 1570 1571
		return nfs_ok;
	/* Misordered replay or misordered new request */
	return nfserr_seq_misordered;
}

1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592
/*
 * Cache the create session result into the create session single DRC
 * slot cache by saving the xdr structure. sl_seqid has been set.
 * Do this for solo or embedded create session operations.
 */
static void
nfsd4_cache_create_session(struct nfsd4_create_session *cr_ses,
			   struct nfsd4_clid_slot *slot, int nfserr)
{
	slot->sl_status = nfserr;
	memcpy(&slot->sl_cr_ses, cr_ses, sizeof(*cr_ses));
}

static __be32
nfsd4_replay_create_session(struct nfsd4_create_session *cr_ses,
			    struct nfsd4_clid_slot *slot)
{
	memcpy(cr_ses, &slot->sl_cr_ses, sizeof(*cr_ses));
	return slot->sl_status;
}

1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615
#define NFSD_MIN_REQ_HDR_SEQ_SZ	((\
			2 * 2 + /* credential,verifier: AUTH_NULL, length 0 */ \
			1 +	/* MIN tag is length with zero, only length */ \
			3 +	/* version, opcount, opcode */ \
			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
				/* seqid, slotID, slotID, cache */ \
			4 ) * sizeof(__be32))

#define NFSD_MIN_RESP_HDR_SEQ_SZ ((\
			2 +	/* verifier: AUTH_NULL, length 0 */\
			1 +	/* status */ \
			1 +	/* MIN tag is length with zero, only length */ \
			3 +	/* opcount, opcode, opstatus*/ \
			XDR_QUADLEN(NFS4_MAX_SESSIONID_LEN) + \
				/* seqid, slotID, slotID, slotID, status */ \
			5 ) * sizeof(__be32))

static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs fchannel)
{
	return fchannel.maxreq_sz < NFSD_MIN_REQ_HDR_SEQ_SZ
		|| fchannel.maxresp_sz < NFSD_MIN_RESP_HDR_SEQ_SZ;
}

A
Andy Adamson 已提交
1616 1617 1618 1619 1620
__be32
nfsd4_create_session(struct svc_rqst *rqstp,
		     struct nfsd4_compound_state *cstate,
		     struct nfsd4_create_session *cr_ses)
{
1621
	struct sockaddr *sa = svc_addr(rqstp);
A
Andy Adamson 已提交
1622
	struct nfs4_client *conf, *unconf;
1623
	struct nfsd4_session *new;
1624
	struct nfsd4_clid_slot *cs_slot = NULL;
1625
	bool confirm_me = false;
A
Andy Adamson 已提交
1626 1627
	int status = 0;

1628 1629 1630
	if (cr_ses->flags & ~SESSION4_FLAG_MASK_A)
		return nfserr_inval;

A
Andy Adamson 已提交
1631 1632 1633 1634 1635
	nfs4_lock_state();
	unconf = find_unconfirmed_client(&cr_ses->clientid);
	conf = find_confirmed_client(&cr_ses->clientid);

	if (conf) {
1636 1637
		cs_slot = &conf->cl_cs_slot;
		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
1638
		if (status == nfserr_replay_cache) {
A
Andy Adamson 已提交
1639
			dprintk("Got a create_session replay! seqid= %d\n",
1640
				cs_slot->sl_seqid);
1641
			/* Return the cached reply status */
1642
			status = nfsd4_replay_create_session(cr_ses, cs_slot);
1643
			goto out;
1644
		} else if (cr_ses->seqid != cs_slot->sl_seqid + 1) {
A
Andy Adamson 已提交
1645 1646 1647
			status = nfserr_seq_misordered;
			dprintk("Sequence misordered!\n");
			dprintk("Expected seqid= %d but got seqid= %d\n",
1648
				cs_slot->sl_seqid, cr_ses->seqid);
A
Andy Adamson 已提交
1649 1650 1651 1652
			goto out;
		}
	} else if (unconf) {
		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred) ||
1653
		    !rpc_cmp_addr(sa, (struct sockaddr *) &unconf->cl_addr)) {
A
Andy Adamson 已提交
1654 1655 1656 1657
			status = nfserr_clid_inuse;
			goto out;
		}

1658 1659
		cs_slot = &unconf->cl_cs_slot;
		status = check_slot_seqid(cr_ses->seqid, cs_slot->sl_seqid, 0);
1660 1661
		if (status) {
			/* an unconfirmed replay returns misordered */
A
Andy Adamson 已提交
1662
			status = nfserr_seq_misordered;
1663
			goto out;
A
Andy Adamson 已提交
1664 1665
		}

1666
		confirm_me = true;
A
Andy Adamson 已提交
1667 1668 1669 1670 1671 1672
		conf = unconf;
	} else {
		status = nfserr_stale_clientid;
		goto out;
	}

1673 1674 1675 1676 1677
	/*
	 * XXX: we should probably set this at creation time, and check
	 * for consistent minorversion use throughout:
	 */
	conf->cl_minorversion = 1;
1678 1679 1680 1681 1682 1683
	/*
	 * We do not support RDMA or persistent sessions
	 */
	cr_ses->flags &= ~SESSION4_PERSIST;
	cr_ses->flags &= ~SESSION4_RDMA;

1684 1685 1686 1687
	status = nfserr_toosmall;
	if (check_forechannel_attrs(cr_ses->fore_channel))
		goto out;

1688 1689 1690
	status = nfserr_jukebox;
	new = alloc_init_session(rqstp, conf, cr_ses);
	if (!new)
A
Andy Adamson 已提交
1691
		goto out;
1692 1693
	status = nfs_ok;
	memcpy(cr_ses->sessionid.data, new->se_sessionid.data,
A
Andy Adamson 已提交
1694
	       NFS4_MAX_SESSIONID_LEN);
1695 1696
	memcpy(&cr_ses->fore_channel, &new->se_fchannel,
		sizeof(struct nfsd4_channel_attrs));
1697
	cs_slot->sl_seqid++;
1698
	cr_ses->seqid = cs_slot->sl_seqid;
A
Andy Adamson 已提交
1699

1700 1701
	/* cache solo and embedded create sessions under the state lock */
	nfsd4_cache_create_session(cr_ses, cs_slot, status);
1702 1703
	if (confirm_me)
		move_to_confirmed(conf);
A
Andy Adamson 已提交
1704 1705 1706 1707
out:
	nfs4_unlock_state();
	dprintk("%s returns %d\n", __func__, ntohl(status));
	return status;
A
Andy Adamson 已提交
1708 1709
}

1710 1711 1712 1713 1714 1715 1716 1717
static bool nfsd4_last_compound_op(struct svc_rqst *rqstp)
{
	struct nfsd4_compoundres *resp = rqstp->rq_resp;
	struct nfsd4_compoundargs *argp = rqstp->rq_argp;

	return argp->opcnt == resp->opcnt;
}

1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752
static __be32 nfsd4_map_bcts_dir(u32 *dir)
{
	switch (*dir) {
	case NFS4_CDFC4_FORE:
	case NFS4_CDFC4_BACK:
		return nfs_ok;
	case NFS4_CDFC4_FORE_OR_BOTH:
	case NFS4_CDFC4_BACK_OR_BOTH:
		*dir = NFS4_CDFC4_BOTH;
		return nfs_ok;
	};
	return nfserr_inval;
}

__be32 nfsd4_bind_conn_to_session(struct svc_rqst *rqstp,
		     struct nfsd4_compound_state *cstate,
		     struct nfsd4_bind_conn_to_session *bcts)
{
	__be32 status;

	if (!nfsd4_last_compound_op(rqstp))
		return nfserr_not_only_op;
	spin_lock(&client_lock);
	cstate->session = find_in_sessionid_hashtbl(&bcts->sessionid);
	/* Sorta weird: we only need the refcnt'ing because new_conn acquires
	 * client_lock iself: */
	if (cstate->session) {
		nfsd4_get_session(cstate->session);
		atomic_inc(&cstate->session->se_client->cl_refcount);
	}
	spin_unlock(&client_lock);
	if (!cstate->session)
		return nfserr_badsession;

	status = nfsd4_map_bcts_dir(&bcts->dir);
1753 1754 1755
	if (!status)
		nfsd4_new_conn(rqstp, cstate->session, bcts->dir);
	return status;
1756 1757
}

1758 1759 1760 1761 1762 1763 1764
static bool nfsd4_compound_in_session(struct nfsd4_session *session, struct nfs4_sessionid *sid)
{
	if (!session)
		return 0;
	return !memcmp(sid, &session->se_sessionid, sizeof(*sid));
}

A
Andy Adamson 已提交
1765 1766 1767 1768 1769
__be32
nfsd4_destroy_session(struct svc_rqst *r,
		      struct nfsd4_compound_state *cstate,
		      struct nfsd4_destroy_session *sessionid)
{
B
Benny Halevy 已提交
1770 1771 1772 1773 1774 1775 1776 1777 1778 1779
	struct nfsd4_session *ses;
	u32 status = nfserr_badsession;

	/* Notes:
	 * - The confirmed nfs4_client->cl_sessionid holds destroyed sessinid
	 * - Should we return nfserr_back_chan_busy if waiting for
	 *   callbacks on to-be-destroyed session?
	 * - Do we need to clear any callback info from previous session?
	 */

1780
	if (nfsd4_compound_in_session(cstate->session, &sessionid->sessionid)) {
1781 1782 1783
		if (!nfsd4_last_compound_op(r))
			return nfserr_not_only_op;
	}
B
Benny Halevy 已提交
1784
	dump_sessionid(__func__, &sessionid->sessionid);
1785
	spin_lock(&client_lock);
B
Benny Halevy 已提交
1786 1787
	ses = find_in_sessionid_hashtbl(&sessionid->sessionid);
	if (!ses) {
1788
		spin_unlock(&client_lock);
B
Benny Halevy 已提交
1789 1790 1791 1792
		goto out;
	}

	unhash_session(ses);
1793
	spin_unlock(&client_lock);
B
Benny Halevy 已提交
1794

1795
	nfs4_lock_state();
1796
	nfsd4_probe_callback_sync(ses->se_client);
1797
	nfs4_unlock_state();
1798 1799 1800

	nfsd4_del_conns(ses);

B
Benny Halevy 已提交
1801 1802 1803 1804 1805
	nfsd4_put_session(ses);
	status = nfs_ok;
out:
	dprintk("%s returns %d\n", __func__, ntohl(status));
	return status;
A
Andy Adamson 已提交
1806 1807
}

1808
static struct nfsd4_conn *__nfsd4_find_conn(struct svc_xprt *xpt, struct nfsd4_session *s)
1809 1810 1811 1812
{
	struct nfsd4_conn *c;

	list_for_each_entry(c, &s->se_conns, cn_persession) {
1813
		if (c->cn_xprt == xpt) {
1814 1815 1816 1817 1818 1819
			return c;
		}
	}
	return NULL;
}

1820
static void nfsd4_sequence_check_conn(struct nfsd4_conn *new, struct nfsd4_session *ses)
1821 1822
{
	struct nfs4_client *clp = ses->se_client;
1823
	struct nfsd4_conn *c;
1824
	int ret;
1825 1826

	spin_lock(&clp->cl_lock);
1827
	c = __nfsd4_find_conn(new->cn_xprt, ses);
1828 1829 1830 1831 1832 1833 1834
	if (c) {
		spin_unlock(&clp->cl_lock);
		free_conn(new);
		return;
	}
	__nfsd4_hash_conn(new, ses);
	spin_unlock(&clp->cl_lock);
1835 1836 1837 1838
	ret = nfsd4_register_conn(new);
	if (ret)
		/* oops; xprt is already down: */
		nfsd4_conn_lost(&new->cn_xpt_user);
1839 1840 1841
	return;
}

1842 1843 1844 1845 1846 1847 1848
static bool nfsd4_session_too_many_ops(struct svc_rqst *rqstp, struct nfsd4_session *session)
{
	struct nfsd4_compoundargs *args = rqstp->rq_argp;

	return args->opcnt > session->se_fchannel.maxops;
}

M
Mi Jinlong 已提交
1849 1850 1851 1852 1853 1854 1855 1856
static bool nfsd4_request_too_big(struct svc_rqst *rqstp,
				  struct nfsd4_session *session)
{
	struct xdr_buf *xb = &rqstp->rq_arg;

	return xb->len > session->se_fchannel.maxreq_sz;
}

A
Andy Adamson 已提交
1857
__be32
B
Benny Halevy 已提交
1858
nfsd4_sequence(struct svc_rqst *rqstp,
A
Andy Adamson 已提交
1859 1860 1861
	       struct nfsd4_compound_state *cstate,
	       struct nfsd4_sequence *seq)
{
1862
	struct nfsd4_compoundres *resp = rqstp->rq_resp;
B
Benny Halevy 已提交
1863 1864
	struct nfsd4_session *session;
	struct nfsd4_slot *slot;
1865
	struct nfsd4_conn *conn;
B
Benny Halevy 已提交
1866 1867
	int status;

1868 1869 1870
	if (resp->opcnt != 1)
		return nfserr_sequence_pos;

1871 1872 1873 1874 1875 1876 1877 1878
	/*
	 * Will be either used or freed by nfsd4_sequence_check_conn
	 * below.
	 */
	conn = alloc_conn(rqstp, NFS4_CDFC4_FORE);
	if (!conn)
		return nfserr_jukebox;

1879
	spin_lock(&client_lock);
B
Benny Halevy 已提交
1880 1881 1882 1883 1884
	status = nfserr_badsession;
	session = find_in_sessionid_hashtbl(&seq->sessionid);
	if (!session)
		goto out;

1885 1886 1887 1888
	status = nfserr_too_many_ops;
	if (nfsd4_session_too_many_ops(rqstp, session))
		goto out;

M
Mi Jinlong 已提交
1889 1890 1891 1892
	status = nfserr_req_too_big;
	if (nfsd4_request_too_big(rqstp, session))
		goto out;

B
Benny Halevy 已提交
1893
	status = nfserr_badslot;
1894
	if (seq->slotid >= session->se_fchannel.maxreqs)
B
Benny Halevy 已提交
1895 1896
		goto out;

1897
	slot = session->se_slots[seq->slotid];
B
Benny Halevy 已提交
1898 1899
	dprintk("%s: slotid %d\n", __func__, seq->slotid);

1900 1901 1902 1903 1904
	/* We do not negotiate the number of slots yet, so set the
	 * maxslots to the session maxreqs which is used to encode
	 * sr_highest_slotid and the sr_target_slot id to maxslots */
	seq->maxslots = session->se_fchannel.maxreqs;

1905
	status = check_slot_seqid(seq->seqid, slot->sl_seqid, slot->sl_inuse);
B
Benny Halevy 已提交
1906 1907 1908
	if (status == nfserr_replay_cache) {
		cstate->slot = slot;
		cstate->session = session;
A
Andy Adamson 已提交
1909
		/* Return the cached reply status and set cstate->status
1910
		 * for nfsd4_proc_compound processing */
1911
		status = nfsd4_replay_cache_entry(resp, seq);
A
Andy Adamson 已提交
1912
		cstate->status = nfserr_replay_cache;
1913
		goto out;
B
Benny Halevy 已提交
1914 1915 1916 1917
	}
	if (status)
		goto out;

1918 1919
	nfsd4_sequence_check_conn(conn, session);
	conn = NULL;
1920

B
Benny Halevy 已提交
1921 1922 1923
	/* Success! bump slot seqid */
	slot->sl_inuse = true;
	slot->sl_seqid = seq->seqid;
1924
	slot->sl_cachethis = seq->cachethis;
B
Benny Halevy 已提交
1925 1926 1927 1928 1929

	cstate->slot = slot;
	cstate->session = session;

out:
1930
	/* Hold a session reference until done processing the compound. */
1931
	if (cstate->session) {
1932 1933
		struct nfs4_client *clp = session->se_client;

1934
		nfsd4_get_session(cstate->session);
1935 1936 1937
		atomic_inc(&clp->cl_refcount);
		if (clp->cl_cb_state == NFSD4_CB_DOWN)
			seq->status_flags |= SEQ4_STATUS_CB_PATH_DOWN;
1938
	}
1939
	kfree(conn);
1940
	spin_unlock(&client_lock);
B
Benny Halevy 已提交
1941 1942
	dprintk("%s: return %d\n", __func__, ntohl(status));
	return status;
A
Andy Adamson 已提交
1943 1944
}

1945 1946 1947
__be32
nfsd4_reclaim_complete(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_reclaim_complete *rc)
{
1948 1949
	int status = 0;

1950 1951 1952 1953 1954 1955 1956 1957 1958
	if (rc->rca_one_fs) {
		if (!cstate->current_fh.fh_dentry)
			return nfserr_nofilehandle;
		/*
		 * We don't take advantage of the rca_one_fs case.
		 * That's OK, it's optional, we can safely ignore it.
		 */
		 return nfs_ok;
	}
1959

1960
	nfs4_lock_state();
1961 1962 1963 1964 1965 1966
	status = nfserr_complete_already;
	if (cstate->session->se_client->cl_firststate)
		goto out;

	status = nfserr_stale_clientid;
	if (is_client_expired(cstate->session->se_client))
1967 1968 1969 1970 1971 1972 1973
		/*
		 * The following error isn't really legal.
		 * But we only get here if the client just explicitly
		 * destroyed the client.  Surely it no longer cares what
		 * error it gets back on an operation for the dead
		 * client.
		 */
1974 1975 1976
		goto out;

	status = nfs_ok;
1977
	nfsd4_create_clid_dir(cstate->session->se_client);
1978
out:
1979
	nfs4_unlock_state();
1980
	return status;
1981 1982
}

1983
__be32
1984 1985
nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		  struct nfsd4_setclientid *setclid)
L
Linus Torvalds 已提交
1986 1987 1988 1989 1990 1991 1992
{
	struct xdr_netobj 	clname = { 
		.len = setclid->se_namelen,
		.data = setclid->se_name,
	};
	nfs4_verifier		clverifier = setclid->se_verf;
	unsigned int 		strhashval;
1993
	struct nfs4_client	*conf, *unconf, *new;
1994
	__be32 			status;
N
NeilBrown 已提交
1995
	char                    dname[HEXDIR_LEN];
L
Linus Torvalds 已提交
1996 1997
	
	if (!check_name(clname))
1998
		return nfserr_inval;
L
Linus Torvalds 已提交
1999

N
NeilBrown 已提交
2000 2001
	status = nfs4_make_rec_clidname(dname, &clname);
	if (status)
2002
		return status;
N
NeilBrown 已提交
2003

L
Linus Torvalds 已提交
2004 2005 2006 2007 2008
	/* 
	 * XXX The Duplicate Request Cache (DRC) has been checked (??)
	 * We get here on a DRC miss.
	 */

N
NeilBrown 已提交
2009
	strhashval = clientstr_hashval(dname);
L
Linus Torvalds 已提交
2010 2011

	nfs4_lock_state();
2012
	conf = find_confirmed_client_by_str(dname, strhashval);
2013
	if (conf) {
2014
		/* RFC 3530 14.2.33 CASE 0: */
L
Linus Torvalds 已提交
2015
		status = nfserr_clid_inuse;
2016 2017
		if (clp_used_exchangeid(conf))
			goto out;
2018
		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred)) {
2019 2020 2021 2022 2023
			char addr_str[INET6_ADDRSTRLEN];
			rpc_ntop((struct sockaddr *) &conf->cl_addr, addr_str,
				 sizeof(addr_str));
			dprintk("NFSD: setclientid: string in use by client "
				"at %s\n", addr_str);
L
Linus Torvalds 已提交
2024 2025 2026
			goto out;
		}
	}
2027 2028 2029 2030 2031
	/*
	 * section 14.2.33 of RFC 3530 (under the heading "IMPLEMENTATION")
	 * has a description of SETCLIENTID request processing consisting
	 * of 5 bullet points, labeled as CASE0 - CASE4 below.
	 */
2032
	unconf = find_unconfirmed_client_by_str(dname, strhashval);
2033
	status = nfserr_jukebox;
L
Linus Torvalds 已提交
2034
	if (!conf) {
2035 2036 2037
		/*
		 * RFC 3530 14.2.33 CASE 4:
		 * placed first, because it is the normal case
L
Linus Torvalds 已提交
2038 2039 2040
		 */
		if (unconf)
			expire_client(unconf);
2041
		new = create_client(clname, dname, rqstp, &clverifier);
N
NeilBrown 已提交
2042
		if (new == NULL)
L
Linus Torvalds 已提交
2043 2044
			goto out;
		gen_clid(new);
2045
	} else if (same_verf(&conf->cl_verifier, &clverifier)) {
L
Linus Torvalds 已提交
2046
		/*
2047 2048
		 * RFC 3530 14.2.33 CASE 1:
		 * probable callback update
L
Linus Torvalds 已提交
2049
		 */
2050 2051 2052 2053 2054 2055 2056
		if (unconf) {
			/* Note this is removing unconfirmed {*x***},
			 * which is stronger than RFC recommended {vxc**}.
			 * This has the advantage that there is at most
			 * one {*x***} in either list at any time.
			 */
			expire_client(unconf);
L
Linus Torvalds 已提交
2057
		}
2058
		new = create_client(clname, dname, rqstp, &clverifier);
N
NeilBrown 已提交
2059
		if (new == NULL)
L
Linus Torvalds 已提交
2060 2061 2062 2063
			goto out;
		copy_clid(new, conf);
	} else if (!unconf) {
		/*
2064 2065 2066
		 * RFC 3530 14.2.33 CASE 2:
		 * probable client reboot; state will be removed if
		 * confirmed.
L
Linus Torvalds 已提交
2067
		 */
2068
		new = create_client(clname, dname, rqstp, &clverifier);
N
NeilBrown 已提交
2069
		if (new == NULL)
L
Linus Torvalds 已提交
2070 2071
			goto out;
		gen_clid(new);
2072
	} else {
2073 2074 2075 2076
		/*
		 * RFC 3530 14.2.33 CASE 3:
		 * probable client reboot; state will be removed if
		 * confirmed.
L
Linus Torvalds 已提交
2077 2078
		 */
		expire_client(unconf);
2079
		new = create_client(clname, dname, rqstp, &clverifier);
N
NeilBrown 已提交
2080
		if (new == NULL)
L
Linus Torvalds 已提交
2081 2082 2083
			goto out;
		gen_clid(new);
	}
2084 2085 2086 2087 2088
	/*
	 * XXX: we should probably set this at creation time, and check
	 * for consistent minorversion use throughout:
	 */
	new->cl_minorversion = 0;
2089
	gen_callback(new, setclid, rqstp);
2090
	add_to_unconfirmed(new, strhashval);
L
Linus Torvalds 已提交
2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101
	setclid->se_clientid.cl_boot = new->cl_clientid.cl_boot;
	setclid->se_clientid.cl_id = new->cl_clientid.cl_id;
	memcpy(setclid->se_confirm.data, new->cl_confirm.data, sizeof(setclid->se_confirm.data));
	status = nfs_ok;
out:
	nfs4_unlock_state();
	return status;
}


/*
2102 2103 2104
 * Section 14.2.34 of RFC 3530 (under the heading "IMPLEMENTATION") has
 * a description of SETCLIENTID_CONFIRM request processing consisting of 4
 * bullets, labeled as CASE1 - CASE4 below.
L
Linus Torvalds 已提交
2105
 */
2106
__be32
2107 2108 2109
nfsd4_setclientid_confirm(struct svc_rqst *rqstp,
			 struct nfsd4_compound_state *cstate,
			 struct nfsd4_setclientid_confirm *setclientid_confirm)
L
Linus Torvalds 已提交
2110
{
2111
	struct sockaddr *sa = svc_addr(rqstp);
2112
	struct nfs4_client *conf, *unconf;
L
Linus Torvalds 已提交
2113 2114
	nfs4_verifier confirm = setclientid_confirm->sc_confirm; 
	clientid_t * clid = &setclientid_confirm->sc_clientid;
2115
	__be32 status;
L
Linus Torvalds 已提交
2116 2117 2118 2119 2120 2121 2122 2123 2124

	if (STALE_CLIENTID(clid))
		return nfserr_stale_clientid;
	/* 
	 * XXX The Duplicate Request Cache (DRC) has been checked (??)
	 * We get here on a DRC miss.
	 */

	nfs4_lock_state();
2125 2126 2127 2128 2129

	conf = find_confirmed_client(clid);
	unconf = find_unconfirmed_client(clid);

	status = nfserr_clid_inuse;
2130
	if (conf && !rpc_cmp_addr((struct sockaddr *) &conf->cl_addr, sa))
2131
		goto out;
2132
	if (unconf && !rpc_cmp_addr((struct sockaddr *) &unconf->cl_addr, sa))
2133 2134
		goto out;

2135 2136 2137 2138 2139
	/*
	 * section 14.2.34 of RFC 3530 has a description of
	 * SETCLIENTID_CONFIRM request processing consisting
	 * of 4 bullet points, labeled as CASE1 - CASE4 below.
	 */
2140
	if (conf && unconf && same_verf(&confirm, &unconf->cl_confirm)) {
2141 2142 2143 2144
		/*
		 * RFC 3530 14.2.34 CASE 1:
		 * callback update
		 */
2145
		if (!same_creds(&conf->cl_cred, &unconf->cl_cred))
L
Linus Torvalds 已提交
2146 2147
			status = nfserr_clid_inuse;
		else {
2148 2149
			nfsd4_change_callback(conf, &unconf->cl_cb_conn);
			nfsd4_probe_callback(conf);
2150
			expire_client(unconf);
L
Linus Torvalds 已提交
2151
			status = nfs_ok;
2152

L
Linus Torvalds 已提交
2153
		}
2154
	} else if (conf && !unconf) {
2155 2156 2157 2158
		/*
		 * RFC 3530 14.2.34 CASE 2:
		 * probable retransmitted request; play it safe and
		 * do nothing.
2159
		 */
2160
		if (!same_creds(&conf->cl_cred, &rqstp->rq_cred))
L
Linus Torvalds 已提交
2161
			status = nfserr_clid_inuse;
2162
		else
L
Linus Torvalds 已提交
2163
			status = nfs_ok;
2164
	} else if (!conf && unconf
2165
			&& same_verf(&unconf->cl_confirm, &confirm)) {
2166 2167 2168
		/*
		 * RFC 3530 14.2.34 CASE 3:
		 * Normal case; new or rebooted client:
2169
		 */
2170
		if (!same_creds(&unconf->cl_cred, &rqstp->rq_cred)) {
L
Linus Torvalds 已提交
2171 2172
			status = nfserr_clid_inuse;
		} else {
2173 2174 2175
			unsigned int hash =
				clientstr_hashval(unconf->cl_recdir);
			conf = find_confirmed_client_by_str(unconf->cl_recdir,
2176
							    hash);
2177
			if (conf) {
2178
				nfsd4_remove_clid_dir(conf);
2179 2180
				expire_client(conf);
			}
L
Linus Torvalds 已提交
2181
			move_to_confirmed(unconf);
2182
			conf = unconf;
2183
			nfsd4_probe_callback(conf);
2184
			status = nfs_ok;
L
Linus Torvalds 已提交
2185
		}
2186 2187
	} else if ((!conf || (conf && !same_verf(&conf->cl_confirm, &confirm)))
	    && (!unconf || (unconf && !same_verf(&unconf->cl_confirm,
2188
				    				&confirm)))) {
2189 2190 2191
		/*
		 * RFC 3530 14.2.34 CASE 4:
		 * Client probably hasn't noticed that we rebooted yet.
2192
		 */
L
Linus Torvalds 已提交
2193
		status = nfserr_stale_clientid;
2194
	} else {
2195 2196 2197
		/* check that we have hit one of the cases...*/
		status = nfserr_clid_inuse;
	}
L
Linus Torvalds 已提交
2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209
out:
	nfs4_unlock_state();
	return status;
}

/* OPEN Share state helper functions */
static inline struct nfs4_file *
alloc_init_file(struct inode *ino)
{
	struct nfs4_file *fp;
	unsigned int hashval = file_hashval(ino);

N
NeilBrown 已提交
2210 2211
	fp = kmem_cache_alloc(file_slab, GFP_KERNEL);
	if (fp) {
2212
		atomic_set(&fp->fi_ref, 1);
L
Linus Torvalds 已提交
2213
		INIT_LIST_HEAD(&fp->fi_hash);
2214 2215
		INIT_LIST_HEAD(&fp->fi_stateids);
		INIT_LIST_HEAD(&fp->fi_delegations);
L
Linus Torvalds 已提交
2216 2217
		fp->fi_inode = igrab(ino);
		fp->fi_id = current_fileid++;
2218
		fp->fi_had_conflict = false;
2219
		fp->fi_lease = NULL;
2220 2221
		memset(fp->fi_fds, 0, sizeof(fp->fi_fds));
		memset(fp->fi_access, 0, sizeof(fp->fi_access));
2222 2223 2224
		spin_lock(&recall_lock);
		list_add(&fp->fi_hash, &file_hashtbl[hashval]);
		spin_unlock(&recall_lock);
L
Linus Torvalds 已提交
2225 2226 2227 2228 2229
		return fp;
	}
	return NULL;
}

N
NeilBrown 已提交
2230
static void
2231
nfsd4_free_slab(struct kmem_cache **slab)
L
Linus Torvalds 已提交
2232
{
N
NeilBrown 已提交
2233 2234
	if (*slab == NULL)
		return;
2235
	kmem_cache_destroy(*slab);
N
NeilBrown 已提交
2236
	*slab = NULL;
L
Linus Torvalds 已提交
2237 2238
}

2239
void
L
Linus Torvalds 已提交
2240 2241
nfsd4_free_slabs(void)
{
2242 2243
	nfsd4_free_slab(&openowner_slab);
	nfsd4_free_slab(&lockowner_slab);
N
NeilBrown 已提交
2244
	nfsd4_free_slab(&file_slab);
N
NeilBrown 已提交
2245
	nfsd4_free_slab(&stateid_slab);
N
NeilBrown 已提交
2246
	nfsd4_free_slab(&deleg_slab);
N
NeilBrown 已提交
2247
}
L
Linus Torvalds 已提交
2248

N
NeilBrown 已提交
2249 2250 2251
static int
nfsd4_init_slabs(void)
{
2252 2253 2254 2255 2256 2257 2258
	openowner_slab = kmem_cache_create("nfsd4_openowners",
			sizeof(struct nfs4_openowner), 0, 0, NULL);
	if (openowner_slab == NULL)
		goto out_nomem;
	lockowner_slab = kmem_cache_create("nfsd4_lockowners",
			sizeof(struct nfs4_openowner), 0, 0, NULL);
	if (lockowner_slab == NULL)
N
NeilBrown 已提交
2259 2260
		goto out_nomem;
	file_slab = kmem_cache_create("nfsd4_files",
2261
			sizeof(struct nfs4_file), 0, 0, NULL);
N
NeilBrown 已提交
2262 2263
	if (file_slab == NULL)
		goto out_nomem;
N
NeilBrown 已提交
2264
	stateid_slab = kmem_cache_create("nfsd4_stateids",
2265
			sizeof(struct nfs4_ol_stateid), 0, 0, NULL);
N
NeilBrown 已提交
2266 2267
	if (stateid_slab == NULL)
		goto out_nomem;
N
NeilBrown 已提交
2268
	deleg_slab = kmem_cache_create("nfsd4_delegations",
2269
			sizeof(struct nfs4_delegation), 0, 0, NULL);
N
NeilBrown 已提交
2270 2271
	if (deleg_slab == NULL)
		goto out_nomem;
N
NeilBrown 已提交
2272 2273 2274 2275 2276
	return 0;
out_nomem:
	nfsd4_free_slabs();
	dprintk("nfsd4: out of memory while initializing nfsv4\n");
	return -ENOMEM;
L
Linus Torvalds 已提交
2277 2278
}

2279 2280 2281 2282 2283 2284 2285
void nfs4_free_openowner(struct nfs4_openowner *oo)
{
	kfree(oo->oo_owner.so_owner.data);
	kmem_cache_free(openowner_slab, oo);
}

void nfs4_free_lockowner(struct nfs4_lockowner *lo)
L
Linus Torvalds 已提交
2286
{
2287 2288
	kfree(lo->lo_owner.so_owner.data);
	kmem_cache_free(lockowner_slab, lo);
L
Linus Torvalds 已提交
2289 2290
}

2291
static void init_nfs4_replay(struct nfs4_replay *rp)
L
Linus Torvalds 已提交
2292
{
2293 2294 2295
	rp->rp_status = nfserr_serverfault;
	rp->rp_buflen = 0;
	rp->rp_buf = rp->rp_ibuf;
L
Linus Torvalds 已提交
2296 2297
}

2298
static inline void *alloc_stateowner(struct kmem_cache *slab, struct xdr_netobj *owner, struct nfs4_client *clp)
2299
{
L
Linus Torvalds 已提交
2300 2301
	struct nfs4_stateowner *sop;

2302
	sop = kmem_cache_alloc(slab, GFP_KERNEL);
2303 2304 2305 2306 2307
	if (!sop)
		return NULL;

	sop->so_owner.data = kmemdup(owner->data, owner->len, GFP_KERNEL);
	if (!sop->so_owner.data) {
2308
		kmem_cache_free(slab, sop);
L
Linus Torvalds 已提交
2309
		return NULL;
2310 2311 2312
	}
	sop->so_owner.len = owner->len;

2313
	INIT_LIST_HEAD(&sop->so_stateids);
2314 2315 2316 2317 2318 2319
	sop->so_id = current_ownerid++;
	sop->so_client = clp;
	init_nfs4_replay(&sop->so_replay);
	return sop;
}

2320
static void hash_openowner(struct nfs4_openowner *oo, struct nfs4_client *clp, unsigned int strhashval)
2321 2322 2323
{
	unsigned int idhashval;

2324 2325 2326 2327
	idhashval = open_ownerid_hashval(oo->oo_owner.so_id);
	list_add(&oo->oo_owner.so_idhash, &open_ownerid_hashtbl[idhashval]);
	list_add(&oo->oo_owner.so_strhash, &open_ownerstr_hashtbl[strhashval]);
	list_add(&oo->oo_perclient, &clp->cl_openowners);
2328 2329
}

2330
static struct nfs4_openowner *
2331
alloc_init_open_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
2332
	struct nfs4_openowner *oo;
2333

2334 2335
	oo = alloc_stateowner(openowner_slab, &open->op_owner, clp);
	if (!oo)
2336
		return NULL;
2337 2338 2339 2340 2341 2342 2343
	oo->oo_owner.so_is_open_owner = 1;
	oo->oo_owner.so_seqid = open->op_seqid;
	oo->oo_confirmed = 0;
	oo->oo_time = 0;
	INIT_LIST_HEAD(&oo->oo_close_lru);
	hash_openowner(oo, clp, strhashval);
	return oo;
L
Linus Torvalds 已提交
2344 2345 2346
}

static inline void
2347
init_open_stateid(struct nfs4_ol_stateid *stp, struct nfs4_file *fp, struct nfsd4_open *open) {
2348
	struct nfs4_openowner *oo = open->op_openowner;
L
Linus Torvalds 已提交
2349

2350
	INIT_LIST_HEAD(&stp->st_lockowners);
2351
	list_add(&stp->st_perstateowner, &oo->oo_owner.so_stateids);
2352
	list_add(&stp->st_perfile, &fp->fi_stateids);
2353
	stp->st_stid.sc_type = NFS4_OPEN_STID;
2354
	stp->st_stateowner = &oo->oo_owner;
2355
	get_nfs4_file(fp);
L
Linus Torvalds 已提交
2356
	stp->st_file = fp;
2357 2358 2359
	stp->st_stid.sc_stateid.si_boot = boot_time;
	stp->st_stid.sc_stateid.si_stateownerid = oo->oo_owner.so_id;
	stp->st_stid.sc_stateid.si_fileid = fp->fi_id;
2360
	/* note will be incremented before first return to client: */
2361
	stp->st_stid.sc_stateid.si_generation = 0;
2362
	hash_stid(&stp->st_stid);
L
Linus Torvalds 已提交
2363 2364
	stp->st_access_bmap = 0;
	stp->st_deny_bmap = 0;
2365 2366
	__set_bit(open->op_share_access & ~NFS4_SHARE_WANT_MASK,
		  &stp->st_access_bmap);
L
Linus Torvalds 已提交
2367
	__set_bit(open->op_share_deny, &stp->st_deny_bmap);
2368
	stp->st_openstp = NULL;
L
Linus Torvalds 已提交
2369 2370
}

2371
static void
2372
move_to_close_lru(struct nfs4_openowner *oo)
L
Linus Torvalds 已提交
2373
{
2374
	dprintk("NFSD: move_to_close_lru nfs4_openowner %p\n", oo);
L
Linus Torvalds 已提交
2375

2376 2377
	list_move_tail(&oo->oo_close_lru, &close_lru);
	oo->oo_time = get_seconds();
L
Linus Torvalds 已提交
2378 2379 2380
}

static int
2381 2382 2383 2384 2385 2386
same_owner_str(struct nfs4_stateowner *sop, struct xdr_netobj *owner,
							clientid_t *clid)
{
	return (sop->so_owner.len == owner->len) &&
		0 == memcmp(sop->so_owner.data, owner->data, owner->len) &&
		(sop->so_client->cl_clientid.cl_id == clid->cl_id);
L
Linus Torvalds 已提交
2387 2388
}

2389
static struct nfs4_openowner *
L
Linus Torvalds 已提交
2390 2391 2392 2393
find_openstateowner_str(unsigned int hashval, struct nfsd4_open *open)
{
	struct nfs4_stateowner *so = NULL;

2394
	list_for_each_entry(so, &open_ownerstr_hashtbl[hashval], so_strhash) {
2395
		if (same_owner_str(so, &open->op_owner, &open->op_clientid))
2396
			return container_of(so, struct nfs4_openowner, oo_owner);
L
Linus Torvalds 已提交
2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407
	}
	return NULL;
}

/* search file_hashtbl[] for file */
static struct nfs4_file *
find_file(struct inode *ino)
{
	unsigned int hashval = file_hashval(ino);
	struct nfs4_file *fp;

2408
	spin_lock(&recall_lock);
L
Linus Torvalds 已提交
2409
	list_for_each_entry(fp, &file_hashtbl[hashval], fi_hash) {
2410 2411
		if (fp->fi_inode == ino) {
			get_nfs4_file(fp);
2412
			spin_unlock(&recall_lock);
L
Linus Torvalds 已提交
2413
			return fp;
2414
		}
L
Linus Torvalds 已提交
2415
	}
2416
	spin_unlock(&recall_lock);
L
Linus Torvalds 已提交
2417 2418 2419
	return NULL;
}

A
Andy Adamson 已提交
2420
static inline int access_valid(u32 x, u32 minorversion)
2421
{
A
Andy Adamson 已提交
2422
	if ((x & NFS4_SHARE_ACCESS_MASK) < NFS4_SHARE_ACCESS_READ)
2423
		return 0;
A
Andy Adamson 已提交
2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
	if ((x & NFS4_SHARE_ACCESS_MASK) > NFS4_SHARE_ACCESS_BOTH)
		return 0;
	x &= ~NFS4_SHARE_ACCESS_MASK;
	if (minorversion && x) {
		if ((x & NFS4_SHARE_WANT_MASK) > NFS4_SHARE_WANT_CANCEL)
			return 0;
		if ((x & NFS4_SHARE_WHEN_MASK) > NFS4_SHARE_PUSH_DELEG_WHEN_UNCONTENDED)
			return 0;
		x &= ~(NFS4_SHARE_WANT_MASK | NFS4_SHARE_WHEN_MASK);
	}
	if (x)
2435 2436
		return 0;
	return 1;
2437 2438
}

2439
static inline int deny_valid(u32 x)
2440
{
2441 2442
	/* Note: unlike access bits, deny bits may be zero. */
	return x <= NFS4_SHARE_DENY_BOTH;
2443
}
L
Linus Torvalds 已提交
2444 2445 2446 2447 2448

/*
 * Called to check deny when READ with all zero stateid or
 * WRITE with all zero or all one stateid
 */
2449
static __be32
L
Linus Torvalds 已提交
2450 2451 2452 2453
nfs4_share_conflict(struct svc_fh *current_fh, unsigned int deny_type)
{
	struct inode *ino = current_fh->fh_dentry->d_inode;
	struct nfs4_file *fp;
2454
	struct nfs4_ol_stateid *stp;
2455
	__be32 ret;
L
Linus Torvalds 已提交
2456 2457 2458 2459

	dprintk("NFSD: nfs4_share_conflict\n");

	fp = find_file(ino);
2460 2461
	if (!fp)
		return nfs_ok;
2462
	ret = nfserr_locked;
L
Linus Torvalds 已提交
2463
	/* Search for conflicting share reservations */
2464 2465 2466 2467
	list_for_each_entry(stp, &fp->fi_stateids, st_perfile) {
		if (test_bit(deny_type, &stp->st_deny_bmap) ||
		    test_bit(NFS4_SHARE_DENY_BOTH, &stp->st_deny_bmap))
			goto out;
L
Linus Torvalds 已提交
2468
	}
2469 2470 2471 2472
	ret = nfs_ok;
out:
	put_nfs4_file(fp);
	return ret;
L
Linus Torvalds 已提交
2473 2474
}

2475
static void nfsd_break_one_deleg(struct nfs4_delegation *dp)
L
Linus Torvalds 已提交
2476 2477 2478 2479 2480 2481 2482 2483 2484 2485
{
	/* We're assuming the state code never drops its reference
	 * without first removing the lease.  Since we're in this lease
	 * callback (and since the lease code is serialized by the kernel
	 * lock) we know the server hasn't removed the lease yet, we know
	 * it's safe to take a reference: */
	atomic_inc(&dp->dl_count);

	list_add_tail(&dp->dl_recall_lru, &del_recall_lru);

2486
	/* only place dl_time is set. protected by lock_flocks*/
L
Linus Torvalds 已提交
2487 2488
	dp->dl_time = get_seconds();

2489 2490 2491
	nfsd4_cb_recall(dp);
}

2492
/* Called from break_lease() with lock_flocks() held. */
2493 2494
static void nfsd_break_deleg_cb(struct file_lock *fl)
{
2495 2496
	struct nfs4_file *fp = (struct nfs4_file *)fl->fl_owner;
	struct nfs4_delegation *dp;
2497

2498 2499 2500
	BUG_ON(!fp);
	/* We assume break_lease is only called once per lease: */
	BUG_ON(fp->fi_had_conflict);
2501 2502
	/*
	 * We don't want the locks code to timeout the lease for us;
2503
	 * we'll remove it ourself if a delegation isn't returned
2504
	 * in time:
2505 2506
	 */
	fl->fl_break_time = 0;
L
Linus Torvalds 已提交
2507

2508
	spin_lock(&recall_lock);
2509 2510 2511
	fp->fi_had_conflict = true;
	list_for_each_entry(dp, &fp->fi_delegations, dl_perfile)
		nfsd_break_one_deleg(dp);
2512
	spin_unlock(&recall_lock);
L
Linus Torvalds 已提交
2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523
}

static
int nfsd_change_deleg_cb(struct file_lock **onlist, int arg)
{
	if (arg & F_UNLCK)
		return lease_modify(onlist, arg);
	else
		return -EAGAIN;
}

2524
static const struct lock_manager_operations nfsd_lease_mng_ops = {
J
J. Bruce Fields 已提交
2525 2526
	.lm_break = nfsd_break_deleg_cb,
	.lm_change = nfsd_change_deleg_cb,
L
Linus Torvalds 已提交
2527 2528
};

2529 2530 2531 2532 2533 2534 2535 2536 2537 2538
static __be32 nfsd4_check_seqid(struct nfsd4_compound_state *cstate, struct nfs4_stateowner *so, u32 seqid)
{
	if (nfsd4_has_session(cstate))
		return nfs_ok;
	if (seqid == so->so_seqid - 1)
		return nfserr_replay_me;
	if (seqid == so->so_seqid)
		return nfs_ok;
	return nfserr_bad_seqid;
}
L
Linus Torvalds 已提交
2539

2540
__be32
A
Andy Adamson 已提交
2541 2542
nfsd4_process_open1(struct nfsd4_compound_state *cstate,
		    struct nfsd4_open *open)
L
Linus Torvalds 已提交
2543 2544 2545 2546
{
	clientid_t *clientid = &open->op_clientid;
	struct nfs4_client *clp = NULL;
	unsigned int strhashval;
2547
	struct nfs4_openowner *oo = NULL;
2548
	__be32 status;
L
Linus Torvalds 已提交
2549 2550

	if (!check_name(open->op_owner))
2551
		return nfserr_inval;
L
Linus Torvalds 已提交
2552 2553 2554 2555

	if (STALE_CLIENTID(&open->op_clientid))
		return nfserr_stale_clientid;

2556
	strhashval = open_ownerstr_hashval(clientid->cl_id, &open->op_owner);
2557 2558 2559
	oo = find_openstateowner_str(strhashval, open);
	open->op_openowner = oo;
	if (!oo) {
2560
		/* Make sure the client's lease hasn't expired. */
L
Linus Torvalds 已提交
2561 2562
		clp = find_confirmed_client(clientid);
		if (clp == NULL)
2563 2564
			return nfserr_expired;
		goto renew;
L
Linus Torvalds 已提交
2565
	}
2566
	if (!oo->oo_confirmed) {
2567
		/* Replace unconfirmed owners without checking for replay. */
2568 2569 2570
		clp = oo->oo_owner.so_client;
		release_openowner(oo);
		open->op_openowner = NULL;
2571 2572
		goto renew;
	}
2573
	status = nfsd4_check_seqid(cstate, &oo->oo_owner, open->op_seqid);
2574 2575
	if (status)
		return status;
L
Linus Torvalds 已提交
2576
renew:
2577 2578 2579
	if (open->op_openowner == NULL) {
		oo = alloc_init_open_stateowner(strhashval, clp, open);
		if (oo == NULL)
2580
			return nfserr_jukebox;
2581
		open->op_openowner = oo;
2582
	}
2583 2584
	list_del_init(&oo->oo_close_lru);
	renew_client(oo->oo_owner.so_client);
2585
	return nfs_ok;
L
Linus Torvalds 已提交
2586 2587
}

2588
static inline __be32
N
NeilBrown 已提交
2589 2590 2591 2592 2593 2594 2595 2596
nfs4_check_delegmode(struct nfs4_delegation *dp, int flags)
{
	if ((flags & WR_STATE) && (dp->dl_type == NFS4_OPEN_DELEGATE_READ))
		return nfserr_openmode;
	else
		return nfs_ok;
}

2597
static int share_access_to_flags(u32 share_access)
2598
{
2599
	share_access &= ~NFS4_SHARE_WANT_MASK;
2600

2601
	return share_access == NFS4_SHARE_ACCESS_READ ? RD_STATE : WR_STATE;
2602 2603
}

2604
static struct nfs4_delegation *find_deleg_stateid(stateid_t *s)
2605
{
2606
	struct nfs4_stid *ret;
2607

2608 2609 2610 2611
	ret = find_stateid_by_type(s, NFS4_DELEG_STID);
	if (!ret)
		return NULL;
	return delegstateid(ret);
2612 2613
}

2614
static __be32
2615 2616 2617 2618
nfs4_check_deleg(struct nfs4_file *fp, struct nfsd4_open *open,
		struct nfs4_delegation **dp)
{
	int flags;
2619
	__be32 status = nfserr_bad_stateid;
2620

2621
	*dp = find_deleg_stateid(&open->op_delegate_stateid);
2622
	if (*dp == NULL)
2623
		goto out;
2624
	flags = share_access_to_flags(open->op_share_access);
2625 2626 2627
	status = nfs4_check_delegmode(*dp, flags);
	if (status)
		*dp = NULL;
2628 2629 2630 2631 2632
out:
	if (open->op_claim_type != NFS4_OPEN_CLAIM_DELEGATE_CUR)
		return nfs_ok;
	if (status)
		return status;
2633
	open->op_openowner->oo_confirmed = 1;
2634
	return nfs_ok;
2635 2636
}

2637
static __be32
2638
nfs4_check_open(struct nfs4_file *fp, struct nfsd4_open *open, struct nfs4_ol_stateid **stpp)
L
Linus Torvalds 已提交
2639
{
2640
	struct nfs4_ol_stateid *local;
2641
	struct nfs4_openowner *oo = open->op_openowner;
L
Linus Torvalds 已提交
2642

2643
	list_for_each_entry(local, &fp->fi_stateids, st_perfile) {
L
Linus Torvalds 已提交
2644 2645 2646 2647
		/* ignore lock owners */
		if (local->st_stateowner->so_is_open_owner == 0)
			continue;
		/* remember if we have seen this open owner */
2648
		if (local->st_stateowner == &oo->oo_owner)
L
Linus Torvalds 已提交
2649 2650 2651
			*stpp = local;
		/* check for conflicting share reservations */
		if (!test_share(local, open))
2652
			return nfserr_share_denied;
L
Linus Torvalds 已提交
2653
	}
2654
	return nfs_ok;
L
Linus Torvalds 已提交
2655 2656
}

2657
static inline struct nfs4_ol_stateid *
N
NeilBrown 已提交
2658 2659 2660 2661 2662
nfs4_alloc_stateid(void)
{
	return kmem_cache_alloc(stateid_slab, GFP_KERNEL);
}

2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673
static inline int nfs4_access_to_access(u32 nfs4_access)
{
	int flags = 0;

	if (nfs4_access & NFS4_SHARE_ACCESS_READ)
		flags |= NFSD_MAY_READ;
	if (nfs4_access & NFS4_SHARE_ACCESS_WRITE)
		flags |= NFSD_MAY_WRITE;
	return flags;
}

2674 2675
static __be32 nfs4_get_vfs_file(struct svc_rqst *rqstp, struct nfs4_file *fp,
		struct svc_fh *cur_fh, struct nfsd4_open *open)
2676 2677
{
	__be32 status;
2678 2679 2680 2681 2682 2683 2684 2685
	int oflag = nfs4_access_to_omode(open->op_share_access);
	int access = nfs4_access_to_access(open->op_share_access);

	/* CLAIM_DELEGATE_CUR is used in response to a broken lease;
	 * allowing it to break the lease and return EAGAIN leaves the
	 * client unable to make progress in returning the delegation */
	if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
		access |= NFSD_MAY_NOT_BREAK_LEASE;
2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697

	if (!fp->fi_fds[oflag]) {
		status = nfsd_open(rqstp, cur_fh, S_IFREG, access,
			&fp->fi_fds[oflag]);
		if (status)
			return status;
	}
	nfs4_file_get_access(fp, oflag);

	return nfs_ok;
}

2698
static __be32
2699
nfs4_new_open(struct svc_rqst *rqstp, struct nfs4_ol_stateid **stpp,
2700 2701
		struct nfs4_file *fp, struct svc_fh *cur_fh,
		struct nfsd4_open *open)
L
Linus Torvalds 已提交
2702
{
2703
	struct nfs4_ol_stateid *stp;
2704
	__be32 status;
L
Linus Torvalds 已提交
2705

N
NeilBrown 已提交
2706
	stp = nfs4_alloc_stateid();
L
Linus Torvalds 已提交
2707
	if (stp == NULL)
2708
		return nfserr_jukebox;
L
Linus Torvalds 已提交
2709

2710
	status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
2711 2712 2713
	if (status) {
		kmem_cache_free(stateid_slab, stp);
		return status;
L
Linus Torvalds 已提交
2714 2715 2716 2717 2718
	}
	*stpp = stp;
	return 0;
}

2719
static inline __be32
L
Linus Torvalds 已提交
2720 2721 2722 2723 2724 2725 2726 2727 2728 2729
nfsd4_truncate(struct svc_rqst *rqstp, struct svc_fh *fh,
		struct nfsd4_open *open)
{
	struct iattr iattr = {
		.ia_valid = ATTR_SIZE,
		.ia_size = 0,
	};
	if (!open->op_truncate)
		return 0;
	if (!(open->op_share_access & NFS4_SHARE_ACCESS_WRITE))
2730
		return nfserr_inval;
L
Linus Torvalds 已提交
2731 2732 2733
	return nfsd_setattr(rqstp, fh, &iattr, 0, (time_t)0);
}

2734
static __be32
2735
nfs4_upgrade_open(struct svc_rqst *rqstp, struct nfs4_file *fp, struct svc_fh *cur_fh, struct nfs4_ol_stateid *stp, struct nfsd4_open *open)
L
Linus Torvalds 已提交
2736
{
2737 2738
	u32 op_share_access = open->op_share_access & ~NFS4_SHARE_WANT_MASK;
	bool new_access;
2739
	__be32 status;
L
Linus Torvalds 已提交
2740

2741
	new_access = !test_bit(op_share_access, &stp->st_access_bmap);
2742
	if (new_access) {
2743
		status = nfs4_get_vfs_file(rqstp, fp, cur_fh, open);
2744 2745
		if (status)
			return status;
2746
	}
L
Linus Torvalds 已提交
2747 2748
	status = nfsd4_truncate(rqstp, cur_fh, open);
	if (status) {
2749
		if (new_access) {
2750
			int oflag = nfs4_access_to_omode(op_share_access);
2751 2752
			nfs4_file_put_access(fp, oflag);
		}
L
Linus Torvalds 已提交
2753 2754 2755
		return status;
	}
	/* remember the open */
2756
	__set_bit(op_share_access, &stp->st_access_bmap);
2757
	__set_bit(open->op_share_deny, &stp->st_deny_bmap);
L
Linus Torvalds 已提交
2758 2759 2760 2761 2762 2763

	return nfs_ok;
}


static void
2764
nfs4_set_claim_prev(struct nfsd4_open *open)
L
Linus Torvalds 已提交
2765
{
2766 2767
	open->op_openowner->oo_confirmed = 1;
	open->op_openowner->oo_owner.so_client->cl_firststate = 1;
L
Linus Torvalds 已提交
2768 2769
}

2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782
/* Should we give out recallable state?: */
static bool nfsd4_cb_channel_good(struct nfs4_client *clp)
{
	if (clp->cl_cb_state == NFSD4_CB_UP)
		return true;
	/*
	 * In the sessions case, since we don't have to establish a
	 * separate connection for callbacks, we assume it's OK
	 * until we hear otherwise:
	 */
	return clp->cl_minorversion && clp->cl_cb_state == NFSD4_CB_UNKNOWN;
}

2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794
static struct file_lock *nfs4_alloc_init_lease(struct nfs4_delegation *dp, int flag)
{
	struct file_lock *fl;

	fl = locks_alloc_lock();
	if (!fl)
		return NULL;
	locks_init_lock(fl);
	fl->fl_lmops = &nfsd_lease_mng_ops;
	fl->fl_flags = FL_LEASE;
	fl->fl_type = flag == NFS4_OPEN_DELEGATE_READ? F_RDLCK: F_WRLCK;
	fl->fl_end = OFFSET_MAX;
2795
	fl->fl_owner = (fl_owner_t)(dp->dl_file);
2796 2797 2798 2799
	fl->fl_pid = current->tgid;
	return fl;
}

2800 2801
static int nfs4_setlease(struct nfs4_delegation *dp, int flag)
{
2802
	struct nfs4_file *fp = dp->dl_file;
2803 2804 2805 2806 2807 2808
	struct file_lock *fl;
	int status;

	fl = nfs4_alloc_init_lease(dp, flag);
	if (!fl)
		return -ENOMEM;
2809 2810 2811
	fl->fl_file = find_readable_file(fp);
	list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
	status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
2812
	if (status) {
2813
		list_del_init(&dp->dl_perclnt);
2814 2815 2816
		locks_free_lock(fl);
		return -ENOMEM;
	}
2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839
	fp->fi_lease = fl;
	fp->fi_deleg_file = fl->fl_file;
	get_file(fp->fi_deleg_file);
	atomic_set(&fp->fi_delegees, 1);
	list_add(&dp->dl_perfile, &fp->fi_delegations);
	return 0;
}

static int nfs4_set_delegation(struct nfs4_delegation *dp, int flag)
{
	struct nfs4_file *fp = dp->dl_file;

	if (!fp->fi_lease)
		return nfs4_setlease(dp, flag);
	spin_lock(&recall_lock);
	if (fp->fi_had_conflict) {
		spin_unlock(&recall_lock);
		return -EAGAIN;
	}
	atomic_inc(&fp->fi_delegees);
	list_add(&dp->dl_perfile, &fp->fi_delegations);
	spin_unlock(&recall_lock);
	list_add(&dp->dl_perclnt, &dp->dl_client->cl_delegations);
2840 2841 2842
	return 0;
}

L
Linus Torvalds 已提交
2843 2844 2845 2846
/*
 * Attempt to hand out a delegation.
 */
static void
2847
nfs4_open_delegation(struct svc_fh *fh, struct nfsd4_open *open, struct nfs4_ol_stateid *stp)
L
Linus Torvalds 已提交
2848 2849
{
	struct nfs4_delegation *dp;
2850
	struct nfs4_openowner *oo = container_of(stp->st_stateowner, struct nfs4_openowner, oo_owner);
2851
	int cb_up;
L
Linus Torvalds 已提交
2852 2853
	int status, flag = 0;

2854
	cb_up = nfsd4_cb_channel_good(oo->oo_owner.so_client);
L
Linus Torvalds 已提交
2855
	flag = NFS4_OPEN_DELEGATE_NONE;
2856 2857 2858
	open->op_recall = 0;
	switch (open->op_claim_type) {
		case NFS4_OPEN_CLAIM_PREVIOUS:
2859
			if (!cb_up)
2860 2861 2862 2863 2864 2865 2866 2867
				open->op_recall = 1;
			flag = open->op_delegate_type;
			if (flag == NFS4_OPEN_DELEGATE_NONE)
				goto out;
			break;
		case NFS4_OPEN_CLAIM_NULL:
			/* Let's not give out any delegations till everyone's
			 * had the chance to reclaim theirs.... */
2868
			if (locks_in_grace())
2869
				goto out;
2870
			if (!cb_up || !oo->oo_confirmed)
2871 2872 2873 2874 2875 2876 2877 2878 2879
				goto out;
			if (open->op_share_access & NFS4_SHARE_ACCESS_WRITE)
				flag = NFS4_OPEN_DELEGATE_WRITE;
			else
				flag = NFS4_OPEN_DELEGATE_READ;
			break;
		default:
			goto out;
	}
L
Linus Torvalds 已提交
2880

2881
	dp = alloc_init_deleg(oo->oo_owner.so_client, stp, fh, flag);
2882 2883
	if (dp == NULL)
		goto out_no_deleg;
2884
	status = nfs4_set_delegation(dp, flag);
2885
	if (status)
2886
		goto out_free;
L
Linus Torvalds 已提交
2887

2888
	memcpy(&open->op_delegate_stateid, &dp->dl_stid.sc_stateid, sizeof(dp->dl_stid.sc_stateid));
L
Linus Torvalds 已提交
2889

2890
	dprintk("NFSD: delegation stateid=" STATEID_FMT "\n",
2891
		STATEID_VAL(&dp->dl_stid.sc_stateid));
L
Linus Torvalds 已提交
2892
out:
2893 2894 2895
	if (open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS
			&& flag == NFS4_OPEN_DELEGATE_NONE
			&& open->op_delegate_type != NFS4_OPEN_DELEGATE_NONE)
2896
		dprintk("NFSD: WARNING: refusing delegation reclaim\n");
L
Linus Torvalds 已提交
2897
	open->op_delegate_type = flag;
2898 2899
	return;
out_free:
2900
	nfs4_put_delegation(dp);
2901 2902 2903
out_no_deleg:
	flag = NFS4_OPEN_DELEGATE_NONE;
	goto out;
L
Linus Torvalds 已提交
2904 2905 2906 2907 2908
}

/*
 * called with nfs4_lock_state() held.
 */
2909
__be32
L
Linus Torvalds 已提交
2910 2911
nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
{
A
Andy Adamson 已提交
2912
	struct nfsd4_compoundres *resp = rqstp->rq_resp;
L
Linus Torvalds 已提交
2913 2914
	struct nfs4_file *fp = NULL;
	struct inode *ino = current_fh->fh_dentry->d_inode;
2915
	struct nfs4_ol_stateid *stp = NULL;
2916
	struct nfs4_delegation *dp = NULL;
2917
	__be32 status;
L
Linus Torvalds 已提交
2918 2919

	status = nfserr_inval;
A
Andy Adamson 已提交
2920
	if (!access_valid(open->op_share_access, resp->cstate.minorversion)
2921
			|| !deny_valid(open->op_share_deny))
L
Linus Torvalds 已提交
2922 2923 2924 2925 2926 2927 2928 2929 2930 2931
		goto out;
	/*
	 * Lookup file; if found, lookup stateid and check open request,
	 * and check for delegations in the process of being recalled.
	 * If not found, create the nfs4_file struct
	 */
	fp = find_file(ino);
	if (fp) {
		if ((status = nfs4_check_open(fp, open, &stp)))
			goto out;
2932 2933 2934
		status = nfs4_check_deleg(fp, open, &dp);
		if (status)
			goto out;
L
Linus Torvalds 已提交
2935
	} else {
2936 2937 2938
		status = nfserr_bad_stateid;
		if (open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
			goto out;
2939
		status = nfserr_jukebox;
L
Linus Torvalds 已提交
2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950
		fp = alloc_init_file(ino);
		if (fp == NULL)
			goto out;
	}

	/*
	 * OPEN the file, or upgrade an existing OPEN.
	 * If truncate fails, the OPEN fails.
	 */
	if (stp) {
		/* Stateid was found, this is an OPEN upgrade */
2951
		status = nfs4_upgrade_open(rqstp, fp, current_fh, stp, open);
L
Linus Torvalds 已提交
2952 2953 2954
		if (status)
			goto out;
	} else {
2955
		status = nfs4_new_open(rqstp, &stp, fp, current_fh, open);
2956
		if (status)
L
Linus Torvalds 已提交
2957
			goto out;
J
J. Bruce Fields 已提交
2958
		init_open_stateid(stp, fp, open);
L
Linus Torvalds 已提交
2959 2960
		status = nfsd4_truncate(rqstp, current_fh, open);
		if (status) {
2961
			release_open_stateid(stp);
L
Linus Torvalds 已提交
2962 2963 2964
			goto out;
		}
	}
2965 2966
	update_stateid(&stp->st_stid.sc_stateid);
	memcpy(&open->op_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
L
Linus Torvalds 已提交
2967

2968
	if (nfsd4_has_session(&resp->cstate))
2969
		open->op_openowner->oo_confirmed = 1;
A
Andy Adamson 已提交
2970

L
Linus Torvalds 已提交
2971 2972 2973 2974 2975 2976 2977 2978
	/*
	* Attempt to hand out a delegation. No error return, because the
	* OPEN succeeds even if we fail.
	*/
	nfs4_open_delegation(current_fh, open, stp);

	status = nfs_ok;

2979
	dprintk("%s: stateid=" STATEID_FMT "\n", __func__,
2980
		STATEID_VAL(&stp->st_stid.sc_stateid));
L
Linus Torvalds 已提交
2981
out:
2982 2983
	if (fp)
		put_nfs4_file(fp);
2984 2985
	if (status == 0 && open->op_claim_type == NFS4_OPEN_CLAIM_PREVIOUS)
		nfs4_set_claim_prev(open);
L
Linus Torvalds 已提交
2986 2987 2988 2989
	/*
	* To finish the open response, we just need to set the rflags.
	*/
	open->op_rflags = NFS4_OPEN_RESULT_LOCKTYPE_POSIX;
2990
	if (!open->op_openowner->oo_confirmed &&
A
Andy Adamson 已提交
2991
	    !nfsd4_has_session(&resp->cstate))
L
Linus Torvalds 已提交
2992 2993 2994 2995 2996
		open->op_rflags |= NFS4_OPEN_RESULT_CONFIRM;

	return status;
}

2997
__be32
2998 2999
nfsd4_renew(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    clientid_t *clid)
L
Linus Torvalds 已提交
3000 3001
{
	struct nfs4_client *clp;
3002
	__be32 status;
L
Linus Torvalds 已提交
3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018

	nfs4_lock_state();
	dprintk("process_renew(%08x/%08x): starting\n", 
			clid->cl_boot, clid->cl_id);
	status = nfserr_stale_clientid;
	if (STALE_CLIENTID(clid))
		goto out;
	clp = find_confirmed_client(clid);
	status = nfserr_expired;
	if (clp == NULL) {
		/* We assume the client took too long to RENEW. */
		dprintk("nfsd4_renew: clientid not found!\n");
		goto out;
	}
	renew_client(clp);
	status = nfserr_cb_path_down;
3019
	if (!list_empty(&clp->cl_delegations)
3020
			&& clp->cl_cb_state != NFSD4_CB_UP)
L
Linus Torvalds 已提交
3021 3022 3023 3024 3025 3026 3027
		goto out;
	status = nfs_ok;
out:
	nfs4_unlock_state();
	return status;
}

D
Daniel Mack 已提交
3028
static struct lock_manager nfsd4_manager = {
3029 3030
};

3031
static void
3032
nfsd4_end_grace(void)
3033 3034
{
	dprintk("NFSD: end of grace period\n");
3035
	nfsd4_recdir_purge_old();
3036
	locks_end_grace(&nfsd4_manager);
3037 3038 3039 3040 3041 3042
	/*
	 * Now that every NFSv4 client has had the chance to recover and
	 * to see the (possibly new, possibly shorter) lease time, we
	 * can safely set the next grace time to the current lease time:
	 */
	nfsd4_grace = nfsd4_lease;
3043 3044
}

3045
static time_t
L
Linus Torvalds 已提交
3046 3047 3048
nfs4_laundromat(void)
{
	struct nfs4_client *clp;
3049
	struct nfs4_openowner *oo;
L
Linus Torvalds 已提交
3050 3051
	struct nfs4_delegation *dp;
	struct list_head *pos, *next, reaplist;
3052 3053 3054
	time_t cutoff = get_seconds() - nfsd4_lease;
	time_t t, clientid_val = nfsd4_lease;
	time_t u, test_val = nfsd4_lease;
L
Linus Torvalds 已提交
3055 3056 3057 3058

	nfs4_lock_state();

	dprintk("NFSD: laundromat service - starting\n");
3059 3060
	if (locks_in_grace())
		nfsd4_end_grace();
3061 3062
	INIT_LIST_HEAD(&reaplist);
	spin_lock(&client_lock);
L
Linus Torvalds 已提交
3063 3064 3065 3066 3067 3068 3069 3070
	list_for_each_safe(pos, next, &client_lru) {
		clp = list_entry(pos, struct nfs4_client, cl_lru);
		if (time_after((unsigned long)clp->cl_time, (unsigned long)cutoff)) {
			t = clp->cl_time - cutoff;
			if (clientid_val > t)
				clientid_val = t;
			break;
		}
3071 3072 3073 3074 3075 3076 3077
		if (atomic_read(&clp->cl_refcount)) {
			dprintk("NFSD: client in use (clientid %08x)\n",
				clp->cl_clientid.cl_id);
			continue;
		}
		unhash_client_locked(clp);
		list_add(&clp->cl_lru, &reaplist);
3078 3079 3080 3081
	}
	spin_unlock(&client_lock);
	list_for_each_safe(pos, next, &reaplist) {
		clp = list_entry(pos, struct nfs4_client, cl_lru);
L
Linus Torvalds 已提交
3082 3083
		dprintk("NFSD: purging unused client (clientid %08x)\n",
			clp->cl_clientid.cl_id);
3084
		nfsd4_remove_clid_dir(clp);
L
Linus Torvalds 已提交
3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103
		expire_client(clp);
	}
	spin_lock(&recall_lock);
	list_for_each_safe(pos, next, &del_recall_lru) {
		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
		if (time_after((unsigned long)dp->dl_time, (unsigned long)cutoff)) {
			u = dp->dl_time - cutoff;
			if (test_val > u)
				test_val = u;
			break;
		}
		list_move(&dp->dl_recall_lru, &reaplist);
	}
	spin_unlock(&recall_lock);
	list_for_each_safe(pos, next, &reaplist) {
		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
		list_del_init(&dp->dl_recall_lru);
		unhash_delegation(dp);
	}
3104
	test_val = nfsd4_lease;
L
Linus Torvalds 已提交
3105
	list_for_each_safe(pos, next, &close_lru) {
3106 3107 3108
		oo = container_of(pos, struct nfs4_openowner, oo_close_lru);
		if (time_after((unsigned long)oo->oo_time, (unsigned long)cutoff)) {
			u = oo->oo_time - cutoff;
L
Linus Torvalds 已提交
3109 3110 3111 3112 3113
			if (test_val > u)
				test_val = u;
			break;
		}
		dprintk("NFSD: purging unused open stateowner (so_id %d)\n",
3114 3115
			oo->oo_owner.so_id);
		release_openowner(oo);
L
Linus Torvalds 已提交
3116 3117 3118 3119 3120 3121 3122
	}
	if (clientid_val < NFSD_LAUNDROMAT_MINTIMEOUT)
		clientid_val = NFSD_LAUNDROMAT_MINTIMEOUT;
	nfs4_unlock_state();
	return clientid_val;
}

H
Harvey Harrison 已提交
3123 3124 3125 3126 3127
static struct workqueue_struct *laundry_wq;
static void laundromat_main(struct work_struct *);
static DECLARE_DELAYED_WORK(laundromat_work, laundromat_main);

static void
D
David Howells 已提交
3128
laundromat_main(struct work_struct *not_used)
L
Linus Torvalds 已提交
3129 3130 3131 3132 3133
{
	time_t t;

	t = nfs4_laundromat();
	dprintk("NFSD: laundromat_main - sleeping for %ld seconds\n", t);
3134
	queue_delayed_work(laundry_wq, &laundromat_work, t*HZ);
L
Linus Torvalds 已提交
3135 3136
}

3137
static struct nfs4_openowner * search_close_lru(u32 st_id)
3138
{
3139
	struct nfs4_openowner *local;
L
Linus Torvalds 已提交
3140

3141 3142
	list_for_each_entry(local, &close_lru, oo_close_lru) {
		if (local->oo_owner.so_id == st_id)
3143
			return local;
L
Linus Torvalds 已提交
3144 3145 3146 3147 3148
	}
	return NULL;
}

static inline int
3149
nfs4_check_fh(struct svc_fh *fhp, struct nfs4_ol_stateid *stp)
L
Linus Torvalds 已提交
3150
{
3151
	return fhp->fh_dentry->d_inode != stp->st_file->fi_inode;
L
Linus Torvalds 已提交
3152 3153 3154 3155 3156
}

static int
STALE_STATEID(stateid_t *stateid)
{
3157 3158 3159
	if (stateid->si_boot == boot_time)
		return 0;
	dprintk("NFSD: stale stateid " STATEID_FMT "!\n",
3160
		STATEID_VAL(stateid));
3161
	return 1;
L
Linus Torvalds 已提交
3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179
}

static inline int
access_permit_read(unsigned long access_bmap)
{
	return test_bit(NFS4_SHARE_ACCESS_READ, &access_bmap) ||
		test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap) ||
		test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap);
}

static inline int
access_permit_write(unsigned long access_bmap)
{
	return test_bit(NFS4_SHARE_ACCESS_WRITE, &access_bmap) ||
		test_bit(NFS4_SHARE_ACCESS_BOTH, &access_bmap);
}

static
3180
__be32 nfs4_check_openmode(struct nfs4_ol_stateid *stp, int flags)
L
Linus Torvalds 已提交
3181
{
3182
        __be32 status = nfserr_openmode;
L
Linus Torvalds 已提交
3183

3184 3185 3186
	/* For lock stateid's, we test the parent open, not the lock: */
	if (stp->st_openstp)
		stp = stp->st_openstp;
L
Linus Torvalds 已提交
3187 3188 3189 3190 3191 3192 3193 3194 3195
	if ((flags & WR_STATE) && (!access_permit_write(stp->st_access_bmap)))
                goto out;
	if ((flags & RD_STATE) && (!access_permit_read(stp->st_access_bmap)))
                goto out;
	status = nfs_ok;
out:
	return status;
}

3196
static inline __be32
L
Linus Torvalds 已提交
3197 3198
check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags)
{
3199
	if (ONE_STATEID(stateid) && (flags & RD_STATE))
L
Linus Torvalds 已提交
3200
		return nfs_ok;
3201
	else if (locks_in_grace()) {
L
Lucas De Marchi 已提交
3202
		/* Answer in remaining cases depends on existence of
L
Linus Torvalds 已提交
3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217
		 * conflicting state; so we must wait out the grace period. */
		return nfserr_grace;
	} else if (flags & WR_STATE)
		return nfs4_share_conflict(current_fh,
				NFS4_SHARE_DENY_WRITE);
	else /* (flags & RD_STATE) && ZERO_STATEID(stateid) */
		return nfs4_share_conflict(current_fh,
				NFS4_SHARE_DENY_READ);
}

/*
 * Allow READ/WRITE during grace period on recovered state only for files
 * that are not able to provide mandatory locking.
 */
static inline int
3218
grace_disallows_io(struct inode *inode)
L
Linus Torvalds 已提交
3219
{
3220
	return locks_in_grace() && mandatory_lock(inode);
L
Linus Torvalds 已提交
3221 3222
}

3223 3224 3225 3226 3227 3228
/* Returns true iff a is later than b: */
static bool stateid_generation_after(stateid_t *a, stateid_t *b)
{
	return (s32)a->si_generation - (s32)b->si_generation > 0;
}

J
J. Bruce Fields 已提交
3229
static int check_stateid_generation(stateid_t *in, stateid_t *ref, bool has_session)
3230
{
A
Andy Adamson 已提交
3231 3232 3233 3234
	/*
	 * When sessions are used the stateid generation number is ignored
	 * when it is zero.
	 */
J
J. Bruce Fields 已提交
3235
	if (has_session && in->si_generation == 0)
3236 3237 3238 3239
		return nfs_ok;

	if (in->si_generation == ref->si_generation)
		return nfs_ok;
A
Andy Adamson 已提交
3240

3241
	/* If the client sends us a stateid from the future, it's buggy: */
3242
	if (stateid_generation_after(in, ref))
3243 3244
		return nfserr_bad_stateid;
	/*
3245 3246 3247 3248 3249 3250 3251 3252
	 * However, we could see a stateid from the past, even from a
	 * non-buggy client.  For example, if the client sends a lock
	 * while some IO is outstanding, the lock may bump si_generation
	 * while the IO is still in flight.  The client could avoid that
	 * situation by waiting for responses on all the IO requests,
	 * but better performance may result in retrying IO that
	 * receives an old_stateid error if requests are rarely
	 * reordered in flight:
3253
	 */
3254
	return nfserr_old_stateid;
3255 3256
}

3257 3258 3259 3260 3261
static int is_delegation_stateid(stateid_t *stateid)
{
	return stateid->si_fileid == 0;
}

J
J. Bruce Fields 已提交
3262
__be32 nfs4_validate_stateid(stateid_t *stateid, bool has_session)
3263
{
3264 3265 3266
	struct nfs4_stid *s;
	struct nfs4_ol_stateid *ols;
	__be32 status;
3267 3268

	if (STALE_STATEID(stateid))
3269
		return nfserr_stale_stateid;
3270

3271 3272 3273 3274
	s = find_stateid(stateid);
	if (!s)
		 return nfserr_stale_stateid;
	status = check_stateid_generation(stateid, &s->sc_stateid, has_session);
3275
	if (status)
3276 3277 3278 3279 3280 3281 3282 3283
		return status;
	if (!(s->sc_type & (NFS4_OPEN_STID | NFS4_LOCK_STID)))
		return nfs_ok;
	ols = openlockstateid(s);
	if (ols->st_stateowner->so_is_open_owner
	    && !openowner(ols->st_stateowner)->oo_confirmed)
		return nfserr_bad_stateid;
	return nfs_ok;
3284 3285
}

L
Linus Torvalds 已提交
3286 3287 3288
/*
* Checks for stateid operations
*/
3289
__be32
3290 3291
nfs4_preprocess_stateid_op(struct nfsd4_compound_state *cstate,
			   stateid_t *stateid, int flags, struct file **filpp)
L
Linus Torvalds 已提交
3292
{
3293
	struct nfs4_stid *s;
3294
	struct nfs4_ol_stateid *stp = NULL;
L
Linus Torvalds 已提交
3295
	struct nfs4_delegation *dp = NULL;
3296
	struct svc_fh *current_fh = &cstate->current_fh;
L
Linus Torvalds 已提交
3297
	struct inode *ino = current_fh->fh_dentry->d_inode;
3298
	__be32 status;
L
Linus Torvalds 已提交
3299 3300 3301 3302

	if (filpp)
		*filpp = NULL;

3303
	if (grace_disallows_io(ino))
L
Linus Torvalds 已提交
3304 3305 3306 3307 3308 3309 3310 3311 3312
		return nfserr_grace;

	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
		return check_special_stateids(current_fh, stateid, flags);

	status = nfserr_stale_stateid;
	if (STALE_STATEID(stateid)) 
		goto out;

3313 3314 3315 3316 3317
	/*
	 * We assume that any stateid that has the current boot time,
	 * but that we can't find, is expired:
	 */
	status = nfserr_expired;
3318 3319 3320 3321 3322 3323 3324 3325
	s = find_stateid(stateid);
	if (!s)
		goto out;
	status = check_stateid_generation(stateid, &s->sc_stateid, nfsd4_has_session(cstate));
	if (status)
		goto out;
	if (s->sc_type == NFS4_DELEG_STID) {
		dp = delegstateid(s);
3326 3327 3328 3329
		status = nfs4_check_delegmode(dp, flags);
		if (status)
			goto out;
		renew_client(dp->dl_client);
3330
		if (filpp) {
3331
			*filpp = dp->dl_file->fi_deleg_file;
3332 3333
			BUG_ON(!*filpp);
		}
L
Linus Torvalds 已提交
3334
	} else { /* open or lock stateid */
3335
		stp = openlockstateid(s);
3336
		status = nfserr_bad_stateid;
3337
		if (nfs4_check_fh(current_fh, stp))
L
Linus Torvalds 已提交
3338
			goto out;
3339 3340
		if (stp->st_stateowner->so_is_open_owner
		    && !openowner(stp->st_stateowner)->oo_confirmed)
L
Linus Torvalds 已提交
3341
			goto out;
3342 3343
		status = nfs4_check_openmode(stp, flags);
		if (status)
L
Linus Torvalds 已提交
3344 3345
			goto out;
		renew_client(stp->st_stateowner->so_client);
3346 3347 3348 3349 3350 3351
		if (filpp) {
			if (flags & RD_STATE)
				*filpp = find_readable_file(stp->st_file);
			else
				*filpp = find_writeable_file(stp->st_file);
		}
L
Linus Torvalds 已提交
3352 3353 3354 3355 3356 3357
	}
	status = nfs_ok;
out:
	return status;
}

3358 3359 3360
static __be32
nfsd4_free_delegation_stateid(stateid_t *stateid)
{
3361
	struct nfs4_delegation *dp = find_deleg_stateid(stateid);
3362 3363
	if (dp)
		return nfserr_locks_held;
3364

3365 3366 3367 3368
	return nfserr_bad_stateid;
}

static __be32
3369
nfsd4_free_lock_stateid(struct nfs4_ol_stateid *stp)
3370
{
3371
	if (check_for_locks(stp->st_file, lockowner(stp->st_stateowner)))
3372 3373 3374 3375 3376
		return nfserr_locks_held;
	release_lock_stateid(stp);
	return nfs_ok;
}

3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387
/*
 * Test if the stateid is valid
 */
__be32
nfsd4_test_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		   struct nfsd4_test_stateid *test_stateid)
{
	test_stateid->ts_has_session = nfsd4_has_session(cstate);
	return nfs_ok;
}

3388 3389 3390 3391 3392 3393 3394 3395
/*
 * Free a state id
 */
__be32
nfsd4_free_stateid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		   struct nfsd4_free_stateid *free_stateid)
{
	stateid_t *stateid = &free_stateid->fr_stateid;
3396
	struct nfs4_ol_stateid *stp;
3397 3398 3399 3400 3401 3402 3403 3404
	__be32 ret;

	nfs4_lock_state();
	if (is_delegation_stateid(stateid)) {
		ret = nfsd4_free_delegation_stateid(stateid);
		goto out;
	}

3405
	stp = find_ol_stateid(stateid);
3406 3407 3408 3409
	if (!stp) {
		ret = nfserr_bad_stateid;
		goto out;
	}
3410
	ret = check_stateid_generation(stateid, &stp->st_stid.sc_stateid, 1);
3411 3412
	if (ret)
		goto out;
3413

3414
	if (stp->st_stid.sc_type == NFS4_OPEN_STID) {
3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426
		ret = nfserr_locks_held;
		goto out;
	} else {
		ret = nfsd4_free_lock_stateid(stp);
		goto out;
	}

out:
	nfs4_unlock_state();
	return ret;
}

3427 3428 3429 3430 3431 3432
static inline int
setlkflg (int type)
{
	return (type == NFS4_READW_LT || type == NFS4_READ_LT) ?
		RD_STATE : WR_STATE;
}
L
Linus Torvalds 已提交
3433

3434 3435 3436 3437 3438 3439 3440 3441 3442
static __be32 nfs4_nospecial_stateid_checks(stateid_t *stateid)
{
	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
		return nfserr_bad_stateid;
	if (STALE_STATEID(stateid))
		return nfserr_stale_stateid;
	return nfs_ok;
}

3443
static __be32 nfs4_seqid_op_checks(struct nfsd4_compound_state *cstate, stateid_t *stateid, u32 seqid, struct nfs4_ol_stateid *stp)
3444 3445 3446 3447 3448 3449 3450 3451 3452 3453
{
	struct svc_fh *current_fh = &cstate->current_fh;
	struct nfs4_stateowner *sop = stp->st_stateowner;
	__be32 status;

	if (nfs4_check_fh(current_fh, stp))
		return nfserr_bad_stateid;
	status = nfsd4_check_seqid(cstate, sop, seqid);
	if (status)
		return status;
3454
	return check_stateid_generation(stateid, &stp->st_stid.sc_stateid, nfsd4_has_session(cstate));
3455 3456
}

L
Linus Torvalds 已提交
3457 3458 3459
/* 
 * Checks for sequence id mutating operations. 
 */
3460
static __be32
3461
nfs4_preprocess_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid,
3462
			 stateid_t *stateid, char typemask,
3463
			 struct nfs4_ol_stateid **stpp)
L
Linus Torvalds 已提交
3464
{
3465
	__be32 status;
L
Linus Torvalds 已提交
3466

3467 3468
	dprintk("NFSD: %s: seqid=%d stateid = " STATEID_FMT "\n", __func__,
		seqid, STATEID_VAL(stateid));
3469

L
Linus Torvalds 已提交
3470
	*stpp = NULL;
3471 3472 3473
	status = nfs4_nospecial_stateid_checks(stateid);
	if (status)
		return status;
3474
	*stpp = find_ol_stateid_by_type(stateid, typemask);
3475 3476
	if (*stpp == NULL)
		return nfserr_expired;
3477 3478
	cstate->replay_owner = (*stpp)->st_stateowner;
	renew_client((*stpp)->st_stateowner->so_client);
L
Linus Torvalds 已提交
3479

3480 3481
	return nfs4_seqid_op_checks(cstate, stateid, seqid, *stpp);
}
3482

3483
static __be32 nfs4_preprocess_confirmed_seqid_op(struct nfsd4_compound_state *cstate, u32 seqid, stateid_t *stateid, struct nfs4_ol_stateid **stpp)
3484 3485 3486
{
	__be32 status;
	struct nfs4_openowner *oo;
L
Linus Torvalds 已提交
3487

3488
	status = nfs4_preprocess_seqid_op(cstate, seqid, stateid,
3489
						NFS4_OPEN_STID, stpp);
3490 3491
	if (status)
		return status;
3492 3493
	oo = openowner((*stpp)->st_stateowner);
	if (!oo->oo_confirmed)
3494 3495
		return nfserr_bad_stateid;
	return nfs_ok;
L
Linus Torvalds 已提交
3496 3497
}

3498
__be32
3499
nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3500
		   struct nfsd4_open_confirm *oc)
L
Linus Torvalds 已提交
3501
{
3502
	__be32 status;
3503
	struct nfs4_openowner *oo;
3504
	struct nfs4_ol_stateid *stp;
L
Linus Torvalds 已提交
3505 3506

	dprintk("NFSD: nfsd4_open_confirm on file %.*s\n",
3507 3508
			(int)cstate->current_fh.fh_dentry->d_name.len,
			cstate->current_fh.fh_dentry->d_name.name);
L
Linus Torvalds 已提交
3509

3510
	status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0);
3511 3512
	if (status)
		return status;
L
Linus Torvalds 已提交
3513 3514 3515

	nfs4_lock_state();

3516
	status = nfs4_preprocess_seqid_op(cstate,
3517
					oc->oc_seqid, &oc->oc_req_stateid,
3518
					NFS4_OPEN_STID, &stp);
3519
	if (status)
3520
		goto out;
3521
	oo = openowner(stp->st_stateowner);
3522
	status = nfserr_bad_stateid;
3523
	if (oo->oo_confirmed)
3524
		goto out;
3525
	oo->oo_confirmed = 1;
3526 3527
	update_stateid(&stp->st_stid.sc_stateid);
	memcpy(&oc->oc_resp_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
3528
	dprintk("NFSD: %s: success, seqid=%d stateid=" STATEID_FMT "\n",
3529
		__func__, oc->oc_seqid, STATEID_VAL(&stp->st_stid.sc_stateid));
3530

3531
	nfsd4_create_clid_dir(oo->oo_owner.so_client);
3532
	status = nfs_ok;
L
Linus Torvalds 已提交
3533
out:
3534 3535
	if (!cstate->replay_owner)
		nfs4_unlock_state();
L
Linus Torvalds 已提交
3536 3537 3538
	return status;
}

3539
static inline void nfs4_file_downgrade(struct nfs4_ol_stateid *stp, unsigned int to_access)
L
Linus Torvalds 已提交
3540 3541
{
	int i;
3542

L
Linus Torvalds 已提交
3543
	for (i = 1; i < 4; i++) {
3544 3545 3546 3547
		if (test_bit(i, &stp->st_access_bmap) && !(i & to_access)) {
			nfs4_file_put_access(stp->st_file, i);
			__clear_bit(i, &stp->st_access_bmap);
		}
L
Linus Torvalds 已提交
3548 3549 3550 3551 3552 3553 3554 3555 3556 3557 3558 3559 3560
	}
}

static void
reset_union_bmap_deny(unsigned long deny, unsigned long *bmap)
{
	int i;
	for (i = 0; i < 4; i++) {
		if ((i & deny) != i)
			__clear_bit(i, bmap);
	}
}

3561
__be32
3562 3563
nfsd4_open_downgrade(struct svc_rqst *rqstp,
		     struct nfsd4_compound_state *cstate,
3564
		     struct nfsd4_open_downgrade *od)
L
Linus Torvalds 已提交
3565
{
3566
	__be32 status;
3567
	struct nfs4_ol_stateid *stp;
L
Linus Torvalds 已提交
3568 3569

	dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", 
3570 3571
			(int)cstate->current_fh.fh_dentry->d_name.len,
			cstate->current_fh.fh_dentry->d_name.name);
L
Linus Torvalds 已提交
3572

A
Andy Adamson 已提交
3573
	if (!access_valid(od->od_share_access, cstate->minorversion)
3574
			|| !deny_valid(od->od_share_deny))
L
Linus Torvalds 已提交
3575 3576 3577
		return nfserr_inval;

	nfs4_lock_state();
3578 3579
	status = nfs4_preprocess_confirmed_seqid_op(cstate, od->od_seqid,
					&od->od_stateid, &stp);
3580
	if (status)
L
Linus Torvalds 已提交
3581 3582 3583 3584 3585 3586 3587 3588 3589 3590 3591 3592
		goto out; 
	status = nfserr_inval;
	if (!test_bit(od->od_share_access, &stp->st_access_bmap)) {
		dprintk("NFSD:access not a subset current bitmap: 0x%lx, input access=%08x\n",
			stp->st_access_bmap, od->od_share_access);
		goto out;
	}
	if (!test_bit(od->od_share_deny, &stp->st_deny_bmap)) {
		dprintk("NFSD:deny not a subset current bitmap: 0x%lx, input deny=%08x\n",
			stp->st_deny_bmap, od->od_share_deny);
		goto out;
	}
3593
	nfs4_file_downgrade(stp, od->od_share_access);
L
Linus Torvalds 已提交
3594 3595 3596

	reset_union_bmap_deny(od->od_share_deny, &stp->st_deny_bmap);

3597 3598
	update_stateid(&stp->st_stid.sc_stateid);
	memcpy(&od->od_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
L
Linus Torvalds 已提交
3599 3600
	status = nfs_ok;
out:
3601 3602
	if (!cstate->replay_owner)
		nfs4_unlock_state();
L
Linus Torvalds 已提交
3603 3604 3605 3606 3607 3608
	return status;
}

/*
 * nfs4_unlock_state() called after encode
 */
3609
__be32
3610
nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3611
	    struct nfsd4_close *close)
L
Linus Torvalds 已提交
3612
{
3613
	__be32 status;
3614
	struct nfs4_openowner *oo;
3615
	struct nfs4_ol_stateid *stp;
L
Linus Torvalds 已提交
3616 3617

	dprintk("NFSD: nfsd4_close on file %.*s\n", 
3618 3619
			(int)cstate->current_fh.fh_dentry->d_name.len,
			cstate->current_fh.fh_dentry->d_name.name);
L
Linus Torvalds 已提交
3620 3621 3622

	nfs4_lock_state();
	/* check close_lru for replay */
3623 3624
	status = nfs4_preprocess_confirmed_seqid_op(cstate, close->cl_seqid,
					&close->cl_stateid, &stp);
3625 3626 3627 3628 3629
	if (stp == NULL && status == nfserr_expired) {
		/*
		 * Also, we should make sure this isn't just the result of
		 * a replayed close:
		 */
3630
		oo = search_close_lru(close->cl_stateid.si_stateownerid);
3631
		/* It's not stale; let's assume it's expired: */
3632
		if (oo == NULL)
3633
			goto out;
3634 3635
		cstate->replay_owner = &oo->oo_owner;
		status = nfsd4_check_seqid(cstate, &oo->oo_owner, close->cl_seqid);
3636 3637 3638 3639
		if (status)
			goto out;
		status = nfserr_bad_seqid;
	}
3640
	if (status)
L
Linus Torvalds 已提交
3641
		goto out; 
3642
	oo = openowner(stp->st_stateowner);
L
Linus Torvalds 已提交
3643
	status = nfs_ok;
3644 3645
	update_stateid(&stp->st_stid.sc_stateid);
	memcpy(&close->cl_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
L
Linus Torvalds 已提交
3646

3647
	/* release_stateid() calls nfsd_close() if needed */
3648
	release_open_stateid(stp);
3649 3650 3651 3652 3653

	/* place unused nfs4_stateowners on so_close_lru list to be
	 * released by the laundromat service after the lease period
	 * to enable us to handle CLOSE replay
	 */
3654 3655
	if (list_empty(&oo->oo_owner.so_stateids))
		move_to_close_lru(oo);
L
Linus Torvalds 已提交
3656
out:
3657 3658
	if (!cstate->replay_owner)
		nfs4_unlock_state();
L
Linus Torvalds 已提交
3659 3660 3661
	return status;
}

3662
__be32
3663 3664
nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
		  struct nfsd4_delegreturn *dr)
L
Linus Torvalds 已提交
3665
{
3666 3667 3668
	struct nfs4_delegation *dp;
	stateid_t *stateid = &dr->dr_stateid;
	struct inode *inode;
3669
	__be32 status;
L
Linus Torvalds 已提交
3670

3671
	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
3672 3673
		return status;
	inode = cstate->current_fh.fh_dentry->d_inode;
L
Linus Torvalds 已提交
3674 3675

	nfs4_lock_state();
3676 3677 3678 3679 3680 3681
	status = nfserr_bad_stateid;
	if (ZERO_STATEID(stateid) || ONE_STATEID(stateid))
		goto out;
	status = nfserr_stale_stateid;
	if (STALE_STATEID(stateid))
		goto out;
3682
	status = nfserr_bad_stateid;
3683 3684
	if (!is_delegation_stateid(stateid))
		goto out;
3685
	status = nfserr_expired;
3686
	dp = find_deleg_stateid(stateid);
3687
	if (!dp)
3688
		goto out;
3689
	status = check_stateid_generation(stateid, &dp->dl_stid.sc_stateid, nfsd4_has_session(cstate));
3690 3691 3692 3693 3694
	if (status)
		goto out;
	renew_client(dp->dl_client);

	unhash_delegation(dp);
L
Linus Torvalds 已提交
3695
out:
3696 3697
	nfs4_unlock_state();

L
Linus Torvalds 已提交
3698 3699 3700 3701 3702 3703 3704 3705 3706 3707 3708 3709
	return status;
}


/* 
 * Lock owner state (byte-range locks)
 */
#define LOFF_OVERFLOW(start, len)      ((u64)(len) > ~(u64)(start))
#define LOCK_HASH_BITS              8
#define LOCK_HASH_SIZE             (1 << LOCK_HASH_BITS)
#define LOCK_HASH_MASK             (LOCK_HASH_SIZE - 1)

B
Benny Halevy 已提交
3710 3711 3712 3713 3714 3715 3716 3717 3718 3719 3720 3721 3722 3723 3724 3725 3726 3727 3728 3729
static inline u64
end_offset(u64 start, u64 len)
{
	u64 end;

	end = start + len;
	return end >= start ? end: NFS4_MAX_UINT64;
}

/* last octet in a range */
static inline u64
last_byte_offset(u64 start, u64 len)
{
	u64 end;

	BUG_ON(!len);
	end = start + len;
	return end > start ? end - 1: NFS4_MAX_UINT64;
}

3730 3731 3732 3733
static unsigned int lockownerid_hashval(u32 id)
{
	return id & LOCK_HASH_MASK;
}
L
Linus Torvalds 已提交
3734 3735 3736 3737 3738 3739 3740 3741 3742 3743 3744 3745 3746 3747 3748 3749 3750 3751 3752 3753 3754 3755 3756 3757 3758 3759 3760 3761 3762 3763

static inline unsigned int
lock_ownerstr_hashval(struct inode *inode, u32 cl_id,
		struct xdr_netobj *ownername)
{
	return (file_hashval(inode) + cl_id
			+ opaque_hashval(ownername->data, ownername->len))
		& LOCK_HASH_MASK;
}

static struct list_head lock_ownerid_hashtbl[LOCK_HASH_SIZE];
static struct list_head	lock_ownerstr_hashtbl[LOCK_HASH_SIZE];

/*
 * TODO: Linux file offsets are _signed_ 64-bit quantities, which means that
 * we can't properly handle lock requests that go beyond the (2^63 - 1)-th
 * byte, because of sign extension problems.  Since NFSv4 calls for 64-bit
 * locking, this prevents us from being completely protocol-compliant.  The
 * real solution to this problem is to start using unsigned file offsets in
 * the VFS, but this is a very deep change!
 */
static inline void
nfs4_transform_lock_offset(struct file_lock *lock)
{
	if (lock->fl_start < 0)
		lock->fl_start = OFFSET_MAX;
	if (lock->fl_end < 0)
		lock->fl_end = OFFSET_MAX;
}

3764 3765
/* Hack!: For now, we're defining this just so we can use a pointer to it
 * as a unique cookie to identify our (NFSv4's) posix locks. */
3766
static const struct lock_manager_operations nfsd_posix_mng_ops  = {
3767
};
L
Linus Torvalds 已提交
3768 3769 3770 3771

static inline void
nfs4_set_lock_denied(struct file_lock *fl, struct nfsd4_lock_denied *deny)
{
3772
	struct nfs4_lockowner *lo;
L
Linus Torvalds 已提交
3773

3774
	if (fl->fl_lmops == &nfsd_posix_mng_ops) {
3775 3776 3777
		lo = (struct nfs4_lockowner *) fl->fl_owner;
		deny->ld_owner.data = kmemdup(lo->lo_owner.so_owner.data,
					lo->lo_owner.so_owner.len, GFP_KERNEL);
3778 3779 3780
		if (!deny->ld_owner.data)
			/* We just don't care that much */
			goto nevermind;
3781 3782
		deny->ld_owner.len = lo->lo_owner.so_owner.len;
		deny->ld_clientid = lo->lo_owner.so_client->cl_clientid;
3783
	} else {
3784 3785 3786
nevermind:
		deny->ld_owner.len = 0;
		deny->ld_owner.data = NULL;
3787 3788
		deny->ld_clientid.cl_boot = 0;
		deny->ld_clientid.cl_id = 0;
L
Linus Torvalds 已提交
3789 3790
	}
	deny->ld_start = fl->fl_start;
B
Benny Halevy 已提交
3791 3792
	deny->ld_length = NFS4_MAX_UINT64;
	if (fl->fl_end != NFS4_MAX_UINT64)
L
Linus Torvalds 已提交
3793 3794 3795 3796 3797 3798
		deny->ld_length = fl->fl_end - fl->fl_start + 1;        
	deny->ld_type = NFS4_READ_LT;
	if (fl->fl_type != F_RDLCK)
		deny->ld_type = NFS4_WRITE_LT;
}

3799 3800
static struct nfs4_lockowner *
find_lockowner_str(struct inode *inode, clientid_t *clid,
L
Linus Torvalds 已提交
3801 3802 3803 3804 3805 3806
		struct xdr_netobj *owner)
{
	unsigned int hashval = lock_ownerstr_hashval(inode, clid->cl_id, owner);
	struct nfs4_stateowner *op;

	list_for_each_entry(op, &lock_ownerstr_hashtbl[hashval], so_strhash) {
3807
		if (same_owner_str(op, owner, clid))
3808
			return lockowner(op);
L
Linus Torvalds 已提交
3809 3810 3811 3812
	}
	return NULL;
}

3813
static void hash_lockowner(struct nfs4_lockowner *lo, unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp)
3814 3815 3816
{
	unsigned int idhashval;

3817 3818 3819 3820
	idhashval = lockownerid_hashval(lo->lo_owner.so_id);
	list_add(&lo->lo_owner.so_idhash, &lock_ownerid_hashtbl[idhashval]);
	list_add(&lo->lo_owner.so_strhash, &lock_ownerstr_hashtbl[strhashval]);
	list_add(&lo->lo_perstateid, &open_stp->st_lockowners);
3821 3822
}

L
Linus Torvalds 已提交
3823 3824 3825
/*
 * Alloc a lock owner structure.
 * Called in nfsd4_lock - therefore, OPEN and OPEN_CONFIRM (if needed) has 
L
Lucas De Marchi 已提交
3826
 * occurred. 
L
Linus Torvalds 已提交
3827 3828 3829 3830
 *
 * strhashval = lock_ownerstr_hashval 
 */

3831
static struct nfs4_lockowner *
3832
alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfs4_ol_stateid *open_stp, struct nfsd4_lock *lock) {
3833
	struct nfs4_lockowner *lo;
L
Linus Torvalds 已提交
3834

3835 3836
	lo = alloc_stateowner(lockowner_slab, &lock->lk_new_owner, clp);
	if (!lo)
L
Linus Torvalds 已提交
3837
		return NULL;
3838 3839
	INIT_LIST_HEAD(&lo->lo_owner.so_stateids);
	lo->lo_owner.so_is_open_owner = 0;
3840 3841
	/* It is the openowner seqid that will be incremented in encode in the
	 * case of new lockowners; so increment the lock seqid manually: */
3842 3843 3844
	lo->lo_owner.so_seqid = lock->lk_new_lock_seqid + 1;
	hash_lockowner(lo, strhashval, clp, open_stp);
	return lo;
L
Linus Torvalds 已提交
3845 3846
}

3847 3848
static struct nfs4_ol_stateid *
alloc_init_lock_stateid(struct nfs4_lockowner *lo, struct nfs4_file *fp, struct nfs4_ol_stateid *open_stp)
L
Linus Torvalds 已提交
3849
{
3850
	struct nfs4_ol_stateid *stp;
L
Linus Torvalds 已提交
3851

N
NeilBrown 已提交
3852 3853
	stp = nfs4_alloc_stateid();
	if (stp == NULL)
L
Linus Torvalds 已提交
3854
		goto out;
3855
	list_add(&stp->st_perfile, &fp->fi_stateids);
3856 3857
	list_add(&stp->st_perstateowner, &lo->lo_owner.so_stateids);
	stp->st_stateowner = &lo->lo_owner;
3858
	stp->st_stid.sc_type = NFS4_LOCK_STID;
3859
	get_nfs4_file(fp);
L
Linus Torvalds 已提交
3860
	stp->st_file = fp;
3861 3862 3863
	stp->st_stid.sc_stateid.si_boot = boot_time;
	stp->st_stid.sc_stateid.si_stateownerid = lo->lo_owner.so_id;
	stp->st_stid.sc_stateid.si_fileid = fp->fi_id;
3864
	/* note will be incremented before first return to client: */
3865
	stp->st_stid.sc_stateid.si_generation = 0;
3866
	hash_stid(&stp->st_stid);
J
J. Bruce Fields 已提交
3867
	stp->st_access_bmap = 0;
L
Linus Torvalds 已提交
3868
	stp->st_deny_bmap = open_stp->st_deny_bmap;
3869
	stp->st_openstp = open_stp;
L
Linus Torvalds 已提交
3870 3871 3872 3873 3874

out:
	return stp;
}

3875
static int
L
Linus Torvalds 已提交
3876 3877
check_lock_length(u64 offset, u64 length)
{
B
Benny Halevy 已提交
3878
	return ((length == 0)  || ((length != NFS4_MAX_UINT64) &&
L
Linus Torvalds 已提交
3879 3880 3881
	     LOFF_OVERFLOW(offset, length)));
}

3882
static void get_lock_access(struct nfs4_ol_stateid *lock_stp, u32 access)
J
J. Bruce Fields 已提交
3883 3884 3885 3886 3887 3888 3889 3890 3891 3892
{
	struct nfs4_file *fp = lock_stp->st_file;
	int oflag = nfs4_access_to_omode(access);

	if (test_bit(access, &lock_stp->st_access_bmap))
		return;
	nfs4_file_get_access(fp, oflag);
	__set_bit(access, &lock_stp->st_access_bmap);
}

L
Linus Torvalds 已提交
3893 3894 3895
/*
 *  LOCK operation 
 */
3896
__be32
3897
nfsd4_lock(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
3898
	   struct nfsd4_lock *lock)
L
Linus Torvalds 已提交
3899
{
3900 3901
	struct nfs4_openowner *open_sop = NULL;
	struct nfs4_lockowner *lock_sop = NULL;
3902
	struct nfs4_ol_stateid *lock_stp;
3903 3904
	struct nfs4_file *fp;
	struct file *filp = NULL;
L
Linus Torvalds 已提交
3905
	struct file_lock file_lock;
3906
	struct file_lock conflock;
3907
	__be32 status = 0;
L
Linus Torvalds 已提交
3908
	unsigned int strhashval;
3909
	int lkflg;
3910
	int err;
L
Linus Torvalds 已提交
3911 3912 3913 3914 3915 3916 3917 3918

	dprintk("NFSD: nfsd4_lock: start=%Ld length=%Ld\n",
		(long long) lock->lk_offset,
		(long long) lock->lk_length);

	if (check_lock_length(lock->lk_offset, lock->lk_length))
		 return nfserr_inval;

3919
	if ((status = fh_verify(rqstp, &cstate->current_fh,
M
Miklos Szeredi 已提交
3920
				S_IFREG, NFSD_MAY_LOCK))) {
A
Andy Adamson 已提交
3921 3922 3923 3924
		dprintk("NFSD: nfsd4_lock: permission denied!\n");
		return status;
	}

L
Linus Torvalds 已提交
3925 3926 3927
	nfs4_lock_state();

	if (lock->lk_is_new) {
N
NeilBrown 已提交
3928 3929 3930 3931 3932
		/*
		 * Client indicates that this is a new lockowner.
		 * Use open owner and open stateid to create lock owner and
		 * lock stateid.
		 */
3933
		struct nfs4_ol_stateid *open_stp = NULL;
L
Linus Torvalds 已提交
3934 3935
		
		status = nfserr_stale_clientid;
A
Andy Adamson 已提交
3936 3937
		if (!nfsd4_has_session(cstate) &&
		    STALE_CLIENTID(&lock->lk_new_clientid))
L
Linus Torvalds 已提交
3938 3939 3940
			goto out;

		/* validate and update open stateid and open seqid */
3941
		status = nfs4_preprocess_confirmed_seqid_op(cstate,
L
Linus Torvalds 已提交
3942 3943
				        lock->lk_new_open_seqid,
		                        &lock->lk_new_open_stateid,
3944
					&open_stp);
3945
		if (status)
L
Linus Torvalds 已提交
3946
			goto out;
3947
		open_sop = openowner(open_stp->st_stateowner);
3948 3949
		status = nfserr_bad_stateid;
		if (!nfsd4_has_session(cstate) &&
3950
			!same_clid(&open_sop->oo_owner.so_client->cl_clientid,
3951 3952
						&lock->v.new.clientid))
			goto out;
L
Linus Torvalds 已提交
3953 3954
		/* create lockowner and lock stateid */
		fp = open_stp->st_file;
3955 3956
		strhashval = lock_ownerstr_hashval(fp->fi_inode,
				open_sop->oo_owner.so_client->cl_clientid.cl_id,
L
Linus Torvalds 已提交
3957
				&lock->v.new.owner);
3958 3959 3960
		/* XXX: Do we need to check for duplicate stateowners on
		 * the same file, or should they just be allowed (and
		 * create new stateids)? */
3961
		status = nfserr_jukebox;
3962
		lock_sop = alloc_init_lock_stateowner(strhashval,
3963
				open_sop->oo_owner.so_client, open_stp, lock);
3964
		if (lock_sop == NULL)
L
Linus Torvalds 已提交
3965
			goto out;
3966
		lock_stp = alloc_init_lock_stateid(lock_sop, fp, open_stp);
3967
		if (lock_stp == NULL)
L
Linus Torvalds 已提交
3968 3969 3970
			goto out;
	} else {
		/* lock (lock owner + lock stateid) already exists */
3971
		status = nfs4_preprocess_seqid_op(cstate,
3972 3973
				       lock->lk_old_lock_seqid,
				       &lock->lk_old_lock_stateid,
3974
				       NFS4_LOCK_STID, &lock_stp);
L
Linus Torvalds 已提交
3975 3976
		if (status)
			goto out;
3977
		lock_sop = lockowner(lock_stp->st_stateowner);
3978
		fp = lock_stp->st_file;
L
Linus Torvalds 已提交
3979
	}
3980
	/* lock_sop and lock_stp have been created or found */
L
Linus Torvalds 已提交
3981

3982 3983 3984 3985 3986
	lkflg = setlkflg(lock->lk_type);
	status = nfs4_check_openmode(lock_stp, lkflg);
	if (status)
		goto out;

3987
	status = nfserr_grace;
3988
	if (locks_in_grace() && !lock->lk_reclaim)
3989 3990
		goto out;
	status = nfserr_no_grace;
3991
	if (!locks_in_grace() && lock->lk_reclaim)
3992 3993
		goto out;

L
Linus Torvalds 已提交
3994 3995 3996 3997
	locks_init_lock(&file_lock);
	switch (lock->lk_type) {
		case NFS4_READ_LT:
		case NFS4_READW_LT:
J
J. Bruce Fields 已提交
3998 3999 4000
			filp = find_readable_file(lock_stp->st_file);
			if (filp)
				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_READ);
L
Linus Torvalds 已提交
4001
			file_lock.fl_type = F_RDLCK;
4002
			break;
L
Linus Torvalds 已提交
4003 4004
		case NFS4_WRITE_LT:
		case NFS4_WRITEW_LT:
J
J. Bruce Fields 已提交
4005 4006 4007
			filp = find_writeable_file(lock_stp->st_file);
			if (filp)
				get_lock_access(lock_stp, NFS4_SHARE_ACCESS_WRITE);
L
Linus Torvalds 已提交
4008
			file_lock.fl_type = F_WRLCK;
4009
			break;
L
Linus Torvalds 已提交
4010 4011 4012 4013
		default:
			status = nfserr_inval;
		goto out;
	}
4014 4015 4016 4017
	if (!filp) {
		status = nfserr_openmode;
		goto out;
	}
4018
	file_lock.fl_owner = (fl_owner_t)lock_sop;
L
Linus Torvalds 已提交
4019 4020 4021
	file_lock.fl_pid = current->tgid;
	file_lock.fl_file = filp;
	file_lock.fl_flags = FL_POSIX;
4022
	file_lock.fl_lmops = &nfsd_posix_mng_ops;
L
Linus Torvalds 已提交
4023 4024

	file_lock.fl_start = lock->lk_offset;
B
Benny Halevy 已提交
4025
	file_lock.fl_end = last_byte_offset(lock->lk_offset, lock->lk_length);
L
Linus Torvalds 已提交
4026 4027 4028 4029 4030 4031 4032
	nfs4_transform_lock_offset(&file_lock);

	/*
	* Try to lock the file in the VFS.
	* Note: locks.c uses the BKL to protect the inode's lock list.
	*/

4033
	err = vfs_lock_file(filp, F_SETLK, &file_lock, &conflock);
4034
	switch (-err) {
L
Linus Torvalds 已提交
4035
	case 0: /* success! */
4036 4037
		update_stateid(&lock_stp->st_stid.sc_stateid);
		memcpy(&lock->lk_resp_stateid, &lock_stp->st_stid.sc_stateid, 
L
Linus Torvalds 已提交
4038
				sizeof(stateid_t));
4039
		status = 0;
4040 4041 4042 4043 4044 4045
		break;
	case (EAGAIN):		/* conflock holds conflicting lock */
		status = nfserr_denied;
		dprintk("NFSD: nfsd4_lock: conflicting lock found!\n");
		nfs4_set_lock_denied(&conflock, &lock->lk_denied);
		break;
L
Linus Torvalds 已提交
4046 4047
	case (EDEADLK):
		status = nfserr_deadlock;
4048
		break;
4049
	default:
4050
		dprintk("NFSD: nfsd4_lock: vfs_lock_file() failed! status %d\n",err);
4051
		status = nfserrno(err);
4052
		break;
L
Linus Torvalds 已提交
4053 4054
	}
out:
4055
	if (status && lock->lk_is_new && lock_sop)
4056
		release_lockowner(lock_sop);
4057 4058
	if (!cstate->replay_owner)
		nfs4_unlock_state();
L
Linus Torvalds 已提交
4059 4060 4061
	return status;
}

4062 4063 4064 4065 4066 4067 4068 4069 4070 4071 4072 4073 4074 4075 4076 4077 4078 4079 4080
/*
 * The NFSv4 spec allows a client to do a LOCKT without holding an OPEN,
 * so we do a temporary open here just to get an open file to pass to
 * vfs_test_lock.  (Arguably perhaps test_lock should be done with an
 * inode operation.)
 */
static int nfsd_test_lock(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file_lock *lock)
{
	struct file *file;
	int err;

	err = nfsd_open(rqstp, fhp, S_IFREG, NFSD_MAY_READ, &file);
	if (err)
		return err;
	err = vfs_test_lock(file, lock);
	nfsd_close(file);
	return err;
}

L
Linus Torvalds 已提交
4081 4082 4083
/*
 * LOCKT operation
 */
4084
__be32
4085 4086
nfsd4_lockt(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
	    struct nfsd4_lockt *lockt)
L
Linus Torvalds 已提交
4087 4088 4089
{
	struct inode *inode;
	struct file_lock file_lock;
4090
	struct nfs4_lockowner *lo;
4091
	int error;
4092
	__be32 status;
L
Linus Torvalds 已提交
4093

4094
	if (locks_in_grace())
L
Linus Torvalds 已提交
4095 4096 4097 4098 4099 4100 4101 4102
		return nfserr_grace;

	if (check_lock_length(lockt->lt_offset, lockt->lt_length))
		 return nfserr_inval;

	nfs4_lock_state();

	status = nfserr_stale_clientid;
A
Andy Adamson 已提交
4103
	if (!nfsd4_has_session(cstate) && STALE_CLIENTID(&lockt->lt_clientid))
L
Linus Torvalds 已提交
4104 4105
		goto out;

4106
	if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0)))
L
Linus Torvalds 已提交
4107 4108
		goto out;

4109
	inode = cstate->current_fh.fh_dentry->d_inode;
L
Linus Torvalds 已提交
4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120
	locks_init_lock(&file_lock);
	switch (lockt->lt_type) {
		case NFS4_READ_LT:
		case NFS4_READW_LT:
			file_lock.fl_type = F_RDLCK;
		break;
		case NFS4_WRITE_LT:
		case NFS4_WRITEW_LT:
			file_lock.fl_type = F_WRLCK;
		break;
		default:
4121
			dprintk("NFSD: nfs4_lockt: bad lock type!\n");
L
Linus Torvalds 已提交
4122 4123 4124 4125
			status = nfserr_inval;
		goto out;
	}

4126 4127 4128
	lo = find_lockowner_str(inode, &lockt->lt_clientid, &lockt->lt_owner);
	if (lo)
		file_lock.fl_owner = (fl_owner_t)lo;
L
Linus Torvalds 已提交
4129 4130 4131 4132
	file_lock.fl_pid = current->tgid;
	file_lock.fl_flags = FL_POSIX;

	file_lock.fl_start = lockt->lt_offset;
B
Benny Halevy 已提交
4133
	file_lock.fl_end = last_byte_offset(lockt->lt_offset, lockt->lt_length);
L
Linus Torvalds 已提交
4134 4135 4136 4137

	nfs4_transform_lock_offset(&file_lock);

	status = nfs_ok;
4138
	error = nfsd_test_lock(rqstp, &cstate->current_fh, &file_lock);
4139 4140 4141 4142
	if (error) {
		status = nfserrno(error);
		goto out;
	}
4143
	if (file_lock.fl_type != F_UNLCK) {
L
Linus Torvalds 已提交
4144
		status = nfserr_denied;
4145
		nfs4_set_lock_denied(&file_lock, &lockt->lt_denied);
L
Linus Torvalds 已提交
4146 4147 4148 4149 4150 4151
	}
out:
	nfs4_unlock_state();
	return status;
}

4152
__be32
4153
nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
4154
	    struct nfsd4_locku *locku)
L
Linus Torvalds 已提交
4155
{
4156
	struct nfs4_ol_stateid *stp;
L
Linus Torvalds 已提交
4157 4158
	struct file *filp = NULL;
	struct file_lock file_lock;
4159
	__be32 status;
4160
	int err;
L
Linus Torvalds 已提交
4161 4162 4163 4164 4165 4166 4167 4168 4169 4170
						        
	dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
		(long long) locku->lu_offset,
		(long long) locku->lu_length);

	if (check_lock_length(locku->lu_offset, locku->lu_length))
		 return nfserr_inval;

	nfs4_lock_state();
									        
4171
	status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
4172
					&locku->lu_stateid, NFS4_LOCK_STID, &stp);
4173
	if (status)
L
Linus Torvalds 已提交
4174
		goto out;
4175 4176 4177 4178 4179
	filp = find_any_file(stp->st_file);
	if (!filp) {
		status = nfserr_lock_range;
		goto out;
	}
L
Linus Torvalds 已提交
4180 4181 4182
	BUG_ON(!filp);
	locks_init_lock(&file_lock);
	file_lock.fl_type = F_UNLCK;
4183
	file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
L
Linus Torvalds 已提交
4184 4185 4186
	file_lock.fl_pid = current->tgid;
	file_lock.fl_file = filp;
	file_lock.fl_flags = FL_POSIX; 
4187
	file_lock.fl_lmops = &nfsd_posix_mng_ops;
L
Linus Torvalds 已提交
4188 4189
	file_lock.fl_start = locku->lu_offset;

B
Benny Halevy 已提交
4190
	file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length);
L
Linus Torvalds 已提交
4191 4192 4193 4194 4195
	nfs4_transform_lock_offset(&file_lock);

	/*
	*  Try to unlock the file in the VFS.
	*/
4196
	err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL);
4197
	if (err) {
4198
		dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
L
Linus Torvalds 已提交
4199 4200 4201 4202 4203
		goto out_nfserr;
	}
	/*
	* OK, unlock succeeded; the only thing left to do is update the stateid.
	*/
4204 4205
	update_stateid(&stp->st_stid.sc_stateid);
	memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));
L
Linus Torvalds 已提交
4206 4207 4208 4209 4210 4211

out:
	nfs4_unlock_state();
	return status;

out_nfserr:
4212
	status = nfserrno(err);
L
Linus Torvalds 已提交
4213 4214 4215 4216 4217 4218 4219 4220 4221
	goto out;
}

/*
 * returns
 * 	1: locks held by lockowner
 * 	0: no locks held by lockowner
 */
static int
4222
check_for_locks(struct nfs4_file *filp, struct nfs4_lockowner *lowner)
L
Linus Torvalds 已提交
4223 4224
{
	struct file_lock **flpp;
4225
	struct inode *inode = filp->fi_inode;
L
Linus Torvalds 已提交
4226 4227
	int status = 0;

4228
	lock_flocks();
L
Linus Torvalds 已提交
4229
	for (flpp = &inode->i_flock; *flpp != NULL; flpp = &(*flpp)->fl_next) {
4230
		if ((*flpp)->fl_owner == (fl_owner_t)lowner) {
L
Linus Torvalds 已提交
4231 4232
			status = 1;
			goto out;
4233
		}
L
Linus Torvalds 已提交
4234 4235
	}
out:
4236
	unlock_flocks();
L
Linus Torvalds 已提交
4237 4238 4239
	return status;
}

4240
__be32
4241 4242 4243
nfsd4_release_lockowner(struct svc_rqst *rqstp,
			struct nfsd4_compound_state *cstate,
			struct nfsd4_release_lockowner *rlockowner)
L
Linus Torvalds 已提交
4244 4245
{
	clientid_t *clid = &rlockowner->rl_clientid;
4246
	struct nfs4_stateowner *sop;
4247
	struct nfs4_lockowner *lo;
4248
	struct nfs4_ol_stateid *stp;
L
Linus Torvalds 已提交
4249
	struct xdr_netobj *owner = &rlockowner->rl_owner;
4250 4251
	struct list_head matches;
	int i;
4252
	__be32 status;
L
Linus Torvalds 已提交
4253 4254 4255 4256 4257 4258 4259

	dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
		clid->cl_boot, clid->cl_id);

	/* XXX check for lease expiration */

	status = nfserr_stale_clientid;
N
Neil Brown 已提交
4260
	if (STALE_CLIENTID(clid))
L
Linus Torvalds 已提交
4261 4262 4263 4264
		return status;

	nfs4_lock_state();

4265 4266 4267 4268 4269 4270 4271 4272
	status = nfserr_locks_held;
	/* XXX: we're doing a linear search through all the lockowners.
	 * Yipes!  For now we'll just hope clients aren't really using
	 * release_lockowner much, but eventually we have to fix these
	 * data structures. */
	INIT_LIST_HEAD(&matches);
	for (i = 0; i < LOCK_HASH_SIZE; i++) {
		list_for_each_entry(sop, &lock_ownerid_hashtbl[i], so_idhash) {
4273
			if (!same_owner_str(sop, owner, clid))
4274 4275 4276
				continue;
			list_for_each_entry(stp, &sop->so_stateids,
					st_perstateowner) {
4277 4278
				lo = lockowner(sop);
				if (check_for_locks(stp->st_file, lo))
4279
					goto out;
4280
				list_add(&lo->lo_list, &matches);
4281
			}
L
Linus Torvalds 已提交
4282
		}
4283 4284 4285 4286 4287
	}
	/* Clients probably won't expect us to return with some (but not all)
	 * of the lockowner state released; so don't release any until all
	 * have been checked. */
	status = nfs_ok;
N
NeilBrown 已提交
4288
	while (!list_empty(&matches)) {
4289 4290
		lo = list_entry(matches.next, struct nfs4_lockowner,
								lo_list);
N
NeilBrown 已提交
4291 4292
		/* unhash_stateowner deletes so_perclient only
		 * for openowners. */
4293 4294
		list_del(&lo->lo_list);
		release_lockowner(lo);
L
Linus Torvalds 已提交
4295 4296 4297 4298 4299 4300 4301
	}
out:
	nfs4_unlock_state();
	return status;
}

static inline struct nfs4_client_reclaim *
N
NeilBrown 已提交
4302
alloc_reclaim(void)
L
Linus Torvalds 已提交
4303
{
N
NeilBrown 已提交
4304
	return kmalloc(sizeof(struct nfs4_client_reclaim), GFP_KERNEL);
L
Linus Torvalds 已提交
4305 4306
}

4307
int
4308
nfs4_has_reclaimed_state(const char *name, bool use_exchange_id)
4309 4310 4311 4312
{
	unsigned int strhashval = clientstr_hashval(name);
	struct nfs4_client *clp;

4313
	clp = find_confirmed_client_by_str(name, strhashval);
4314 4315 4316
	return clp ? 1 : 0;
}

L
Linus Torvalds 已提交
4317 4318 4319
/*
 * failure => all reset bets are off, nfserr_no_grace...
 */
4320 4321
int
nfs4_client_to_reclaim(const char *name)
L
Linus Torvalds 已提交
4322 4323 4324 4325
{
	unsigned int strhashval;
	struct nfs4_client_reclaim *crp = NULL;

N
NeilBrown 已提交
4326 4327
	dprintk("NFSD nfs4_client_to_reclaim NAME: %.*s\n", HEXDIR_LEN, name);
	crp = alloc_reclaim();
L
Linus Torvalds 已提交
4328 4329
	if (!crp)
		return 0;
N
NeilBrown 已提交
4330
	strhashval = clientstr_hashval(name);
L
Linus Torvalds 已提交
4331 4332
	INIT_LIST_HEAD(&crp->cr_strhash);
	list_add(&crp->cr_strhash, &reclaim_str_hashtbl[strhashval]);
N
NeilBrown 已提交
4333
	memcpy(crp->cr_recdir, name, HEXDIR_LEN);
L
Linus Torvalds 已提交
4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345 4346 4347 4348 4349 4350 4351 4352 4353 4354 4355 4356 4357
	reclaim_str_hashtbl_size++;
	return 1;
}

static void
nfs4_release_reclaim(void)
{
	struct nfs4_client_reclaim *crp = NULL;
	int i;

	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
		while (!list_empty(&reclaim_str_hashtbl[i])) {
			crp = list_entry(reclaim_str_hashtbl[i].next,
			                struct nfs4_client_reclaim, cr_strhash);
			list_del(&crp->cr_strhash);
			kfree(crp);
			reclaim_str_hashtbl_size--;
		}
	}
	BUG_ON(reclaim_str_hashtbl_size);
}

/*
 * called from OPEN, CLAIM_PREVIOUS with a new clientid. */
4358
static struct nfs4_client_reclaim *
L
Linus Torvalds 已提交
4359 4360 4361 4362 4363 4364 4365 4366 4367 4368 4369 4370
nfs4_find_reclaim_client(clientid_t *clid)
{
	unsigned int strhashval;
	struct nfs4_client *clp;
	struct nfs4_client_reclaim *crp = NULL;


	/* find clientid in conf_id_hashtbl */
	clp = find_confirmed_client(clid);
	if (clp == NULL)
		return NULL;

N
NeilBrown 已提交
4371 4372 4373
	dprintk("NFSD: nfs4_find_reclaim_client for %.*s with recdir %s\n",
		            clp->cl_name.len, clp->cl_name.data,
			    clp->cl_recdir);
L
Linus Torvalds 已提交
4374 4375

	/* find clp->cl_name in reclaim_str_hashtbl */
N
NeilBrown 已提交
4376
	strhashval = clientstr_hashval(clp->cl_recdir);
L
Linus Torvalds 已提交
4377
	list_for_each_entry(crp, &reclaim_str_hashtbl[strhashval], cr_strhash) {
N
NeilBrown 已提交
4378
		if (same_name(crp->cr_recdir, clp->cl_recdir)) {
L
Linus Torvalds 已提交
4379 4380 4381 4382 4383 4384 4385 4386 4387
			return crp;
		}
	}
	return NULL;
}

/*
* Called from OPEN. Look for clientid in reclaim list.
*/
4388
__be32
L
Linus Torvalds 已提交
4389 4390
nfs4_check_open_reclaim(clientid_t *clid)
{
4391
	return nfs4_find_reclaim_client(clid) ? nfs_ok : nfserr_reclaim_bad;
L
Linus Torvalds 已提交
4392 4393
}

4394
/* initialization to perform at module load time: */
L
Linus Torvalds 已提交
4395

4396
int
4397
nfs4_state_init(void)
L
Linus Torvalds 已提交
4398
{
4399
	int i, status;
L
Linus Torvalds 已提交
4400

4401 4402 4403
	status = nfsd4_init_slabs();
	if (status)
		return status;
L
Linus Torvalds 已提交
4404 4405 4406 4407 4408
	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
		INIT_LIST_HEAD(&conf_id_hashtbl[i]);
		INIT_LIST_HEAD(&conf_str_hashtbl[i]);
		INIT_LIST_HEAD(&unconf_str_hashtbl[i]);
		INIT_LIST_HEAD(&unconf_id_hashtbl[i]);
W
Wang Chen 已提交
4409
		INIT_LIST_HEAD(&reclaim_str_hashtbl[i]);
L
Linus Torvalds 已提交
4410
	}
M
Marc Eshel 已提交
4411 4412
	for (i = 0; i < SESSION_HASH_SIZE; i++)
		INIT_LIST_HEAD(&sessionid_hashtbl[i]);
L
Linus Torvalds 已提交
4413 4414 4415
	for (i = 0; i < FILE_HASH_SIZE; i++) {
		INIT_LIST_HEAD(&file_hashtbl[i]);
	}
4416 4417 4418
	for (i = 0; i < OPEN_OWNER_HASH_SIZE; i++) {
		INIT_LIST_HEAD(&open_ownerstr_hashtbl[i]);
		INIT_LIST_HEAD(&open_ownerid_hashtbl[i]);
L
Linus Torvalds 已提交
4419
	}
4420
	for (i = 0; i < STATEID_HASH_SIZE; i++)
L
Linus Torvalds 已提交
4421 4422 4423 4424 4425 4426 4427 4428 4429
		INIT_LIST_HEAD(&stateid_hashtbl[i]);
	for (i = 0; i < LOCK_HASH_SIZE; i++) {
		INIT_LIST_HEAD(&lock_ownerid_hashtbl[i]);
		INIT_LIST_HEAD(&lock_ownerstr_hashtbl[i]);
	}
	memset(&onestateid, ~0, sizeof(stateid_t));
	INIT_LIST_HEAD(&close_lru);
	INIT_LIST_HEAD(&client_lru);
	INIT_LIST_HEAD(&del_recall_lru);
4430
	reclaim_str_hashtbl_size = 0;
4431
	return 0;
4432 4433
}

4434 4435 4436 4437 4438
static void
nfsd4_load_reboot_recovery_data(void)
{
	int status;

4439
	nfs4_lock_state();
4440
	nfsd4_init_recdir();
4441
	status = nfsd4_recdir_load();
4442
	nfs4_unlock_state();
4443 4444 4445 4446
	if (status)
		printk("NFSD: Failure reading reboot recovery data\n");
}

4447 4448 4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463 4464 4465 4466 4467
/*
 * Since the lifetime of a delegation isn't limited to that of an open, a
 * client may quite reasonably hang on to a delegation as long as it has
 * the inode cached.  This becomes an obvious problem the first time a
 * client's inode cache approaches the size of the server's total memory.
 *
 * For now we avoid this problem by imposing a hard limit on the number
 * of delegations, which varies according to the server's memory size.
 */
static void
set_max_delegations(void)
{
	/*
	 * Allow at most 4 delegations per megabyte of RAM.  Quick
	 * estimates suggest that in the worst case (where every delegation
	 * is for a different inode), a delegation could take about 1.5K,
	 * giving a worst case usage of about 6% of memory.
	 */
	max_delegations = nr_free_buffer_pages() >> (20 - 2 - PAGE_SHIFT);
}

4468 4469
/* initialization to perform when the nfsd service is started: */

4470
static int
4471 4472
__nfs4_state_start(void)
{
4473 4474
	int ret;

L
Linus Torvalds 已提交
4475
	boot_time = get_seconds();
4476
	locks_start_grace(&nfsd4_manager);
4477
	printk(KERN_INFO "NFSD: starting %ld-second grace period\n",
4478
	       nfsd4_grace);
4479 4480 4481
	ret = set_callback_cred();
	if (ret)
		return -ENOMEM;
4482
	laundry_wq = create_singlethread_workqueue("nfsd4");
4483 4484
	if (laundry_wq == NULL)
		return -ENOMEM;
4485 4486 4487
	ret = nfsd4_create_callback_queue();
	if (ret)
		goto out_free_laundry;
4488
	queue_delayed_work(laundry_wq, &laundromat_work, nfsd4_grace * HZ);
4489
	set_max_delegations();
4490 4491 4492 4493
	return 0;
out_free_laundry:
	destroy_workqueue(laundry_wq);
	return ret;
L
Linus Torvalds 已提交
4494 4495
}

4496
int
4497
nfs4_state_start(void)
L
Linus Torvalds 已提交
4498
{
4499
	nfsd4_load_reboot_recovery_data();
4500
	return __nfs4_state_start();
L
Linus Torvalds 已提交
4501 4502 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 4517 4518 4519 4520 4521 4522 4523 4524 4525 4526 4527 4528 4529 4530 4531 4532 4533
}

static void
__nfs4_state_shutdown(void)
{
	int i;
	struct nfs4_client *clp = NULL;
	struct nfs4_delegation *dp = NULL;
	struct list_head *pos, *next, reaplist;

	for (i = 0; i < CLIENT_HASH_SIZE; i++) {
		while (!list_empty(&conf_id_hashtbl[i])) {
			clp = list_entry(conf_id_hashtbl[i].next, struct nfs4_client, cl_idhash);
			expire_client(clp);
		}
		while (!list_empty(&unconf_str_hashtbl[i])) {
			clp = list_entry(unconf_str_hashtbl[i].next, struct nfs4_client, cl_strhash);
			expire_client(clp);
		}
	}
	INIT_LIST_HEAD(&reaplist);
	spin_lock(&recall_lock);
	list_for_each_safe(pos, next, &del_recall_lru) {
		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
		list_move(&dp->dl_recall_lru, &reaplist);
	}
	spin_unlock(&recall_lock);
	list_for_each_safe(pos, next, &reaplist) {
		dp = list_entry (pos, struct nfs4_delegation, dl_recall_lru);
		list_del_init(&dp->dl_recall_lru);
		unhash_delegation(dp);
	}

4534
	nfsd4_shutdown_recdir();
L
Linus Torvalds 已提交
4535 4536 4537 4538 4539
}

void
nfs4_state_shutdown(void)
{
4540
	cancel_delayed_work_sync(&laundromat_work);
4541
	destroy_workqueue(laundry_wq);
4542
	locks_end_grace(&nfsd4_manager);
L
Linus Torvalds 已提交
4543 4544 4545 4546
	nfs4_lock_state();
	nfs4_release_reclaim();
	__nfs4_state_shutdown();
	nfs4_unlock_state();
4547
	nfsd4_destroy_callback_queue();
L
Linus Torvalds 已提交
4548
}