delegation.c 21.4 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"
L
Linus Torvalds 已提交
23

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

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

43 44 45 46 47 48 49
/**
 * nfs_have_delegation - check if inode has a delegation
 * @inode: inode to check
 * @flags: delegation types to check for
 *
 * Returns one if inode has the indicated delegation, otherwise zero.
 */
50
int nfs4_have_delegation(struct inode *inode, fmode_t flags)
51 52 53 54 55 56 57
{
	struct nfs_delegation *delegation;
	int ret = 0;

	flags &= FMODE_READ|FMODE_WRITE;
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
58 59
	if (delegation != NULL && (delegation->type & flags) == flags &&
	    !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) {
60 61 62 63 64 65 66
		nfs_mark_delegation_referenced(delegation);
		ret = 1;
	}
	rcu_read_unlock();
	return ret;
}

67
static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid)
68 69 70
{
	struct inode *inode = state->inode;
	struct file_lock *fl;
71
	int status = 0;
72

73
	if (inode->i_flock == NULL)
74
		return 0;
75

76 77
	if (inode->i_flock == NULL)
		goto out;
78 79
	/* Protect inode->i_flock using the file locks lock */
	lock_flocks();
H
Harvey Harrison 已提交
80
	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
81 82
		if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
			continue;
83
		if (nfs_file_open_context(fl->fl_file) != ctx)
84
			continue;
85
		unlock_flocks();
86
		status = nfs4_lock_delegation_recall(fl, state, stateid);
87
		if (status < 0)
88
			goto out;
89
		lock_flocks();
90
	}
91
	unlock_flocks();
92
out:
93 94 95
	return status;
}

96
static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid)
L
Linus Torvalds 已提交
97 98 99
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_open_context *ctx;
100
	struct nfs4_state_owner *sp;
L
Linus Torvalds 已提交
101
	struct nfs4_state *state;
102
	unsigned int seq;
103
	int err;
L
Linus Torvalds 已提交
104 105 106 107 108 109 110 111 112

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;
113
		if (!nfs4_stateid_match(&state->stateid, stateid))
114
			continue;
L
Linus Torvalds 已提交
115 116
		get_nfs_open_context(ctx);
		spin_unlock(&inode->i_lock);
117
		sp = state->owner;
118 119
		/* Block nfs4_proc_unlck */
		mutex_lock(&sp->so_delegreturn_mutex);
120
		seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
121
		err = nfs4_open_delegation_recall(ctx, state, stateid);
122
		if (!err)
123
			err = nfs_delegation_claim_locks(ctx, state, stateid);
124 125
		if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
			err = -EAGAIN;
126
		mutex_unlock(&sp->so_delegreturn_mutex);
L
Linus Torvalds 已提交
127
		put_nfs_open_context(ctx);
128
		if (err != 0)
129
			return err;
L
Linus Torvalds 已提交
130 131 132
		goto again;
	}
	spin_unlock(&inode->i_lock);
133
	return 0;
L
Linus Torvalds 已提交
134 135
}

136 137 138 139 140 141
/**
 * 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 已提交
142
 */
143 144
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
				  struct nfs_openres *res)
L
Linus Torvalds 已提交
145
{
146 147
	struct nfs_delegation *delegation;
	struct rpc_cred *oldcred = NULL;
L
Linus Torvalds 已提交
148

149 150 151 152 153
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
	if (delegation != NULL) {
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL) {
154
			nfs4_stateid_copy(&delegation->stateid, &res->delegation);
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173
			delegation->type = res->delegation_type;
			delegation->maxsize = res->maxsize;
			oldcred = delegation->cred;
			delegation->cred = get_rpccred(cred);
			clear_bit(NFS_DELEGATION_NEED_RECLAIM,
				  &delegation->flags);
			NFS_I(inode)->delegation_state = delegation->type;
			spin_unlock(&delegation->lock);
			put_rpccred(oldcred);
			rcu_read_unlock();
		} 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 已提交
174 175
}

176 177 178 179 180 181 182 183 184
static int nfs_do_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
{
	int res = 0;

	res = nfs4_proc_delegreturn(inode, delegation->cred, &delegation->stateid, issync);
	nfs_free_delegation(delegation);
	return res;
}

185 186 187 188 189 190 191 192 193 194 195
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;
}

196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234
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);
}

235 236
static struct nfs_delegation *
nfs_detach_delegation_locked(struct nfs_inode *nfsi,
237 238
		struct nfs_delegation *delegation,
		struct nfs_client *clp)
239
{
240
	struct nfs_delegation *deleg_cur =
241
		rcu_dereference_protected(nfsi->delegation,
242
				lockdep_is_held(&clp->cl_lock));
243

244 245
	if (deleg_cur == NULL || delegation != deleg_cur)
		return NULL;
246

247
	spin_lock(&delegation->lock);
248
	set_bit(NFS_DELEGATION_RETURNING, &delegation->flags);
249
	list_del_rcu(&delegation->super_list);
250
	delegation->inode = NULL;
251 252
	nfsi->delegation_state = 0;
	rcu_assign_pointer(nfsi->delegation, NULL);
253
	spin_unlock(&delegation->lock);
254 255 256
	return delegation;
}

257
static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi,
258 259
		struct nfs_delegation *delegation,
		struct nfs_server *server)
260
{
261
	struct nfs_client *clp = server->nfs_client;
262 263

	spin_lock(&clp->cl_lock);
264
	delegation = nfs_detach_delegation_locked(nfsi, delegation, clp);
265 266 267 268
	spin_unlock(&clp->cl_lock);
	return delegation;
}

269 270 271 272 273 274 275 276 277 278 279 280 281
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);
}

282 283 284 285 286 287 288
/**
 * 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 已提交
289 290 291
 */
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
{
292 293
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
294
	struct nfs_inode *nfsi = NFS_I(inode);
295
	struct nfs_delegation *delegation, *old_delegation;
296
	struct nfs_delegation *freeme = NULL;
L
Linus Torvalds 已提交
297 298
	int status = 0;

299
	delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
L
Linus Torvalds 已提交
300 301
	if (delegation == NULL)
		return -ENOMEM;
302
	nfs4_stateid_copy(&delegation->stateid, &res->delegation);
L
Linus Torvalds 已提交
303 304
	delegation->type = res->delegation_type;
	delegation->maxsize = res->maxsize;
305
	delegation->change_attr = inode->i_version;
L
Linus Torvalds 已提交
306 307
	delegation->cred = get_rpccred(cred);
	delegation->inode = inode;
308
	delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
309
	spin_lock_init(&delegation->lock);
L
Linus Torvalds 已提交
310 311

	spin_lock(&clp->cl_lock);
312
	old_delegation = rcu_dereference_protected(nfsi->delegation,
313
					lockdep_is_held(&clp->cl_lock));
314
	if (old_delegation != NULL) {
315 316
		if (nfs4_stateid_match(&delegation->stateid,
					&old_delegation->stateid) &&
317
				delegation->type == old_delegation->type) {
318
			goto out;
L
Linus Torvalds 已提交
319
		}
320 321 322
		/*
		 * Deal with broken servers that hand out two
		 * delegations for the same file.
323 324
		 * Allow for upgrades to a WRITE delegation, but
		 * nothing else.
325 326 327
		 */
		dfprintk(FILE, "%s: server %s handed out "
				"a duplicate delegation!\n",
328
				__func__, clp->cl_hostname);
329 330
		if (delegation->type == old_delegation->type ||
		    !(delegation->type & FMODE_WRITE)) {
331 332 333 334
			freeme = delegation;
			delegation = NULL;
			goto out;
		}
335 336 337 338
		freeme = nfs_detach_delegation_locked(nfsi, 
				old_delegation, clp);
		if (freeme == NULL)
			goto out;
L
Linus Torvalds 已提交
339
	}
340
	list_add_rcu(&delegation->super_list, &server->delegations);
341 342 343
	nfsi->delegation_state = delegation->type;
	rcu_assign_pointer(nfsi->delegation, delegation);
	delegation = NULL;
344 345 346 347 348 349

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

350
out:
L
Linus Torvalds 已提交
351
	spin_unlock(&clp->cl_lock);
352 353
	if (delegation != NULL)
		nfs_free_delegation(delegation);
354 355
	if (freeme != NULL)
		nfs_do_return_delegation(inode, freeme, 0);
L
Linus Torvalds 已提交
356 357 358 359 360 361
	return status;
}

/*
 * Basic procedure for returning a delegation to the server
 */
362
static int nfs_end_delegation_return(struct inode *inode, struct nfs_delegation *delegation, int issync)
L
Linus Torvalds 已提交
363
{
364
	struct nfs_client *clp = NFS_SERVER(inode)->nfs_client;
L
Linus Torvalds 已提交
365
	struct nfs_inode *nfsi = NFS_I(inode);
366
	int err;
L
Linus Torvalds 已提交
367

368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
	if (delegation == NULL)
		return 0;
	do {
		err = nfs_delegation_claim_opens(inode, &delegation->stateid);
		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)))
385
		goto out;
L
Linus Torvalds 已提交
386

387 388 389
	err = nfs_do_return_delegation(inode, delegation, issync);
out:
	return err;
390 391
}

392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
{
	bool ret = false;

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

410 411 412 413
/**
 * nfs_client_return_marked_delegations - return previously marked delegations
 * @clp: nfs_client to process
 *
414 415 416 417
 * 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.
 *
418
 * Returns zero on success, or a negative errno value.
419
 */
420
int nfs_client_return_marked_delegations(struct nfs_client *clp)
421 422
{
	struct nfs_delegation *delegation;
423
	struct nfs_server *server;
424
	struct inode *inode;
425
	int err = 0;
426 427 428

restart:
	rcu_read_lock();
429 430 431
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		list_for_each_entry_rcu(delegation, &server->delegations,
								super_list) {
432
			if (!nfs_delegation_need_return(delegation))
433 434 435 436
				continue;
			inode = nfs_delegation_grab_inode(delegation);
			if (inode == NULL)
				continue;
437
			delegation = nfs_start_delegation_return_locked(NFS_I(inode));
438 439
			rcu_read_unlock();

440
			err = nfs_end_delegation_return(inode, delegation, 0);
441 442 443 444 445
			iput(inode);
			if (!err)
				goto restart;
			set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
			return err;
446
		}
447 448
	}
	rcu_read_unlock();
449
	return 0;
450 451
}

452 453 454 455 456 457
/**
 * 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().
458 459 460 461 462
 */
void nfs_inode_return_delegation_noreclaim(struct inode *inode)
{
	struct nfs_delegation *delegation;

463 464 465
	delegation = nfs_inode_detach_delegation(inode);
	if (delegation != NULL)
		nfs_do_return_delegation(inode, delegation, 0);
466 467
}

468 469 470 471
/**
 * nfs_inode_return_delegation - synchronously return a delegation
 * @inode: inode to process
 *
472 473 474 475
 * 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.
 *
476 477
 * Returns zero on success, or a negative errno value.
 */
478
int nfs4_inode_return_delegation(struct inode *inode)
479 480 481 482 483
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
	int err = 0;

484
	nfs_wb_all(inode);
485 486 487
	delegation = nfs_start_delegation_return(nfsi);
	if (delegation != NULL)
		err = nfs_end_delegation_return(inode, delegation, 1);
488
	return err;
L
Linus Torvalds 已提交
489 490
}

491 492 493 494 495 496 497
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);
}

498 499
static void nfs_mark_return_delegation(struct nfs_server *server,
		struct nfs_delegation *delegation)
500 501
{
	set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
502
	set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
503 504
}

505 506 507 508 509 510 511 512 513 514 515 516
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;
}

517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
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);
}

544 545 546 547
/**
 * nfs_super_return_all_delegations - return delegations for one superblock
 * @sb: sb to process
 *
L
Linus Torvalds 已提交
548
 */
549
void nfs_server_return_all_delegations(struct nfs_server *server)
L
Linus Torvalds 已提交
550
{
551
	struct nfs_client *clp = server->nfs_client;
552
	bool need_wait;
L
Linus Torvalds 已提交
553 554 555

	if (clp == NULL)
		return;
556

557
	rcu_read_lock();
558
	need_wait = nfs_server_mark_return_all_delegations(server);
559
	rcu_read_unlock();
560

561
	if (need_wait) {
562
		nfs4_schedule_state_manager(clp);
563 564
		nfs4_wait_clnt_recover(clp);
	}
565 566
}

567
static void nfs_mark_return_unused_delegation_types(struct nfs_server *server,
568
						 fmode_t flags)
569 570 571
{
	struct nfs_delegation *delegation;

572
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
573 574 575
		if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
			continue;
		if (delegation->type & flags)
576
			nfs_mark_return_if_closed_delegation(server, delegation);
577
	}
578 579
}

580
static void nfs_client_mark_return_unused_delegation_types(struct nfs_client *clp,
581 582 583 584 585 586
							fmode_t flags)
{
	struct nfs_server *server;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
587
		nfs_mark_return_unused_delegation_types(server, flags);
588
	rcu_read_unlock();
L
Linus Torvalds 已提交
589 590
}

591 592 593 594
void nfs_remove_bad_delegation(struct inode *inode)
{
	struct nfs_delegation *delegation;

595
	delegation = nfs_inode_detach_delegation(inode);
596 597 598 599 600
	if (delegation) {
		nfs_inode_find_state_and_recover(inode, &delegation->stateid);
		nfs_free_delegation(delegation);
	}
}
A
Andy Adamson 已提交
601
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
602

603
/**
604
 * nfs_expire_unused_delegation_types
605 606 607 608
 * @clp: client to process
 * @flags: delegation types to expire
 *
 */
609
void nfs_expire_unused_delegation_types(struct nfs_client *clp, fmode_t flags)
610
{
611
	nfs_client_mark_return_unused_delegation_types(clp, flags);
612
	nfs_delegation_run_state_manager(clp);
613 614
}

615
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
616 617 618
{
	struct nfs_delegation *delegation;

619
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
620 621
		if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
			continue;
622
		nfs_mark_return_if_closed_delegation(server, delegation);
623 624 625
	}
}

626 627 628 629 630
/**
 * nfs_expire_unreferenced_delegations - Eliminate unused delegations
 * @clp: nfs_client to process
 *
 */
631 632
void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
{
633 634 635 636 637 638 639
	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();

640 641 642
	nfs_delegation_run_state_manager(clp);
}

643 644 645
/**
 * nfs_async_inode_return_delegation - asynchronously return a delegation
 * @inode: inode to process
646
 * @stateid: state ID information
647 648
 *
 * Returns zero on success, or a negative errno value.
L
Linus Torvalds 已提交
649
 */
650 651
int nfs_async_inode_return_delegation(struct inode *inode,
				      const nfs4_stateid *stateid)
L
Linus Torvalds 已提交
652
{
653 654
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
655
	struct nfs_delegation *delegation;
L
Linus Torvalds 已提交
656

657 658
	filemap_flush(inode->i_mapping);

659 660
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
A
Alexandros Batsakis 已提交
661

662
	if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
663 664 665
		rcu_read_unlock();
		return -ENOENT;
	}
666
	nfs_mark_return_delegation(server, delegation);
667
	rcu_read_unlock();
668

669 670
	nfs_delegation_run_state_manager(clp);
	return 0;
L
Linus Torvalds 已提交
671 672
}

673 674 675
static struct inode *
nfs_delegation_find_inode_server(struct nfs_server *server,
				 const struct nfs_fh *fhandle)
L
Linus Torvalds 已提交
676 677 678
{
	struct nfs_delegation *delegation;
	struct inode *res = NULL;
679 680

	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
681 682 683
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL &&
		    nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
L
Linus Torvalds 已提交
684 685
			res = igrab(delegation->inode);
		}
686 687 688
		spin_unlock(&delegation->lock);
		if (res != NULL)
			break;
L
Linus Torvalds 已提交
689
	}
690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712
	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;
	}
713
	rcu_read_unlock();
L
Linus Torvalds 已提交
714 715 716
	return res;
}

717 718 719 720 721 722 723 724 725 726 727 728
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 已提交
729
 */
730
void nfs_delegation_mark_reclaim(struct nfs_client *clp)
L
Linus Torvalds 已提交
731
{
732 733
	struct nfs_server *server;

734
	rcu_read_lock();
735 736
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_delegation_mark_reclaim_server(server);
737
	rcu_read_unlock();
L
Linus Torvalds 已提交
738 739
}

740 741 742 743
/**
 * nfs_delegation_reap_unclaimed - reap unclaimed delegations after reboot recovery is done
 * @clp: nfs_client to process
 *
L
Linus Torvalds 已提交
744
 */
745
void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
L
Linus Torvalds 已提交
746
{
747
	struct nfs_delegation *delegation;
748
	struct nfs_server *server;
749
	struct inode *inode;
750

751 752
restart:
	rcu_read_lock();
753 754 755 756 757 758 759 760 761 762
	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_NEED_RECLAIM,
						&delegation->flags) == 0)
				continue;
			inode = nfs_delegation_grab_inode(delegation);
			if (inode == NULL)
				continue;
			delegation = nfs_detach_delegation(NFS_I(inode),
763
					delegation, server);
764 765 766 767 768 769 770
			rcu_read_unlock();

			if (delegation != NULL)
				nfs_free_delegation(delegation);
			iput(inode);
			goto restart;
		}
L
Linus Torvalds 已提交
771
	}
772
	rcu_read_unlock();
L
Linus Torvalds 已提交
773
}
774

775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800
/**
 * 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
 * @dst: stateid data structure to fill in
 * @inode: inode to check
801
 * @flags: delegation type requirement
802
 *
803 804
 * Returns "true" and fills in "dst->data" * if inode had a delegation,
 * otherwise "false" is returned.
805
 */
806 807
bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
		fmode_t flags)
808 809 810
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
811
	bool ret;
812

813
	flags &= FMODE_READ|FMODE_WRITE;
814 815
	rcu_read_lock();
	delegation = rcu_dereference(nfsi->delegation);
816 817
	ret = (delegation != NULL && (delegation->type & flags) == flags);
	if (ret) {
818
		nfs4_stateid_copy(dst, &delegation->stateid);
819
		nfs_mark_delegation_referenced(delegation);
820
	}
821 822
	rcu_read_unlock();
	return ret;
823
}