delegation.c 29.2 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9
/*
 * linux/fs/nfs/delegation.c
 *
 * Copyright (C) 2004 Trond Myklebust
 *
 * NFS file delegation management
 *
 */
#include <linux/completion.h>
10
#include <linux/kthread.h>
L
Linus Torvalds 已提交
11 12
#include <linux/module.h>
#include <linux/sched.h>
13
#include <linux/slab.h>
L
Linus Torvalds 已提交
14 15 16 17 18 19
#include <linux/spinlock.h>

#include <linux/nfs4.h>
#include <linux/nfs_fs.h>
#include <linux/nfs_xdr.h>

20
#include "nfs4_fs.h"
L
Linus Torvalds 已提交
21
#include "delegation.h"
22
#include "internal.h"
23
#include "nfs4trace.h"
L
Linus Torvalds 已提交
24

25 26
static void nfs_free_delegation(struct nfs_delegation *delegation)
{
27 28 29 30
	if (delegation->cred) {
		put_rpccred(delegation->cred);
		delegation->cred = NULL;
	}
31
	kfree_rcu(delegation, rcu);
32 33
}

34 35 36 37 38
/**
 * nfs_mark_delegation_referenced - set delegation's REFERENCED flag
 * @delegation: delegation to process
 *
 */
39 40 41 42 43
void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
{
	set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
}

44 45 46 47 48 49 50 51 52 53 54
static bool
nfs4_is_valid_delegation(const struct nfs_delegation *delegation,
		fmode_t flags)
{
	if (delegation != NULL && (delegation->type & flags) == flags &&
	    !test_bit(NFS_DELEGATION_REVOKED, &delegation->flags) &&
	    !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
		return true;
	return false;
}

P
Peng Tao 已提交
55 56
static int
nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark)
57 58 59 60 61 62 63
{
	struct nfs_delegation *delegation;
	int ret = 0;

	flags &= FMODE_READ|FMODE_WRITE;
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
64
	if (nfs4_is_valid_delegation(delegation, flags)) {
P
Peng Tao 已提交
65 66
		if (mark)
			nfs_mark_delegation_referenced(delegation);
67 68 69 70 71
		ret = 1;
	}
	rcu_read_unlock();
	return ret;
}
P
Peng Tao 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
/**
 * nfs_have_delegation - check if inode has a delegation, mark it
 * NFS_DELEGATION_REFERENCED if there is one.
 * @inode: inode to check
 * @flags: delegation types to check for
 *
 * Returns one if inode has the indicated delegation, otherwise zero.
 */
int nfs4_have_delegation(struct inode *inode, fmode_t flags)
{
	return nfs4_do_check_delegation(inode, flags, true);
}

/*
 * nfs4_check_delegation - check if inode has a delegation, do not mark
 * NFS_DELEGATION_REFERENCED if it has one.
 */
int nfs4_check_delegation(struct inode *inode, fmode_t flags)
{
	return nfs4_do_check_delegation(inode, flags, false);
}
93

94
static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
95 96 97
{
	struct inode *inode = state->inode;
	struct file_lock *fl;
98 99
	struct file_lock_context *flctx = inode->i_flctx;
	struct list_head *list;
100
	int status = 0;
101

102
	if (flctx == NULL)
103
		goto out;
104

105
	list = &flctx->flc_posix;
106
	spin_lock(&flctx->flc_lock);
107 108
restart:
	list_for_each_entry(fl, list, fl_list) {
109
		if (nfs_file_open_context(fl->fl_file) != ctx)
110
			continue;
111
		spin_unlock(&flctx->flc_lock);
112
		status = nfs4_lock_delegation_recall(fl, state, stateid);
113
		if (status < 0)
114
			goto out;
115
		spin_lock(&flctx->flc_lock);
116
	}
117 118 119
	if (list == &flctx->flc_posix) {
		list = &flctx->flc_flock;
		goto restart;
120
	}
121
	spin_unlock(&flctx->flc_lock);
122
out:
123 124 125
	return status;
}

126 127
static int nfs_delegation_claim_opens(struct inode *inode,
		const nfs4_stateid *stateid, fmode_t type)
L
Linus Torvalds 已提交
128 129 130
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_open_context *ctx;
131
	struct nfs4_state_owner *sp;
L
Linus Torvalds 已提交
132
	struct nfs4_state *state;
133
	unsigned int seq;
134
	int err;
L
Linus Torvalds 已提交
135 136 137 138 139 140 141 142 143

again:
	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;
144 145
		if (!nfs4_valid_open_stateid(state))
			continue;
146
		if (!nfs4_stateid_match(&state->stateid, stateid))
147
			continue;
L
Linus Torvalds 已提交
148 149
		get_nfs_open_context(ctx);
		spin_unlock(&inode->i_lock);
150
		sp = state->owner;
151 152
		/* Block nfs4_proc_unlck */
		mutex_lock(&sp->so_delegreturn_mutex);
153
		seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
154
		err = nfs4_open_delegation_recall(ctx, state, stateid, type);
155
		if (!err)
156
			err = nfs_delegation_claim_locks(ctx, state, stateid);
157 158
		if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
			err = -EAGAIN;
159
		mutex_unlock(&sp->so_delegreturn_mutex);
L
Linus Torvalds 已提交
160
		put_nfs_open_context(ctx);
161
		if (err != 0)
162
			return err;
L
Linus Torvalds 已提交
163 164 165
		goto again;
	}
	spin_unlock(&inode->i_lock);
166
	return 0;
L
Linus Torvalds 已提交
167 168
}

169 170 171 172 173 174
/**
 * nfs_inode_reclaim_delegation - process a delegation reclaim request
 * @inode: inode to process
 * @cred: credential to use for request
 * @res: new delegation state from server
 *
L
Linus Torvalds 已提交
175
 */
176 177
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
				  struct nfs_openres *res)
L
Linus Torvalds 已提交
178
{
179 180
	struct nfs_delegation *delegation;
	struct rpc_cred *oldcred = NULL;
L
Linus Torvalds 已提交
181

182 183 184 185 186
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
	if (delegation != NULL) {
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL) {
187
			nfs4_stateid_copy(&delegation->stateid, &res->delegation);
188
			delegation->type = res->delegation_type;
189
			delegation->pagemod_limit = res->pagemod_limit;
190 191 192 193 194 195
			oldcred = delegation->cred;
			delegation->cred = get_rpccred(cred);
			clear_bit(NFS_DELEGATION_NEED_RECLAIM,
				  &delegation->flags);
			spin_unlock(&delegation->lock);
			rcu_read_unlock();
196
			put_rpccred(oldcred);
197
			trace_nfs4_reclaim_delegation(inode, res->delegation_type);
198
			return;
199
		}
200 201
		/* We appear to have raced with a delegation return. */
		spin_unlock(&delegation->lock);
202
	}
203 204
	rcu_read_unlock();
	nfs_inode_set_delegation(inode, cred, res);
L
Linus Torvalds 已提交
205 206
}

207 208 209 210
static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
{
	int res = 0;

211 212 213 214 215
	if (!test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
		res = nfs4_proc_delegreturn(inode,
				delegation->cred,
				&delegation->stateid,
				issync);
216 217 218 219
	nfs_free_delegation(delegation);
	return res;
}

220 221 222 223 224 225 226 227 228 229 230
static struct inode *nfs_delegation_grab_inode(struct nfs_delegation *delegation)
{
	struct inode *inode = NULL;

	spin_lock(&delegation->lock);
	if (delegation->inode != NULL)
		inode = igrab(delegation->inode);
	spin_unlock(&delegation->lock);
	return inode;
}

231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269
static struct nfs_delegation *
nfs_start_delegation_return_locked(struct nfs_inode *nfsi)
{
	struct nfs_delegation *ret = NULL;
	struct nfs_delegation *delegation = rcu_dereference(nfsi->delegation);

	if (delegation == NULL)
		goto out;
	spin_lock(&delegation->lock);
	if (!test_and_set_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
		ret = delegation;
	spin_unlock(&delegation->lock);
out:
	return ret;
}

static struct nfs_delegation *
nfs_start_delegation_return(struct nfs_inode *nfsi)
{
	struct nfs_delegation *delegation;

	rcu_read_lock();
	delegation = nfs_start_delegation_return_locked(nfsi);
	rcu_read_unlock();
	return delegation;
}

static void
nfs_abort_delegation_return(struct nfs_delegation *delegation,
		struct nfs_client *clp)
{

	spin_lock(&delegation->lock);
	clear_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
	set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
	spin_unlock(&delegation->lock);
	set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
}

270 271
static struct nfs_delegation *
nfs_detach_delegation_locked(struct nfs_inode *nfsi,
272 273
		struct nfs_delegation *delegation,
		struct nfs_client *clp)
274
{
275
	struct nfs_delegation *deleg_cur =
276
		rcu_dereference_protected(nfsi->delegation,
277
				lockdep_is_held(&clp->cl_lock));
278

279 280
	if (deleg_cur == NULL || delegation != deleg_cur)
		return NULL;
281

282
	spin_lock(&delegation->lock);
283
	set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
284
	list_del_rcu(&delegation->super_list);
285
	delegation->inode = NULL;
286
	rcu_assign_pointer(nfsi->delegation, NULL);
287
	spin_unlock(&delegation->lock);
288 289 290
	return delegation;
}

291
static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi,
292 293
		struct nfs_delegation *delegation,
		struct nfs_server *server)
294
{
295
	struct nfs_client *clp = server->nfs_client;
296 297

	spin_lock(&clp->cl_lock);
298
	delegation = nfs_detach_delegation_locked(nfsi, delegation, clp);
299 300 301 302
	spin_unlock(&clp->cl_lock);
	return delegation;
}

303 304 305 306 307 308 309 310 311 312 313 314 315
static struct nfs_delegation *
nfs_inode_detach_delegation(struct inode *inode)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_delegation *delegation;

	delegation = nfs_start_delegation_return(nfsi);
	if (delegation == NULL)
		return NULL;
	return nfs_detach_delegation(nfsi, delegation, server);
}

316 317 318 319 320 321 322 323 324 325 326
static void
nfs_update_inplace_delegation(struct nfs_delegation *delegation,
		const struct nfs_delegation *update)
{
	if (nfs4_stateid_is_newer(&update->stateid, &delegation->stateid)) {
		delegation->stateid.seqid = update->stateid.seqid;
		smp_wmb();
		delegation->type = update->type;
	}
}

327 328 329 330 331 332 333
/**
 * nfs_inode_set_delegation - set up a delegation on an inode
 * @inode: inode to which delegation applies
 * @cred: cred to use for subsequent delegation processing
 * @res: new delegation state from server
 *
 * Returns zero on success, or a negative errno value.
L
Linus Torvalds 已提交
334 335 336
 */
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
{
337 338
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
339
	struct nfs_inode *nfsi = NFS_I(inode);
340
	struct nfs_delegation *delegation, *old_delegation;
341
	struct nfs_delegation *freeme = NULL;
L
Linus Torvalds 已提交
342 343
	int status = 0;

344
	delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
L
Linus Torvalds 已提交
345 346
	if (delegation == NULL)
		return -ENOMEM;
347
	nfs4_stateid_copy(&delegation->stateid, &res->delegation);
L
Linus Torvalds 已提交
348
	delegation->type = res->delegation_type;
349
	delegation->pagemod_limit = res->pagemod_limit;
350
	delegation->change_attr = inode->i_version;
L
Linus Torvalds 已提交
351 352
	delegation->cred = get_rpccred(cred);
	delegation->inode = inode;
353
	delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
354
	spin_lock_init(&delegation->lock);
L
Linus Torvalds 已提交
355 356

	spin_lock(&clp->cl_lock);
357
	old_delegation = rcu_dereference_protected(nfsi->delegation,
358
					lockdep_is_held(&clp->cl_lock));
359
	if (old_delegation != NULL) {
360 361 362 363 364
		/* Is this an update of the existing delegation? */
		if (nfs4_stateid_match_other(&old_delegation->stateid,
					&delegation->stateid)) {
			nfs_update_inplace_delegation(old_delegation,
					delegation);
365
			goto out;
L
Linus Torvalds 已提交
366
		}
367 368 369
		/*
		 * Deal with broken servers that hand out two
		 * delegations for the same file.
370 371
		 * Allow for upgrades to a WRITE delegation, but
		 * nothing else.
372 373 374
		 */
		dfprintk(FILE, "%s: server %s handed out "
				"a duplicate delegation!\n",
375
				__func__, clp->cl_hostname);
376 377
		if (delegation->type == old_delegation->type ||
		    !(delegation->type & FMODE_WRITE)) {
378 379 380 381
			freeme = delegation;
			delegation = NULL;
			goto out;
		}
382 383 384 385
		if (test_and_set_bit(NFS_DELEGATION_RETURNING,
					&old_delegation->flags))
			goto out;
		freeme = nfs_detach_delegation_locked(nfsi,
386 387 388
				old_delegation, clp);
		if (freeme == NULL)
			goto out;
L
Linus Torvalds 已提交
389
	}
390
	list_add_tail_rcu(&delegation->super_list, &server->delegations);
391 392
	rcu_assign_pointer(nfsi->delegation, delegation);
	delegation = NULL;
393 394 395 396 397

	/* Ensure we revalidate the attributes and page cache! */
	spin_lock(&inode->i_lock);
	nfsi->cache_validity |= NFS_INO_REVAL_FORCED;
	spin_unlock(&inode->i_lock);
398
	trace_nfs4_set_delegation(inode, res->delegation_type);
399

400
out:
L
Linus Torvalds 已提交
401
	spin_unlock(&clp->cl_lock);
402 403
	if (delegation != NULL)
		nfs_free_delegation(delegation);
404 405
	if (freeme != NULL)
		nfs_do_return_delegation(inode, freeme, 0);
L
Linus Torvalds 已提交
406 407 408 409 410 411
	return status;
}

/*
 * Basic procedure for returning a delegation to the server
 */
412
static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync)
L
Linus Torvalds 已提交
413
{
414
	struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
L
Linus Torvalds 已提交
415
	struct nfs_inode *nfsi = NFS_I(inode);
416
	int err = 0;
L
Linus Torvalds 已提交
417

418 419 420
	if (delegation == NULL)
		return 0;
	do {
421 422
		if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
			break;
423 424
		err = nfs_delegation_claim_opens(inode, &delegation->stateid,
				delegation->type);
425 426 427 428 429 430 431 432 433 434 435 436 437
		if (!issync || err != -EAGAIN)
			break;
		/*
		 * Guard against state recovery
		 */
		err = nfs4_wait_clnt_recover(clp);
	} while (err == 0);

	if (err) {
		nfs_abort_delegation_return(delegation, clp);
		goto out;
	}
	if (!nfs_detach_delegation(nfsi, delegation, NFS_SERVER(inode)))
438
		goto out;
L
Linus Torvalds 已提交
439

440 441 442
	err = nfs_do_return_delegation(inode, delegation, issync);
out:
	return err;
443 444
}

445 446 447 448
static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
{
	bool ret = false;

449 450
	if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
		goto out;
451 452 453 454 455 456 457 458 459 460 461
	if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
		ret = true;
	if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) {
		struct inode *inode;

		spin_lock(&delegation->lock);
		inode = delegation->inode;
		if (inode && list_empty(&NFS_I(inode)->open_files))
			ret = true;
		spin_unlock(&delegation->lock);
	}
462
out:
463 464 465
	return ret;
}

466 467 468 469
/**
 * nfs_client_return_marked_delegations - return previously marked delegations
 * @clp: nfs_client to process
 *
470 471 472 473
 * Note that this function is designed to be called by the state
 * manager thread. For this reason, it cannot flush the dirty data,
 * since that could deadlock in case of a state recovery error.
 *
474
 * Returns zero on success, or a negative errno value.
475
 */
476
int nfs_client_return_marked_delegations(struct nfs_client *clp)
477 478
{
	struct nfs_delegation *delegation;
479
	struct nfs_server *server;
480
	struct inode *inode;
481
	int err = 0;
482 483 484

restart:
	rcu_read_lock();
485 486 487
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		list_for_each_entry_rcu(delegation, &server->delegations,
								super_list) {
488
			if (!nfs_delegation_need_return(delegation))
489
				continue;
490
			if (!nfs_sb_active(server->super))
491
				continue;
492 493 494 495 496 497
			inode = nfs_delegation_grab_inode(delegation);
			if (inode == NULL) {
				rcu_read_unlock();
				nfs_sb_deactive(server->super);
				goto restart;
			}
498
			delegation = nfs_start_delegation_return_locked(NFS_I(inode));
499 500
			rcu_read_unlock();

501
			err = nfs_end_delegation_return(inode, delegation, 0);
502
			iput(inode);
503
			nfs_sb_deactive(server->super);
504 505 506 507
			if (!err)
				goto restart;
			set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
			return err;
508
		}
509 510
	}
	rcu_read_unlock();
511
	return 0;
512 513
}

514 515 516 517 518 519
/**
 * nfs_inode_return_delegation_noreclaim - return delegation, don't reclaim opens
 * @inode: inode to process
 *
 * Does not protect against delegation reclaims, therefore really only safe
 * to be called from nfs4_clear_inode().
520 521 522 523 524
 */
void nfs_inode_return_delegation_noreclaim(struct inode *inode)
{
	struct nfs_delegation *delegation;

525 526
	delegation = nfs_inode_detach_delegation(inode);
	if (delegation != NULL)
527
		nfs_do_return_delegation(inode, delegation, 1);
528 529
}

530 531 532 533
/**
 * nfs_inode_return_delegation - synchronously return a delegation
 * @inode: inode to process
 *
534 535 536 537
 * This routine will always flush any dirty data to disk on the
 * assumption that if we need to return the delegation, then
 * we should stop caching.
 *
538 539
 * Returns zero on success, or a negative errno value.
 */
540
int nfs4_inode_return_delegation(struct inode *inode)
541 542 543 544 545
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
	int err = 0;

546
	nfs_wb_all(inode);
547 548 549
	delegation = nfs_start_delegation_return(nfsi);
	if (delegation != NULL)
		err = nfs_end_delegation_return(inode, delegation, 1);
550
	return err;
L
Linus Torvalds 已提交
551 552
}

553 554 555 556 557 558 559
static void nfs_mark_return_if_closed_delegation(struct nfs_server *server,
		struct nfs_delegation *delegation)
{
	set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
	set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
}

560 561
static void nfs_mark_return_delegation(struct nfs_server *server,
		struct nfs_delegation *delegation)
562 563
{
	set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
564
	set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
565 566
}

567 568 569 570 571 572 573 574 575 576 577 578
static bool nfs_server_mark_return_all_delegations(struct nfs_server *server)
{
	struct nfs_delegation *delegation;
	bool ret = false;

	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
		nfs_mark_return_delegation(server, delegation);
		ret = true;
	}
	return ret;
}

579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605
static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
{
	struct nfs_server *server;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_server_mark_return_all_delegations(server);
	rcu_read_unlock();
}

static void nfs_delegation_run_state_manager(struct nfs_client *clp)
{
	if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
		nfs4_schedule_state_manager(clp);
}

/**
 * nfs_expire_all_delegations
 * @clp: client to process
 *
 */
void nfs_expire_all_delegations(struct nfs_client *clp)
{
	nfs_client_mark_return_all_delegations(clp);
	nfs_delegation_run_state_manager(clp);
}

606 607 608 609
/**
 * nfs_super_return_all_delegations - return delegations for one superblock
 * @sb: sb to process
 *
L
Linus Torvalds 已提交
610
 */
611
void nfs_server_return_all_delegations(struct nfs_server *server)
L
Linus Torvalds 已提交
612
{
613
	struct nfs_client *clp = server->nfs_client;
614
	bool need_wait;
L
Linus Torvalds 已提交
615 616 617

	if (clp == NULL)
		return;
618

619
	rcu_read_lock();
620
	need_wait = nfs_server_mark_return_all_delegations(server);
621
	rcu_read_unlock();
622

623
	if (need_wait) {
624
		nfs4_schedule_state_manager(clp);
625 626
		nfs4_wait_clnt_recover(clp);
	}
627 628
}

629
static void nfs_mark_return_unused_delegation_types(struct nfs_server *server,
630
						 fmode_t flags)
631 632 633
{
	struct nfs_delegation *delegation;

634
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
635 636 637
		if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
			continue;
		if (delegation->type & flags)
638
			nfs_mark_return_if_closed_delegation(server, delegation);
639
	}
640 641
}

642
static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *clp,
643 644 645 646 647 648
							fmode_t flags)
{
	struct nfs_server *server;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
649
		nfs_mark_return_unused_delegation_types(server, flags);
650
	rcu_read_unlock();
L
Linus Torvalds 已提交
651 652
}

653 654 655 656
static void nfs_mark_delegation_revoked(struct nfs_server *server,
		struct nfs_delegation *delegation)
{
	set_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
657
	delegation->stateid.type = NFS4_INVALID_STATEID_TYPE;
658 659 660 661 662
	nfs_mark_return_delegation(server, delegation);
}

static bool nfs_revoke_delegation(struct inode *inode,
		const nfs4_stateid *stateid)
663 664
{
	struct nfs_delegation *delegation;
665
	nfs4_stateid tmp;
666 667
	bool ret = false;

668 669
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
670 671
	if (delegation == NULL)
		goto out;
672 673 674 675
	if (stateid == NULL) {
		nfs4_stateid_copy(&tmp, &delegation->stateid);
		stateid = &tmp;
	} else if (!nfs4_stateid_match(stateid, &delegation->stateid))
676 677 678 679
		goto out;
	nfs_mark_delegation_revoked(NFS_SERVER(inode), delegation);
	ret = true;
out:
680
	rcu_read_unlock();
681 682
	if (ret)
		nfs_inode_find_state_and_recover(inode, stateid);
683
	return ret;
684 685
}

686 687
void nfs_remove_bad_delegation(struct inode *inode,
		const nfs4_stateid *stateid)
688 689 690
{
	struct nfs_delegation *delegation;

691 692
	if (!nfs_revoke_delegation(inode, stateid))
		return;
693
	delegation = nfs_inode_detach_delegation(inode);
694
	if (delegation)
695 696
		nfs_free_delegation(delegation);
}
A
Andy Adamson 已提交
697
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
698

699
/**
700
 * nfs_expire_unused_delegation_types
701 702 703 704
 * @clp: client to process
 * @flags: delegation types to expire
 *
 */
705
void nfs_expire_unused_delegation_types(struct nfs_client *clp, fmode_t flags)
706
{
707
	nfs_client_mark_return_unused_delegation_types(clp, flags);
708
	nfs_delegation_run_state_manager(clp);
709 710
}

711
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
712 713 714
{
	struct nfs_delegation *delegation;

715
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
716 717
		if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
			continue;
718
		nfs_mark_return_if_closed_delegation(server, delegation);
719 720 721
	}
}

722 723 724 725 726
/**
 * nfs_expire_unreferenced_delegations - Eliminate unused delegations
 * @clp: nfs_client to process
 *
 */
727 728
void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
{
729 730 731 732 733 734 735
	struct nfs_server *server;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_mark_return_unreferenced_delegations(server);
	rcu_read_unlock();

736 737 738
	nfs_delegation_run_state_manager(clp);
}

739 740 741
/**
 * nfs_async_inode_return_delegation - asynchronously return a delegation
 * @inode: inode to process
742
 * @stateid: state ID information
743 744
 *
 * Returns zero on success, or a negative errno value.
L
Linus Torvalds 已提交
745
 */
746 747
int nfs_async_inode_return_delegation(struct inode *inode,
				      const nfs4_stateid *stateid)
L
Linus Torvalds 已提交
748
{
749 750
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
751
	struct nfs_delegation *delegation;
L
Linus Torvalds 已提交
752

753 754
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
755 756
	if (delegation == NULL)
		goto out_enoent;
757 758
	if (stateid != NULL &&
	    !clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
759
		goto out_enoent;
760
	nfs_mark_return_delegation(server, delegation);
761
	rcu_read_unlock();
762

763 764
	nfs_delegation_run_state_manager(clp);
	return 0;
765 766 767
out_enoent:
	rcu_read_unlock();
	return -ENOENT;
L
Linus Torvalds 已提交
768 769
}

770 771 772
static struct inode *
nfs_delegation_find_inode_server(struct nfs_server *server,
				 const struct nfs_fh *fhandle)
L
Linus Torvalds 已提交
773 774 775
{
	struct nfs_delegation *delegation;
	struct inode *res = NULL;
776 777

	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
778 779 780
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL &&
		    nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
L
Linus Torvalds 已提交
781 782
			res = igrab(delegation->inode);
		}
783 784 785
		spin_unlock(&delegation->lock);
		if (res != NULL)
			break;
L
Linus Torvalds 已提交
786
	}
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
	return res;
}

/**
 * nfs_delegation_find_inode - retrieve the inode associated with a delegation
 * @clp: client state handle
 * @fhandle: filehandle from a delegation recall
 *
 * Returns pointer to inode matching "fhandle," or NULL if a matching inode
 * cannot be found.
 */
struct inode *nfs_delegation_find_inode(struct nfs_client *clp,
					const struct nfs_fh *fhandle)
{
	struct nfs_server *server;
	struct inode *res = NULL;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		res = nfs_delegation_find_inode_server(server, fhandle);
		if (res != NULL)
			break;
	}
810
	rcu_read_unlock();
L
Linus Torvalds 已提交
811 812 813
	return res;
}

814 815 816 817
static void nfs_delegation_mark_reclaim_server(struct nfs_server *server)
{
	struct nfs_delegation *delegation;

818 819 820 821 822 823 824
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
		/*
		 * If the delegation may have been admin revoked, then we
		 * cannot reclaim it.
		 */
		if (test_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags))
			continue;
825
		set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
826
	}
827 828 829 830 831 832
}

/**
 * nfs_delegation_mark_reclaim - mark all delegations as needing to be reclaimed
 * @clp: nfs_client to process
 *
L
Linus Torvalds 已提交
833
 */
834
void nfs_delegation_mark_reclaim(struct nfs_client *clp)
L
Linus Torvalds 已提交
835
{
836 837
	struct nfs_server *server;

838
	rcu_read_lock();
839 840
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_delegation_mark_reclaim_server(server);
841
	rcu_read_unlock();
L
Linus Torvalds 已提交
842 843
}

844 845 846 847
/**
 * nfs_delegation_reap_unclaimed - reap unclaimed delegations after reboot recovery is done
 * @clp: nfs_client to process
 *
L
Linus Torvalds 已提交
848
 */
849
void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
L
Linus Torvalds 已提交
850
{
851
	struct nfs_delegation *delegation;
852
	struct nfs_server *server;
853
	struct inode *inode;
854

855 856
restart:
	rcu_read_lock();
857 858 859
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		list_for_each_entry_rcu(delegation, &server->delegations,
								super_list) {
860 861 862
			if (test_bit(NFS_DELEGATION_RETURNING,
						&delegation->flags))
				continue;
863 864 865
			if (test_bit(NFS_DELEGATION_NEED_RECLAIM,
						&delegation->flags) == 0)
				continue;
866
			if (!nfs_sb_active(server->super))
867
				continue;
868 869 870 871 872 873
			inode = nfs_delegation_grab_inode(delegation);
			if (inode == NULL) {
				rcu_read_unlock();
				nfs_sb_deactive(server->super);
				goto restart;
			}
874
			delegation = nfs_start_delegation_return_locked(NFS_I(inode));
875
			rcu_read_unlock();
876 877 878 879 880 881
			if (delegation != NULL) {
				delegation = nfs_detach_delegation(NFS_I(inode),
					delegation, server);
				if (delegation != NULL)
					nfs_free_delegation(delegation);
			}
882
			iput(inode);
883
			nfs_sb_deactive(server->super);
884 885
			goto restart;
		}
L
Linus Torvalds 已提交
886
	}
887
	rcu_read_unlock();
L
Linus Torvalds 已提交
888
}
889

890 891 892 893 894 895 896
static inline bool nfs4_server_rebooted(const struct nfs_client *clp)
{
	return (clp->cl_state & (BIT(NFS4CLNT_CHECK_LEASE) |
				BIT(NFS4CLNT_LEASE_EXPIRED) |
				BIT(NFS4CLNT_SESSION_RESET))) != 0;
}

897 898 899
static void nfs_mark_test_expired_delegation(struct nfs_server *server,
	    struct nfs_delegation *delegation)
{
900 901
	if (delegation->stateid.type == NFS4_INVALID_STATEID_TYPE)
		return;
902 903 904 905 906
	clear_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
	set_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
	set_bit(NFS4CLNT_DELEGATION_EXPIRED, &server->nfs_client->cl_state);
}

907 908 909 910 911 912 913 914 915 916 917 918 919
static void nfs_inode_mark_test_expired_delegation(struct nfs_server *server,
		struct inode *inode)
{
	struct nfs_delegation *delegation;

	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
	if (delegation)
		nfs_mark_test_expired_delegation(server, delegation);
	rcu_read_unlock();

}

920 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 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991
static void nfs_delegation_mark_test_expired_server(struct nfs_server *server)
{
	struct nfs_delegation *delegation;

	list_for_each_entry_rcu(delegation, &server->delegations, super_list)
		nfs_mark_test_expired_delegation(server, delegation);
}

/**
 * nfs_mark_test_expired_all_delegations - mark all delegations for testing
 * @clp: nfs_client to process
 *
 * Iterates through all the delegations associated with this server and
 * marks them as needing to be checked for validity.
 */
void nfs_mark_test_expired_all_delegations(struct nfs_client *clp)
{
	struct nfs_server *server;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_delegation_mark_test_expired_server(server);
	rcu_read_unlock();
}

/**
 * nfs_reap_expired_delegations - reap expired delegations
 * @clp: nfs_client to process
 *
 * Iterates through all the delegations associated with this server and
 * checks if they have may have been revoked. This function is usually
 * expected to be called in cases where the server may have lost its
 * lease.
 */
void nfs_reap_expired_delegations(struct nfs_client *clp)
{
	const struct nfs4_minor_version_ops *ops = clp->cl_mvops;
	struct nfs_delegation *delegation;
	struct nfs_server *server;
	struct inode *inode;
	struct rpc_cred *cred;
	nfs4_stateid stateid;

restart:
	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		list_for_each_entry_rcu(delegation, &server->delegations,
								super_list) {
			if (test_bit(NFS_DELEGATION_RETURNING,
						&delegation->flags))
				continue;
			if (test_bit(NFS_DELEGATION_TEST_EXPIRED,
						&delegation->flags) == 0)
				continue;
			if (!nfs_sb_active(server->super))
				continue;
			inode = nfs_delegation_grab_inode(delegation);
			if (inode == NULL) {
				rcu_read_unlock();
				nfs_sb_deactive(server->super);
				goto restart;
			}
			cred = get_rpccred_rcu(delegation->cred);
			nfs4_stateid_copy(&stateid, &delegation->stateid);
			clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
			rcu_read_unlock();
			if (cred != NULL &&
			    ops->test_and_free_expired(server, &stateid, cred) < 0) {
				nfs_revoke_delegation(inode, &stateid);
				nfs_inode_find_state_and_recover(inode, &stateid);
			}
			put_rpccred(cred);
992 993 994 995 996 997
			if (nfs4_server_rebooted(clp)) {
				nfs_inode_mark_test_expired_delegation(server,inode);
				iput(inode);
				nfs_sb_deactive(server->super);
				return;
			}
998 999 1000 1001 1002 1003 1004 1005
			iput(inode);
			nfs_sb_deactive(server->super);
			goto restart;
		}
	}
	rcu_read_unlock();
}

1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
void nfs_inode_find_delegation_state_and_recover(struct inode *inode,
		const nfs4_stateid *stateid)
{
	struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
	struct nfs_delegation *delegation;
	bool found = false;

	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
	if (delegation &&
	    nfs4_stateid_match_other(&delegation->stateid, stateid)) {
		nfs_mark_test_expired_delegation(NFS_SERVER(inode), delegation);
		found = true;
	}
	rcu_read_unlock();
	if (found)
		nfs4_schedule_state_manager(clp);
}

1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049
/**
 * nfs_delegations_present - check for existence of delegations
 * @clp: client state handle
 *
 * Returns one if there are any nfs_delegation structures attached
 * to this nfs_client.
 */
int nfs_delegations_present(struct nfs_client *clp)
{
	struct nfs_server *server;
	int ret = 0;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		if (!list_empty(&server->delegations)) {
			ret = 1;
			break;
		}
	rcu_read_unlock();
	return ret;
}

/**
 * nfs4_copy_delegation_stateid - Copy inode's state ID information
 * @inode: inode to check
1050
 * @flags: delegation type requirement
1051 1052
 * @dst: stateid data structure to fill in
 * @cred: optional argument to retrieve credential
1053
 *
1054 1055
 * Returns "true" and fills in "dst->data" * if inode had a delegation,
 * otherwise "false" is returned.
1056
 */
1057 1058
bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags,
		nfs4_stateid *dst, struct rpc_cred **cred)
1059 1060 1061
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
1062
	bool ret;
1063

1064
	flags &= FMODE_READ|FMODE_WRITE;
1065 1066
	rcu_read_lock();
	delegation = rcu_dereference(nfsi->delegation);
1067
	ret = nfs4_is_valid_delegation(delegation, flags);
1068
	if (ret) {
1069
		nfs4_stateid_copy(dst, &delegation->stateid);
1070
		nfs_mark_delegation_referenced(delegation);
1071 1072
		if (cred)
			*cred = get_rpccred(delegation->cred);
1073
	}
1074 1075
	rcu_read_unlock();
	return ret;
1076
}
1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101

/**
 * nfs4_delegation_flush_on_close - Check if we must flush file on close
 * @inode: inode to check
 *
 * This function checks the number of outstanding writes to the file
 * against the delegation 'space_limit' field to see if
 * the spec requires us to flush the file on close.
 */
bool nfs4_delegation_flush_on_close(const struct inode *inode)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
	bool ret = true;

	rcu_read_lock();
	delegation = rcu_dereference(nfsi->delegation);
	if (delegation == NULL || !(delegation->type & FMODE_WRITE))
		goto out;
	if (nfsi->nrequests < delegation->pagemod_limit)
		ret = false;
out:
	rcu_read_unlock();
	return ret;
}