delegation.c 20.9 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
/**
 * nfs_super_return_all_delegations - return delegations for one superblock
 * @sb: sb to process
 *
L
Linus Torvalds 已提交
509
 */
510
void nfs_server_return_all_delegations(struct nfs_server *server)
L
Linus Torvalds 已提交
511
{
512
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
513 514 515 516
	struct nfs_delegation *delegation;

	if (clp == NULL)
		return;
517

518
	rcu_read_lock();
519
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
520
		spin_lock(&delegation->lock);
521
		set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
522
		spin_unlock(&delegation->lock);
L
Linus Torvalds 已提交
523
	}
524
	rcu_read_unlock();
525

526 527
	if (nfs_client_return_marked_delegations(clp) != 0)
		nfs4_schedule_state_manager(clp);
528 529
}

530 531
static void nfs_mark_return_all_delegation_types(struct nfs_server *server,
						 fmode_t flags)
532 533 534
{
	struct nfs_delegation *delegation;

535
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
536 537 538
		if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
			continue;
		if (delegation->type & flags)
539
			nfs_mark_return_delegation(server, delegation);
540
	}
541 542 543 544 545 546 547 548 549 550
}

static void nfs_client_mark_return_all_delegation_types(struct nfs_client *clp,
							fmode_t flags)
{
	struct nfs_server *server;

	rcu_read_lock();
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_mark_return_all_delegation_types(server, flags);
551
	rcu_read_unlock();
L
Linus Torvalds 已提交
552 553
}

554
static void nfs_delegation_run_state_manager(struct nfs_client *clp)
555
{
556 557
	if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
		nfs4_schedule_state_manager(clp);
558 559
}

560 561 562 563
void nfs_remove_bad_delegation(struct inode *inode)
{
	struct nfs_delegation *delegation;

564
	delegation = nfs_inode_detach_delegation(inode);
565 566 567 568 569
	if (delegation) {
		nfs_inode_find_state_and_recover(inode, &delegation->stateid);
		nfs_free_delegation(delegation);
	}
}
A
Andy Adamson 已提交
570
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
571

572 573 574 575 576 577
/**
 * nfs_expire_all_delegation_types
 * @clp: client to process
 * @flags: delegation types to expire
 *
 */
578
void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags)
579
{
580
	nfs_client_mark_return_all_delegation_types(clp, flags);
581
	nfs_delegation_run_state_manager(clp);
582 583
}

584 585 586 587 588
/**
 * nfs_expire_all_delegations
 * @clp: client to process
 *
 */
589 590 591 592 593
void nfs_expire_all_delegations(struct nfs_client *clp)
{
	nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
}

594
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
595 596 597
{
	struct nfs_delegation *delegation;

598
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
599 600
		if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
			continue;
601
		nfs_mark_return_if_closed_delegation(server, delegation);
602 603 604
	}
}

605 606 607 608 609
/**
 * nfs_expire_unreferenced_delegations - Eliminate unused delegations
 * @clp: nfs_client to process
 *
 */
610 611
void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
{
612 613 614 615 616 617 618
	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();

619 620 621
	nfs_delegation_run_state_manager(clp);
}

622 623 624
/**
 * nfs_async_inode_return_delegation - asynchronously return a delegation
 * @inode: inode to process
625
 * @stateid: state ID information
626 627
 *
 * Returns zero on success, or a negative errno value.
L
Linus Torvalds 已提交
628
 */
629 630
int nfs_async_inode_return_delegation(struct inode *inode,
				      const nfs4_stateid *stateid)
L
Linus Torvalds 已提交
631
{
632 633
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
634
	struct nfs_delegation *delegation;
L
Linus Torvalds 已提交
635

636 637
	filemap_flush(inode->i_mapping);

638 639
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
A
Alexandros Batsakis 已提交
640

641
	if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
642 643 644
		rcu_read_unlock();
		return -ENOENT;
	}
645
	nfs_mark_return_delegation(server, delegation);
646
	rcu_read_unlock();
647

648 649
	nfs_delegation_run_state_manager(clp);
	return 0;
L
Linus Torvalds 已提交
650 651
}

652 653 654
static struct inode *
nfs_delegation_find_inode_server(struct nfs_server *server,
				 const struct nfs_fh *fhandle)
L
Linus Torvalds 已提交
655 656 657
{
	struct nfs_delegation *delegation;
	struct inode *res = NULL;
658 659

	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
660 661 662
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL &&
		    nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
L
Linus Torvalds 已提交
663 664
			res = igrab(delegation->inode);
		}
665 666 667
		spin_unlock(&delegation->lock);
		if (res != NULL)
			break;
L
Linus Torvalds 已提交
668
	}
669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691
	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;
	}
692
	rcu_read_unlock();
L
Linus Torvalds 已提交
693 694 695
	return res;
}

696 697 698 699 700 701 702 703 704 705 706 707
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 已提交
708
 */
709
void nfs_delegation_mark_reclaim(struct nfs_client *clp)
L
Linus Torvalds 已提交
710
{
711 712
	struct nfs_server *server;

713
	rcu_read_lock();
714 715
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_delegation_mark_reclaim_server(server);
716
	rcu_read_unlock();
L
Linus Torvalds 已提交
717 718
}

719 720 721 722
/**
 * nfs_delegation_reap_unclaimed - reap unclaimed delegations after reboot recovery is done
 * @clp: nfs_client to process
 *
L
Linus Torvalds 已提交
723
 */
724
void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
L
Linus Torvalds 已提交
725
{
726
	struct nfs_delegation *delegation;
727
	struct nfs_server *server;
728
	struct inode *inode;
729

730 731
restart:
	rcu_read_lock();
732 733 734 735 736 737 738 739 740 741
	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),
742
					delegation, server);
743 744 745 746 747 748 749
			rcu_read_unlock();

			if (delegation != NULL)
				nfs_free_delegation(delegation);
			iput(inode);
			goto restart;
		}
L
Linus Torvalds 已提交
750
	}
751
	rcu_read_unlock();
L
Linus Torvalds 已提交
752
}
753

754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779
/**
 * 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
780
 * @flags: delegation type requirement
781
 *
782 783
 * Returns "true" and fills in "dst->data" * if inode had a delegation,
 * otherwise "false" is returned.
784
 */
785 786
bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
		fmode_t flags)
787 788 789
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
790
	bool ret;
791

792
	flags &= FMODE_READ|FMODE_WRITE;
793 794
	rcu_read_lock();
	delegation = rcu_dereference(nfsi->delegation);
795 796
	ret = (delegation != NULL && (delegation->type & flags) == flags);
	if (ret) {
797
		nfs4_stateid_copy(dst, &delegation->stateid);
798
		nfs_mark_delegation_referenced(delegation);
799
	}
800 801
	rcu_read_unlock();
	return ret;
802
}