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

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

20
#include "nfs4_fs.h"
L
Linus Torvalds 已提交
21
#include "delegation.h"
22
#include "internal.h"
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 68 69 70
static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state)
{
	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(state, fl);
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);
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
/**
 * nfs_client_return_marked_delegations - return previously marked delegations
 * @clp: nfs_client to process
 *
396 397 398 399
 * 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.
 *
400
 * Returns zero on success, or a negative errno value.
401
 */
402
int nfs_client_return_marked_delegations(struct nfs_client *clp)
403 404
{
	struct nfs_delegation *delegation;
405
	struct nfs_server *server;
406
	struct inode *inode;
407
	int err = 0;
408 409 410

restart:
	rcu_read_lock();
411 412 413 414 415 416 417 418 419
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
		list_for_each_entry_rcu(delegation, &server->delegations,
								super_list) {
			if (!test_and_clear_bit(NFS_DELEGATION_RETURN,
							&delegation->flags))
				continue;
			inode = nfs_delegation_grab_inode(delegation);
			if (inode == NULL)
				continue;
420
			delegation = nfs_start_delegation_return_locked(NFS_I(inode));
421 422
			rcu_read_unlock();

423
			err = nfs_end_delegation_return(inode, delegation, 0);
424 425 426 427 428
			iput(inode);
			if (!err)
				goto restart;
			set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
			return err;
429
		}
430 431
	}
	rcu_read_unlock();
432
	return 0;
433 434
}

435 436 437 438 439 440
/**
 * 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().
441 442 443 444 445
 */
void nfs_inode_return_delegation_noreclaim(struct inode *inode)
{
	struct nfs_delegation *delegation;

446 447 448
	delegation = nfs_inode_detach_delegation(inode);
	if (delegation != NULL)
		nfs_do_return_delegation(inode, delegation, 0);
449 450
}

451 452 453 454
/**
 * nfs_inode_return_delegation - synchronously return a delegation
 * @inode: inode to process
 *
455 456 457 458
 * 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.
 *
459 460
 * Returns zero on success, or a negative errno value.
 */
461
int nfs4_inode_return_delegation(struct inode *inode)
462 463 464 465 466
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
	int err = 0;

467
	nfs_wb_all(inode);
468 469 470
	delegation = nfs_start_delegation_return(nfsi);
	if (delegation != NULL)
		err = nfs_end_delegation_return(inode, delegation, 1);
471
	return err;
L
Linus Torvalds 已提交
472 473
}

474 475
static void nfs_mark_return_delegation(struct nfs_server *server,
		struct nfs_delegation *delegation)
476 477
{
	set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
478
	set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
479 480
}

481 482 483 484
/**
 * nfs_super_return_all_delegations - return delegations for one superblock
 * @sb: sb to process
 *
L
Linus Torvalds 已提交
485
 */
486
void nfs_server_return_all_delegations(struct nfs_server *server)
L
Linus Torvalds 已提交
487
{
488
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
489 490 491 492
	struct nfs_delegation *delegation;

	if (clp == NULL)
		return;
493

494
	rcu_read_lock();
495
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
496
		spin_lock(&delegation->lock);
497
		set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
498
		spin_unlock(&delegation->lock);
L
Linus Torvalds 已提交
499
	}
500
	rcu_read_unlock();
501

502 503
	if (nfs_client_return_marked_delegations(clp) != 0)
		nfs4_schedule_state_manager(clp);
504 505
}

506 507
static void nfs_mark_return_all_delegation_types(struct nfs_server *server,
						 fmode_t flags)
508 509 510
{
	struct nfs_delegation *delegation;

511
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
512 513 514
		if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
			continue;
		if (delegation->type & flags)
515
			nfs_mark_return_delegation(server, delegation);
516
	}
517 518 519 520 521 522 523 524 525 526
}

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);
527
	rcu_read_unlock();
L
Linus Torvalds 已提交
528 529
}

530
static void nfs_delegation_run_state_manager(struct nfs_client *clp)
531
{
532 533
	if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
		nfs4_schedule_state_manager(clp);
534 535
}

536 537 538 539
void nfs_remove_bad_delegation(struct inode *inode)
{
	struct nfs_delegation *delegation;

540
	delegation = nfs_inode_detach_delegation(inode);
541 542 543 544 545
	if (delegation) {
		nfs_inode_find_state_and_recover(inode, &delegation->stateid);
		nfs_free_delegation(delegation);
	}
}
A
Andy Adamson 已提交
546
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
547

548 549 550 551 552 553
/**
 * nfs_expire_all_delegation_types
 * @clp: client to process
 * @flags: delegation types to expire
 *
 */
554
void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags)
555
{
556
	nfs_client_mark_return_all_delegation_types(clp, flags);
557
	nfs_delegation_run_state_manager(clp);
558 559
}

560 561 562 563 564
/**
 * nfs_expire_all_delegations
 * @clp: client to process
 *
 */
565 566 567 568 569
void nfs_expire_all_delegations(struct nfs_client *clp)
{
	nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
}

570
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
571 572 573
{
	struct nfs_delegation *delegation;

574
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
575 576
		if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
			continue;
577
		nfs_mark_return_delegation(server, delegation);
578 579 580
	}
}

581 582 583 584 585
/**
 * nfs_expire_unreferenced_delegations - Eliminate unused delegations
 * @clp: nfs_client to process
 *
 */
586 587
void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
{
588 589 590 591 592 593 594
	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();

595 596 597
	nfs_delegation_run_state_manager(clp);
}

598 599 600
/**
 * nfs_async_inode_return_delegation - asynchronously return a delegation
 * @inode: inode to process
601
 * @stateid: state ID information
602 603
 *
 * Returns zero on success, or a negative errno value.
L
Linus Torvalds 已提交
604
 */
605 606
int nfs_async_inode_return_delegation(struct inode *inode,
				      const nfs4_stateid *stateid)
L
Linus Torvalds 已提交
607
{
608 609
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
610
	struct nfs_delegation *delegation;
L
Linus Torvalds 已提交
611

612 613
	filemap_flush(inode->i_mapping);

614 615
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
A
Alexandros Batsakis 已提交
616

617
	if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
618 619 620
		rcu_read_unlock();
		return -ENOENT;
	}
621
	nfs_mark_return_delegation(server, delegation);
622
	rcu_read_unlock();
623

624 625
	nfs_delegation_run_state_manager(clp);
	return 0;
L
Linus Torvalds 已提交
626 627
}

628 629 630
static struct inode *
nfs_delegation_find_inode_server(struct nfs_server *server,
				 const struct nfs_fh *fhandle)
L
Linus Torvalds 已提交
631 632 633
{
	struct nfs_delegation *delegation;
	struct inode *res = NULL;
634 635

	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
636 637 638
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL &&
		    nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
L
Linus Torvalds 已提交
639 640
			res = igrab(delegation->inode);
		}
641 642 643
		spin_unlock(&delegation->lock);
		if (res != NULL)
			break;
L
Linus Torvalds 已提交
644
	}
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
	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;
	}
668
	rcu_read_unlock();
L
Linus Torvalds 已提交
669 670 671
	return res;
}

672 673 674 675 676 677 678 679 680 681 682 683
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 已提交
684
 */
685
void nfs_delegation_mark_reclaim(struct nfs_client *clp)
L
Linus Torvalds 已提交
686
{
687 688
	struct nfs_server *server;

689
	rcu_read_lock();
690 691
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_delegation_mark_reclaim_server(server);
692
	rcu_read_unlock();
L
Linus Torvalds 已提交
693 694
}

695 696 697 698
/**
 * nfs_delegation_reap_unclaimed - reap unclaimed delegations after reboot recovery is done
 * @clp: nfs_client to process
 *
L
Linus Torvalds 已提交
699
 */
700
void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
L
Linus Torvalds 已提交
701
{
702
	struct nfs_delegation *delegation;
703
	struct nfs_server *server;
704
	struct inode *inode;
705

706 707
restart:
	rcu_read_lock();
708 709 710 711 712 713 714 715 716 717
	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),
718
					delegation, server);
719 720 721 722 723 724 725
			rcu_read_unlock();

			if (delegation != NULL)
				nfs_free_delegation(delegation);
			iput(inode);
			goto restart;
		}
L
Linus Torvalds 已提交
726
	}
727
	rcu_read_unlock();
L
Linus Torvalds 已提交
728
}
729

730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755
/**
 * 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
756
 * @flags: delegation type requirement
757
 *
758 759
 * Returns "true" and fills in "dst->data" * if inode had a delegation,
 * otherwise "false" is returned.
760
 */
761 762
bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode,
		fmode_t flags)
763 764 765
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
766
	bool ret;
767

768
	flags &= FMODE_READ|FMODE_WRITE;
769 770
	rcu_read_lock();
	delegation = rcu_dereference(nfsi->delegation);
771 772
	ret = (delegation != NULL && (delegation->type & flags) == flags);
	if (ret) {
773
		nfs4_stateid_copy(dst, &delegation->stateid);
774
		nfs_mark_delegation_referenced(delegation);
775
	}
776 777
	rcu_read_unlock();
	return ret;
778
}