nfs4state.c 40.5 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/*
 *  fs/nfs/nfs4state.c
 *
 *  Client-side XDR for NFSv4.
 *
 *  Copyright (c) 2002 The Regents of the University of Michigan.
 *  All rights reserved.
 *
 *  Kendrick Smith <kmsmith@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.
 *
 * Implementation of the NFSv4 state model.  For the time being,
 * this is minimal, but will be made much more complex in a
 * subsequent patch.
 */

41
#include <linux/kernel.h>
L
Linus Torvalds 已提交
42 43 44 45
#include <linux/slab.h>
#include <linux/smp_lock.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_idmap.h>
46 47
#include <linux/kthread.h>
#include <linux/module.h>
48
#include <linux/random.h>
L
Linus Torvalds 已提交
49 50 51
#include <linux/workqueue.h>
#include <linux/bitops.h>

52
#include "nfs4_fs.h"
L
Linus Torvalds 已提交
53 54
#include "callback.h"
#include "delegation.h"
55
#include "internal.h"
L
Linus Torvalds 已提交
56 57 58

#define OPENOWNER_POOL_SIZE	8

59
const nfs4_stateid zero_stateid;
L
Linus Torvalds 已提交
60 61 62

static LIST_HEAD(nfs4_clientid_list);

63
int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
L
Linus Torvalds 已提交
64
{
65
	struct nfs4_setclientid_res clid;
66 67 68 69 70 71 72
	unsigned short port;
	int status;

	port = nfs_callback_tcpport;
	if (clp->cl_addr.ss_family == AF_INET6)
		port = nfs_callback_tcpport6;

73 74 75 76 77 78 79 80 81
	status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
	if (status != 0)
		goto out;
	status = nfs4_proc_setclientid_confirm(clp, &clid, cred);
	if (status != 0)
		goto out;
	clp->cl_clientid = clid.clientid;
	nfs4_schedule_state_renewal(clp);
out:
L
Linus Torvalds 已提交
82 83 84
	return status;
}

85
struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
{
	struct rpc_cred *cred = NULL;

	if (clp->cl_machine_cred != NULL)
		cred = get_rpccred(clp->cl_machine_cred);
	return cred;
}

static void nfs4_clear_machine_cred(struct nfs_client *clp)
{
	struct rpc_cred *cred;

	spin_lock(&clp->cl_lock);
	cred = clp->cl_machine_cred;
	clp->cl_machine_cred = NULL;
	spin_unlock(&clp->cl_lock);
	if (cred != NULL)
		put_rpccred(cred);
}

106
struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
107 108
{
	struct nfs4_state_owner *sp;
109
	struct rb_node *pos;
110 111
	struct rpc_cred *cred = NULL;

112 113
	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
114 115 116 117 118 119 120 121
		if (list_empty(&sp->so_states))
			continue;
		cred = get_rpccred(sp->so_cred);
		break;
	}
	return cred;
}

122 123
#if defined(CONFIG_NFS_V4_1)

R
Ricardo Labiaga 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
static int nfs41_setup_state_renewal(struct nfs_client *clp)
{
	int status;
	struct nfs_fsinfo fsinfo;

	status = nfs4_proc_get_lease_time(clp, &fsinfo);
	if (status == 0) {
		/* Update lease time and schedule renewal */
		spin_lock(&clp->cl_lock);
		clp->cl_lease_time = fsinfo.lease_time * HZ;
		clp->cl_last_renewal = jiffies;
		spin_unlock(&clp->cl_lock);

		nfs4_schedule_state_renewal(clp);
	}

	return status;
}

143
static void nfs4_end_drain_session(struct nfs_client *clp)
144
{
145
	struct nfs4_session *ses = clp->cl_session;
146 147
	int max_slots;

148 149 150
	if (ses == NULL)
		return;
	if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
151 152 153 154 155 156 157 158 159 160 161 162 163
		spin_lock(&ses->fc_slot_table.slot_tbl_lock);
		max_slots = ses->fc_slot_table.max_slots;
		while (max_slots--) {
			struct rpc_task *task;

			task = rpc_wake_up_next(&ses->fc_slot_table.
						slot_tbl_waitq);
			if (!task)
				break;
			rpc_task_set_priority(task, RPC_PRIORITY_PRIVILEGED);
		}
		spin_unlock(&ses->fc_slot_table.slot_tbl_lock);
	}
164 165
}

166
static int nfs4_begin_drain_session(struct nfs_client *clp)
167
{
168
	struct nfs4_session *ses = clp->cl_session;
169 170 171
	struct nfs4_slot_table *tbl = &ses->fc_slot_table;

	spin_lock(&tbl->slot_tbl_lock);
172
	set_bit(NFS4_SESSION_DRAINING, &ses->session_state);
173 174 175 176 177 178 179 180 181
	if (tbl->highest_used_slotid != -1) {
		INIT_COMPLETION(ses->complete);
		spin_unlock(&tbl->slot_tbl_lock);
		return wait_for_completion_interruptible(&ses->complete);
	}
	spin_unlock(&tbl->slot_tbl_lock);
	return 0;
}

182 183 184 185
int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
{
	int status;

186
	nfs4_begin_drain_session(clp);
187
	status = nfs4_proc_exchange_id(clp, cred);
R
Ricardo Labiaga 已提交
188 189 190 191 192 193 194 195
	if (status != 0)
		goto out;
	status = nfs4_proc_create_session(clp);
	if (status != 0)
		goto out;
	nfs41_setup_state_renewal(clp);
	nfs_mark_client_ready(clp, NFS_CS_READY);
out:
196 197 198
	return status;
}

199 200 201 202 203 204 205 206 207 208 209 210
struct rpc_cred *nfs4_get_exchange_id_cred(struct nfs_client *clp)
{
	struct rpc_cred *cred;

	spin_lock(&clp->cl_lock);
	cred = nfs4_get_machine_cred_locked(clp);
	spin_unlock(&clp->cl_lock);
	return cred;
}

#endif /* CONFIG_NFS_V4_1 */

211
struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
212 213
{
	struct nfs4_state_owner *sp;
214
	struct rb_node *pos;
215
	struct rpc_cred *cred;
216

217 218
	spin_lock(&clp->cl_lock);
	cred = nfs4_get_machine_cred_locked(clp);
219 220
	if (cred != NULL)
		goto out;
221 222 223
	pos = rb_first(&clp->cl_state_owners);
	if (pos != NULL) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
224
		cred = get_rpccred(sp->so_cred);
225
	}
226
out:
227
	spin_unlock(&clp->cl_lock);
228
	return cred;
229 230
}

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new,
		__u64 minval, int maxbits)
{
	struct rb_node **p, *parent;
	struct nfs_unique_id *pos;
	__u64 mask = ~0ULL;

	if (maxbits < 64)
		mask = (1ULL << maxbits) - 1ULL;

	/* Ensure distribution is more or less flat */
	get_random_bytes(&new->id, sizeof(new->id));
	new->id &= mask;
	if (new->id < minval)
		new->id += minval;
retry:
	p = &root->rb_node;
	parent = NULL;

	while (*p != NULL) {
		parent = *p;
		pos = rb_entry(parent, struct nfs_unique_id, rb_node);

		if (new->id < pos->id)
			p = &(*p)->rb_left;
		else if (new->id > pos->id)
			p = &(*p)->rb_right;
		else
			goto id_exists;
	}
	rb_link_node(&new->rb_node, parent, p);
	rb_insert_color(&new->rb_node, root);
	return;
id_exists:
	for (;;) {
		new->id++;
		if (new->id < minval || (new->id & mask) != new->id) {
			new->id = minval;
			break;
		}
		parent = rb_next(parent);
		if (parent == NULL)
			break;
		pos = rb_entry(parent, struct nfs_unique_id, rb_node);
		if (new->id < pos->id)
			break;
	}
	goto retry;
}

static void nfs_free_unique_id(struct rb_root *root, struct nfs_unique_id *id)
{
	rb_erase(&id->rb_node, root);
}

L
Linus Torvalds 已提交
286
static struct nfs4_state_owner *
287
nfs4_find_state_owner(struct nfs_server *server, struct rpc_cred *cred)
L
Linus Torvalds 已提交
288
{
289
	struct nfs_client *clp = server->nfs_client;
290 291
	struct rb_node **p = &clp->cl_state_owners.rb_node,
		       *parent = NULL;
L
Linus Torvalds 已提交
292 293
	struct nfs4_state_owner *sp, *res = NULL;

294 295 296 297
	while (*p != NULL) {
		parent = *p;
		sp = rb_entry(parent, struct nfs4_state_owner, so_client_node);

298 299 300 301 302 303 304 305
		if (server < sp->so_server) {
			p = &parent->rb_left;
			continue;
		}
		if (server > sp->so_server) {
			p = &parent->rb_right;
			continue;
		}
306 307 308 309 310 311 312 313 314
		if (cred < sp->so_cred)
			p = &parent->rb_left;
		else if (cred > sp->so_cred)
			p = &parent->rb_right;
		else {
			atomic_inc(&sp->so_count);
			res = sp;
			break;
		}
L
Linus Torvalds 已提交
315 316 317 318
	}
	return res;
}

319 320 321 322 323 324 325 326 327 328 329
static struct nfs4_state_owner *
nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new)
{
	struct rb_node **p = &clp->cl_state_owners.rb_node,
		       *parent = NULL;
	struct nfs4_state_owner *sp;

	while (*p != NULL) {
		parent = *p;
		sp = rb_entry(parent, struct nfs4_state_owner, so_client_node);

330 331 332 333 334 335 336 337
		if (new->so_server < sp->so_server) {
			p = &parent->rb_left;
			continue;
		}
		if (new->so_server > sp->so_server) {
			p = &parent->rb_right;
			continue;
		}
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
		if (new->so_cred < sp->so_cred)
			p = &parent->rb_left;
		else if (new->so_cred > sp->so_cred)
			p = &parent->rb_right;
		else {
			atomic_inc(&sp->so_count);
			return sp;
		}
	}
	nfs_alloc_unique_id(&clp->cl_openowner_id, &new->so_owner_id, 1, 64);
	rb_link_node(&new->so_client_node, parent, p);
	rb_insert_color(&new->so_client_node, &clp->cl_state_owners);
	return new;
}

static void
nfs4_remove_state_owner(struct nfs_client *clp, struct nfs4_state_owner *sp)
{
	if (!RB_EMPTY_NODE(&sp->so_client_node))
		rb_erase(&sp->so_client_node, &clp->cl_state_owners);
	nfs_free_unique_id(&clp->cl_openowner_id, &sp->so_owner_id);
}

L
Linus Torvalds 已提交
361 362 363 364 365 366 367 368 369 370
/*
 * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to
 * create a new state_owner.
 *
 */
static struct nfs4_state_owner *
nfs4_alloc_state_owner(void)
{
	struct nfs4_state_owner *sp;

371
	sp = kzalloc(sizeof(*sp),GFP_NOFS);
L
Linus Torvalds 已提交
372 373
	if (!sp)
		return NULL;
374
	spin_lock_init(&sp->so_lock);
L
Linus Torvalds 已提交
375
	INIT_LIST_HEAD(&sp->so_states);
376 377 378 379
	rpc_init_wait_queue(&sp->so_sequence.wait, "Seqid_waitqueue");
	sp->so_seqid.sequence = &sp->so_sequence;
	spin_lock_init(&sp->so_sequence.lock);
	INIT_LIST_HEAD(&sp->so_sequence.list);
L
Linus Torvalds 已提交
380 381 382 383
	atomic_set(&sp->so_count, 1);
	return sp;
}

384
static void
L
Linus Torvalds 已提交
385 386
nfs4_drop_state_owner(struct nfs4_state_owner *sp)
{
387
	if (!RB_EMPTY_NODE(&sp->so_client_node)) {
388
		struct nfs_client *clp = sp->so_server->nfs_client;
389 390 391 392 393 394

		spin_lock(&clp->cl_lock);
		rb_erase(&sp->so_client_node, &clp->cl_state_owners);
		RB_CLEAR_NODE(&sp->so_client_node);
		spin_unlock(&clp->cl_lock);
	}
L
Linus Torvalds 已提交
395 396 397 398
}

struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
{
399
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
400 401 402
	struct nfs4_state_owner *sp, *new;

	spin_lock(&clp->cl_lock);
403
	sp = nfs4_find_state_owner(server, cred);
L
Linus Torvalds 已提交
404 405 406
	spin_unlock(&clp->cl_lock);
	if (sp != NULL)
		return sp;
407 408 409
	new = nfs4_alloc_state_owner();
	if (new == NULL)
		return NULL;
410
	new->so_server = server;
411 412 413 414 415 416
	new->so_cred = cred;
	spin_lock(&clp->cl_lock);
	sp = nfs4_insert_state_owner(clp, new);
	spin_unlock(&clp->cl_lock);
	if (sp == new)
		get_rpccred(cred);
417 418
	else {
		rpc_destroy_wait_queue(&new->so_sequence.wait);
419
		kfree(new);
420
	}
421
	return sp;
L
Linus Torvalds 已提交
422 423 424 425
}

void nfs4_put_state_owner(struct nfs4_state_owner *sp)
{
426
	struct nfs_client *clp = sp->so_server->nfs_client;
L
Linus Torvalds 已提交
427 428 429 430
	struct rpc_cred *cred = sp->so_cred;

	if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
		return;
431
	nfs4_remove_state_owner(clp, sp);
L
Linus Torvalds 已提交
432
	spin_unlock(&clp->cl_lock);
433
	rpc_destroy_wait_queue(&sp->so_sequence.wait);
L
Linus Torvalds 已提交
434 435 436 437 438 439 440 441 442
	put_rpccred(cred);
	kfree(sp);
}

static struct nfs4_state *
nfs4_alloc_open_state(void)
{
	struct nfs4_state *state;

443
	state = kzalloc(sizeof(*state), GFP_NOFS);
L
Linus Torvalds 已提交
444 445 446 447
	if (!state)
		return NULL;
	atomic_set(&state->count, 1);
	INIT_LIST_HEAD(&state->lock_states);
448
	spin_lock_init(&state->state_lock);
449
	seqlock_init(&state->seqlock);
L
Linus Torvalds 已提交
450 451 452
	return state;
}

453
void
454
nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode)
455
{
456
	if (state->state == fmode)
457 458
		return;
	/* NB! List reordering - see the reclaim code for why.  */
459 460
	if ((fmode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {
		if (fmode & FMODE_WRITE)
461 462 463 464
			list_move(&state->open_states, &state->owner->so_states);
		else
			list_move_tail(&state->open_states, &state->owner->so_states);
	}
465
	state->state = fmode;
466 467
}

L
Linus Torvalds 已提交
468 469 470 471 472 473 474
static struct nfs4_state *
__nfs4_find_state_byowner(struct inode *inode, struct nfs4_state_owner *owner)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs4_state *state;

	list_for_each_entry(state, &nfsi->open_states, inode_states) {
475
		if (state->owner != owner)
L
Linus Torvalds 已提交
476
			continue;
477
		if (atomic_inc_not_zero(&state->count))
L
Linus Torvalds 已提交
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
			return state;
	}
	return NULL;
}

static void
nfs4_free_open_state(struct nfs4_state *state)
{
	kfree(state);
}

struct nfs4_state *
nfs4_get_open_state(struct inode *inode, struct nfs4_state_owner *owner)
{
	struct nfs4_state *state, *new;
	struct nfs_inode *nfsi = NFS_I(inode);

	spin_lock(&inode->i_lock);
	state = __nfs4_find_state_byowner(inode, owner);
	spin_unlock(&inode->i_lock);
	if (state)
		goto out;
	new = nfs4_alloc_open_state();
501
	spin_lock(&owner->so_lock);
L
Linus Torvalds 已提交
502 503 504 505 506 507 508 509 510
	spin_lock(&inode->i_lock);
	state = __nfs4_find_state_byowner(inode, owner);
	if (state == NULL && new != NULL) {
		state = new;
		state->owner = owner;
		atomic_inc(&owner->so_count);
		list_add(&state->inode_states, &nfsi->open_states);
		state->inode = igrab(inode);
		spin_unlock(&inode->i_lock);
511 512 513 514
		/* Note: The reclaim code dictates that we add stateless
		 * and read-only stateids to the end of the list */
		list_add_tail(&state->open_states, &owner->so_states);
		spin_unlock(&owner->so_lock);
L
Linus Torvalds 已提交
515 516
	} else {
		spin_unlock(&inode->i_lock);
517
		spin_unlock(&owner->so_lock);
L
Linus Torvalds 已提交
518 519 520 521 522 523 524 525 526 527 528 529
		if (new)
			nfs4_free_open_state(new);
	}
out:
	return state;
}

void nfs4_put_open_state(struct nfs4_state *state)
{
	struct inode *inode = state->inode;
	struct nfs4_state_owner *owner = state->owner;

530
	if (!atomic_dec_and_lock(&state->count, &owner->so_lock))
L
Linus Torvalds 已提交
531
		return;
532
	spin_lock(&inode->i_lock);
533
	list_del(&state->inode_states);
L
Linus Torvalds 已提交
534
	list_del(&state->open_states);
535 536
	spin_unlock(&inode->i_lock);
	spin_unlock(&owner->so_lock);
L
Linus Torvalds 已提交
537 538 539 540 541 542
	iput(inode);
	nfs4_free_open_state(state);
	nfs4_put_state_owner(owner);
}

/*
543
 * Close the current file.
L
Linus Torvalds 已提交
544
 */
545 546
static void __nfs4_close(struct path *path, struct nfs4_state *state,
		fmode_t fmode, gfp_t gfp_mask, int wait)
L
Linus Torvalds 已提交
547 548
{
	struct nfs4_state_owner *owner = state->owner;
549
	int call_close = 0;
550
	fmode_t newstate;
L
Linus Torvalds 已提交
551 552 553

	atomic_inc(&owner->so_count);
	/* Protect against nfs4_find_state() */
554
	spin_lock(&owner->so_lock);
555
	switch (fmode & (FMODE_READ | FMODE_WRITE)) {
556 557 558 559 560 561 562 563 564
		case FMODE_READ:
			state->n_rdonly--;
			break;
		case FMODE_WRITE:
			state->n_wronly--;
			break;
		case FMODE_READ|FMODE_WRITE:
			state->n_rdwr--;
	}
565
	newstate = FMODE_READ|FMODE_WRITE;
566
	if (state->n_rdwr == 0) {
567
		if (state->n_rdonly == 0) {
568
			newstate &= ~FMODE_READ;
569 570 571 572
			call_close |= test_bit(NFS_O_RDONLY_STATE, &state->flags);
			call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
		}
		if (state->n_wronly == 0) {
573
			newstate &= ~FMODE_WRITE;
574 575 576 577 578
			call_close |= test_bit(NFS_O_WRONLY_STATE, &state->flags);
			call_close |= test_bit(NFS_O_RDWR_STATE, &state->flags);
		}
		if (newstate == 0)
			clear_bit(NFS_DELEGATED_STATE, &state->flags);
579
	}
580
	nfs4_state_set_mode_locked(state, newstate);
581
	spin_unlock(&owner->so_lock);
582

583
	if (!call_close) {
584 585 586
		nfs4_put_open_state(state);
		nfs4_put_state_owner(owner);
	} else
587
		nfs4_do_close(path, state, gfp_mask, wait);
588 589
}

590
void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode)
591
{
592
	__nfs4_close(path, state, fmode, GFP_NOFS, 0);
593 594
}

595
void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode)
596
{
597
	__nfs4_close(path, state, fmode, GFP_KERNEL, 1);
L
Linus Torvalds 已提交
598 599 600 601 602 603 604
}

/*
 * Search the state->lock_states for an existing lock_owner
 * that is compatible with current->files
 */
static struct nfs4_lock_state *
605
__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type)
L
Linus Torvalds 已提交
606 607 608
{
	struct nfs4_lock_state *pos;
	list_for_each_entry(pos, &state->lock_states, ls_locks) {
609
		if (type != NFS4_ANY_LOCK_TYPE && pos->ls_owner.lo_type != type)
L
Linus Torvalds 已提交
610
			continue;
611 612 613 614 615 616 617 618 619
		switch (pos->ls_owner.lo_type) {
		case NFS4_POSIX_LOCK_TYPE:
			if (pos->ls_owner.lo_u.posix_owner != fl_owner)
				continue;
			break;
		case NFS4_FLOCK_LOCK_TYPE:
			if (pos->ls_owner.lo_u.flock_owner != fl_pid)
				continue;
		}
L
Linus Torvalds 已提交
620 621 622 623 624 625 626 627 628 629 630
		atomic_inc(&pos->ls_count);
		return pos;
	}
	return NULL;
}

/*
 * Return a compatible lock_state. If no initialized lock_state structure
 * exists, return an uninitialized one.
 *
 */
631
static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type)
L
Linus Torvalds 已提交
632 633
{
	struct nfs4_lock_state *lsp;
634
	struct nfs_client *clp = state->owner->so_server->nfs_client;
L
Linus Torvalds 已提交
635

636
	lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
L
Linus Torvalds 已提交
637 638
	if (lsp == NULL)
		return NULL;
639 640 641 642
	rpc_init_wait_queue(&lsp->ls_sequence.wait, "lock_seqid_waitqueue");
	spin_lock_init(&lsp->ls_sequence.lock);
	INIT_LIST_HEAD(&lsp->ls_sequence.list);
	lsp->ls_seqid.sequence = &lsp->ls_sequence;
L
Linus Torvalds 已提交
643
	atomic_set(&lsp->ls_count, 1);
644
	lsp->ls_state = state;
645 646 647 648 649 650 651 652 653 654 655 656
	lsp->ls_owner.lo_type = type;
	switch (lsp->ls_owner.lo_type) {
	case NFS4_FLOCK_LOCK_TYPE:
		lsp->ls_owner.lo_u.flock_owner = fl_pid;
		break;
	case NFS4_POSIX_LOCK_TYPE:
		lsp->ls_owner.lo_u.posix_owner = fl_owner;
		break;
	default:
		kfree(lsp);
		return NULL;
	}
L
Linus Torvalds 已提交
657
	spin_lock(&clp->cl_lock);
658
	nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64);
L
Linus Torvalds 已提交
659
	spin_unlock(&clp->cl_lock);
660
	INIT_LIST_HEAD(&lsp->ls_locks);
L
Linus Torvalds 已提交
661 662 663
	return lsp;
}

664 665
static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
{
666
	struct nfs_client *clp = lsp->ls_state->owner->so_server->nfs_client;
667 668 669 670

	spin_lock(&clp->cl_lock);
	nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id);
	spin_unlock(&clp->cl_lock);
671
	rpc_destroy_wait_queue(&lsp->ls_sequence.wait);
672 673 674
	kfree(lsp);
}

L
Linus Torvalds 已提交
675 676 677 678 679
/*
 * Return a compatible lock_state. If no initialized lock_state structure
 * exists, return an uninitialized one.
 *
 */
680
static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner, pid_t pid, unsigned int type)
L
Linus Torvalds 已提交
681
{
682
	struct nfs4_lock_state *lsp, *new = NULL;
L
Linus Torvalds 已提交
683
	
684 685
	for(;;) {
		spin_lock(&state->state_lock);
686
		lsp = __nfs4_find_lock_state(state, owner, pid, type);
687 688 689 690 691 692 693 694 695 696
		if (lsp != NULL)
			break;
		if (new != NULL) {
			list_add(&new->ls_locks, &state->lock_states);
			set_bit(LK_STATE_IN_USE, &state->flags);
			lsp = new;
			new = NULL;
			break;
		}
		spin_unlock(&state->state_lock);
697
		new = nfs4_alloc_lock_state(state, owner, pid, type);
698 699 700 701
		if (new == NULL)
			return NULL;
	}
	spin_unlock(&state->state_lock);
702 703
	if (new != NULL)
		nfs4_free_lock_state(new);
L
Linus Torvalds 已提交
704 705 706 707
	return lsp;
}

/*
708 709
 * Release reference to lock_state, and free it if we see that
 * it is no longer in use
L
Linus Torvalds 已提交
710
 */
711
void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
L
Linus Torvalds 已提交
712
{
713
	struct nfs4_state *state;
L
Linus Torvalds 已提交
714

715 716 717 718 719 720 721 722 723
	if (lsp == NULL)
		return;
	state = lsp->ls_state;
	if (!atomic_dec_and_lock(&lsp->ls_count, &state->state_lock))
		return;
	list_del(&lsp->ls_locks);
	if (list_empty(&state->lock_states))
		clear_bit(LK_STATE_IN_USE, &state->flags);
	spin_unlock(&state->state_lock);
724 725
	if (lsp->ls_flags & NFS_LOCK_INITIALIZED)
		nfs4_release_lockowner(lsp);
726
	nfs4_free_lock_state(lsp);
L
Linus Torvalds 已提交
727 728
}

729
static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
L
Linus Torvalds 已提交
730
{
731
	struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner;
L
Linus Torvalds 已提交
732

733 734 735
	dst->fl_u.nfs4_fl.owner = lsp;
	atomic_inc(&lsp->ls_count);
}
L
Linus Torvalds 已提交
736

737
static void nfs4_fl_release_lock(struct file_lock *fl)
L
Linus Torvalds 已提交
738
{
739
	nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner);
L
Linus Torvalds 已提交
740 741
}

742
static const struct file_lock_operations nfs4_fl_lock_ops = {
743 744 745 746 747
	.fl_copy_lock = nfs4_fl_copy_lock,
	.fl_release_private = nfs4_fl_release_lock,
};

int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
L
Linus Torvalds 已提交
748
{
749 750 751 752
	struct nfs4_lock_state *lsp;

	if (fl->fl_ops != NULL)
		return 0;
753 754 755 756 757 758
	if (fl->fl_flags & FL_POSIX)
		lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE);
	else if (fl->fl_flags & FL_FLOCK)
		lsp = nfs4_get_lock_state(state, 0, fl->fl_pid, NFS4_FLOCK_LOCK_TYPE);
	else
		return -EINVAL;
759 760 761 762 763
	if (lsp == NULL)
		return -ENOMEM;
	fl->fl_u.nfs4_fl.owner = lsp;
	fl->fl_ops = &nfs4_fl_lock_ops;
	return 0;
L
Linus Torvalds 已提交
764 765
}

766 767 768
/*
 * Byte-range lock aware utility to initialize the stateid of read/write
 * requests.
L
Linus Torvalds 已提交
769
 */
770
void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid)
L
Linus Torvalds 已提交
771
{
772
	struct nfs4_lock_state *lsp;
773
	int seq;
L
Linus Torvalds 已提交
774

775 776 777 778
	do {
		seq = read_seqbegin(&state->seqlock);
		memcpy(dst, &state->stateid, sizeof(*dst));
	} while (read_seqretry(&state->seqlock, seq));
779 780
	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
		return;
L
Linus Torvalds 已提交
781

782
	spin_lock(&state->state_lock);
783
	lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
784 785 786
	if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
		memcpy(dst, &lsp->ls_stateid, sizeof(*dst));
	spin_unlock(&state->state_lock);
L
Linus Torvalds 已提交
787 788 789
	nfs4_put_lock_state(lsp);
}

790
struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
791 792 793
{
	struct nfs_seqid *new;

794
	new = kmalloc(sizeof(*new), gfp_mask);
795 796
	if (new != NULL) {
		new->sequence = counter;
797
		INIT_LIST_HEAD(&new->list);
798 799 800 801
	}
	return new;
}

802
void nfs_release_seqid(struct nfs_seqid *seqid)
L
Linus Torvalds 已提交
803
{
804 805
	if (!list_empty(&seqid->list)) {
		struct rpc_sequence *sequence = seqid->sequence->sequence;
806

807
		spin_lock(&sequence->lock);
808
		list_del_init(&seqid->list);
809 810 811
		spin_unlock(&sequence->lock);
		rpc_wake_up(&sequence->wait);
	}
812 813 814 815 816
}

void nfs_free_seqid(struct nfs_seqid *seqid)
{
	nfs_release_seqid(seqid);
817
	kfree(seqid);
L
Linus Torvalds 已提交
818 819 820
}

/*
821 822 823 824
 * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
 * failed with a seqid incrementing error -
 * see comments nfs_fs.h:seqid_mutating_error()
 */
825
static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
826
{
827
	BUG_ON(list_first_entry(&seqid->sequence->sequence->list, struct nfs_seqid, list) != seqid);
828 829 830 831
	switch (status) {
		case 0:
			break;
		case -NFS4ERR_BAD_SEQID:
832 833 834
			if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
				return;
			printk(KERN_WARNING "NFS: v4 server returned a bad"
D
Dan Muntz 已提交
835 836
					" sequence-id error on an"
					" unconfirmed sequence %p!\n",
837
					seqid->sequence);
838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855
		case -NFS4ERR_STALE_CLIENTID:
		case -NFS4ERR_STALE_STATEID:
		case -NFS4ERR_BAD_STATEID:
		case -NFS4ERR_BADXDR:
		case -NFS4ERR_RESOURCE:
		case -NFS4ERR_NOFILEHANDLE:
			/* Non-seqid mutating errors */
			return;
	};
	/*
	 * Note: no locking needed as we are guaranteed to be first
	 * on the sequence list
	 */
	seqid->sequence->counter++;
}

void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
{
856 857 858 859 860
	struct nfs4_state_owner *sp = container_of(seqid->sequence,
					struct nfs4_state_owner, so_seqid);
	struct nfs_server *server = sp->so_server;

	if (status == -NFS4ERR_BAD_SEQID)
L
Linus Torvalds 已提交
861
		nfs4_drop_state_owner(sp);
862 863
	if (!nfs4_has_session(server->nfs_client))
		nfs_increment_seqid(status, seqid);
864 865 866 867 868 869 870 871 872
}

/*
 * Increment the seqid if the LOCK/LOCKU succeeded, or
 * failed with a seqid incrementing error -
 * see comments nfs_fs.h:seqid_mutating_error()
 */
void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
{
873
	nfs_increment_seqid(status, seqid);
874 875 876 877 878 879 880 881
}

int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
{
	struct rpc_sequence *sequence = seqid->sequence->sequence;
	int status = 0;

	spin_lock(&sequence->lock);
882 883 884 885
	if (list_empty(&seqid->list))
		list_add_tail(&seqid->list, &sequence->list);
	if (list_first_entry(&sequence->list, struct nfs_seqid, list) == seqid)
		goto unlock;
886
	rpc_sleep_on(&sequence->wait, task, NULL);
887 888
	status = -EAGAIN;
unlock:
889 890
	spin_unlock(&sequence->lock);
	return status;
L
Linus Torvalds 已提交
891 892
}

893
static int nfs4_run_state_manager(void *);
L
Linus Torvalds 已提交
894

895
static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
T
Trond Myklebust 已提交
896 897
{
	smp_mb__before_clear_bit();
898
	clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
T
Trond Myklebust 已提交
899
	smp_mb__after_clear_bit();
900
	wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING);
T
Trond Myklebust 已提交
901 902 903
	rpc_wake_up(&clp->cl_rpcwaitq);
}

L
Linus Torvalds 已提交
904
/*
905
 * Schedule the nfs_client asynchronous state management routine
L
Linus Torvalds 已提交
906
 */
907
void nfs4_schedule_state_manager(struct nfs_client *clp)
L
Linus Torvalds 已提交
908
{
909
	struct task_struct *task;
L
Linus Torvalds 已提交
910

911 912
	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
		return;
913 914
	__module_get(THIS_MODULE);
	atomic_inc(&clp->cl_count);
915
	task = kthread_run(nfs4_run_state_manager, clp, "%s-manager",
916 917
				rpc_peeraddr2str(clp->cl_rpcclient,
							RPC_DISPLAY_ADDR));
918 919
	if (!IS_ERR(task))
		return;
920
	nfs4_clear_state_manager_bit(clp);
921
	nfs_put_client(clp);
922
	module_put(THIS_MODULE);
L
Linus Torvalds 已提交
923 924 925 926 927
}

/*
 * Schedule a state recovery attempt
 */
928
void nfs4_schedule_state_recovery(struct nfs_client *clp)
L
Linus Torvalds 已提交
929 930 931
{
	if (!clp)
		return;
932 933
	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
934
	nfs4_schedule_state_manager(clp);
L
Linus Torvalds 已提交
935 936
}

937
int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
938 939 940 941 942 943 944 945
{

	set_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
	/* Don't recover state that expired before the reboot */
	if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags)) {
		clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
		return 0;
	}
946
	set_bit(NFS_OWNER_RECLAIM_REBOOT, &state->owner->so_flags);
947 948 949 950
	set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
	return 1;
}

951
int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
952 953 954
{
	set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
	clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
955
	set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags);
956 957 958 959
	set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
	return 1;
}

960
static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
961 962
{
	struct inode *inode = state->inode;
963
	struct nfs_inode *nfsi = NFS_I(inode);
L
Linus Torvalds 已提交
964 965 966
	struct file_lock *fl;
	int status = 0;

967 968 969 970
	if (inode->i_flock == NULL)
		return 0;

	/* Guard against delegation returns and new lock/unlock calls */
971
	down_write(&nfsi->rwsem);
972 973
	/* Protect inode->i_flock using the BKL */
	lock_kernel();
H
Harvey Harrison 已提交
974
	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
975
		if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
L
Linus Torvalds 已提交
976
			continue;
977
		if (nfs_file_open_context(fl->fl_file)->state != state)
L
Linus Torvalds 已提交
978
			continue;
979
		unlock_kernel();
L
Linus Torvalds 已提交
980 981
		status = ops->recover_lock(state, fl);
		switch (status) {
982 983 984 985 986 987 988 989 990
			case 0:
				break;
			case -ESTALE:
			case -NFS4ERR_ADMIN_REVOKED:
			case -NFS4ERR_STALE_STATEID:
			case -NFS4ERR_BAD_STATEID:
			case -NFS4ERR_EXPIRED:
			case -NFS4ERR_NO_GRACE:
			case -NFS4ERR_STALE_CLIENTID:
991 992 993 994
			case -NFS4ERR_BADSESSION:
			case -NFS4ERR_BADSLOT:
			case -NFS4ERR_BAD_HIGH_SLOT:
			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
995
				goto out;
L
Linus Torvalds 已提交
996 997
			default:
				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
998
						__func__, status);
999 1000
			case -ENOMEM:
			case -NFS4ERR_DENIED:
L
Linus Torvalds 已提交
1001 1002
			case -NFS4ERR_RECLAIM_BAD:
			case -NFS4ERR_RECLAIM_CONFLICT:
1003
				/* kill_proc(fl->fl_pid, SIGLOST, 1); */
1004
				status = 0;
L
Linus Torvalds 已提交
1005
		}
1006
		lock_kernel();
L
Linus Torvalds 已提交
1007
	}
1008
	unlock_kernel();
1009
out:
1010
	up_write(&nfsi->rwsem);
L
Linus Torvalds 已提交
1011 1012 1013
	return status;
}

1014
static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027
{
	struct nfs4_state *state;
	struct nfs4_lock_state *lock;
	int status = 0;

	/* Note: we rely on the sp->so_states list being ordered 
	 * so that we always reclaim open(O_RDWR) and/or open(O_WRITE)
	 * states first.
	 * This is needed to ensure that the server won't give us any
	 * read delegations that we have to return if, say, we are
	 * recovering after a network partition or a reboot from a
	 * server that doesn't support a grace period.
	 */
1028 1029
restart:
	spin_lock(&sp->so_lock);
L
Linus Torvalds 已提交
1030
	list_for_each_entry(state, &sp->so_states, open_states) {
1031 1032
		if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
			continue;
L
Linus Torvalds 已提交
1033 1034
		if (state->state == 0)
			continue;
1035 1036
		atomic_inc(&state->count);
		spin_unlock(&sp->so_lock);
L
Linus Torvalds 已提交
1037 1038
		status = ops->recover_open(sp, state);
		if (status >= 0) {
1039 1040 1041 1042 1043
			status = nfs4_reclaim_locks(state, ops);
			if (status >= 0) {
				list_for_each_entry(lock, &state->lock_states, ls_locks) {
					if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
						printk("%s: Lock reclaim failed!\n",
1044
							__func__);
1045
				}
1046 1047
				nfs4_put_open_state(state);
				goto restart;
L
Linus Torvalds 已提交
1048 1049 1050 1051 1052
			}
		}
		switch (status) {
			default:
				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
1053
						__func__, status);
L
Linus Torvalds 已提交
1054
			case -ENOENT:
1055
			case -ENOMEM:
1056
			case -ESTALE:
L
Linus Torvalds 已提交
1057 1058 1059 1060 1061 1062 1063 1064 1065
				/*
				 * Open state on this file cannot be recovered
				 * All we can do is revert to using the zero stateid.
				 */
				memset(state->stateid.data, 0,
					sizeof(state->stateid.data));
				/* Mark the file as being 'closed' */
				state->state = 0;
				break;
1066 1067 1068
			case -NFS4ERR_ADMIN_REVOKED:
			case -NFS4ERR_STALE_STATEID:
			case -NFS4ERR_BAD_STATEID:
1069 1070
			case -NFS4ERR_RECLAIM_BAD:
			case -NFS4ERR_RECLAIM_CONFLICT:
1071
				nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
1072
				break;
L
Linus Torvalds 已提交
1073 1074
			case -NFS4ERR_EXPIRED:
			case -NFS4ERR_NO_GRACE:
1075
				nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
L
Linus Torvalds 已提交
1076
			case -NFS4ERR_STALE_CLIENTID:
1077 1078 1079 1080
			case -NFS4ERR_BADSESSION:
			case -NFS4ERR_BADSLOT:
			case -NFS4ERR_BAD_HIGH_SLOT:
			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
L
Linus Torvalds 已提交
1081 1082
				goto out_err;
		}
1083 1084
		nfs4_put_open_state(state);
		goto restart;
L
Linus Torvalds 已提交
1085
	}
1086
	spin_unlock(&sp->so_lock);
L
Linus Torvalds 已提交
1087 1088
	return 0;
out_err:
1089
	nfs4_put_open_state(state);
L
Linus Torvalds 已提交
1090 1091 1092
	return status;
}

1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
static void nfs4_clear_open_state(struct nfs4_state *state)
{
	struct nfs4_lock_state *lock;

	clear_bit(NFS_DELEGATED_STATE, &state->flags);
	clear_bit(NFS_O_RDONLY_STATE, &state->flags);
	clear_bit(NFS_O_WRONLY_STATE, &state->flags);
	clear_bit(NFS_O_RDWR_STATE, &state->flags);
	list_for_each_entry(lock, &state->lock_states, ls_locks) {
		lock->ls_seqid.flags = 0;
		lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
	}
}

static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp, int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
1108 1109
{
	struct nfs4_state_owner *sp;
1110
	struct rb_node *pos;
1111 1112 1113
	struct nfs4_state *state;

	/* Reset all sequence ids to zero */
1114 1115
	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
1116
		sp->so_seqid.flags = 0;
1117
		spin_lock(&sp->so_lock);
1118
		list_for_each_entry(state, &sp->so_states, open_states) {
1119 1120
			if (mark_reclaim(clp, state))
				nfs4_clear_open_state(state);
1121
		}
1122
		spin_unlock(&sp->so_lock);
1123 1124 1125
	}
}

1126 1127 1128 1129 1130 1131 1132
static void nfs4_state_start_reclaim_reboot(struct nfs_client *clp)
{
	/* Mark all delegations for reclaim */
	nfs_delegation_mark_reclaim(clp);
	nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_reboot);
}

1133 1134 1135 1136 1137 1138 1139 1140
static void nfs4_reclaim_complete(struct nfs_client *clp,
				 const struct nfs4_state_recovery_ops *ops)
{
	/* Notify the server we're done reclaiming our state */
	if (ops->reclaim_complete)
		(void)ops->reclaim_complete(clp);
}

1141 1142 1143 1144 1145 1146 1147 1148 1149
static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
{
	struct nfs4_state_owner *sp;
	struct rb_node *pos;
	struct nfs4_state *state;

	if (!test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
		return;

1150
	nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops);
1151

1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177
	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
		spin_lock(&sp->so_lock);
		list_for_each_entry(state, &sp->so_states, open_states) {
			if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags))
				continue;
			nfs4_state_mark_reclaim_nograce(clp, state);
		}
		spin_unlock(&sp->so_lock);
	}

	nfs_delegation_reap_unclaimed(clp);
}

static void nfs_delegation_clear_all(struct nfs_client *clp)
{
	nfs_delegation_mark_reclaim(clp);
	nfs_delegation_reap_unclaimed(clp);
}

static void nfs4_state_start_reclaim_nograce(struct nfs_client *clp)
{
	nfs_delegation_clear_all(clp);
	nfs4_state_mark_reclaim_helper(clp, nfs4_state_mark_reclaim_nograce);
}

1178
static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
1179 1180 1181
{
	switch (error) {
		case -NFS4ERR_CB_PATH_DOWN:
1182
			nfs_handle_cb_pathdown(clp);
1183
			return 0;
1184 1185 1186
		case -NFS4ERR_NO_GRACE:
			nfs4_state_end_reclaim_reboot(clp);
			return 0;
1187 1188 1189
		case -NFS4ERR_STALE_CLIENTID:
		case -NFS4ERR_LEASE_MOVED:
			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1190
			nfs4_state_end_reclaim_reboot(clp);
1191 1192 1193 1194 1195
			nfs4_state_start_reclaim_reboot(clp);
			break;
		case -NFS4ERR_EXPIRED:
			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
			nfs4_state_start_reclaim_nograce(clp);
1196
			break;
1197 1198 1199 1200 1201 1202 1203
		case -NFS4ERR_BADSESSION:
		case -NFS4ERR_BADSLOT:
		case -NFS4ERR_BAD_HIGH_SLOT:
		case -NFS4ERR_DEADSESSION:
		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
		case -NFS4ERR_SEQ_FALSE_RETRY:
		case -NFS4ERR_SEQ_MISORDERED:
1204
			set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
1205 1206
			/* Zero session reset errors */
			return 0;
1207
	}
1208
	return error;
1209 1210
}

1211
static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
1212
{
1213
	struct rb_node *pos;
L
Linus Torvalds 已提交
1214 1215
	int status = 0;

1216 1217
restart:
	spin_lock(&clp->cl_lock);
1218 1219
	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
		struct nfs4_state_owner *sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
1220 1221 1222 1223
		if (!test_and_clear_bit(ops->owner_flag_bit, &sp->so_flags))
			continue;
		atomic_inc(&sp->so_count);
		spin_unlock(&clp->cl_lock);
1224
		status = nfs4_reclaim_open_state(sp, ops);
1225 1226 1227
		if (status < 0) {
			set_bit(ops->owner_flag_bit, &sp->so_flags);
			nfs4_put_state_owner(sp);
1228
			return nfs4_recovery_handle_error(clp, status);
1229 1230 1231
		}
		nfs4_put_state_owner(sp);
		goto restart;
1232
	}
1233
	spin_unlock(&clp->cl_lock);
1234 1235 1236 1237 1238 1239
	return status;
}

static int nfs4_check_lease(struct nfs_client *clp)
{
	struct rpc_cred *cred;
1240 1241
	const struct nfs4_state_maintenance_ops *ops =
		clp->cl_mvops->state_renewal_ops;
1242
	int status = -NFS4ERR_EXPIRED;
L
Linus Torvalds 已提交
1243

1244 1245 1246
	/* Is the client already known to have an expired lease? */
	if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
		return 0;
1247 1248 1249
	spin_lock(&clp->cl_lock);
	cred = ops->get_state_renewal_cred_locked(clp);
	spin_unlock(&clp->cl_lock);
1250 1251 1252 1253
	if (cred == NULL) {
		cred = nfs4_get_setclientid_cred(clp);
		if (cred == NULL)
			goto out;
1254
	}
1255
	status = ops->renew_lease(clp, cred);
1256 1257
	put_rpccred(cred);
out:
1258
	return nfs4_recovery_handle_error(clp, status);
1259 1260 1261 1262 1263
}

static int nfs4_reclaim_lease(struct nfs_client *clp)
{
	struct rpc_cred *cred;
1264 1265
	const struct nfs4_state_recovery_ops *ops =
		clp->cl_mvops->reboot_recovery_ops;
1266 1267
	int status = -ENOENT;

1268
	cred = ops->get_clid_cred(clp);
1269
	if (cred != NULL) {
1270
		status = ops->establish_clid(clp, cred);
1271
		put_rpccred(cred);
1272 1273 1274
		/* Handle case where the user hasn't set up machine creds */
		if (status == -EACCES && cred == clp->cl_machine_cred) {
			nfs4_clear_machine_cred(clp);
1275
			status = -EAGAIN;
1276
		}
1277 1278
		if (status == -NFS4ERR_MINOR_VERS_MISMATCH)
			status = -EPROTONOSUPPORT;
1279
	}
1280 1281 1282
	return status;
}

1283
#ifdef CONFIG_NFS_V4_1
A
Andy Adamson 已提交
1284 1285 1286 1287 1288 1289
void nfs41_handle_recall_slot(struct nfs_client *clp)
{
	set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
	nfs4_schedule_state_recovery(clp);
}

1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325
static void nfs4_reset_all_state(struct nfs_client *clp)
{
	if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
		clp->cl_boot_time = CURRENT_TIME;
		nfs4_state_start_reclaim_nograce(clp);
		nfs4_schedule_state_recovery(clp);
	}
}

static void nfs41_handle_server_reboot(struct nfs_client *clp)
{
	if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
		nfs4_state_start_reclaim_reboot(clp);
		nfs4_schedule_state_recovery(clp);
	}
}

static void nfs41_handle_state_revoked(struct nfs_client *clp)
{
	/* Temporary */
	nfs4_reset_all_state(clp);
}

static void nfs41_handle_recallable_state_revoked(struct nfs_client *clp)
{
	/* This will need to handle layouts too */
	nfs_expire_all_delegations(clp);
}

static void nfs41_handle_cb_path_down(struct nfs_client *clp)
{
	nfs_expire_all_delegations(clp);
	if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0)
		nfs4_schedule_state_recovery(clp);
}

1326 1327 1328 1329
void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
{
	if (!flags)
		return;
1330 1331 1332
	else if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
		nfs41_handle_server_reboot(clp);
	else if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
1333 1334
			    SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
			    SEQ4_STATUS_ADMIN_STATE_REVOKED |
1335 1336 1337 1338 1339
			    SEQ4_STATUS_LEASE_MOVED))
		nfs41_handle_state_revoked(clp);
	else if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
		nfs41_handle_recallable_state_revoked(clp);
	else if (flags & (SEQ4_STATUS_CB_PATH_DOWN |
1340 1341
			    SEQ4_STATUS_BACKCHANNEL_FAULT |
			    SEQ4_STATUS_CB_PATH_DOWN_SESSION))
1342
		nfs41_handle_cb_path_down(clp);
1343 1344
}

1345 1346 1347 1348
static int nfs4_reset_session(struct nfs_client *clp)
{
	int status;

1349
	nfs4_begin_drain_session(clp);
1350 1351 1352
	status = nfs4_proc_destroy_session(clp->cl_session);
	if (status && status != -NFS4ERR_BADSESSION &&
	    status != -NFS4ERR_DEADSESSION) {
1353
		status = nfs4_recovery_handle_error(clp, status);
1354 1355 1356 1357
		goto out;
	}

	memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
1358
	status = nfs4_proc_create_session(clp);
1359
	if (status) {
1360
		status = nfs4_recovery_handle_error(clp, status);
1361 1362 1363 1364
		goto out;
	}
	/* create_session negotiated new slot table */
	clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
1365

1366 1367
	 /* Let the state manager reestablish state */
	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
1368
		nfs41_setup_state_renewal(clp);
1369
out:
1370 1371
	return status;
}
1372

A
Andy Adamson 已提交
1373 1374 1375 1376 1377 1378 1379 1380 1381
static int nfs4_recall_slot(struct nfs_client *clp)
{
	struct nfs4_slot_table *fc_tbl = &clp->cl_session->fc_slot_table;
	struct nfs4_channel_attrs *fc_attrs = &clp->cl_session->fc_attrs;
	struct nfs4_slot *new, *old;
	int i;

	nfs4_begin_drain_session(clp);
	new = kmalloc(fc_tbl->target_max_slots * sizeof(struct nfs4_slot),
1382
		      GFP_NOFS);
A
Andy Adamson 已提交
1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400
        if (!new)
		return -ENOMEM;

	spin_lock(&fc_tbl->slot_tbl_lock);
	for (i = 0; i < fc_tbl->target_max_slots; i++)
		new[i].seq_nr = fc_tbl->slots[i].seq_nr;
	old = fc_tbl->slots;
	fc_tbl->slots = new;
	fc_tbl->max_slots = fc_tbl->target_max_slots;
	fc_tbl->target_max_slots = 0;
	fc_attrs->max_reqs = fc_tbl->max_slots;
	spin_unlock(&fc_tbl->slot_tbl_lock);

	kfree(old);
	nfs4_end_drain_session(clp);
	return 0;
}

1401
#else /* CONFIG_NFS_V4_1 */
1402
static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
1403
static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
A
Andy Adamson 已提交
1404
static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }
1405 1406
#endif /* CONFIG_NFS_V4_1 */

1407 1408 1409 1410 1411 1412 1413 1414 1415 1416
/* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
 * on EXCHANGE_ID for v4.1
 */
static void nfs4_set_lease_expired(struct nfs_client *clp, int status)
{
	if (nfs4_has_session(clp)) {
		switch (status) {
		case -NFS4ERR_DELAY:
		case -NFS4ERR_CLID_INUSE:
		case -EAGAIN:
1417
		case -EKEYEXPIRED:
1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428
			break;

		case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
					 * in nfs4_exchange_id */
		default:
			return;
		}
	}
	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
}

1429
static void nfs4_state_manager(struct nfs_client *clp)
1430 1431 1432 1433
{
	int status = 0;

	/* Ensure exclusive access to NFSv4 state */
1434
	for(;;) {
1435 1436 1437 1438
		if (test_and_clear_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state)) {
			/* We're going to have to re-establish a clientid */
			status = nfs4_reclaim_lease(clp);
			if (status) {
1439
				nfs4_set_lease_expired(clp, status);
1440 1441
				if (test_bit(NFS4CLNT_LEASE_EXPIRED,
							&clp->cl_state))
1442
					continue;
1443 1444 1445
				if (clp->cl_cons_state ==
							NFS_CS_SESSION_INITING)
					nfs_mark_client_ready(clp, status);
1446 1447
				goto out_error;
			}
1448
			clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
1449
			set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
1450 1451 1452 1453
		}

		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
			status = nfs4_check_lease(clp);
1454
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
1455
				continue;
1456 1457
			if (status < 0 && status != -NFS4ERR_CB_PATH_DOWN)
				goto out_error;
1458
		}
1459

1460
		/* Initialize or reset the session */
1461
		if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)
1462
		   && nfs4_has_session(clp)) {
1463
			status = nfs4_reset_session(clp);
1464 1465 1466
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
				continue;
			if (status < 0)
1467 1468
				goto out_error;
		}
1469

1470
		/* First recover reboot state... */
1471
		if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
1472
			status = nfs4_do_reclaim(clp,
1473
				clp->cl_mvops->reboot_recovery_ops);
1474
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
1475
			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
1476
				continue;
1477
			nfs4_state_end_reclaim_reboot(clp);
1478 1479 1480 1481
			if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
				continue;
			if (status < 0)
				goto out_error;
1482 1483
		}

1484 1485
		/* Now recover expired state... */
		if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
1486
			status = nfs4_do_reclaim(clp,
1487
				clp->cl_mvops->nograce_recovery_ops);
1488
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
1489
			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) ||
1490 1491 1492
			    test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
				continue;
			if (status < 0)
1493
				goto out_error;
L
Linus Torvalds 已提交
1494
		}
1495

1496
		nfs4_end_drain_session(clp);
1497 1498 1499 1500
		if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
			nfs_client_return_marked_delegations(clp);
			continue;
		}
A
Andy Adamson 已提交
1501 1502 1503 1504 1505 1506 1507 1508 1509
		/* Recall session slots */
		if (test_and_clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state)
		   && nfs4_has_session(clp)) {
			status = nfs4_recall_slot(clp);
			if (status < 0)
				goto out_error;
			continue;
		}

1510 1511

		nfs4_clear_state_manager_bit(clp);
1512 1513 1514 1515 1516
		/* Did we race with an attempt to give us more work? */
		if (clp->cl_state == 0)
			break;
		if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
			break;
L
Linus Torvalds 已提交
1517
	}
1518
	return;
L
Linus Torvalds 已提交
1519
out_error:
1520
	printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
1521
			" with error %d\n", clp->cl_hostname, -status);
1522
	nfs4_end_drain_session(clp);
1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534
	nfs4_clear_state_manager_bit(clp);
}

static int nfs4_run_state_manager(void *ptr)
{
	struct nfs_client *clp = ptr;

	allow_signal(SIGKILL);
	nfs4_state_manager(clp);
	nfs_put_client(clp);
	module_put_and_exit(0);
	return 0;
L
Linus Torvalds 已提交
1535 1536 1537 1538 1539 1540 1541
}

/*
 * Local variables:
 *  c-basic-offset: 8
 * End:
 */