nfs4state.c 50.8 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

C
Chuck Lever 已提交
60 61
#define NFSDBG_FACILITY		NFSDBG_STATE

L
Linus Torvalds 已提交
62 63
#define OPENOWNER_POOL_SIZE	8

64
const nfs4_stateid zero_stateid;
L
Linus Torvalds 已提交
65 66 67

static LIST_HEAD(nfs4_clientid_list);

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

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

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

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

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

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

139 140 141 142 143 144 145 146 147 148 149 150
/**
 * 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;

151 152 153 154 155
	/* Use machine credentials if available */
	cred = nfs4_get_machine_cred_locked(clp);
	if (cred != NULL)
		goto out;

156 157 158 159 160 161 162
	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();
163 164

out:
165 166 167
	return cred;
}

168 169
#if defined(CONFIG_NFS_V4_1)

R
Ricardo Labiaga 已提交
170 171 172 173 174
static int nfs41_setup_state_renewal(struct nfs_client *clp)
{
	int status;
	struct nfs_fsinfo fsinfo;

175 176 177 178 179
	if (!test_bit(NFS_CS_CHECK_LEASE_TIME, &clp->cl_res_state)) {
		nfs4_schedule_state_renewal(clp);
		return 0;
	}

R
Ricardo Labiaga 已提交
180 181 182 183 184 185 186 187 188 189 190 191 192 193
	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;
}

194 195 196 197 198
/*
 * 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.
 */
199
static void nfs4_end_drain_session(struct nfs_client *clp)
200
{
201
	struct nfs4_session *ses = clp->cl_session;
202
	struct nfs4_slot_table *tbl;
203 204
	int max_slots;

205 206
	if (ses == NULL)
		return;
207
	tbl = &ses->fc_slot_table;
208
	if (test_and_clear_bit(NFS4_SESSION_DRAINING, &ses->session_state)) {
209 210
		spin_lock(&tbl->slot_tbl_lock);
		max_slots = tbl->max_slots;
211
		while (max_slots--) {
212 213 214
			if (rpc_wake_up_first(&tbl->slot_tbl_waitq,
						nfs4_set_task_privileged,
						NULL) == NULL)
215 216
				break;
		}
217
		spin_unlock(&tbl->slot_tbl_lock);
218
	}
219 220
}

221
static int nfs4_wait_on_slot_tbl(struct nfs4_slot_table *tbl)
222 223
{
	spin_lock(&tbl->slot_tbl_lock);
224
	if (tbl->highest_used_slotid != NFS4_NO_SLOT) {
225
		INIT_COMPLETION(tbl->complete);
226
		spin_unlock(&tbl->slot_tbl_lock);
227
		return wait_for_completion_interruptible(&tbl->complete);
228 229 230 231 232
	}
	spin_unlock(&tbl->slot_tbl_lock);
	return 0;
}

233 234 235 236 237 238 239 240 241 242 243 244 245 246
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);
}

247 248 249 250
int nfs41_init_clientid(struct nfs_client *clp, struct rpc_cred *cred)
{
	int status;

251 252
	if (test_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state))
		goto do_confirm;
253
	nfs4_begin_drain_session(clp);
254
	status = nfs4_proc_exchange_id(clp, cred);
R
Ricardo Labiaga 已提交
255 256
	if (status != 0)
		goto out;
257 258
	set_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
do_confirm:
259
	status = nfs4_proc_create_session(clp, cred);
R
Ricardo Labiaga 已提交
260 261
	if (status != 0)
		goto out;
262
	clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
R
Ricardo Labiaga 已提交
263 264 265
	nfs41_setup_state_renewal(clp);
	nfs_mark_client_ready(clp, NFS_CS_READY);
out:
266 267 268
	return status;
}

269 270 271 272 273 274 275 276 277 278 279 280
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 */

281 282
static struct rpc_cred *
nfs4_get_setclientid_cred_server(struct nfs_server *server)
283
{
284 285
	struct nfs_client *clp = server->nfs_client;
	struct rpc_cred *cred = NULL;
286
	struct nfs4_state_owner *sp;
287
	struct rb_node *pos;
288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307

	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;
308
	struct rpc_cred *cred;
309

310 311
	spin_lock(&clp->cl_lock);
	cred = nfs4_get_machine_cred_locked(clp);
312
	spin_unlock(&clp->cl_lock);
313 314
	if (cred != NULL)
		goto out;
315 316 317 318 319 320

	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;
321
	}
322 323
	rcu_read_unlock();

324 325
out:
	return cred;
326 327
}

L
Linus Torvalds 已提交
328
static struct nfs4_state_owner *
329
nfs4_find_state_owner_locked(struct nfs_server *server, struct rpc_cred *cred)
L
Linus Torvalds 已提交
330
{
331
	struct rb_node **p = &server->state_owners.rb_node,
332
		       *parent = NULL;
333
	struct nfs4_state_owner *sp;
L
Linus Torvalds 已提交
334

335 336
	while (*p != NULL) {
		parent = *p;
337
		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
338 339 340 341 342 343

		if (cred < sp->so_cred)
			p = &parent->rb_left;
		else if (cred > sp->so_cred)
			p = &parent->rb_right;
		else {
344 345
			if (!list_empty(&sp->so_lru))
				list_del_init(&sp->so_lru);
346
			atomic_inc(&sp->so_count);
347
			return sp;
348
		}
L
Linus Torvalds 已提交
349
	}
350
	return NULL;
L
Linus Torvalds 已提交
351 352
}

353
static struct nfs4_state_owner *
354
nfs4_insert_state_owner_locked(struct nfs4_state_owner *new)
355
{
356 357
	struct nfs_server *server = new->so_server;
	struct rb_node **p = &server->state_owners.rb_node,
358 359
		       *parent = NULL;
	struct nfs4_state_owner *sp;
360
	int err;
361 362 363

	while (*p != NULL) {
		parent = *p;
364
		sp = rb_entry(parent, struct nfs4_state_owner, so_server_node);
365 366 367 368 369 370

		if (new->so_cred < sp->so_cred)
			p = &parent->rb_left;
		else if (new->so_cred > sp->so_cred)
			p = &parent->rb_right;
		else {
371 372
			if (!list_empty(&sp->so_lru))
				list_del_init(&sp->so_lru);
373 374 375 376
			atomic_inc(&sp->so_count);
			return sp;
		}
	}
377
	err = ida_get_new(&server->openowner_id, &new->so_seqid.owner_id);
378 379
	if (err)
		return ERR_PTR(err);
380 381
	rb_link_node(&new->so_server_node, parent, p);
	rb_insert_color(&new->so_server_node, &server->state_owners);
382 383 384 385
	return new;
}

static void
386
nfs4_remove_state_owner_locked(struct nfs4_state_owner *sp)
387
{
388 389 390 391
	struct nfs_server *server = sp->so_server;

	if (!RB_EMPTY_NODE(&sp->so_server_node))
		rb_erase(&sp->so_server_node, &server->state_owners);
392
	ida_remove(&server->openowner_id, sp->so_seqid.owner_id);
393 394
}

395 396 397
static void
nfs4_init_seqid_counter(struct nfs_seqid_counter *sc)
{
398
	sc->create_time = ktime_get();
399 400 401 402 403 404 405 406 407 408 409 410 411
	sc->flags = 0;
	sc->counter = 0;
	spin_lock_init(&sc->lock);
	INIT_LIST_HEAD(&sc->list);
	rpc_init_wait_queue(&sc->wait, "Seqid_waitqueue");
}

static void
nfs4_destroy_seqid_counter(struct nfs_seqid_counter *sc)
{
	rpc_destroy_wait_queue(&sc->wait);
}

L
Linus Torvalds 已提交
412 413 414 415 416 417
/*
 * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to
 * create a new state_owner.
 *
 */
static struct nfs4_state_owner *
418 419 420
nfs4_alloc_state_owner(struct nfs_server *server,
		struct rpc_cred *cred,
		gfp_t gfp_flags)
L
Linus Torvalds 已提交
421 422 423
{
	struct nfs4_state_owner *sp;

424
	sp = kzalloc(sizeof(*sp), gfp_flags);
L
Linus Torvalds 已提交
425 426
	if (!sp)
		return NULL;
427 428
	sp->so_server = server;
	sp->so_cred = get_rpccred(cred);
429
	spin_lock_init(&sp->so_lock);
L
Linus Torvalds 已提交
430
	INIT_LIST_HEAD(&sp->so_states);
431
	nfs4_init_seqid_counter(&sp->so_seqid);
L
Linus Torvalds 已提交
432
	atomic_set(&sp->so_count, 1);
433
	INIT_LIST_HEAD(&sp->so_lru);
L
Linus Torvalds 已提交
434 435 436
	return sp;
}

437
static void
L
Linus Torvalds 已提交
438 439
nfs4_drop_state_owner(struct nfs4_state_owner *sp)
{
440 441 442
	struct rb_node *rb_node = &sp->so_server_node;

	if (!RB_EMPTY_NODE(rb_node)) {
443 444
		struct nfs_server *server = sp->so_server;
		struct nfs_client *clp = server->nfs_client;
445 446

		spin_lock(&clp->cl_lock);
447 448 449 450
		if (!RB_EMPTY_NODE(rb_node)) {
			rb_erase(rb_node, &server->state_owners);
			RB_CLEAR_NODE(rb_node);
		}
451 452
		spin_unlock(&clp->cl_lock);
	}
L
Linus Torvalds 已提交
453 454
}

455 456
static void nfs4_free_state_owner(struct nfs4_state_owner *sp)
{
457
	nfs4_destroy_seqid_counter(&sp->so_seqid);
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
	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);
	}
}

487 488 489 490 491 492 493 494
/**
 * 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,
495 496
					      struct rpc_cred *cred,
					      gfp_t gfp_flags)
L
Linus Torvalds 已提交
497
{
498
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
499 500 501
	struct nfs4_state_owner *sp, *new;

	spin_lock(&clp->cl_lock);
502
	sp = nfs4_find_state_owner_locked(server, cred);
L
Linus Torvalds 已提交
503 504
	spin_unlock(&clp->cl_lock);
	if (sp != NULL)
505
		goto out;
506
	new = nfs4_alloc_state_owner(server, cred, gfp_flags);
507
	if (new == NULL)
508
		goto out;
509 510 511 512 513 514 515
	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));
516 517
	if (sp != new)
		nfs4_free_state_owner(new);
518 519
out:
	nfs4_gc_state_owners(server);
520
	return sp;
L
Linus Torvalds 已提交
521 522
}

523 524 525
/**
 * nfs4_put_state_owner - Release a nfs4_state_owner
 * @sp: state owner data to release
526 527 528 529 530 531 532 533
 *
 * Note that we keep released state owners on an LRU
 * list.
 * This caches valid state owners so that they can be
 * reused, to avoid the OPEN_CONFIRM on minor version 0.
 * It also pins the uniquifier of dropped state owners for
 * a while, to ensure that those state owner names are
 * never reused.
534
 */
L
Linus Torvalds 已提交
535 536
void nfs4_put_state_owner(struct nfs4_state_owner *sp)
{
537 538
	struct nfs_server *server = sp->so_server;
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
539 540 541

	if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
		return;
542

543 544 545
	sp->so_expires = jiffies;
	list_add_tail(&sp->so_lru, &server->state_owners_lru);
	spin_unlock(&clp->cl_lock);
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565
}

/**
 * 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 已提交
566
	spin_unlock(&clp->cl_lock);
567 568 569 570 571

	list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
		list_del(&sp->so_lru);
		nfs4_free_state_owner(sp);
	}
L
Linus Torvalds 已提交
572 573 574 575 576 577 578
}

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

579
	state = kzalloc(sizeof(*state), GFP_NOFS);
L
Linus Torvalds 已提交
580 581 582 583
	if (!state)
		return NULL;
	atomic_set(&state->count, 1);
	INIT_LIST_HEAD(&state->lock_states);
584
	spin_lock_init(&state->state_lock);
585
	seqlock_init(&state->seqlock);
L
Linus Torvalds 已提交
586 587 588
	return state;
}

589
void
590
nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode)
591
{
592
	if (state->state == fmode)
593 594
		return;
	/* NB! List reordering - see the reclaim code for why.  */
595 596
	if ((fmode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {
		if (fmode & FMODE_WRITE)
597 598 599 600
			list_move(&state->open_states, &state->owner->so_states);
		else
			list_move_tail(&state->open_states, &state->owner->so_states);
	}
601
	state->state = fmode;
602 603
}

L
Linus Torvalds 已提交
604 605 606 607 608 609 610
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) {
611
		if (state->owner != owner)
L
Linus Torvalds 已提交
612
			continue;
613
		if (atomic_inc_not_zero(&state->count))
L
Linus Torvalds 已提交
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
			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();
637
	spin_lock(&owner->so_lock);
L
Linus Torvalds 已提交
638 639 640 641 642 643 644
	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);
645 646
		ihold(inode);
		state->inode = inode;
L
Linus Torvalds 已提交
647
		spin_unlock(&inode->i_lock);
648 649 650 651
		/* 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 已提交
652 653
	} else {
		spin_unlock(&inode->i_lock);
654
		spin_unlock(&owner->so_lock);
L
Linus Torvalds 已提交
655 656 657 658 659 660 661 662 663 664 665 666
		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;

667
	if (!atomic_dec_and_lock(&state->count, &owner->so_lock))
L
Linus Torvalds 已提交
668
		return;
669
	spin_lock(&inode->i_lock);
670
	list_del(&state->inode_states);
L
Linus Torvalds 已提交
671
	list_del(&state->open_states);
672 673
	spin_unlock(&inode->i_lock);
	spin_unlock(&owner->so_lock);
L
Linus Torvalds 已提交
674 675 676 677 678 679
	iput(inode);
	nfs4_free_open_state(state);
	nfs4_put_state_owner(owner);
}

/*
680
 * Close the current file.
L
Linus Torvalds 已提交
681
 */
682
static void __nfs4_close(struct nfs4_state *state,
683
		fmode_t fmode, gfp_t gfp_mask, int wait)
L
Linus Torvalds 已提交
684 685
{
	struct nfs4_state_owner *owner = state->owner;
686
	int call_close = 0;
687
	fmode_t newstate;
L
Linus Torvalds 已提交
688 689 690

	atomic_inc(&owner->so_count);
	/* Protect against nfs4_find_state() */
691
	spin_lock(&owner->so_lock);
692
	switch (fmode & (FMODE_READ | FMODE_WRITE)) {
693 694 695 696 697 698 699 700 701
		case FMODE_READ:
			state->n_rdonly--;
			break;
		case FMODE_WRITE:
			state->n_wronly--;
			break;
		case FMODE_READ|FMODE_WRITE:
			state->n_rdwr--;
	}
702
	newstate = FMODE_READ|FMODE_WRITE;
703
	if (state->n_rdwr == 0) {
704
		if (state->n_rdonly == 0) {
705
			newstate &= ~FMODE_READ;
706 707 708 709
			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) {
710
			newstate &= ~FMODE_WRITE;
711 712 713 714 715
			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);
716
	}
717
	nfs4_state_set_mode_locked(state, newstate);
718
	spin_unlock(&owner->so_lock);
719

720
	if (!call_close) {
721 722
		nfs4_put_open_state(state);
		nfs4_put_state_owner(owner);
F
Fred Isaman 已提交
723 724 725
	} else {
		bool roc = pnfs_roc(state->inode);

726
		nfs4_do_close(state, gfp_mask, wait, roc);
F
Fred Isaman 已提交
727
	}
728 729
}

730
void nfs4_close_state(struct nfs4_state *state, fmode_t fmode)
731
{
732
	__nfs4_close(state, fmode, GFP_NOFS, 0);
733 734
}

735
void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode)
736
{
737
	__nfs4_close(state, fmode, GFP_KERNEL, 1);
L
Linus Torvalds 已提交
738 739 740 741 742 743 744
}

/*
 * Search the state->lock_states for an existing lock_owner
 * that is compatible with current->files
 */
static struct nfs4_lock_state *
745
__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type)
L
Linus Torvalds 已提交
746 747 748
{
	struct nfs4_lock_state *pos;
	list_for_each_entry(pos, &state->lock_states, ls_locks) {
749
		if (type != NFS4_ANY_LOCK_TYPE && pos->ls_owner.lo_type != type)
L
Linus Torvalds 已提交
750
			continue;
751 752 753 754 755 756 757 758 759
		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 已提交
760 761 762 763 764 765 766 767 768 769 770
		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.
 *
 */
771
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 已提交
772 773
{
	struct nfs4_lock_state *lsp;
774
	struct nfs_server *server = state->owner->so_server;
L
Linus Torvalds 已提交
775

776
	lsp = kzalloc(sizeof(*lsp), GFP_NOFS);
L
Linus Torvalds 已提交
777 778
	if (lsp == NULL)
		return NULL;
779
	nfs4_init_seqid_counter(&lsp->ls_seqid);
L
Linus Torvalds 已提交
780
	atomic_set(&lsp->ls_count, 1);
781
	lsp->ls_state = state;
782 783 784 785 786 787 788 789 790
	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:
791
		goto out_free;
792
	}
793 794
	lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS);
	if (lsp->ls_seqid.owner_id < 0)
795
		goto out_free;
796
	INIT_LIST_HEAD(&lsp->ls_locks);
L
Linus Torvalds 已提交
797
	return lsp;
798 799 800
out_free:
	kfree(lsp);
	return NULL;
L
Linus Torvalds 已提交
801 802
}

803
void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
804
{
805
	ida_simple_remove(&server->lockowner_id, lsp->ls_seqid.owner_id);
806
	nfs4_destroy_seqid_counter(&lsp->ls_seqid);
807 808 809
	kfree(lsp);
}

L
Linus Torvalds 已提交
810 811 812 813 814
/*
 * Return a compatible lock_state. If no initialized lock_state structure
 * exists, return an uninitialized one.
 *
 */
815
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 已提交
816
{
817
	struct nfs4_lock_state *lsp, *new = NULL;
L
Linus Torvalds 已提交
818
	
819 820
	for(;;) {
		spin_lock(&state->state_lock);
821
		lsp = __nfs4_find_lock_state(state, owner, pid, type);
822 823 824 825 826 827 828 829 830 831
		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);
832
		new = nfs4_alloc_lock_state(state, owner, pid, type);
833 834 835 836
		if (new == NULL)
			return NULL;
	}
	spin_unlock(&state->state_lock);
837
	if (new != NULL)
838
		nfs4_free_lock_state(state->owner->so_server, new);
L
Linus Torvalds 已提交
839 840 841 842
	return lsp;
}

/*
843 844
 * Release reference to lock_state, and free it if we see that
 * it is no longer in use
L
Linus Torvalds 已提交
845
 */
846
void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
L
Linus Torvalds 已提交
847
{
848
	struct nfs4_state *state;
L
Linus Torvalds 已提交
849

850 851 852 853 854 855 856 857 858
	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);
859 860 861 862
	if (lsp->ls_flags & NFS_LOCK_INITIALIZED) {
		if (nfs4_release_lockowner(lsp) == 0)
			return;
	}
863
	nfs4_free_lock_state(lsp->ls_state->owner->so_server, lsp);
L
Linus Torvalds 已提交
864 865
}

866
static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
L
Linus Torvalds 已提交
867
{
868
	struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner;
L
Linus Torvalds 已提交
869

870 871 872
	dst->fl_u.nfs4_fl.owner = lsp;
	atomic_inc(&lsp->ls_count);
}
L
Linus Torvalds 已提交
873

874
static void nfs4_fl_release_lock(struct file_lock *fl)
L
Linus Torvalds 已提交
875
{
876
	nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner);
L
Linus Torvalds 已提交
877 878
}

879
static const struct file_lock_operations nfs4_fl_lock_ops = {
880 881 882 883 884
	.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 已提交
885
{
886 887 888 889
	struct nfs4_lock_state *lsp;

	if (fl->fl_ops != NULL)
		return 0;
890 891 892
	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)
893 894
		lsp = nfs4_get_lock_state(state, NULL, fl->fl_pid,
				NFS4_FLOCK_LOCK_TYPE);
895 896
	else
		return -EINVAL;
897 898 899 900 901
	if (lsp == NULL)
		return -ENOMEM;
	fl->fl_u.nfs4_fl.owner = lsp;
	fl->fl_ops = &nfs4_fl_lock_ops;
	return 0;
L
Linus Torvalds 已提交
902 903
}

904 905
static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
		fl_owner_t fl_owner, pid_t fl_pid)
L
Linus Torvalds 已提交
906
{
907
	struct nfs4_lock_state *lsp;
908
	bool ret = false;
L
Linus Torvalds 已提交
909

910
	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
911
		goto out;
L
Linus Torvalds 已提交
912

913
	spin_lock(&state->state_lock);
914
	lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
915
	if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) {
916
		nfs4_stateid_copy(dst, &lsp->ls_stateid);
917 918
		ret = true;
	}
919
	spin_unlock(&state->state_lock);
L
Linus Torvalds 已提交
920
	nfs4_put_lock_state(lsp);
921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946
out:
	return ret;
}

static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
{
	int seq;

	do {
		seq = read_seqbegin(&state->seqlock);
		nfs4_stateid_copy(dst, &state->stateid);
	} while (read_seqretry(&state->seqlock, seq));
}

/*
 * Byte-range lock aware utility to initialize the stateid of read/write
 * requests.
 */
void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
		fmode_t fmode, fl_owner_t fl_owner, pid_t fl_pid)
{
	if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
		return;
	if (nfs4_copy_lock_stateid(dst, state, fl_owner, fl_pid))
		return;
	nfs4_copy_open_stateid(dst, state);
L
Linus Torvalds 已提交
947 948
}

949
struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
950 951 952
{
	struct nfs_seqid *new;

953
	new = kmalloc(sizeof(*new), gfp_mask);
954 955
	if (new != NULL) {
		new->sequence = counter;
956
		INIT_LIST_HEAD(&new->list);
957
		new->task = NULL;
958 959 960 961
	}
	return new;
}

962
void nfs_release_seqid(struct nfs_seqid *seqid)
L
Linus Torvalds 已提交
963
{
964
	struct nfs_seqid_counter *sequence;
965

966 967 968 969 970 971 972 973 974 975 976
	if (list_empty(&seqid->list))
		return;
	sequence = seqid->sequence;
	spin_lock(&sequence->lock);
	list_del_init(&seqid->list);
	if (!list_empty(&sequence->list)) {
		struct nfs_seqid *next;

		next = list_first_entry(&sequence->list,
				struct nfs_seqid, list);
		rpc_wake_up_queued_task(&sequence->wait, next->task);
977
	}
978
	spin_unlock(&sequence->lock);
979 980 981 982 983
}

void nfs_free_seqid(struct nfs_seqid *seqid)
{
	nfs_release_seqid(seqid);
984
	kfree(seqid);
L
Linus Torvalds 已提交
985 986 987
}

/*
988 989 990 991
 * 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()
 */
992
static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
993
{
994
	BUG_ON(list_first_entry(&seqid->sequence->list, struct nfs_seqid, list) != seqid);
995 996 997 998
	switch (status) {
		case 0:
			break;
		case -NFS4ERR_BAD_SEQID:
999 1000
			if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
				return;
1001
			pr_warn_ratelimited("NFS: v4 server returned a bad"
D
Dan Muntz 已提交
1002 1003
					" sequence-id error on an"
					" unconfirmed sequence %p!\n",
1004
					seqid->sequence);
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
		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)
{
1023 1024 1025 1026 1027
	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 已提交
1028
		nfs4_drop_state_owner(sp);
1029 1030
	if (!nfs4_has_session(server->nfs_client))
		nfs_increment_seqid(status, seqid);
1031 1032 1033 1034 1035 1036 1037 1038 1039
}

/*
 * 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)
{
1040
	nfs_increment_seqid(status, seqid);
1041 1042 1043 1044
}

int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task)
{
1045
	struct nfs_seqid_counter *sequence = seqid->sequence;
1046 1047 1048
	int status = 0;

	spin_lock(&sequence->lock);
1049
	seqid->task = task;
1050 1051 1052 1053
	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;
1054
	rpc_sleep_on(&sequence->wait, task, NULL);
1055 1056
	status = -EAGAIN;
unlock:
1057 1058
	spin_unlock(&sequence->lock);
	return status;
L
Linus Torvalds 已提交
1059 1060
}

1061
static int nfs4_run_state_manager(void *);
L
Linus Torvalds 已提交
1062

1063
static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
T
Trond Myklebust 已提交
1064 1065
{
	smp_mb__before_clear_bit();
1066
	clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
T
Trond Myklebust 已提交
1067
	smp_mb__after_clear_bit();
1068
	wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING);
T
Trond Myklebust 已提交
1069 1070 1071
	rpc_wake_up(&clp->cl_rpcwaitq);
}

L
Linus Torvalds 已提交
1072
/*
1073
 * Schedule the nfs_client asynchronous state management routine
L
Linus Torvalds 已提交
1074
 */
1075
void nfs4_schedule_state_manager(struct nfs_client *clp)
L
Linus Torvalds 已提交
1076
{
1077
	struct task_struct *task;
1078
	char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
L
Linus Torvalds 已提交
1079

1080 1081
	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
		return;
1082 1083
	__module_get(THIS_MODULE);
	atomic_inc(&clp->cl_count);
1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099

	/* The rcu_read_lock() is not strictly necessary, as the state
	 * manager is the only thread that ever changes the rpc_xprt
	 * after it's initialized.  At this point, we're single threaded. */
	rcu_read_lock();
	snprintf(buf, sizeof(buf), "%s-manager",
			rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
	rcu_read_unlock();
	task = kthread_run(nfs4_run_state_manager, clp, buf);
	if (IS_ERR(task)) {
		printk(KERN_ERR "%s: kthread_run: %ld\n",
			__func__, PTR_ERR(task));
		nfs4_clear_state_manager_bit(clp);
		nfs_put_client(clp);
		module_put(THIS_MODULE);
	}
L
Linus Torvalds 已提交
1100 1101 1102
}

/*
1103
 * Schedule a lease recovery attempt
L
Linus Torvalds 已提交
1104
 */
1105
void nfs4_schedule_lease_recovery(struct nfs_client *clp)
L
Linus Torvalds 已提交
1106 1107 1108
{
	if (!clp)
		return;
1109 1110
	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
1111
	nfs4_schedule_state_manager(clp);
L
Linus Torvalds 已提交
1112
}
A
Andy Adamson 已提交
1113
EXPORT_SYMBOL_GPL(nfs4_schedule_lease_recovery);
L
Linus Torvalds 已提交
1114

1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128
/*
 * nfs40_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
 * @clp: client to process
 *
 * Set the NFS4CLNT_LEASE_EXPIRED state in order to force a
 * resend of the SETCLIENTID and hence re-establish the
 * callback channel. Then return all existing delegations.
 */
static void nfs40_handle_cb_pathdown(struct nfs_client *clp)
{
	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
	nfs_expire_all_delegations(clp);
}

1129 1130
void nfs4_schedule_path_down_recovery(struct nfs_client *clp)
{
1131
	nfs40_handle_cb_pathdown(clp);
1132 1133 1134
	nfs4_schedule_state_manager(clp);
}

1135
static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
1136 1137 1138 1139 1140 1141 1142 1143
{

	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;
	}
1144
	set_bit(NFS_OWNER_RECLAIM_REBOOT, &state->owner->so_flags);
1145 1146 1147 1148
	set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
	return 1;
}

1149
static int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
1150 1151 1152
{
	set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
	clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
1153
	set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags);
1154 1155 1156 1157
	set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
	return 1;
}

1158 1159 1160 1161 1162 1163 1164
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);
}
A
Andy Adamson 已提交
1165
EXPORT_SYMBOL_GPL(nfs4_schedule_stateid_recovery);
1166

1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182
void nfs_inode_find_state_and_recover(struct inode *inode,
		const nfs4_stateid *stateid)
{
	struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_open_context *ctx;
	struct nfs4_state *state;
	bool found = false;

	spin_lock(&inode->i_lock);
	list_for_each_entry(ctx, &nfsi->open_files, list) {
		state = ctx->state;
		if (state == NULL)
			continue;
		if (!test_bit(NFS_DELEGATED_STATE, &state->flags))
			continue;
1183
		if (!nfs4_stateid_match(&state->stateid, stateid))
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
			continue;
		nfs4_state_mark_reclaim_nograce(clp, state);
		found = true;
	}
	spin_unlock(&inode->i_lock);
	if (found)
		nfs4_schedule_state_manager(clp);
}


1194
static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
1195 1196
{
	struct inode *inode = state->inode;
1197
	struct nfs_inode *nfsi = NFS_I(inode);
L
Linus Torvalds 已提交
1198 1199 1200
	struct file_lock *fl;
	int status = 0;

1201 1202 1203 1204
	if (inode->i_flock == NULL)
		return 0;

	/* Guard against delegation returns and new lock/unlock calls */
1205
	down_write(&nfsi->rwsem);
1206
	/* Protect inode->i_flock using the BKL */
1207
	lock_flocks();
H
Harvey Harrison 已提交
1208
	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
1209
		if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
L
Linus Torvalds 已提交
1210
			continue;
1211
		if (nfs_file_open_context(fl->fl_file)->state != state)
L
Linus Torvalds 已提交
1212
			continue;
1213
		unlock_flocks();
L
Linus Torvalds 已提交
1214 1215
		status = ops->recover_lock(state, fl);
		switch (status) {
1216 1217 1218 1219 1220 1221 1222 1223 1224
			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:
1225 1226 1227 1228
			case -NFS4ERR_BADSESSION:
			case -NFS4ERR_BADSLOT:
			case -NFS4ERR_BAD_HIGH_SLOT:
			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
1229
				goto out;
L
Linus Torvalds 已提交
1230
			default:
1231 1232
				printk(KERN_ERR "NFS: %s: unhandled error %d. "
					"Zeroing state\n", __func__, status);
1233 1234
			case -ENOMEM:
			case -NFS4ERR_DENIED:
L
Linus Torvalds 已提交
1235 1236
			case -NFS4ERR_RECLAIM_BAD:
			case -NFS4ERR_RECLAIM_CONFLICT:
1237
				/* kill_proc(fl->fl_pid, SIGLOST, 1); */
1238
				status = 0;
L
Linus Torvalds 已提交
1239
		}
1240
		lock_flocks();
L
Linus Torvalds 已提交
1241
	}
1242
	unlock_flocks();
1243
out:
1244
	up_write(&nfsi->rwsem);
L
Linus Torvalds 已提交
1245 1246 1247
	return status;
}

1248
static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261
{
	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.
	 */
1262 1263
restart:
	spin_lock(&sp->so_lock);
L
Linus Torvalds 已提交
1264
	list_for_each_entry(state, &sp->so_states, open_states) {
1265 1266
		if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
			continue;
L
Linus Torvalds 已提交
1267 1268
		if (state->state == 0)
			continue;
1269 1270
		atomic_inc(&state->count);
		spin_unlock(&sp->so_lock);
L
Linus Torvalds 已提交
1271 1272
		status = ops->recover_open(sp, state);
		if (status >= 0) {
1273 1274
			status = nfs4_reclaim_locks(state, ops);
			if (status >= 0) {
1275
				spin_lock(&state->state_lock);
1276 1277
				list_for_each_entry(lock, &state->lock_states, ls_locks) {
					if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
1278 1279
						pr_warn_ratelimited("NFS: "
							"%s: Lock reclaim "
1280
							"failed!\n", __func__);
1281
				}
1282
				spin_unlock(&state->state_lock);
1283 1284
				nfs4_put_open_state(state);
				goto restart;
L
Linus Torvalds 已提交
1285 1286 1287 1288
			}
		}
		switch (status) {
			default:
1289 1290
				printk(KERN_ERR "NFS: %s: unhandled error %d. "
					"Zeroing state\n", __func__, status);
L
Linus Torvalds 已提交
1291
			case -ENOENT:
1292
			case -ENOMEM:
1293
			case -ESTALE:
L
Linus Torvalds 已提交
1294 1295 1296 1297
				/*
				 * Open state on this file cannot be recovered
				 * All we can do is revert to using the zero stateid.
				 */
1298 1299
				memset(&state->stateid, 0,
					sizeof(state->stateid));
L
Linus Torvalds 已提交
1300 1301 1302
				/* Mark the file as being 'closed' */
				state->state = 0;
				break;
1303 1304 1305 1306 1307 1308 1309 1310
			case -EKEYEXPIRED:
				/*
				 * User RPCSEC_GSS context has expired.
				 * We cannot recover this stateid now, so
				 * skip it and allow recovery thread to
				 * proceed.
				 */
				break;
1311 1312 1313
			case -NFS4ERR_ADMIN_REVOKED:
			case -NFS4ERR_STALE_STATEID:
			case -NFS4ERR_BAD_STATEID:
1314 1315
			case -NFS4ERR_RECLAIM_BAD:
			case -NFS4ERR_RECLAIM_CONFLICT:
1316
				nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
1317
				break;
L
Linus Torvalds 已提交
1318 1319
			case -NFS4ERR_EXPIRED:
			case -NFS4ERR_NO_GRACE:
1320
				nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
L
Linus Torvalds 已提交
1321
			case -NFS4ERR_STALE_CLIENTID:
1322 1323 1324 1325
			case -NFS4ERR_BADSESSION:
			case -NFS4ERR_BADSLOT:
			case -NFS4ERR_BAD_HIGH_SLOT:
			case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
L
Linus Torvalds 已提交
1326 1327
				goto out_err;
		}
1328 1329
		nfs4_put_open_state(state);
		goto restart;
L
Linus Torvalds 已提交
1330
	}
1331
	spin_unlock(&sp->so_lock);
L
Linus Torvalds 已提交
1332 1333
	return 0;
out_err:
1334
	nfs4_put_open_state(state);
L
Linus Torvalds 已提交
1335 1336 1337
	return status;
}

1338 1339 1340 1341 1342 1343 1344 1345
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);
1346
	spin_lock(&state->state_lock);
1347 1348 1349 1350
	list_for_each_entry(lock, &state->lock_states, ls_locks) {
		lock->ls_seqid.flags = 0;
		lock->ls_flags &= ~NFS_LOCK_INITIALIZED;
	}
1351
	spin_unlock(&state->state_lock);
1352 1353
}

1354 1355
static void nfs4_reset_seqids(struct nfs_server *server,
	int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
1356
{
1357
	struct nfs_client *clp = server->nfs_client;
1358
	struct nfs4_state_owner *sp;
1359
	struct rb_node *pos;
1360 1361
	struct nfs4_state *state;

1362 1363 1364 1365 1366
	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);
1367
		sp->so_seqid.flags = 0;
1368
		spin_lock(&sp->so_lock);
1369
		list_for_each_entry(state, &sp->so_states, open_states) {
1370 1371
			if (mark_reclaim(clp, state))
				nfs4_clear_open_state(state);
1372
		}
1373
		spin_unlock(&sp->so_lock);
1374
	}
1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386
	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();
1387 1388
}

1389 1390 1391 1392 1393 1394 1395
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);
}

1396 1397 1398 1399 1400 1401 1402 1403
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);
}

1404
static void nfs4_clear_reclaim_server(struct nfs_server *server)
1405
{
1406
	struct nfs_client *clp = server->nfs_client;
1407 1408 1409 1410
	struct nfs4_state_owner *sp;
	struct rb_node *pos;
	struct nfs4_state *state;

1411 1412 1413 1414 1415
	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);
1416 1417
		spin_lock(&sp->so_lock);
		list_for_each_entry(state, &sp->so_states, open_states) {
1418 1419
			if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT,
						&state->flags))
1420 1421 1422 1423 1424
				continue;
			nfs4_state_mark_reclaim_nograce(clp, state);
		}
		spin_unlock(&sp->so_lock);
	}
1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
	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();
1439 1440

	nfs_delegation_reap_unclaimed(clp);
1441 1442 1443 1444 1445 1446 1447 1448
	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);
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462
}

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

1463 1464 1465 1466 1467 1468 1469 1470
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);
}

1471
static int nfs4_recovery_handle_error(struct nfs_client *clp, int error)
1472 1473
{
	switch (error) {
1474 1475
		case 0:
			break;
1476
		case -NFS4ERR_CB_PATH_DOWN:
1477
			nfs40_handle_cb_pathdown(clp);
1478
			break;
1479 1480
		case -NFS4ERR_NO_GRACE:
			nfs4_state_end_reclaim_reboot(clp);
1481
			break;
1482 1483 1484
		case -NFS4ERR_STALE_CLIENTID:
		case -NFS4ERR_LEASE_MOVED:
			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
1485
			nfs4_state_clear_reclaim_reboot(clp);
1486 1487 1488 1489 1490
			nfs4_state_start_reclaim_reboot(clp);
			break;
		case -NFS4ERR_EXPIRED:
			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
			nfs4_state_start_reclaim_nograce(clp);
1491
			break;
1492 1493 1494 1495 1496 1497
		case -NFS4ERR_BADSESSION:
		case -NFS4ERR_BADSLOT:
		case -NFS4ERR_BAD_HIGH_SLOT:
		case -NFS4ERR_DEADSESSION:
		case -NFS4ERR_SEQ_FALSE_RETRY:
		case -NFS4ERR_SEQ_MISORDERED:
1498
			set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
1499
			/* Zero session reset errors */
1500
			break;
1501 1502 1503
		case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
			set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
			break;
1504 1505 1506
		case -EKEYEXPIRED:
			/* Nothing we can do */
			nfs4_warn_keyexpired(clp->cl_hostname);
1507 1508 1509
			break;
		default:
			return error;
1510
	}
1511
	return 0;
1512 1513
}

1514
static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
1515
{
1516 1517
	struct nfs4_state_owner *sp;
	struct nfs_server *server;
1518
	struct rb_node *pos;
L
Linus Torvalds 已提交
1519 1520
	int status = 0;

1521
restart:
1522 1523
	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
1524
		nfs4_purge_state_owners(server);
1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544
		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);
			}

1545
			nfs4_put_state_owner(sp);
1546
			goto restart;
1547
		}
1548
		spin_unlock(&clp->cl_lock);
1549
	}
1550
	rcu_read_unlock();
1551 1552 1553 1554 1555 1556
	return status;
}

static int nfs4_check_lease(struct nfs_client *clp)
{
	struct rpc_cred *cred;
1557 1558
	const struct nfs4_state_maintenance_ops *ops =
		clp->cl_mvops->state_renewal_ops;
1559
	int status;
L
Linus Torvalds 已提交
1560

1561 1562 1563
	/* Is the client already known to have an expired lease? */
	if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
		return 0;
1564 1565 1566
	spin_lock(&clp->cl_lock);
	cred = ops->get_state_renewal_cred_locked(clp);
	spin_unlock(&clp->cl_lock);
1567 1568
	if (cred == NULL) {
		cred = nfs4_get_setclientid_cred(clp);
1569
		status = -ENOKEY;
1570 1571
		if (cred == NULL)
			goto out;
1572
	}
1573
	status = ops->renew_lease(clp, cred);
1574 1575
	put_rpccred(cred);
out:
1576
	return nfs4_recovery_handle_error(clp, status);
1577 1578
}

1579 1580 1581 1582 1583 1584
/* Set NFS4CLNT_LEASE_EXPIRED for all v4.0 errors and for recoverable errors
 * on EXCHANGE_ID for v4.1
 */
static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
{
	switch (status) {
1585 1586 1587 1588 1589
	case -NFS4ERR_SEQ_MISORDERED:
		if (test_and_set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state))
			return -ESERVERFAULT;
		/* Lease confirmation error: retry after purging the lease */
		ssleep(1);
1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619
	case -NFS4ERR_CLID_INUSE:
	case -NFS4ERR_STALE_CLIENTID:
		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
		break;
	case -EACCES:
		if (clp->cl_machine_cred == NULL)
			return -EACCES;
		/* Handle case where the user hasn't set up machine creds */
		nfs4_clear_machine_cred(clp);
	case -NFS4ERR_DELAY:
	case -ETIMEDOUT:
	case -EAGAIN:
		ssleep(1);
		break;

	case -NFS4ERR_MINOR_VERS_MISMATCH:
		if (clp->cl_cons_state == NFS_CS_SESSION_INITING)
			nfs_mark_client_ready(clp, -EPROTONOSUPPORT);
		return -EPROTONOSUPPORT;
	case -EKEYEXPIRED:
		nfs4_warn_keyexpired(clp->cl_hostname);
	case -NFS4ERR_NOT_SAME: /* FixMe: implement recovery
				 * in nfs4_exchange_id */
	default:
		return status;
	}
	set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
	return 0;
}

1620 1621 1622
static int nfs4_reclaim_lease(struct nfs_client *clp)
{
	struct rpc_cred *cred;
1623 1624
	const struct nfs4_state_recovery_ops *ops =
		clp->cl_mvops->reboot_recovery_ops;
1625
	int status;
1626

1627
	cred = ops->get_clid_cred(clp);
1628 1629 1630 1631 1632 1633 1634
	if (cred == NULL)
		return -ENOENT;
	status = ops->establish_clid(clp, cred);
	put_rpccred(cred);
	if (status != 0)
		return nfs4_handle_reclaim_lease_error(clp, status);
	return 0;
1635 1636
}

1637
#ifdef CONFIG_NFS_V4_1
1638 1639
void nfs4_schedule_session_recovery(struct nfs4_session *session)
{
1640 1641 1642 1643
	struct nfs_client *clp = session->clp;

	set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
	nfs4_schedule_lease_recovery(clp);
1644
}
1645
EXPORT_SYMBOL_GPL(nfs4_schedule_session_recovery);
1646

A
Andy Adamson 已提交
1647 1648 1649
void nfs41_handle_recall_slot(struct nfs_client *clp)
{
	set_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
1650
	nfs4_schedule_state_manager(clp);
A
Andy Adamson 已提交
1651 1652
}

1653 1654 1655
static void nfs4_reset_all_state(struct nfs_client *clp)
{
	if (test_and_set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) == 0) {
1656
		set_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
1657
		clear_bit(NFS4CLNT_LEASE_CONFIRM, &clp->cl_state);
1658
		nfs4_state_start_reclaim_nograce(clp);
1659
		nfs4_schedule_state_manager(clp);
1660 1661 1662 1663 1664 1665 1666
	}
}

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);
1667
		nfs4_schedule_state_manager(clp);
1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681
	}
}

static void nfs41_handle_state_revoked(struct nfs_client *clp)
{
	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);
}

1682
static void nfs41_handle_backchannel_fault(struct nfs_client *clp)
1683 1684 1685
{
	nfs_expire_all_delegations(clp);
	if (test_and_set_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) == 0)
1686
		nfs4_schedule_state_manager(clp);
1687 1688
}

1689 1690 1691 1692 1693 1694 1695
static void nfs41_handle_cb_path_down(struct nfs_client *clp)
{
	if (test_and_set_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
		&clp->cl_state) == 0)
		nfs4_schedule_state_manager(clp);
}

1696 1697 1698 1699
void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags)
{
	if (!flags)
		return;
1700 1701 1702 1703

	dprintk("%s: \"%s\" (client ID %llx) flags=0x%08x\n",
		__func__, clp->cl_hostname, clp->cl_clientid, flags);

1704
	if (flags & SEQ4_STATUS_RESTART_RECLAIM_NEEDED)
1705
		nfs41_handle_server_reboot(clp);
1706
	if (flags & (SEQ4_STATUS_EXPIRED_ALL_STATE_REVOKED |
1707 1708
			    SEQ4_STATUS_EXPIRED_SOME_STATE_REVOKED |
			    SEQ4_STATUS_ADMIN_STATE_REVOKED |
1709 1710
			    SEQ4_STATUS_LEASE_MOVED))
		nfs41_handle_state_revoked(clp);
1711
	if (flags & SEQ4_STATUS_RECALLABLE_STATE_REVOKED)
1712
		nfs41_handle_recallable_state_revoked(clp);
1713 1714 1715 1716
	if (flags & SEQ4_STATUS_BACKCHANNEL_FAULT)
		nfs41_handle_backchannel_fault(clp);
	else if (flags & (SEQ4_STATUS_CB_PATH_DOWN |
				SEQ4_STATUS_CB_PATH_DOWN_SESSION))
1717
		nfs41_handle_cb_path_down(clp);
1718 1719
}

1720 1721
static int nfs4_reset_session(struct nfs_client *clp)
{
1722
	struct rpc_cred *cred;
1723 1724
	int status;

1725
	nfs4_begin_drain_session(clp);
1726 1727
	cred = nfs4_get_exchange_id_cred(clp);
	status = nfs4_proc_destroy_session(clp->cl_session, cred);
1728 1729
	if (status && status != -NFS4ERR_BADSESSION &&
	    status != -NFS4ERR_DEADSESSION) {
1730
		status = nfs4_recovery_handle_error(clp, status);
1731 1732 1733 1734
		goto out;
	}

	memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
1735
	status = nfs4_proc_create_session(clp, cred);
1736
	if (status) {
1737
		status = nfs4_recovery_handle_error(clp, status);
1738 1739
		goto out;
	}
1740
	clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state);
1741 1742
	/* create_session negotiated new slot table */
	clear_bit(NFS4CLNT_RECALL_SLOT, &clp->cl_state);
1743
	clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
1744

1745 1746
	 /* Let the state manager reestablish state */
	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
1747
		nfs41_setup_state_renewal(clp);
1748
out:
1749 1750
	if (cred)
		put_rpccred(cred);
1751 1752
	return status;
}
1753

A
Andy Adamson 已提交
1754 1755 1756 1757 1758 1759 1760 1761 1762
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),
1763
		      GFP_NOFS);
A
Andy Adamson 已提交
1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781
        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;
}

1782 1783
static int nfs4_bind_conn_to_session(struct nfs_client *clp)
{
1784 1785 1786
	struct rpc_cred *cred;
	int ret;

1787
	nfs4_begin_drain_session(clp);
1788 1789 1790 1791
	cred = nfs4_get_exchange_id_cred(clp);
	ret = nfs4_proc_bind_conn_to_session(clp, cred);
	if (cred)
		put_rpccred(cred);
1792
	clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
	switch (ret) {
	case 0:
		break;
	case -NFS4ERR_DELAY:
		ssleep(1);
		set_bit(NFS4CLNT_BIND_CONN_TO_SESSION, &clp->cl_state);
		break;
	default:
		return nfs4_recovery_handle_error(clp, ret);
	}
	return 0;
1804
}
1805
#else /* CONFIG_NFS_V4_1 */
1806
static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
1807
static int nfs4_end_drain_session(struct nfs_client *clp) { return 0; }
A
Andy Adamson 已提交
1808
static int nfs4_recall_slot(struct nfs_client *clp) { return 0; }
1809 1810 1811 1812 1813

static int nfs4_bind_conn_to_session(struct nfs_client *clp)
{
	return 0;
}
1814 1815
#endif /* CONFIG_NFS_V4_1 */

1816
static void nfs4_state_manager(struct nfs_client *clp)
1817 1818 1819 1820
{
	int status = 0;

	/* Ensure exclusive access to NFSv4 state */
1821
	do {
1822
		if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
1823 1824 1825
			status = nfs4_reclaim_lease(clp);
			if (status < 0)
				goto out_error;
1826 1827 1828 1829
			clear_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state);
			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
		}

1830 1831 1832
		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);
1833
			if (status < 0)
1834
				goto out_error;
1835 1836
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
				continue;
1837
			clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
1838 1839 1840 1841 1842 1843 1844 1845

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

1846
			pnfs_destroy_all_layouts(clp);
1847 1848 1849 1850
		}

		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
			status = nfs4_check_lease(clp);
1851 1852
			if (status < 0)
				goto out_error;
1853
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
1854
				continue;
1855
		}
1856

1857
		/* Initialize or reset the session */
1858
		if (test_and_clear_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state)
1859
		   && nfs4_has_session(clp)) {
1860
			status = nfs4_reset_session(clp);
1861 1862 1863
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
				continue;
			if (status < 0)
1864 1865
				goto out_error;
		}
1866

1867 1868 1869 1870 1871 1872
		/* Send BIND_CONN_TO_SESSION */
		if (test_and_clear_bit(NFS4CLNT_BIND_CONN_TO_SESSION,
				&clp->cl_state) && nfs4_has_session(clp)) {
			status = nfs4_bind_conn_to_session(clp);
			if (status < 0)
				goto out_error;
1873
			continue;
1874 1875
		}

1876
		/* First recover reboot state... */
1877
		if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
1878
			status = nfs4_do_reclaim(clp,
1879
				clp->cl_mvops->reboot_recovery_ops);
1880
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
1881
			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state))
1882
				continue;
1883
			nfs4_state_end_reclaim_reboot(clp);
1884 1885 1886 1887
			if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state))
				continue;
			if (status < 0)
				goto out_error;
1888 1889
		}

1890 1891
		/* Now recover expired state... */
		if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
1892
			status = nfs4_do_reclaim(clp,
1893
				clp->cl_mvops->nograce_recovery_ops);
1894
			if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state) ||
1895
			    test_bit(NFS4CLNT_SESSION_RESET, &clp->cl_state) ||
1896 1897 1898
			    test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
				continue;
			if (status < 0)
1899
				goto out_error;
L
Linus Torvalds 已提交
1900
		}
1901

1902
		nfs4_end_drain_session(clp);
1903 1904 1905 1906
		if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
			nfs_client_return_marked_delegations(clp);
			continue;
		}
A
Andy Adamson 已提交
1907 1908 1909 1910 1911 1912 1913 1914 1915
		/* 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;
		}

1916 1917

		nfs4_clear_state_manager_bit(clp);
1918 1919 1920 1921 1922
		/* 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;
1923
	} while (atomic_read(&clp->cl_count) > 1);
1924
	return;
L
Linus Torvalds 已提交
1925
out_error:
1926
	pr_warn_ratelimited("NFS: state manager failed on NFSv4 server %s"
1927
			" with error %d\n", clp->cl_hostname, -status);
1928
	nfs4_end_drain_session(clp);
1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940
	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 已提交
1941 1942 1943 1944 1945 1946 1947
}

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