nfs4state.c 46.2 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
#include <linux/slab.h>
43
#include <linux/fs.h>
L
Linus Torvalds 已提交
44 45
#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>
49
#include <linux/ratelimit.h>
L
Linus Torvalds 已提交
50 51
#include <linux/workqueue.h>
#include <linux/bitops.h>
52
#include <linux/jiffies.h>
L
Linus Torvalds 已提交
53

54
#include "nfs4_fs.h"
L
Linus Torvalds 已提交
55 56
#include "callback.h"
#include "delegation.h"
57
#include "internal.h"
58
#include "pnfs.h"
L
Linus Torvalds 已提交
59 60 61

#define OPENOWNER_POOL_SIZE	8

62
const nfs4_stateid zero_stateid;
L
Linus Torvalds 已提交
63 64 65

static LIST_HEAD(nfs4_clientid_list);

66
int nfs4_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
L
Linus Torvalds 已提交
67
{
68 69 70 71
	struct nfs4_setclientid_res clid = {
		.clientid = clp->cl_clientid,
		.confirm = clp->cl_confirm,
	};
72 73 74
	unsigned short port;
	int status;

75 76
	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
		goto do_confirm;
77 78 79 80
	port = nfs_callback_tcpport;
	if (clp->cl_addr.ss_family == AF_INET6)
		port = nfs_callback_tcpport6;

81 82 83
	status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred, &clid);
	if (status != 0)
		goto out;
84 85 86 87
	clp->cl_clientid = clid.clientid;
	clp->cl_confirm = clid.confirm;
	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
do_confirm:
88 89 90
	status = nfs4_proc_setclientid_confirm(clp, &clid, cred);
	if (status != 0)
		goto out;
91
	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
92 93
	nfs4_schedule_state_renewal(clp);
out:
L
Linus Torvalds 已提交
94 95 96
	return status;
}

97
struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
{
	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);
}

118 119
static struct rpc_cred *
nfs4_get_renew_cred_server_locked(struct nfs_server *server)
120
{
121
	struct rpc_cred *cred = NULL;
122
	struct nfs4_state_owner *sp;
123
	struct rb_node *pos;
124

125 126 127 128
	for (pos = rb_first(&server->state_owners);
	     pos != NULL;
	     pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
129 130 131 132 133 134 135 136
		if (list_empty(&sp->so_states))
			continue;
		cred = get_rpccred(sp->so_cred);
		break;
	}
	return cred;
}

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
/**
 * nfs4_get_renew_cred_locked - Acquire credential for a renew operation
 * @clp: client state handle
 *
 * Returns an rpc_cred with reference count bumped, or NULL.
 * Caller must hold clp->cl_lock.
 */
struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
{
	struct rpc_cred *cred = NULL;
	struct nfs_server *server;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		cred = nfs4_get_renew_cred_server_locked(server);
		if (cred != NULL)
			break;
	}
	rcu_read_unlock();
	return cred;
}

159 160
#if defined(CONFIG_NFS_V4_1)

R
Ricardo Labiaga 已提交
161 162 163 164 165
static int nfs41_setup_state_renewal(struct nfs_client *clp)
{
	int status;
	struct nfs_fsinfo fsinfo;

166 167 168 169 170
	if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) {
		nfs4_schedule_state_renewal(clp);
		return 0;
	}

R
Ricardo Labiaga 已提交
171 172 173 174 175 176 177 178 179 180 181 182 183 184
	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;
}

185 186 187 188 189
/*
 * Back channel returns NFS4ERR_DELAY for new requests when
 * NFS4_SESSION_DRAINING is set so there is no work to be done when draining
 * is ended.
 */
190
static void nfs4_end_drain_session(struct nfs_client *clp)
191
{
192
	struct nfs4_session *ses = clp->cl_session;
193 194
	int max_slots;

195 196 197
	if (ses == NULL)
		return;
	if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
198 199 200 201 202 203 204 205 206 207 208 209 210
		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);
	}
211 212
}

213
static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
214 215 216
{
	spin_lock(&tbl->slot_tbl_lock);
	if (tbl->highest_used_slotid != -1) {
217
		INIT_COMPLETION(tbl->complete);
218
		spin_unlock(&tbl->slot_tbl_lock);
219
		return wait_for_completion_interruptible(&tbl->complete);
220 221 222 223 224
	}
	spin_unlock(&tbl->slot_tbl_lock);
	return 0;
}

225 226 227 228 229 230 231 232 233 234 235 236 237 238
static int nfs4_begin_drain_session(struct nfs_client *clp)
{
	struct nfs4_session *ses = clp->cl_session;
	int ret = 0;

	set_bit(NFS4_SESSION_DRAINING, &ses->session_state);
	/* back channel */
	ret = nfs4_wait_on_slot_tbl(&ses->bc_slot_table);
	if (ret)
		return ret;
	/* fore channel */
	return nfs4_wait_on_slot_tbl(&ses->fc_slot_table);
}

239 240 241 242
int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
{
	int status;

243 244
	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
		goto do_confirm;
245
	nfs4_begin_drain_session(clp);
246
	status = nfs4_proc_exchange_id(clp, cred);
R
Ricardo Labiaga 已提交
247 248
	if (status != 0)
		goto out;
249 250
	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
do_confirm:
R
Ricardo Labiaga 已提交
251 252 253
	status = nfs4_proc_create_session(clp);
	if (status != 0)
		goto out;
254
	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
R
Ricardo Labiaga 已提交
255 256 257
	nfs41_setup_state_renewal(clp);
	nfs_mark_client_ready(clp, NFS_CS_READY);
out:
258 259 260
	return status;
}

261 262 263 264 265 266 267 268 269 270 271 272
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 */

273 274
static struct rpc_cred *
nfs4_get_setclientid_cred_server(struct nfs_server *server)
275
{
276 277
	struct nfs_client *clp = server->nfs_client;
	struct rpc_cred *cred = NULL;
278
	struct nfs4_state_owner *sp;
279
	struct rb_node *pos;
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299

	spin_lock(&clp->cl_lock);
	pos = rb_first(&server->state_owners);
	if (pos != NULL) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
		cred = get_rpccred(sp->so_cred);
	}
	spin_unlock(&clp->cl_lock);
	return cred;
}

/**
 * nfs4_get_setclientid_cred - Acquire credential for a setclientid operation
 * @clp: client state handle
 *
 * Returns an rpc_cred with reference count bumped, or NULL.
 */
struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
{
	struct nfs_server *server;
300
	struct rpc_cred *cred;
301

302 303
	spin_lock(&clp->cl_lock);
	cred = nfs4_get_machine_cred_locked(clp);
304
	spin_unlock(&clp->cl_lock);
305 306
	if (cred != NULL)
		goto out;
307 308 309 310 311 312

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		cred = nfs4_get_setclientid_cred_server(server);
		if (cred != NULL)
			break;
313
	}
314 315
	rcu_read_unlock();

316 317
out:
	return cred;
318 319
}

L
Linus Torvalds 已提交
320
static struct nfs4_state_owner *
321
nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred)
L
Linus Torvalds 已提交
322
{
323
	struct rb_node **p = &server->state_owners.rb_node,
324
		       *parent = NULL;
325
	struct nfs4_state_owner *sp;
L
Linus Torvalds 已提交
326

327 328
	while (*p != NULL) {
		parent = *p;
329
		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
330 331 332 333 334 335

		if (cred < sp->so_cred)
			p = &parent->rb_left;
		else if (cred > sp->so_cred)
			p = &parent->rb_right;
		else {
336 337
			if (!list_empty(&sp->so_lru))
				list_del_init(&sp->so_lru);
338
			atomic_inc(&sp->so_count);
339
			return sp;
340
		}
L
Linus Torvalds 已提交
341
	}
342
	return NULL;
L
Linus Torvalds 已提交
343 344
}

345
static struct nfs4_state_owner *
346
nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
347
{
348 349
	struct nfs_server *server = new->so_server;
	struct rb_node **p = &server->state_owners.rb_node,
350 351
		       *parent = NULL;
	struct nfs4_state_owner *sp;
352
	int err;
353 354 355

	while (*p != NULL) {
		parent = *p;
356
		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
357 358 359 360 361 362

		if (new->so_cred < sp->so_cred)
			p = &parent->rb_left;
		else if (new->so_cred > sp->so_cred)
			p = &parent->rb_right;
		else {
363 364
			if (!list_empty(&sp->so_lru))
				list_del_init(&sp->so_lru);
365 366 367 368
			atomic_inc(&sp->so_count);
			return sp;
		}
	}
369 370 371
	err = ida_get_new(&server->openowner_id, &new->so_owner_id);
	if (err)
		return ERR_PTR(err);
372 373
	rb_link_node(&new->so_server_node, parent, p);
	rb_insert_color(&new->so_server_node, &server->state_owners);
374 375 376 377
	return new;
}

static void
378
nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
379
{
380 381 382 383
	struct nfs_server *server = sp->so_server;

	if (!RB_EMPTY_NODE(&sp->so_server_node))
		rb_erase(&sp->so_server_node, &server->state_owners);
384
	ida_remove(&server->openowner_id, sp->so_owner_id);
385 386
}

L
Linus Torvalds 已提交
387 388 389 390 391 392
/*
 * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to
 * create a new state_owner.
 *
 */
static struct nfs4_state_owner *
393 394 395
nfs4_alloc_state_owner(struct nfs_server *server,
		struct rpc_cred *cred,
		gfp_t gfp_flags)
L
Linus Torvalds 已提交
396 397 398
{
	struct nfs4_state_owner *sp;

399
	sp = kzalloc(sizeof(*sp), gfp_flags);
L
Linus Torvalds 已提交
400 401
	if (!sp)
		return NULL;
402 403
	sp->so_server = server;
	sp->so_cred = get_rpccred(cred);
404
	spin_lock_init(&sp->so_lock);
L
Linus Torvalds 已提交
405
	INIT_LIST_HEAD(&sp->so_states);
406 407 408 409
	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 已提交
410
	atomic_set(&sp->so_count, 1);
411
	INIT_LIST_HEAD(&sp->so_lru);
L
Linus Torvalds 已提交
412 413 414
	return sp;
}

415
static void
L
Linus Torvalds 已提交
416 417
nfs4_drop_state_owner(struct nfs4_state_owner *sp)
{
418 419 420
	if (!RB_EMPTY_NODE(&sp->so_server_node)) {
		struct nfs_server *server = sp->so_server;
		struct nfs_client *clp = server->nfs_client;
421 422

		spin_lock(&clp->cl_lock);
423 424
		rb_erase(&sp->so_server_node, &server->state_owners);
		RB_CLEAR_NODE(&sp->so_server_node);
425 426
		spin_unlock(&clp->cl_lock);
	}
L
Linus Torvalds 已提交
427 428
}

429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
{
	rpc_destroy_wait_queue(&sp->so_sequence.wait);
	put_rpccred(sp->so_cred);
	kfree(sp);
}

static void nfs4_gc_state_owners(struct nfs_server *server)
{
	struct nfs_client *clp = server->nfs_client;
	struct nfs4_state_owner *sp, *tmp;
	unsigned long time_min, time_max;
	LIST_HEAD(doomed);

	spin_lock(&clp->cl_lock);
	time_max = jiffies;
	time_min = (long)time_max - (long)clp->cl_lease_time;
	list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
		/* NB: LRU is sorted so that oldest is at the head */
		if (time_in_range(sp->so_expires, time_min, time_max))
			break;
		list_move(&sp->so_lru, &doomed);
		nfs4_remove_state_owner_locked(sp);
	}
	spin_unlock(&clp->cl_lock);

	list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
		list_del(&sp->so_lru);
		nfs4_free_state_owner(sp);
	}
}

461 462 463 464 465 466 467 468
/**
 * nfs4_get_state_owner - Look up a state owner given a credential
 * @server: nfs_server to search
 * @cred: RPC credential to match
 *
 * Returns a pointer to an instantiated nfs4_state_owner struct, or NULL.
 */
struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server,
469 470
					      struct rpc_cred *cred,
					      gfp_t gfp_flags)
L
Linus Torvalds 已提交
471
{
472
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
473 474 475
	struct nfs4_state_owner *sp, *new;

	spin_lock(&clp->cl_lock);
476
	sp = nfs4_find_state_owner_locked(server, cred);
L
Linus Torvalds 已提交
477 478
	spin_unlock(&clp->cl_lock);
	if (sp != NULL)
479
		goto out;
480
	new = nfs4_alloc_state_owner(server, cred, gfp_flags);
481
	if (new == NULL)
482
		goto out;
483 484 485 486 487 488 489
	do {
		if (ida_pre_get(&server->openowner_id, gfp_flags) == 0)
			break;
		spin_lock(&clp->cl_lock);
		sp = nfs4_insert_state_owner_locked(new);
		spin_unlock(&clp->cl_lock);
	} while (sp == ERR_PTR(-EAGAIN));
490 491
	if (sp != new)
		nfs4_free_state_owner(new);
492 493
out:
	nfs4_gc_state_owners(server);
494
	return sp;
L
Linus Torvalds 已提交
495 496
}

497 498 499 500
/**
 * nfs4_put_state_owner - Release a nfs4_state_owner
 * @sp: state owner data to release
 */
L
Linus Torvalds 已提交
501 502
void nfs4_put_state_owner(struct nfs4_state_owner *sp)
{
503 504
	struct nfs_server *server = sp->so_server;
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
505 506 507

	if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
		return;
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537

	if (!RB_EMPTY_NODE(&sp->so_server_node)) {
		sp->so_expires = jiffies;
		list_add_tail(&sp->so_lru, &server->state_owners_lru);
		spin_unlock(&clp->cl_lock);
	} else {
		nfs4_remove_state_owner_locked(sp);
		spin_unlock(&clp->cl_lock);
		nfs4_free_state_owner(sp);
	}
}

/**
 * nfs4_purge_state_owners - Release all cached state owners
 * @server: nfs_server with cached state owners to release
 *
 * Called at umount time.  Remaining state owners will be on
 * the LRU with ref count of zero.
 */
void nfs4_purge_state_owners(struct nfs_server *server)
{
	struct nfs_client *clp = server->nfs_client;
	struct nfs4_state_owner *sp, *tmp;
	LIST_HEAD(doomed);

	spin_lock(&clp->cl_lock);
	list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
		list_move(&sp->so_lru, &doomed);
		nfs4_remove_state_owner_locked(sp);
	}
L
Linus Torvalds 已提交
538
	spin_unlock(&clp->cl_lock);
539 540 541 542 543

	list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
		list_del(&sp->so_lru);
		nfs4_free_state_owner(sp);
	}
L
Linus Torvalds 已提交
544 545 546 547 548 549 550
}

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

551
	state = kzalloc(sizeof(*state), GFP_NOFS);
L
Linus Torvalds 已提交
552 553 554 555
	if (!state)
		return NULL;
	atomic_set(&state->count, 1);
	INIT_LIST_HEAD(&state->lock_states);
556
	spin_lock_init(&state->state_lock);
557
	seqlock_init(&state->seqlock);
L
Linus Torvalds 已提交
558 559 560
	return state;
}

561
void
562
nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode)
563
{
564
	if (state->state == fmode)
565 566
		return;
	/* NB! List reordering - see the reclaim code for why.  */
567 568
	if ((fmode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {
		if (fmode & FMODE_WRITE)
569 570 571 572
			list_move(&state->open_states, &state->owner->so_states);
		else
			list_move_tail(&state->open_states, &state->owner->so_states);
	}
573
	state->state = fmode;
574 575
}

L
Linus Torvalds 已提交
576 577 578 579 580 581 582
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) {
583
		if (state->owner != owner)
L
Linus Torvalds 已提交
584
			continue;
585
		if (atomic_inc_not_zero(&state->count))
L
Linus Torvalds 已提交
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
			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();
609
	spin_lock(&owner->so_lock);
L
Linus Torvalds 已提交
610 611 612 613 614 615 616
	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);
617 618
		ihold(inode);
		state->inode = inode;
L
Linus Torvalds 已提交
619
		spin_unlock(&inode->i_lock);
620 621 622 623
		/* 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 已提交
624 625
	} else {
		spin_unlock(&inode->i_lock);
626
		spin_unlock(&owner->so_lock);
L
Linus Torvalds 已提交
627 628 629 630 631 632 633 634 635 636 637 638
		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;

639
	if (!atomic_dec_and_lock(&state->count, &owner->so_lock))
L
Linus Torvalds 已提交
640
		return;
641
	spin_lock(&inode->i_lock);
642
	list_del(&state->inode_states);
L
Linus Torvalds 已提交
643
	list_del(&state->open_states);
644 645
	spin_unlock(&inode->i_lock);
	spin_unlock(&owner->so_lock);
L
Linus Torvalds 已提交
646 647 648 649 650 651
	iput(inode);
	nfs4_free_open_state(state);
	nfs4_put_state_owner(owner);
}

/*
652
 * Close the current file.
L
Linus Torvalds 已提交
653
 */
654
static void __nfs4_close(struct nfs4_state *state,
655
		fmode_t fmode, gfp_t gfp_mask, int wait)
L
Linus Torvalds 已提交
656 657
{
	struct nfs4_state_owner *owner = state->owner;
658
	int call_close = 0;
659
	fmode_t newstate;
L
Linus Torvalds 已提交
660 661 662

	atomic_inc(&owner->so_count);
	/* Protect against nfs4_find_state() */
663
	spin_lock(&owner->so_lock);
664
	switch (fmode & (FMODE_READ | FMODE_WRITE)) {
665 666 667 668 669 670 671 672 673
		case FMODE_READ:
			state->n_rdonly--;
			break;
		case FMODE_WRITE:
			state->n_wronly--;
			break;
		case FMODE_READ|FMODE_WRITE:
			state->n_rdwr--;
	}
674
	newstate = FMODE_READ|FMODE_WRITE;
675
	if (state->n_rdwr == 0) {
676
		if (state->n_rdonly == 0) {
677
			newstate &= ~FMODE_READ;
678 679 680 681
			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) {
682
			newstate &= ~FMODE_WRITE;
683 684 685 686 687
			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);
688
	}
689
	nfs4_state_set_mode_locked(state, newstate);
690
	spin_unlock(&owner->so_lock);
691

692
	if (!call_close) {
693 694
		nfs4_put_open_state(state);
		nfs4_put_state_owner(owner);
F
Fred Isaman 已提交
695 696 697
	} else {
		bool roc = pnfs_roc(state->inode);

698
		nfs4_do_close(state, gfp_mask, wait, roc);
F
Fred Isaman 已提交
699
	}
700 701
}

702
void nfs4_close_state(struct nfs4_state *state, fmode_t fmode)
703
{
704
	__nfs4_close(state, fmode, GFP_NOFS, 0);
705 706
}

707
void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
708
{
709
	__nfs4_close(state, fmode, GFP_KERNEL, 1);
L
Linus Torvalds 已提交
710 711 712 713 714 715 716
}

/*
 * Search the state->lock_states for an existing lock_owner
 * that is compatible with current->files
 */
static struct nfs4_lock_state *
717
__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type)
L
Linus Torvalds 已提交
718 719 720
{
	struct nfs4_lock_state *pos;
	list_for_each_entry(pos, &state->lock_states, ls_locks) {
721
		if (type != NFS4_ANY_LOCK_TYPE && pos->ls_owner.lo_type != type)
L
Linus Torvalds 已提交
722
			continue;
723 724 725 726 727 728 729 730 731
		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 已提交
732 733 734 735 736 737 738 739 740 741 742
		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.
 *
 */
743
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 已提交
744 745
{
	struct nfs4_lock_state *lsp;
746
	struct nfs_server *server = state->owner->so_server;
L
Linus Torvalds 已提交
747

748
	lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
L
Linus Torvalds 已提交
749 750
	if (lsp == NULL)
		return NULL;
751 752 753 754
	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 已提交
755
	atomic_set(&lsp->ls_count, 1);
756
	lsp->ls_state = state;
757 758 759 760 761 762 763 764 765
	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:
766
		goto out_free;
767
	}
768 769 770
	lsp->ls_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS);
	if (lsp->ls_id < 0)
		goto out_free;
771
	INIT_LIST_HEAD(&lsp->ls_locks);
L
Linus Torvalds 已提交
772
	return lsp;
773 774 775
out_free:
	kfree(lsp);
	return NULL;
L
Linus Torvalds 已提交
776 777
}

778 779
static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
{
780
	struct nfs_server *server = lsp->ls_state->owner->so_server;
781

782
	ida_simple_remove(&server->lockowner_id, lsp->ls_id);
783
	rpc_destroy_wait_queue(&lsp->ls_sequence.wait);
784 785 786
	kfree(lsp);
}

L
Linus Torvalds 已提交
787 788 789 790 791
/*
 * Return a compatible lock_state. If no initialized lock_state structure
 * exists, return an uninitialized one.
 *
 */
792
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 已提交
793
{
794
	struct nfs4_lock_state *lsp, *new = NULL;
L
Linus Torvalds 已提交
795
	
796 797
	for(;;) {
		spin_lock(&state->state_lock);
798
		lsp = __nfs4_find_lock_state(state, owner, pid, type);
799 800 801 802 803 804 805 806 807 808
		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);
809
		new = nfs4_alloc_lock_state(state, owner, pid, type);
810 811 812 813
		if (new == NULL)
			return NULL;
	}
	spin_unlock(&state->state_lock);
814 815
	if (new != NULL)
		nfs4_free_lock_state(new);
L
Linus Torvalds 已提交
816 817 818 819
	return lsp;
}

/*
820 821
 * Release reference to lock_state, and free it if we see that
 * it is no longer in use
L
Linus Torvalds 已提交
822
 */
823
void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
L
Linus Torvalds 已提交
824
{
825
	struct nfs4_state *state;
L
Linus Torvalds 已提交
826

827 828 829 830 831 832 833 834 835
	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);
836 837
	if (lsp->ls_flags & NFS_LOCK_INITIALIZED)
		nfs4_release_lockowner(lsp);
838
	nfs4_free_lock_state(lsp);
L
Linus Torvalds 已提交
839 840
}

841
static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
L
Linus Torvalds 已提交
842
{
843
	struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner;
L
Linus Torvalds 已提交
844

845 846 847
	dst->fl_u.nfs4_fl.owner = lsp;
	atomic_inc(&lsp->ls_count);
}
L
Linus Torvalds 已提交
848

849
static void nfs4_fl_release_lock(struct file_lock *fl)
L
Linus Torvalds 已提交
850
{
851
	nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner);
L
Linus Torvalds 已提交
852 853
}

854
static const struct file_lock_operations nfs4_fl_lock_ops = {
855 856 857 858 859
	.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 已提交
860
{
861 862 863 864
	struct nfs4_lock_state *lsp;

	if (fl->fl_ops != NULL)
		return 0;
865 866 867 868 869 870
	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;
871 872 873 874 875
	if (lsp == NULL)
		return -ENOMEM;
	fl->fl_u.nfs4_fl.owner = lsp;
	fl->fl_ops = &nfs4_fl_lock_ops;
	return 0;
L
Linus Torvalds 已提交
876 877
}

878 879 880
/*
 * Byte-range lock aware utility to initialize the stateid of read/write
 * requests.
L
Linus Torvalds 已提交
881
 */
882
void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid)
L
Linus Torvalds 已提交
883
{
884
	struct nfs4_lock_state *lsp;
885
	int seq;
L
Linus Torvalds 已提交
886

887 888 889 890
	do {
		seq = read_seqbegin(&state->seqlock);
		memcpy(dst, &state->stateid, sizeof(*dst));
	} while (read_seqretry(&state->seqlock, seq));
891 892
	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
		return;
L
Linus Torvalds 已提交
893

894
	spin_lock(&state->state_lock);
895
	lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
896 897 898
	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 已提交
899 900 901
	nfs4_put_lock_state(lsp);
}

902
struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
903 904 905
{
	struct nfs_seqid *new;

906
	new = kmalloc(sizeof(*new), gfp_mask);
907 908
	if (new != NULL) {
		new->sequence = counter;
909
		INIT_LIST_HEAD(&new->list);
910 911 912 913
	}
	return new;
}

914
void nfs_release_seqid(struct nfs_seqid *seqid)
L
Linus Torvalds 已提交
915
{
916 917
	if (!list_empty(&seqid->list)) {
		struct rpc_sequence *sequence = seqid->sequence->sequence;
918

919
		spin_lock(&sequence->lock);
920
		list_del_init(&seqid->list);
921 922 923
		spin_unlock(&sequence->lock);
		rpc_wake_up(&sequence->wait);
	}
924 925 926 927 928
}

void nfs_free_seqid(struct nfs_seqid *seqid)
{
	nfs_release_seqid(seqid);
929
	kfree(seqid);
L
Linus Torvalds 已提交
930 931 932
}

/*
933 934 935 936
 * 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()
 */
937
static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
938
{
939
	BUG_ON(list_first_entry(&seqid->sequence->sequence->list, struct nfs_seqid, list) != seqid);
940 941 942 943
	switch (status) {
		case 0:
			break;
		case -NFS4ERR_BAD_SEQID:
944 945 946
			if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
				return;
			printk(KERN_WARNING "NFS: v4 server returned a bad"
D
Dan Muntz 已提交
947 948
					" sequence-id error on an"
					" unconfirmed sequence %p!\n",
949
					seqid->sequence);
950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967
		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)
{
968 969 970 971 972
	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 已提交
973
		nfs4_drop_state_owner(sp);
974 975
	if (!nfs4_has_session(server->nfs_client))
		nfs_increment_seqid(status, seqid);
976 977 978 979 980 981 982 983 984
}

/*
 * 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)
{
985
	nfs_increment_seqid(status, seqid);
986 987 988 989 990 991 992 993
}

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);
994 995 996 997
	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;
998
	rpc_sleep_on(&sequence->wait, task, NULL);
999 1000
	status = -EAGAIN;
unlock:
1001 1002
	spin_unlock(&sequence->lock);
	return status;
L
Linus Torvalds 已提交
1003 1004
}

1005
static int nfs4_run_state_manager(void *);
L
Linus Torvalds 已提交
1006

1007
static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
T
Trond Myklebust 已提交
1008 1009
{
	smp_mb__before_clear_bit();
1010
	clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
T
Trond Myklebust 已提交
1011
	smp_mb__after_clear_bit();
1012
	wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING);
T
Trond Myklebust 已提交
1013 1014 1015
	rpc_wake_up(&clp->cl_rpcwaitq);
}

L
Linus Torvalds 已提交
1016
/*
1017
 * Schedule the nfs_client asynchronous state management routine
L
Linus Torvalds 已提交
1018
 */
1019
void nfs4_schedule_state_manager(struct nfs_client *clp)
L
Linus Torvalds 已提交
1020
{
1021
	struct task_struct *task;
L
Linus Torvalds 已提交
1022

1023 1024
	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
		return;
1025 1026
	__module_get(THIS_MODULE);
	atomic_inc(&clp->cl_count);
1027
	task = kthread_run(nfs4_run_state_manager, clp, "%s-manager",
1028 1029
				rpc_peeraddr2str(clp->cl_rpcclient,
							RPC_DISPLAY_ADDR));
1030 1031
	if (!IS_ERR(task))
		return;
1032
	nfs4_clear_state_manager_bit(clp);
1033
	nfs_put_client(clp);
1034
	module_put(THIS_MODULE);
L
Linus Torvalds 已提交
1035 1036 1037
}

/*
1038
 * Schedule a lease recovery attempt
L
Linus Torvalds 已提交
1039
 */
1040
void nfs4_schedule_lease_recovery(struct nfs_client *clp)
L
Linus Torvalds 已提交
1041 1042 1043
{
	if (!clp)
		return;
1044 1045
	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
1046
	nfs4_schedule_state_manager(clp);
L
Linus Torvalds 已提交
1047 1048
}

1049 1050 1051 1052 1053 1054
void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
{
	nfs_handle_cb_pathdown(clp);
	nfs4_schedule_state_manager(clp);
}

1055
static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
1056 1057 1058 1059 1060 1061 1062 1063
{

	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;
	}
1064
	set_bit(NFS_OWNER_RECLAIM_REBOOT, &state->owner->so_flags);
1065 1066 1067 1068
	set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
	return 1;
}

1069
static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
1070 1071 1072
{
	set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
	clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
1073
	set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags);
1074 1075 1076 1077
	set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
	return 1;
}

1078 1079 1080 1081 1082 1083 1084 1085
void nfs4_schedule_stateid_recovery(const struct nfs_server *server, struct nfs4_state *state)
{
	struct nfs_client *clp = server->nfs_client;

	nfs4_state_mark_reclaim_nograce(clp, state);
	nfs4_schedule_state_manager(clp);
}

1086
static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
1087 1088
{
	struct inode *inode = state->inode;
1089
	struct nfs_inode *nfsi = NFS_I(inode);
L
Linus Torvalds 已提交
1090 1091 1092
	struct file_lock *fl;
	int status = 0;

1093 1094 1095 1096
	if (inode->i_flock == NULL)
		return 0;

	/* Guard against delegation returns and new lock/unlock calls */
1097
	down_write(&nfsi->rwsem);
1098
	/* Protect inode->i_flock using the BKL */
1099
	lock_flocks();
H
Harvey Harrison 已提交
1100
	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
1101
		if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
L
Linus Torvalds 已提交
1102
			continue;
1103
		if (nfs_file_open_context(fl->fl_file)->state != state)
L
Linus Torvalds 已提交
1104
			continue;
1105
		unlock_flocks();
L
Linus Torvalds 已提交
1106 1107
		status = ops->recover_lock(state, fl);
		switch (status) {
1108 1109 1110 1111 1112 1113 1114 1115 1116
			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:
1117 1118 1119 1120
			case -NFS4ERR_BADSESSION:
			case -NFS4ERR_BADSLOT:
			case -NFS4ERR_BAD_HIGH_SLOT:
			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1121
				goto out;
L
Linus Torvalds 已提交
1122 1123
			default:
				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
1124
						__func__, status);
1125 1126
			case -ENOMEM:
			case -NFS4ERR_DENIED:
L
Linus Torvalds 已提交
1127 1128
			case -NFS4ERR_RECLAIM_BAD:
			case -NFS4ERR_RECLAIM_CONFLICT:
1129
				/* kill_proc(fl->fl_pid, SIGLOST, 1); */
1130
				status = 0;
L
Linus Torvalds 已提交
1131
		}
1132
		lock_flocks();
L
Linus Torvalds 已提交
1133
	}
1134
	unlock_flocks();
1135
out:
1136
	up_write(&nfsi->rwsem);
L
Linus Torvalds 已提交
1137 1138 1139
	return status;
}

1140
static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
{
	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.
	 */
1154 1155
restart:
	spin_lock(&sp->so_lock);
L
Linus Torvalds 已提交
1156
	list_for_each_entry(state, &sp->so_states, open_states) {
1157 1158
		if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
			continue;
L
Linus Torvalds 已提交
1159 1160
		if (state->state == 0)
			continue;
1161 1162
		atomic_inc(&state->count);
		spin_unlock(&sp->so_lock);
L
Linus Torvalds 已提交
1163 1164
		status = ops->recover_open(sp, state);
		if (status >= 0) {
1165 1166
			status = nfs4_reclaim_locks(state, ops);
			if (status >= 0) {
1167
				spin_lock(&state->state_lock);
1168 1169 1170
				list_for_each_entry(lock, &state->lock_states, ls_locks) {
					if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
						printk("%s: Lock reclaim failed!\n",
1171
							__func__);
1172
				}
1173
				spin_unlock(&state->state_lock);
1174 1175
				nfs4_put_open_state(state);
				goto restart;
L
Linus Torvalds 已提交
1176 1177 1178 1179 1180
			}
		}
		switch (status) {
			default:
				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
1181
						__func__, status);
L
Linus Torvalds 已提交
1182
			case -ENOENT:
1183
			case -ENOMEM:
1184
			case -ESTALE:
L
Linus Torvalds 已提交
1185 1186 1187 1188 1189 1190 1191 1192 1193
				/*
				 * 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;
1194 1195 1196 1197 1198 1199 1200 1201
			case -EKEYEXPIRED:
				/*
				 * User RPCSEC_GSS context has expired.
				 * We cannot recover this stateid now, so
				 * skip it and allow recovery thread to
				 * proceed.
				 */
				break;
1202 1203 1204
			case -NFS4ERR_ADMIN_REVOKED:
			case -NFS4ERR_STALE_STATEID:
			case -NFS4ERR_BAD_STATEID:
1205 1206
			case -NFS4ERR_RECLAIM_BAD:
			case -NFS4ERR_RECLAIM_CONFLICT:
1207
				nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
1208
				break;
L
Linus Torvalds 已提交
1209 1210
			case -NFS4ERR_EXPIRED:
			case -NFS4ERR_NO_GRACE:
1211
				nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
L
Linus Torvalds 已提交
1212
			case -NFS4ERR_STALE_CLIENTID:
1213 1214 1215 1216
			case -NFS4ERR_BADSESSION:
			case -NFS4ERR_BADSLOT:
			case -NFS4ERR_BAD_HIGH_SLOT:
			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
L
Linus Torvalds 已提交
1217 1218
				goto out_err;
		}
1219 1220
		nfs4_put_open_state(state);
		goto restart;
L
Linus Torvalds 已提交
1221
	}
1222
	spin_unlock(&sp->so_lock);
L
Linus Torvalds 已提交
1223 1224
	return 0;
out_err:
1225
	nfs4_put_open_state(state);
L
Linus Torvalds 已提交
1226 1227 1228
	return status;
}

1229 1230 1231 1232 1233 1234 1235 1236
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);
1237
	spin_lock(&state->state_lock);
1238 1239 1240 1241
	list_for_each_entry(lock, &state->lock_states, ls_locks) {
		lock->ls_seqid.flags = 0;
		lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
	}
1242
	spin_unlock(&state->state_lock);
1243 1244
}

1245 1246
static void nfs4_reset_seqids(struct nfs_server *server,
	int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
1247
{
1248
	struct nfs_client *clp = server->nfs_client;
1249
	struct nfs4_state_owner *sp;
1250
	struct rb_node *pos;
1251 1252
	struct nfs4_state *state;

1253 1254 1255 1256 1257
	spin_lock(&clp->cl_lock);
	for (pos = rb_first(&server->state_owners);
	     pos != NULL;
	     pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
1258
		sp->so_seqid.flags = 0;
1259
		spin_lock(&sp->so_lock);
1260
		list_for_each_entry(state, &sp->so_states, open_states) {
1261 1262
			if (mark_reclaim(clp, state))
				nfs4_clear_open_state(state);
1263
		}
1264
		spin_unlock(&sp->so_lock);
1265
	}
1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
	spin_unlock(&clp->cl_lock);
}

static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp,
	int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
{
	struct nfs_server *server;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs4_reset_seqids(server, mark_reclaim);
	rcu_read_unlock();
1278 1279
}

1280 1281 1282 1283 1284 1285 1286
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);
}

1287 1288 1289 1290 1291 1292 1293 1294
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);
}

1295
static void nfs4_clear_reclaim_server(struct nfs_server *server)
1296
{
1297
	struct nfs_client *clp = server->nfs_client;
1298 1299 1300 1301
	struct nfs4_state_owner *sp;
	struct rb_node *pos;
	struct nfs4_state *state;

1302 1303 1304 1305 1306
	spin_lock(&clp->cl_lock);
	for (pos = rb_first(&server->state_owners);
	     pos != NULL;
	     pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_server_node);
1307 1308
		spin_lock(&sp->so_lock);
		list_for_each_entry(state, &sp->so_states, open_states) {
1309 1310
			if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT,
						&state->flags))
1311 1312 1313 1314 1315
				continue;
			nfs4_state_mark_reclaim_nograce(clp, state);
		}
		spin_unlock(&sp->so_lock);
	}
1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329
	spin_unlock(&clp->cl_lock);
}

static int nfs4_state_clear_reclaim_reboot(struct nfs_client *clp)
{
	struct nfs_server *server;

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

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs4_clear_reclaim_server(server);
	rcu_read_unlock();
1330 1331

	nfs_delegation_reap_unclaimed(clp);
1332 1333 1334 1335 1336 1337 1338 1339
	return 1;
}

static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
{
	if (!nfs4_state_clear_reclaim_reboot(clp))
		return;
	nfs4_reclaim_complete(clp, clp->cl_mvops->reboot_recovery_ops);
1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353
}

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);
}

1354 1355 1356 1357 1358 1359 1360 1361
static void nfs4_warn_keyexpired(const char *s)
{
	printk_ratelimited(KERN_WARNING "Error: state manager"
			" encountered RPCSEC_GSS session"
			" expired against NFSv4 server %s.\n",
			s);
}

1362
static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
1363 1364
{
	switch (error) {
1365 1366
		case 0:
			break;
1367
		case -NFS4ERR_CB_PATH_DOWN:
1368
			nfs_handle_cb_pathdown(clp);
1369
			break;
1370 1371
		case -NFS4ERR_NO_GRACE:
			nfs4_state_end_reclaim_reboot(clp);
1372
			break;
1373 1374 1375
		case -NFS4ERR_STALE_CLIENTID:
		case -NFS4ERR_LEASE_MOVED:
			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1376
			nfs4_state_clear_reclaim_reboot(clp);
1377 1378 1379 1380 1381
			nfs4_state_start_reclaim_reboot(clp);
			break;
		case -NFS4ERR_EXPIRED:
			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
			nfs4_state_start_reclaim_nograce(clp);
1382
			break;
1383 1384 1385 1386 1387 1388 1389
		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:
1390
			set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
1391
			/* Zero session reset errors */
1392
			break;
1393 1394 1395
		case -EKEYEXPIRED:
			/* Nothing we can do */
			nfs4_warn_keyexpired(clp->cl_hostname);
1396 1397 1398
			break;
		default:
			return error;
1399
	}
1400
	return 0;
1401 1402
}

1403
static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
1404
{
1405 1406
	struct nfs4_state_owner *sp;
	struct nfs_server *server;
1407
	struct rb_node *pos;
L
Linus Torvalds 已提交
1408 1409
	int status = 0;

1410
restart:
1411 1412
	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
1413
		nfs4_purge_state_owners(server);
1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
		spin_lock(&clp->cl_lock);
		for (pos = rb_first(&server->state_owners);
		     pos != NULL;
		     pos = rb_next(pos)) {
			sp = rb_entry(pos,
				struct nfs4_state_owner, so_server_node);
			if (!test_and_clear_bit(ops->owner_flag_bit,
							&sp->so_flags))
				continue;
			atomic_inc(&sp->so_count);
			spin_unlock(&clp->cl_lock);
			rcu_read_unlock();

			status = nfs4_reclaim_open_state(sp, ops);
			if (status < 0) {
				set_bit(ops->owner_flag_bit, &sp->so_flags);
				nfs4_put_state_owner(sp);
				return nfs4_recovery_handle_error(clp, status);
			}

1434
			nfs4_put_state_owner(sp);
1435
			goto restart;
1436
		}
1437
		spin_unlock(&clp->cl_lock);
1438
	}
1439
	rcu_read_unlock();
1440 1441 1442 1443 1444 1445
	return status;
}

static int nfs4_check_lease(struct nfs_client *clp)
{
	struct rpc_cred *cred;
1446 1447
	const struct nfs4_state_maintenance_ops *ops =
		clp->cl_mvops->state_renewal_ops;
1448
	int status;
L
Linus Torvalds 已提交
1449

1450 1451 1452
	/* Is the client already known to have an expired lease? */
	if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
		return 0;
1453 1454 1455
	spin_lock(&clp->cl_lock);
	cred = ops->get_state_renewal_cred_locked(clp);
	spin_unlock(&clp->cl_lock);
1456 1457
	if (cred == NULL) {
		cred = nfs4_get_setclientid_cred(clp);
1458
		status = -ENOKEY;
1459 1460
		if (cred == NULL)
			goto out;
1461
	}
1462
	status = ops->renew_lease(clp, cred);
1463 1464
	put_rpccred(cred);
out:
1465
	return nfs4_recovery_handle_error(clp, status);
1466 1467 1468 1469 1470
}

static int nfs4_reclaim_lease(struct nfs_client *clp)
{
	struct rpc_cred *cred;
1471 1472
	const struct nfs4_state_recovery_ops *ops =
		clp->cl_mvops->reboot_recovery_ops;
1473 1474
	int status = -ENOENT;

1475
	cred = ops->get_clid_cred(clp);
1476
	if (cred != NULL) {
1477
		status = ops->establish_clid(clp, cred);
1478
		put_rpccred(cred);
1479 1480 1481
		/* Handle case where the user hasn't set up machine creds */
		if (status == -EACCES && cred == clp->cl_machine_cred) {
			nfs4_clear_machine_cred(clp);
1482
			status = -EAGAIN;
1483
		}
1484 1485
		if (status == -NFS4ERR_MINOR_VERS_MISMATCH)
			status = -EPROTONOSUPPORT;
1486
	}
1487 1488 1489
	return status;
}

1490
#ifdef CONFIG_NFS_V4_1
1491 1492
void nfs4_schedule_session_recovery(struct nfs4_session *session)
{
1493 1494 1495 1496
	struct nfs_client *clp = session->clp;

	set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
	nfs4_schedule_lease_recovery(clp);
1497
}
1498
EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
1499

A
Andy Adamson 已提交
1500 1501 1502
void nfs41_handle_recall_slot(struct nfs_client *clp)
{
	set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
1503
	nfs4_schedule_state_manager(clp);
A
Andy Adamson 已提交
1504 1505
}

1506 1507 1508 1509 1510
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);
1511
		nfs4_schedule_state_manager(clp);
1512 1513 1514 1515 1516 1517 1518
	}
}

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);
1519
		nfs4_schedule_state_manager(clp);
1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538
	}
}

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)
1539
		nfs4_schedule_state_manager(clp);
1540 1541
}

1542 1543 1544 1545
void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
{
	if (!flags)
		return;
1546
	if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
1547
		nfs41_handle_server_reboot(clp);
1548
	if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
1549 1550
			    SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
			    SEQ4_STATUS_ADMIN_STATE_REVOKED |
1551 1552
			    SEQ4_STATUS_LEASE_MOVED))
		nfs41_handle_state_revoked(clp);
1553
	if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
1554
		nfs41_handle_recallable_state_revoked(clp);
1555
	if (flags & (SEQ4_STATUS_CB_PATH_DOWN |
1556 1557
			    SEQ4_STATUS_BACKCHANNEL_FAULT |
			    SEQ4_STATUS_CB_PATH_DOWN_SESSION))
1558
		nfs41_handle_cb_path_down(clp);
1559 1560
}

1561 1562 1563 1564
static int nfs4_reset_session(struct nfs_client *clp)
{
	int status;

1565
	nfs4_begin_drain_session(clp);
1566 1567 1568
	status = nfs4_proc_destroy_session(clp->cl_session);
	if (status && status != -NFS4ERR_BADSESSION &&
	    status != -NFS4ERR_DEADSESSION) {
1569
		status = nfs4_recovery_handle_error(clp, status);
1570 1571 1572 1573
		goto out;
	}

	memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
1574
	status = nfs4_proc_create_session(clp);
1575
	if (status) {
1576
		status = nfs4_recovery_handle_error(clp, status);
1577 1578
		goto out;
	}
1579
	clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
1580 1581
	/* create_session negotiated new slot table */
	clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
1582

1583 1584
	 /* Let the state manager reestablish state */
	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
1585
		nfs41_setup_state_renewal(clp);
1586
out:
1587 1588
	return status;
}
1589

A
Andy Adamson 已提交
1590 1591 1592 1593 1594 1595 1596 1597 1598
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),
1599
		      GFP_NOFS);
A
Andy Adamson 已提交
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617
        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;
}

1618
#else /* CONFIG_NFS_V4_1 */
1619
static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
1620
static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
A
Andy Adamson 已提交
1621
static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }
1622 1623
#endif /* CONFIG_NFS_V4_1 */

1624 1625 1626 1627 1628
/* 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)
{
1629 1630 1631 1632 1633 1634
	switch (status) {
	case -NFS4ERR_CLID_INUSE:
	case -NFS4ERR_STALE_CLIENTID:
		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
		break;
	case -NFS4ERR_DELAY:
1635
	case -ETIMEDOUT:
1636 1637 1638
	case -EAGAIN:
		ssleep(1);
		break;
1639

1640 1641 1642 1643 1644 1645
	case -EKEYEXPIRED:
		nfs4_warn_keyexpired(clp->cl_hostname);
	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
				 * in nfs4_exchange_id */
	default:
		return;
1646 1647 1648 1649
	}
	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
}

1650
static void nfs4_state_manager(struct nfs_client *clp)
1651 1652 1653 1654
{
	int status = 0;

	/* Ensure exclusive access to NFSv4 state */
1655
	do {
1656 1657 1658 1659
		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) {
1660
				nfs4_set_lease_expired(clp, status);
1661 1662
				if (test_bit(NFS4CLNT_LEASE_EXPIRED,
							&clp->cl_state))
1663
					continue;
1664 1665 1666
				if (clp->cl_cons_state ==
							NFS_CS_SESSION_INITING)
					nfs_mark_client_ready(clp, status);
1667 1668
				goto out_error;
			}
1669
			clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
1670 1671 1672 1673 1674 1675 1676 1677

			if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH,
					       &clp->cl_state))
				nfs4_state_start_reclaim_nograce(clp);
			else
				set_bit(NFS4CLNT_RECLAIM_REBOOT,
					&clp->cl_state);

1678
			pnfs_destroy_all_layouts(clp);
1679 1680 1681 1682
		}

		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
			status = nfs4_check_lease(clp);
1683 1684
			if (status < 0)
				goto out_error;
1685
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
1686
				continue;
1687
		}
1688

1689
		/* Initialize or reset the session */
1690
		if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)
1691
		   && nfs4_has_session(clp)) {
1692
			status = nfs4_reset_session(clp);
1693 1694 1695
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
				continue;
			if (status < 0)
1696 1697
				goto out_error;
		}
1698

1699
		/* First recover reboot state... */
1700
		if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
1701
			status = nfs4_do_reclaim(clp,
1702
				clp->cl_mvops->reboot_recovery_ops);
1703
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
1704
			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
1705
				continue;
1706
			nfs4_state_end_reclaim_reboot(clp);
1707 1708 1709 1710
			if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
				continue;
			if (status < 0)
				goto out_error;
1711 1712
		}

1713 1714
		/* Now recover expired state... */
		if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
1715
			status = nfs4_do_reclaim(clp,
1716
				clp->cl_mvops->nograce_recovery_ops);
1717
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
1718
			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) ||
1719 1720 1721
			    test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
				continue;
			if (status < 0)
1722
				goto out_error;
L
Linus Torvalds 已提交
1723
		}
1724

1725
		nfs4_end_drain_session(clp);
1726 1727 1728 1729
		if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
			nfs_client_return_marked_delegations(clp);
			continue;
		}
A
Andy Adamson 已提交
1730 1731 1732 1733 1734 1735 1736 1737 1738
		/* 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;
		}

1739 1740

		nfs4_clear_state_manager_bit(clp);
1741 1742 1743 1744 1745
		/* 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;
1746
	} while (atomic_read(&clp->cl_count) > 1);
1747
	return;
L
Linus Torvalds 已提交
1748
out_error:
1749
	printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
1750
			" with error %d\n", clp->cl_hostname, -status);
1751
	nfs4_end_drain_session(clp);
1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763
	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 已提交
1764 1765 1766 1767 1768 1769 1770
}

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