delegation.c 29.0 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
	trace_nfs4_set_delegation(inode, res->delegation_type);
395

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

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

414 415 416
	if (delegation == NULL)
		return 0;
	do {
417 418
		if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags))
			break;
419 420
		err = nfs_delegation_claim_opens(inode, &delegation->stateid,
				delegation->type);
421 422 423 424 425 426 427 428 429 430 431 432 433
		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)))
434
		goto out;
L
Linus Torvalds 已提交
435

436 437 438
	err = nfs_do_return_delegation(inode, delegation, issync);
out:
	return err;
439 440
}

441 442 443 444
static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
{
	bool ret = false;

445 446
	if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
		goto out;
447 448 449 450 451 452 453 454 455 456 457
	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);
	}
458
out:
459 460 461
	return ret;
}

462 463 464 465
/**
 * nfs_client_return_marked_delegations - return previously marked delegations
 * @clp: nfs_client to process
 *
466 467 468 469
 * 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.
 *
470
 * Returns zero on success, or a negative errno value.
471
 */
472
int nfs_client_return_marked_delegations(struct nfs_client *clp)
473 474
{
	struct nfs_delegation *delegation;
475
	struct nfs_server *server;
476
	struct inode *inode;
477
	int err = 0;
478 479 480

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

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

510 511 512 513 514 515
/**
 * 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().
516 517 518 519 520
 */
void nfs_inode_return_delegation_noreclaim(struct inode *inode)
{
	struct nfs_delegation *delegation;

521 522
	delegation = nfs_inode_detach_delegation(inode);
	if (delegation != NULL)
523
		nfs_do_return_delegation(inode, delegation, 1);
524 525
}

526 527 528 529
/**
 * nfs_inode_return_delegation - synchronously return a delegation
 * @inode: inode to process
 *
530 531 532 533
 * 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.
 *
534 535
 * Returns zero on success, or a negative errno value.
 */
536
int nfs4_inode_return_delegation(struct inode *inode)
537 538 539 540 541
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
	int err = 0;

542
	nfs_wb_all(inode);
543 544 545
	delegation = nfs_start_delegation_return(nfsi);
	if (delegation != NULL)
		err = nfs_end_delegation_return(inode, delegation, 1);
546
	return err;
L
Linus Torvalds 已提交
547 548
}

549 550 551 552 553 554 555
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);
}

556 557
static void nfs_mark_return_delegation(struct nfs_server *server,
		struct nfs_delegation *delegation)
558 559
{
	set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
560
	set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
561 562
}

563 564 565 566 567 568 569 570 571 572 573 574
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;
}

575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601
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);
}

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

	if (clp == NULL)
		return;
614

615
	rcu_read_lock();
616
	need_wait = nfs_server_mark_return_all_delegations(server);
617
	rcu_read_unlock();
618

619
	if (need_wait) {
620
		nfs4_schedule_state_manager(clp);
621 622
		nfs4_wait_clnt_recover(clp);
	}
623 624
}

625
static void nfs_mark_return_unused_delegation_types(struct nfs_server *server,
626
						 fmode_t flags)
627 628 629
{
	struct nfs_delegation *delegation;

630
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
631 632 633
		if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
			continue;
		if (delegation->type & flags)
634
			nfs_mark_return_if_closed_delegation(server, delegation);
635
	}
636 637
}

638
static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *clp,
639 640 641 642 643 644
							fmode_t flags)
{
	struct nfs_server *server;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
645
		nfs_mark_return_unused_delegation_types(server, flags);
646
	rcu_read_unlock();
L
Linus Torvalds 已提交
647 648
}

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

static bool nfs_revoke_delegation(struct inode *inode,
		const nfs4_stateid *stateid)
659 660
{
	struct nfs_delegation *delegation;
661
	nfs4_stateid tmp;
662 663
	bool ret = false;

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

682 683
void nfs_remove_bad_delegation(struct inode *inode,
		const nfs4_stateid *stateid)
684 685 686
{
	struct nfs_delegation *delegation;

687 688
	if (!nfs_revoke_delegation(inode, stateid))
		return;
689
	delegation = nfs_inode_detach_delegation(inode);
690
	if (delegation)
691 692
		nfs_free_delegation(delegation);
}
A
Andy Adamson 已提交
693
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
694

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

707
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
708 709 710
{
	struct nfs_delegation *delegation;

711
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
712 713
		if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
			continue;
714
		nfs_mark_return_if_closed_delegation(server, delegation);
715 716 717
	}
}

718 719 720 721 722
/**
 * nfs_expire_unreferenced_delegations - Eliminate unused delegations
 * @clp: nfs_client to process
 *
 */
723 724
void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
{
725 726 727 728 729 730 731
	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();

732 733 734
	nfs_delegation_run_state_manager(clp);
}

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

749 750
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
751 752
	if (delegation == NULL)
		goto out_enoent;
753 754
	if (stateid != NULL &&
	    !clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
755
		goto out_enoent;
756
	nfs_mark_return_delegation(server, delegation);
757
	rcu_read_unlock();
758

759 760
	nfs_delegation_run_state_manager(clp);
	return 0;
761 762 763
out_enoent:
	rcu_read_unlock();
	return -ENOENT;
L
Linus Torvalds 已提交
764 765
}

766 767 768
static struct inode *
nfs_delegation_find_inode_server(struct nfs_server *server,
				 const struct nfs_fh *fhandle)
L
Linus Torvalds 已提交
769 770 771
{
	struct nfs_delegation *delegation;
	struct inode *res = NULL;
772 773

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

810 811 812 813
static void nfs_delegation_mark_reclaim_server(struct nfs_server *server)
{
	struct nfs_delegation *delegation;

814 815 816 817 818 819 820
	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;
821
		set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
822
	}
823 824 825 826 827 828
}

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

834
	rcu_read_lock();
835 836
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_delegation_mark_reclaim_server(server);
837
	rcu_read_unlock();
L
Linus Torvalds 已提交
838 839
}

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

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

886 887 888 889 890 891 892
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;
}

893 894 895
static void nfs_mark_test_expired_delegation(struct nfs_server *server,
	    struct nfs_delegation *delegation)
{
896 897
	if (delegation->stateid.type == NFS4_INVALID_STATEID_TYPE)
		return;
898 899 900 901 902
	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);
}

903 904 905 906 907 908 909 910 911 912 913 914 915
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();

}

916 917 918 919 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
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);
988 989 990 991 992 993
			if (nfs4_server_rebooted(clp)) {
				nfs_inode_mark_test_expired_delegation(server,inode);
				iput(inode);
				nfs_sb_deactive(server->super);
				return;
			}
994 995 996 997 998 999 1000 1001
			iput(inode);
			nfs_sb_deactive(server->super);
			goto restart;
		}
	}
	rcu_read_unlock();
}

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
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);
}

1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045
/**
 * 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
1046
 * @flags: delegation type requirement
1047 1048
 * @dst: stateid data structure to fill in
 * @cred: optional argument to retrieve credential
1049
 *
1050 1051
 * Returns "true" and fills in "dst->data" * if inode had a delegation,
 * otherwise "false" is returned.
1052
 */
1053 1054
bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags,
		nfs4_stateid *dst, struct rpc_cred **cred)
1055 1056 1057
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
1058
	bool ret;
1059

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

/**
 * 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;
}