nfs4state.c 33.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
/*
 *  fs/nfs/nfs4state.c
 *
 *  Client-side XDR for NFSv4.
 *
 *  Copyright (c) 2002 The Regents of the University of Michigan.
 *  All rights reserved.
 *
 *  Kendrick Smith <kmsmith@umich.edu>
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *  3. Neither the name of the University nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
 *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
 *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Implementation of the NFSv4 state model.  For the time being,
 * this is minimal, but will be made much more complex in a
 * subsequent patch.
 */

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

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

#define OPENOWNER_POOL_SIZE	8

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

static LIST_HEAD(nfs4_clientid_list);

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

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

	status = nfs4_proc_setclientid(clp, NFS4_CALLBACK, port, cred);
L
Linus Torvalds 已提交
73
	if (status == 0)
74
		status = nfs4_proc_setclientid_confirm(clp, cred);
L
Linus Torvalds 已提交
75 76 77 78 79
	if (status == 0)
		nfs4_schedule_state_renewal(clp);
	return status;
}

80
struct rpc_cred *nfs4_get_machine_cred_locked(struct nfs_client *clp)
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
{
	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);
}

101
struct rpc_cred *nfs4_get_renew_cred_locked(struct nfs_client *clp)
102 103
{
	struct nfs4_state_owner *sp;
104
	struct rb_node *pos;
105 106
	struct rpc_cred *cred = NULL;

107 108
	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
109 110 111 112 113 114 115 116
		if (list_empty(&sp->so_states))
			continue;
		cred = get_rpccred(sp->so_cred);
		break;
	}
	return cred;
}

117
struct rpc_cred *nfs4_get_setclientid_cred(struct nfs_client *clp)
118 119
{
	struct nfs4_state_owner *sp;
120
	struct rb_node *pos;
121
	struct rpc_cred *cred;
122

123 124
	spin_lock(&clp->cl_lock);
	cred = nfs4_get_machine_cred_locked(clp);
125 126
	if (cred != NULL)
		goto out;
127 128 129
	pos = rb_first(&clp->cl_state_owners);
	if (pos != NULL) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
130
		cred = get_rpccred(sp->so_cred);
131
	}
132
out:
133
	spin_unlock(&clp->cl_lock);
134
	return cred;
135 136
}

137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
static void nfs_alloc_unique_id(struct rb_root *root, struct nfs_unique_id *new,
		__u64 minval, int maxbits)
{
	struct rb_node **p, *parent;
	struct nfs_unique_id *pos;
	__u64 mask = ~0ULL;

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

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

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

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

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

L
Linus Torvalds 已提交
192
static struct nfs4_state_owner *
193
nfs4_find_state_owner(struct nfs_server *server, struct rpc_cred *cred)
L
Linus Torvalds 已提交
194
{
195
	struct nfs_client *clp = server->nfs_client;
196 197
	struct rb_node **p = &clp->cl_state_owners.rb_node,
		       *parent = NULL;
L
Linus Torvalds 已提交
198 199
	struct nfs4_state_owner *sp, *res = NULL;

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

204 205 206 207 208 209 210 211
		if (server < sp->so_server) {
			p = &parent->rb_left;
			continue;
		}
		if (server > sp->so_server) {
			p = &parent->rb_right;
			continue;
		}
212 213 214 215 216 217 218 219 220
		if (cred < sp->so_cred)
			p = &parent->rb_left;
		else if (cred > sp->so_cred)
			p = &parent->rb_right;
		else {
			atomic_inc(&sp->so_count);
			res = sp;
			break;
		}
L
Linus Torvalds 已提交
221 222 223 224
	}
	return res;
}

225 226 227 228 229 230 231 232 233 234 235
static struct nfs4_state_owner *
nfs4_insert_state_owner(struct nfs_client *clp, struct nfs4_state_owner *new)
{
	struct rb_node **p = &clp->cl_state_owners.rb_node,
		       *parent = NULL;
	struct nfs4_state_owner *sp;

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

236 237 238 239 240 241 242 243
		if (new->so_server < sp->so_server) {
			p = &parent->rb_left;
			continue;
		}
		if (new->so_server > sp->so_server) {
			p = &parent->rb_right;
			continue;
		}
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
		if (new->so_cred < sp->so_cred)
			p = &parent->rb_left;
		else if (new->so_cred > sp->so_cred)
			p = &parent->rb_right;
		else {
			atomic_inc(&sp->so_count);
			return sp;
		}
	}
	nfs_alloc_unique_id(&clp->cl_openowner_id, &new->so_owner_id, 1, 64);
	rb_link_node(&new->so_client_node, parent, p);
	rb_insert_color(&new->so_client_node, &clp->cl_state_owners);
	return new;
}

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

L
Linus Torvalds 已提交
267 268 269 270 271 272 273 274 275 276
/*
 * nfs4_alloc_state_owner(): this is called on the OPEN or CREATE path to
 * create a new state_owner.
 *
 */
static struct nfs4_state_owner *
nfs4_alloc_state_owner(void)
{
	struct nfs4_state_owner *sp;

277
	sp = kzalloc(sizeof(*sp),GFP_KERNEL);
L
Linus Torvalds 已提交
278 279
	if (!sp)
		return NULL;
280
	spin_lock_init(&sp->so_lock);
L
Linus Torvalds 已提交
281 282
	INIT_LIST_HEAD(&sp->so_states);
	INIT_LIST_HEAD(&sp->so_delegations);
283 284 285 286
	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 已提交
287 288 289 290
	atomic_set(&sp->so_count, 1);
	return sp;
}

291
static void
L
Linus Torvalds 已提交
292 293
nfs4_drop_state_owner(struct nfs4_state_owner *sp)
{
294 295 296 297 298 299 300 301
	if (!RB_EMPTY_NODE(&sp->so_client_node)) {
		struct nfs_client *clp = sp->so_client;

		spin_lock(&clp->cl_lock);
		rb_erase(&sp->so_client_node, &clp->cl_state_owners);
		RB_CLEAR_NODE(&sp->so_client_node);
		spin_unlock(&clp->cl_lock);
	}
L
Linus Torvalds 已提交
302 303 304 305
}

struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *server, struct rpc_cred *cred)
{
306
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
307 308 309
	struct nfs4_state_owner *sp, *new;

	spin_lock(&clp->cl_lock);
310
	sp = nfs4_find_state_owner(server, cred);
L
Linus Torvalds 已提交
311 312 313
	spin_unlock(&clp->cl_lock);
	if (sp != NULL)
		return sp;
314 315 316 317
	new = nfs4_alloc_state_owner();
	if (new == NULL)
		return NULL;
	new->so_client = clp;
318
	new->so_server = server;
319 320 321 322 323 324
	new->so_cred = cred;
	spin_lock(&clp->cl_lock);
	sp = nfs4_insert_state_owner(clp, new);
	spin_unlock(&clp->cl_lock);
	if (sp == new)
		get_rpccred(cred);
325 326
	else {
		rpc_destroy_wait_queue(&new->so_sequence.wait);
327
		kfree(new);
328
	}
329
	return sp;
L
Linus Torvalds 已提交
330 331 332 333
}

void nfs4_put_state_owner(struct nfs4_state_owner *sp)
{
334
	struct nfs_client *clp = sp->so_client;
L
Linus Torvalds 已提交
335 336 337 338
	struct rpc_cred *cred = sp->so_cred;

	if (!atomic_dec_and_lock(&sp->so_count, &clp->cl_lock))
		return;
339
	nfs4_remove_state_owner(clp, sp);
L
Linus Torvalds 已提交
340
	spin_unlock(&clp->cl_lock);
341
	rpc_destroy_wait_queue(&sp->so_sequence.wait);
L
Linus Torvalds 已提交
342 343 344 345 346 347 348 349 350
	put_rpccred(cred);
	kfree(sp);
}

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

351
	state = kzalloc(sizeof(*state), GFP_KERNEL);
L
Linus Torvalds 已提交
352 353 354 355
	if (!state)
		return NULL;
	atomic_set(&state->count, 1);
	INIT_LIST_HEAD(&state->lock_states);
356
	spin_lock_init(&state->state_lock);
357
	seqlock_init(&state->seqlock);
L
Linus Torvalds 已提交
358 359 360
	return state;
}

361
void
362
nfs4_state_set_mode_locked(struct nfs4_state *state, fmode_t fmode)
363
{
364
	if (state->state == fmode)
365 366
		return;
	/* NB! List reordering - see the reclaim code for why.  */
367 368
	if ((fmode & FMODE_WRITE) != (state->state & FMODE_WRITE)) {
		if (fmode & FMODE_WRITE)
369 370 371 372
			list_move(&state->open_states, &state->owner->so_states);
		else
			list_move_tail(&state->open_states, &state->owner->so_states);
	}
373
	state->state = fmode;
374 375
}

L
Linus Torvalds 已提交
376 377 378 379 380 381 382
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) {
383
		if (state->owner != owner)
L
Linus Torvalds 已提交
384
			continue;
385
		if (atomic_inc_not_zero(&state->count))
L
Linus Torvalds 已提交
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
			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();
409
	spin_lock(&owner->so_lock);
L
Linus Torvalds 已提交
410 411 412 413 414 415 416 417 418
	spin_lock(&inode->i_lock);
	state = __nfs4_find_state_byowner(inode, owner);
	if (state == NULL && new != NULL) {
		state = new;
		state->owner = owner;
		atomic_inc(&owner->so_count);
		list_add(&state->inode_states, &nfsi->open_states);
		state->inode = igrab(inode);
		spin_unlock(&inode->i_lock);
419 420 421 422
		/* 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 已提交
423 424
	} else {
		spin_unlock(&inode->i_lock);
425
		spin_unlock(&owner->so_lock);
L
Linus Torvalds 已提交
426 427 428 429 430 431 432 433 434 435 436 437
		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;

438
	if (!atomic_dec_and_lock(&state->count, &owner->so_lock))
L
Linus Torvalds 已提交
439
		return;
440
	spin_lock(&inode->i_lock);
441
	list_del(&state->inode_states);
L
Linus Torvalds 已提交
442
	list_del(&state->open_states);
443 444
	spin_unlock(&inode->i_lock);
	spin_unlock(&owner->so_lock);
L
Linus Torvalds 已提交
445 446 447 448 449 450
	iput(inode);
	nfs4_free_open_state(state);
	nfs4_put_state_owner(owner);
}

/*
451
 * Close the current file.
L
Linus Torvalds 已提交
452
 */
453
static void __nfs4_close(struct path *path, struct nfs4_state *state, fmode_t fmode, int wait)
L
Linus Torvalds 已提交
454 455
{
	struct nfs4_state_owner *owner = state->owner;
456
	int call_close = 0;
457
	fmode_t newstate;
L
Linus Torvalds 已提交
458 459 460

	atomic_inc(&owner->so_count);
	/* Protect against nfs4_find_state() */
461
	spin_lock(&owner->so_lock);
462
	switch (fmode & (FMODE_READ | FMODE_WRITE)) {
463 464 465 466 467 468 469 470 471
		case FMODE_READ:
			state->n_rdonly--;
			break;
		case FMODE_WRITE:
			state->n_wronly--;
			break;
		case FMODE_READ|FMODE_WRITE:
			state->n_rdwr--;
	}
472
	newstate = FMODE_READ|FMODE_WRITE;
473
	if (state->n_rdwr == 0) {
474
		if (state->n_rdonly == 0) {
475
			newstate &= ~FMODE_READ;
476 477 478 479
			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) {
480
			newstate &= ~FMODE_WRITE;
481 482 483 484 485
			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);
486
	}
487
	nfs4_state_set_mode_locked(state, newstate);
488
	spin_unlock(&owner->so_lock);
489

490
	if (!call_close) {
491 492 493
		nfs4_put_open_state(state);
		nfs4_put_state_owner(owner);
	} else
494 495 496
		nfs4_do_close(path, state, wait);
}

497
void nfs4_close_state(struct path *path, struct nfs4_state *state, fmode_t fmode)
498
{
499
	__nfs4_close(path, state, fmode, 0);
500 501
}

502
void nfs4_close_sync(struct path *path, struct nfs4_state *state, fmode_t fmode)
503
{
504
	__nfs4_close(path, state, fmode, 1);
L
Linus Torvalds 已提交
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
}

/*
 * Search the state->lock_states for an existing lock_owner
 * that is compatible with current->files
 */
static struct nfs4_lock_state *
__nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
{
	struct nfs4_lock_state *pos;
	list_for_each_entry(pos, &state->lock_states, ls_locks) {
		if (pos->ls_owner != fl_owner)
			continue;
		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.
 *
 */
static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner)
{
	struct nfs4_lock_state *lsp;
532
	struct nfs_client *clp = state->owner->so_client;
L
Linus Torvalds 已提交
533

534
	lsp = kzalloc(sizeof(*lsp), GFP_KERNEL);
L
Linus Torvalds 已提交
535 536
	if (lsp == NULL)
		return NULL;
537 538 539 540
	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 已提交
541 542 543
	atomic_set(&lsp->ls_count, 1);
	lsp->ls_owner = fl_owner;
	spin_lock(&clp->cl_lock);
544
	nfs_alloc_unique_id(&clp->cl_lockowner_id, &lsp->ls_id, 1, 64);
L
Linus Torvalds 已提交
545
	spin_unlock(&clp->cl_lock);
546
	INIT_LIST_HEAD(&lsp->ls_locks);
L
Linus Torvalds 已提交
547 548 549
	return lsp;
}

550 551 552 553 554 555 556
static void nfs4_free_lock_state(struct nfs4_lock_state *lsp)
{
	struct nfs_client *clp = lsp->ls_state->owner->so_client;

	spin_lock(&clp->cl_lock);
	nfs_free_unique_id(&clp->cl_lockowner_id, &lsp->ls_id);
	spin_unlock(&clp->cl_lock);
557
	rpc_destroy_wait_queue(&lsp->ls_sequence.wait);
558 559 560
	kfree(lsp);
}

L
Linus Torvalds 已提交
561 562 563 564 565
/*
 * Return a compatible lock_state. If no initialized lock_state structure
 * exists, return an uninitialized one.
 *
 */
566
static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner)
L
Linus Torvalds 已提交
567
{
568
	struct nfs4_lock_state *lsp, *new = NULL;
L
Linus Torvalds 已提交
569
	
570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588
	for(;;) {
		spin_lock(&state->state_lock);
		lsp = __nfs4_find_lock_state(state, owner);
		if (lsp != NULL)
			break;
		if (new != NULL) {
			new->ls_state = state;
			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);
		new = nfs4_alloc_lock_state(state, owner);
		if (new == NULL)
			return NULL;
	}
	spin_unlock(&state->state_lock);
589 590
	if (new != NULL)
		nfs4_free_lock_state(new);
L
Linus Torvalds 已提交
591 592 593 594
	return lsp;
}

/*
595 596
 * Release reference to lock_state, and free it if we see that
 * it is no longer in use
L
Linus Torvalds 已提交
597
 */
598
void nfs4_put_lock_state(struct nfs4_lock_state *lsp)
L
Linus Torvalds 已提交
599
{
600
	struct nfs4_state *state;
L
Linus Torvalds 已提交
601

602 603 604 605 606 607 608 609 610
	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);
611
	nfs4_free_lock_state(lsp);
L
Linus Torvalds 已提交
612 613
}

614
static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src)
L
Linus Torvalds 已提交
615
{
616
	struct nfs4_lock_state *lsp = src->fl_u.nfs4_fl.owner;
L
Linus Torvalds 已提交
617

618 619 620
	dst->fl_u.nfs4_fl.owner = lsp;
	atomic_inc(&lsp->ls_count);
}
L
Linus Torvalds 已提交
621

622
static void nfs4_fl_release_lock(struct file_lock *fl)
L
Linus Torvalds 已提交
623
{
624
	nfs4_put_lock_state(fl->fl_u.nfs4_fl.owner);
L
Linus Torvalds 已提交
625 626
}

627 628 629 630 631 632
static struct file_lock_operations nfs4_fl_lock_ops = {
	.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 已提交
633
{
634 635 636 637 638 639 640 641 642 643
	struct nfs4_lock_state *lsp;

	if (fl->fl_ops != NULL)
		return 0;
	lsp = nfs4_get_lock_state(state, fl->fl_owner);
	if (lsp == NULL)
		return -ENOMEM;
	fl->fl_u.nfs4_fl.owner = lsp;
	fl->fl_ops = &nfs4_fl_lock_ops;
	return 0;
L
Linus Torvalds 已提交
644 645
}

646 647 648
/*
 * Byte-range lock aware utility to initialize the stateid of read/write
 * requests.
L
Linus Torvalds 已提交
649
 */
650
void nfs4_copy_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner)
L
Linus Torvalds 已提交
651
{
652
	struct nfs4_lock_state *lsp;
653
	int seq;
L
Linus Torvalds 已提交
654

655 656 657 658
	do {
		seq = read_seqbegin(&state->seqlock);
		memcpy(dst, &state->stateid, sizeof(*dst));
	} while (read_seqretry(&state->seqlock, seq));
659 660
	if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
		return;
L
Linus Torvalds 已提交
661

662 663 664 665 666
	spin_lock(&state->state_lock);
	lsp = __nfs4_find_lock_state(state, fl_owner);
	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 已提交
667 668 669
	nfs4_put_lock_state(lsp);
}

670 671 672 673 674 675 676
struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter)
{
	struct nfs_seqid *new;

	new = kmalloc(sizeof(*new), GFP_KERNEL);
	if (new != NULL) {
		new->sequence = counter;
677
		INIT_LIST_HEAD(&new->list);
678 679 680 681 682
	}
	return new;
}

void nfs_free_seqid(struct nfs_seqid *seqid)
L
Linus Torvalds 已提交
683
{
684 685
	if (!list_empty(&seqid->list)) {
		struct rpc_sequence *sequence = seqid->sequence->sequence;
686

687 688 689 690 691
		spin_lock(&sequence->lock);
		list_del(&seqid->list);
		spin_unlock(&sequence->lock);
		rpc_wake_up(&sequence->wait);
	}
692
	kfree(seqid);
L
Linus Torvalds 已提交
693 694 695
}

/*
696 697 698 699
 * 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()
 */
700
static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
701
{
702
	BUG_ON(list_first_entry(&seqid->sequence->sequence->list, struct nfs_seqid, list) != seqid);
703 704 705 706
	switch (status) {
		case 0:
			break;
		case -NFS4ERR_BAD_SEQID:
707 708 709
			if (seqid->sequence->flags & NFS_SEQID_CONFIRMED)
				return;
			printk(KERN_WARNING "NFS: v4 server returned a bad"
D
Dan Muntz 已提交
710 711
					" sequence-id error on an"
					" unconfirmed sequence %p!\n",
712
					seqid->sequence);
713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
		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)
{
	if (status == -NFS4ERR_BAD_SEQID) {
		struct nfs4_state_owner *sp = container_of(seqid->sequence,
				struct nfs4_state_owner, so_seqid);
L
Linus Torvalds 已提交
734
		nfs4_drop_state_owner(sp);
735
	}
736
	nfs_increment_seqid(status, seqid);
737 738 739 740 741 742 743 744 745
}

/*
 * 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)
{
746
	nfs_increment_seqid(status, seqid);
747 748 749 750 751 752 753 754
}

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);
755 756 757 758
	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;
759
	rpc_sleep_on(&sequence->wait, task, NULL);
760 761
	status = -EAGAIN;
unlock:
762 763
	spin_unlock(&sequence->lock);
	return status;
L
Linus Torvalds 已提交
764 765
}

766
static int nfs4_run_state_manager(void *);
L
Linus Torvalds 已提交
767

768
static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
T
Trond Myklebust 已提交
769 770
{
	smp_mb__before_clear_bit();
771
	clear_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state);
T
Trond Myklebust 已提交
772
	smp_mb__after_clear_bit();
773
	wake_up_bit(&clp->cl_state, NFS4CLNT_MANAGER_RUNNING);
T
Trond Myklebust 已提交
774 775 776
	rpc_wake_up(&clp->cl_rpcwaitq);
}

L
Linus Torvalds 已提交
777
/*
778
 * Schedule the nfs_client asynchronous state management routine
L
Linus Torvalds 已提交
779
 */
780
void nfs4_schedule_state_manager(struct nfs_client *clp)
L
Linus Torvalds 已提交
781
{
782
	struct task_struct *task;
L
Linus Torvalds 已提交
783

784 785
	if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
		return;
786 787
	__module_get(THIS_MODULE);
	atomic_inc(&clp->cl_count);
788
	task = kthread_run(nfs4_run_state_manager, clp, "%s-manager",
789 790
				rpc_peeraddr2str(clp->cl_rpcclient,
							RPC_DISPLAY_ADDR));
791 792
	if (!IS_ERR(task))
		return;
793
	nfs4_clear_state_manager_bit(clp);
794
	nfs_put_client(clp);
795
	module_put(THIS_MODULE);
L
Linus Torvalds 已提交
796 797 798 799 800
}

/*
 * Schedule a state recovery attempt
 */
801
void nfs4_schedule_state_recovery(struct nfs_client *clp)
L
Linus Torvalds 已提交
802 803 804
{
	if (!clp)
		return;
805 806
	if (!test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
		set_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
807
	nfs4_schedule_state_manager(clp);
L
Linus Torvalds 已提交
808 809
}

810 811 812 813 814 815 816 817 818
static int nfs4_state_mark_reclaim_reboot(struct nfs_client *clp, struct nfs4_state *state)
{

	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;
	}
819
	set_bit(NFS_OWNER_RECLAIM_REBOOT, &state->owner->so_flags);
820 821 822 823
	set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state);
	return 1;
}

824
int nfs4_state_mark_reclaim_nograce(struct nfs_client *clp, struct nfs4_state *state)
825 826 827
{
	set_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags);
	clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags);
828
	set_bit(NFS_OWNER_RECLAIM_NOGRACE, &state->owner->so_flags);
829 830 831 832
	set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
	return 1;
}

833
static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
834 835
{
	struct inode *inode = state->inode;
836
	struct nfs_inode *nfsi = NFS_I(inode);
L
Linus Torvalds 已提交
837 838 839
	struct file_lock *fl;
	int status = 0;

840
	down_write(&nfsi->rwsem);
H
Harvey Harrison 已提交
841
	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
842
		if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
L
Linus Torvalds 已提交
843
			continue;
844
		if (nfs_file_open_context(fl->fl_file)->state != state)
L
Linus Torvalds 已提交
845 846 847 848 849 850 851
			continue;
		status = ops->recover_lock(state, fl);
		if (status >= 0)
			continue;
		switch (status) {
			default:
				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
852
						__func__, status);
L
Linus Torvalds 已提交
853 854 855 856
			case -NFS4ERR_EXPIRED:
			case -NFS4ERR_NO_GRACE:
			case -NFS4ERR_RECLAIM_BAD:
			case -NFS4ERR_RECLAIM_CONFLICT:
857
				/* kill_proc(fl->fl_pid, SIGLOST, 1); */
L
Linus Torvalds 已提交
858 859 860 861 862
				break;
			case -NFS4ERR_STALE_CLIENTID:
				goto out_err;
		}
	}
863
	up_write(&nfsi->rwsem);
L
Linus Torvalds 已提交
864 865
	return 0;
out_err:
866
	up_write(&nfsi->rwsem);
L
Linus Torvalds 已提交
867 868 869
	return status;
}

870
static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
871 872 873 874 875 876 877 878 879 880 881 882 883
{
	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.
	 */
884 885
restart:
	spin_lock(&sp->so_lock);
L
Linus Torvalds 已提交
886
	list_for_each_entry(state, &sp->so_states, open_states) {
887 888
		if (!test_and_clear_bit(ops->state_flag_bit, &state->flags))
			continue;
L
Linus Torvalds 已提交
889 890
		if (state->state == 0)
			continue;
891 892
		atomic_inc(&state->count);
		spin_unlock(&sp->so_lock);
L
Linus Torvalds 已提交
893 894
		status = ops->recover_open(sp, state);
		if (status >= 0) {
895 896 897 898 899
			status = nfs4_reclaim_locks(state, ops);
			if (status >= 0) {
				list_for_each_entry(lock, &state->lock_states, ls_locks) {
					if (!(lock->ls_flags & NFS_LOCK_INITIALIZED))
						printk("%s: Lock reclaim failed!\n",
900
							__func__);
901
				}
902 903
				nfs4_put_open_state(state);
				goto restart;
L
Linus Torvalds 已提交
904 905 906 907 908
			}
		}
		switch (status) {
			default:
				printk(KERN_ERR "%s: unhandled error %d. Zeroing state\n",
909
						__func__, status);
L
Linus Torvalds 已提交
910
			case -ENOENT:
911
			case -ESTALE:
L
Linus Torvalds 已提交
912 913 914 915 916 917 918 919 920
				/*
				 * 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;
921 922 923 924
			case -NFS4ERR_RECLAIM_BAD:
			case -NFS4ERR_RECLAIM_CONFLICT:
				nfs4_state_mark_reclaim_nograce(sp->so_client, state);
				break;
L
Linus Torvalds 已提交
925 926
			case -NFS4ERR_EXPIRED:
			case -NFS4ERR_NO_GRACE:
927
				nfs4_state_mark_reclaim_nograce(sp->so_client, state);
L
Linus Torvalds 已提交
928 929 930
			case -NFS4ERR_STALE_CLIENTID:
				goto out_err;
		}
931 932
		nfs4_put_open_state(state);
		goto restart;
L
Linus Torvalds 已提交
933
	}
934
	spin_unlock(&sp->so_lock);
L
Linus Torvalds 已提交
935 936
	return 0;
out_err:
937
	nfs4_put_open_state(state);
L
Linus Torvalds 已提交
938 939 940
	return status;
}

941 942 943 944 945 946 947 948 949 950 951 952 953 954 955
static void nfs4_clear_open_state(struct nfs4_state *state)
{
	struct nfs4_lock_state *lock;

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

static void nfs4_state_mark_reclaim_helper(struct nfs_client *clp, int (*mark_reclaim)(struct nfs_client *clp, struct nfs4_state *state))
956 957
{
	struct nfs4_state_owner *sp;
958
	struct rb_node *pos;
959 960 961
	struct nfs4_state *state;

	/* Reset all sequence ids to zero */
962 963
	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
964
		sp->so_seqid.flags = 0;
965
		spin_lock(&sp->so_lock);
966
		list_for_each_entry(state, &sp->so_states, open_states) {
967 968
			if (mark_reclaim(clp, state))
				nfs4_clear_open_state(state);
969
		}
970
		spin_unlock(&sp->so_lock);
971 972 973
	}
}

974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
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);
}

static void nfs4_state_end_reclaim_reboot(struct nfs_client *clp)
{
	struct nfs4_state_owner *sp;
	struct rb_node *pos;
	struct nfs4_state *state;

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

	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
		sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
		spin_lock(&sp->so_lock);
		list_for_each_entry(state, &sp->so_states, open_states) {
			if (!test_and_clear_bit(NFS_STATE_RECLAIM_REBOOT, &state->flags))
				continue;
			nfs4_state_mark_reclaim_nograce(clp, state);
		}
		spin_unlock(&sp->so_lock);
	}

	nfs_delegation_reap_unclaimed(clp);
}

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

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

static void nfs4_state_end_reclaim_nograce(struct nfs_client *clp)
{
	clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
}

1021 1022 1023 1024
static void nfs4_recovery_handle_error(struct nfs_client *clp, int error)
{
	switch (error) {
		case -NFS4ERR_CB_PATH_DOWN:
1025
			nfs_handle_cb_pathdown(clp);
1026 1027 1028 1029 1030 1031 1032 1033 1034
			break;
		case -NFS4ERR_STALE_CLIENTID:
		case -NFS4ERR_LEASE_MOVED:
			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
			nfs4_state_start_reclaim_reboot(clp);
			break;
		case -NFS4ERR_EXPIRED:
			set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
			nfs4_state_start_reclaim_nograce(clp);
1035 1036 1037 1038 1039 1040 1041 1042
		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:
			set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
1043 1044 1045
	}
}

1046
static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recovery_ops *ops)
L
Linus Torvalds 已提交
1047
{
1048
	struct rb_node *pos;
L
Linus Torvalds 已提交
1049 1050
	int status = 0;

1051 1052
restart:
	spin_lock(&clp->cl_lock);
1053 1054
	for (pos = rb_first(&clp->cl_state_owners); pos != NULL; pos = rb_next(pos)) {
		struct nfs4_state_owner *sp = rb_entry(pos, struct nfs4_state_owner, so_client_node);
1055 1056 1057 1058
		if (!test_and_clear_bit(ops->owner_flag_bit, &sp->so_flags))
			continue;
		atomic_inc(&sp->so_count);
		spin_unlock(&clp->cl_lock);
1059
		status = nfs4_reclaim_open_state(sp, ops);
1060 1061 1062 1063 1064 1065 1066 1067
		if (status < 0) {
			set_bit(ops->owner_flag_bit, &sp->so_flags);
			nfs4_put_state_owner(sp);
			nfs4_recovery_handle_error(clp, status);
			return status;
		}
		nfs4_put_state_owner(sp);
		goto restart;
1068
	}
1069
	spin_unlock(&clp->cl_lock);
1070 1071 1072 1073 1074 1075
	return status;
}

static int nfs4_check_lease(struct nfs_client *clp)
{
	struct rpc_cred *cred;
1076 1077
	struct nfs4_state_maintenance_ops *ops =
		nfs4_state_renewal_ops[clp->cl_minorversion];
1078
	int status = -NFS4ERR_EXPIRED;
L
Linus Torvalds 已提交
1079

1080 1081 1082
	/* Is the client already known to have an expired lease? */
	if (test_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state))
		return 0;
1083 1084 1085
	spin_lock(&clp->cl_lock);
	cred = ops->get_state_renewal_cred_locked(clp);
	spin_unlock(&clp->cl_lock);
1086 1087 1088 1089
	if (cred == NULL) {
		cred = nfs4_get_setclientid_cred(clp);
		if (cred == NULL)
			goto out;
1090
	}
1091
	status = ops->renew_lease(clp, cred);
1092 1093 1094
	put_rpccred(cred);
out:
	nfs4_recovery_handle_error(clp, status);
1095 1096 1097 1098 1099 1100
	return status;
}

static int nfs4_reclaim_lease(struct nfs_client *clp)
{
	struct rpc_cred *cred;
1101 1102
	struct nfs4_state_recovery_ops *ops =
		nfs4_reboot_recovery_ops[clp->cl_minorversion];
1103 1104
	int status = -ENOENT;

1105
	cred = nfs4_get_setclientid_cred(clp);
1106
	if (cred != NULL) {
1107
		status = ops->establish_clid(clp, cred);
1108
		put_rpccred(cred);
1109 1110 1111
		/* Handle case where the user hasn't set up machine creds */
		if (status == -EACCES && cred == clp->cl_machine_cred) {
			nfs4_clear_machine_cred(clp);
1112
			status = -EAGAIN;
1113
		}
1114 1115
		if (status == -NFS4ERR_MINOR_VERS_MISMATCH)
			status = -EPROTONOSUPPORT;
1116
	}
1117 1118 1119
	return status;
}

1120
#ifdef CONFIG_NFS_V4_1
1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150
static void nfs4_session_recovery_handle_error(struct nfs_client *clp, int err)
{
	switch (err) {
	case -NFS4ERR_STALE_CLIENTID:
		set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
		set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
	}
}

static int nfs4_reset_session(struct nfs_client *clp)
{
	int status;

	status = nfs4_proc_destroy_session(clp->cl_session);
	if (status && status != -NFS4ERR_BADSESSION &&
	    status != -NFS4ERR_DEADSESSION) {
		nfs4_session_recovery_handle_error(clp, status);
		goto out;
	}

	memset(clp->cl_session->sess_id.data, 0, NFS4_MAX_SESSIONID_LEN);
	status = nfs4_proc_create_session(clp, 1);
	if (status)
		nfs4_session_recovery_handle_error(clp, status);
		/* fall through*/
out:
	/* Wake up the next rpc task even on error */
	rpc_wake_up_next(&clp->cl_session->fc_slot_table.slot_tbl_waitq);
	return status;
}
1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167

static int nfs4_initialize_session(struct nfs_client *clp)
{
	int status;

	status = nfs4_proc_create_session(clp, 0);
	if (!status) {
		nfs_mark_client_ready(clp, NFS_CS_READY);
	} else if (status == -NFS4ERR_STALE_CLIENTID) {
		set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
		set_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state);
	} else {
		nfs_mark_client_ready(clp, status);
	}
	return status;
}
#else /* CONFIG_NFS_V4_1 */
1168
static int nfs4_reset_session(struct nfs_client *clp) { return 0; }
1169 1170 1171
static int nfs4_initialize_session(struct nfs_client *clp) { return 0; }
#endif /* CONFIG_NFS_V4_1 */

1172
static void nfs4_state_manager(struct nfs_client *clp)
1173 1174 1175 1176
{
	int status = 0;

	/* Ensure exclusive access to NFSv4 state */
1177
	for(;;) {
1178 1179 1180 1181 1182 1183 1184
		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) {
				set_bit(NFS4CLNT_LEASE_EXPIRED, &clp->cl_state);
				if (status == -EAGAIN)
					continue;
1185 1186 1187
				if (clp->cl_cons_state ==
							NFS_CS_SESSION_INITING)
					nfs_mark_client_ready(clp, status);
1188 1189
				goto out_error;
			}
1190 1191 1192 1193 1194 1195 1196
			clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state);
		}

		if (test_and_clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state)) {
			status = nfs4_check_lease(clp);
			if (status != 0)
				continue;
1197
		}
1198
		/* Initialize or reset the session */
1199 1200
		if (nfs4_has_session(clp) &&
		   test_and_clear_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state)) {
1201 1202 1203 1204
			if (clp->cl_cons_state == NFS_CS_SESSION_INITING)
				status = nfs4_initialize_session(clp);
			else
				status = nfs4_reset_session(clp);
1205 1206 1207 1208 1209 1210
			if (status) {
				if (status == -NFS4ERR_STALE_CLIENTID)
					continue;
				goto out_error;
			}
		}
1211 1212
		/* First recover reboot state... */
		if (test_and_clear_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state)) {
1213 1214
			status = nfs4_do_reclaim(clp,
				nfs4_reboot_recovery_ops[clp->cl_minorversion]);
1215
			if (status == -NFS4ERR_STALE_CLIENTID)
1216
				continue;
1217 1218
			if (test_bit(NFS4CLNT_SESSION_SETUP, &clp->cl_state))
				continue;
1219 1220
			nfs4_state_end_reclaim_reboot(clp);
			continue;
1221 1222
		}

1223 1224
		/* Now recover expired state... */
		if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
1225 1226
			status = nfs4_do_reclaim(clp,
				nfs4_nograce_recovery_ops[clp->cl_minorversion]);
1227 1228 1229 1230 1231 1232
			if (status < 0) {
				set_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
				if (status == -NFS4ERR_STALE_CLIENTID)
					continue;
				if (status == -NFS4ERR_EXPIRED)
					continue;
1233 1234 1235
				if (test_bit(NFS4CLNT_SESSION_SETUP,
								&clp->cl_state))
					continue;
1236 1237 1238 1239
				goto out_error;
			} else
				nfs4_state_end_reclaim_nograce(clp);
			continue;
L
Linus Torvalds 已提交
1240
		}
1241 1242 1243 1244 1245

		if (test_and_clear_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state)) {
			nfs_client_return_marked_delegations(clp);
			continue;
		}
1246 1247

		nfs4_clear_state_manager_bit(clp);
1248 1249 1250 1251 1252
		/* Did we race with an attempt to give us more work? */
		if (clp->cl_state == 0)
			break;
		if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
			break;
L
Linus Torvalds 已提交
1253
	}
1254
	return;
L
Linus Torvalds 已提交
1255
out_error:
1256
	printk(KERN_WARNING "Error: state manager failed on NFSv4 server %s"
1257
			" with error %d\n", clp->cl_hostname, -status);
1258 1259
	if (test_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state))
		nfs4_state_end_reclaim_reboot(clp);
1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271
	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 已提交
1272 1273 1274 1275 1276 1277 1278
}

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