delegation.c 25.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 199 200 201 202 203 204 205 206
		} else {
			/* We appear to have raced with a delegation return. */
			spin_unlock(&delegation->lock);
			rcu_read_unlock();
			nfs_inode_set_delegation(inode, cred, res);
		}
	} else {
		rcu_read_unlock();
	}
L
Linus Torvalds 已提交
207 208
}

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

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

222 223 224 225 226 227 228 229 230 231 232
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;
}

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

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

281 282
	if (deleg_cur == NULL || delegation != deleg_cur)
		return NULL;
283

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

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

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

305 306 307 308 309 310 311 312 313 314 315 316 317
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);
}

318 319 320 321 322 323 324 325 326 327 328
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;
	}
}

329 330 331 332 333 334 335
/**
 * 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 已提交
336 337 338
 */
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
{
339 340
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
341
	struct nfs_inode *nfsi = NFS_I(inode);
342
	struct nfs_delegation *delegation, *old_delegation;
343
	struct nfs_delegation *freeme = NULL;
L
Linus Torvalds 已提交
344 345
	int status = 0;

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

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

	/* 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);
400
	trace_nfs4_set_delegation(inode, res->delegation_type);
401

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

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

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

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

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

451 452
	if (test_bit(NFS_DELEGATION_RETURNING, &delegation->flags))
		goto out;
453 454 455 456 457 458 459 460 461 462 463
	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);
	}
464
out:
465 466 467
	return ret;
}

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

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

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

516 517 518 519 520 521
/**
 * 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().
522 523 524 525 526
 */
void nfs_inode_return_delegation_noreclaim(struct inode *inode)
{
	struct nfs_delegation *delegation;

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

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

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

555 556 557 558 559 560 561
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);
}

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

569 570 571 572 573 574 575 576 577 578 579 580
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;
}

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

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

	if (clp == NULL)
		return;
620

621
	rcu_read_lock();
622
	need_wait = nfs_server_mark_return_all_delegations(server);
623
	rcu_read_unlock();
624

625
	if (need_wait) {
626
		nfs4_schedule_state_manager(clp);
627 628
		nfs4_wait_clnt_recover(clp);
	}
629 630
}

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

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

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

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

655 656 657 658 659 660 661 662 663
static void nfs_mark_delegation_revoked(struct nfs_server *server,
		struct nfs_delegation *delegation)
{
	set_bit(NFS_DELEGATION_REVOKED, &delegation->flags);
	nfs_mark_return_delegation(server, delegation);
}

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

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

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

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

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

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

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

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

733 734 735
	nfs_delegation_run_state_manager(clp);
}

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

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

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

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

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

811 812 813 814 815 816 817 818 819 820 821 822
static void nfs_delegation_mark_reclaim_server(struct nfs_server *server)
{
	struct nfs_delegation *delegation;

	list_for_each_entry_rcu(delegation, &server->delegations, super_list)
		set_bit(NFS_DELEGATION_NEED_RECLAIM, &delegation->flags);
}

/**
 * nfs_delegation_mark_reclaim - mark all delegations as needing to be reclaimed
 * @clp: nfs_client to process
 *
L
Linus Torvalds 已提交
823
 */
824
void nfs_delegation_mark_reclaim(struct nfs_client *clp)
L
Linus Torvalds 已提交
825
{
826 827
	struct nfs_server *server;

828
	rcu_read_lock();
829 830
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_delegation_mark_reclaim_server(server);
831
	rcu_read_unlock();
L
Linus Torvalds 已提交
832 833
}

834 835 836 837
/**
 * nfs_delegation_reap_unclaimed - reap unclaimed delegations after reboot recovery is done
 * @clp: nfs_client to process
 *
L
Linus Torvalds 已提交
838
 */
839
void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
L
Linus Torvalds 已提交
840
{
841
	struct nfs_delegation *delegation;
842
	struct nfs_server *server;
843
	struct inode *inode;
844

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

880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
/**
 * 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
905
 * @flags: delegation type requirement
906 907
 * @dst: stateid data structure to fill in
 * @cred: optional argument to retrieve credential
908
 *
909 910
 * Returns "true" and fills in "dst->data" * if inode had a delegation,
 * otherwise "false" is returned.
911
 */
912 913
bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags,
		nfs4_stateid *dst, struct rpc_cred **cred)
914 915 916
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
917
	bool ret;
918

919
	flags &= FMODE_READ|FMODE_WRITE;
920 921
	rcu_read_lock();
	delegation = rcu_dereference(nfsi->delegation);
922
	ret = nfs4_is_valid_delegation(delegation, flags);
923
	if (ret) {
924
		nfs4_stateid_copy(dst, &delegation->stateid);
925
		nfs_mark_delegation_referenced(delegation);
926 927
		if (cred)
			*cred = get_rpccred(delegation->cred);
928
	}
929 930
	rcu_read_unlock();
	return ret;
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

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