delegation.c 21.6 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
/**
 * 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.
 */
51
int nfs4_have_delegation(struct inode *inode, fmode_t flags)
52 53 54 55 56 57 58
{
	struct nfs_delegation *delegation;
	int ret = 0;

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

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

74 75
	if (inode->i_flock == NULL)
		goto out;
76

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

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

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

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

148 149 150 151 152
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
	if (delegation != NULL) {
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL) {
153
			nfs4_stateid_copy(&delegation->stateid, &res->delegation);
154 155 156 157 158 159 160 161 162 163
			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();
164
			trace_nfs4_reclaim_delegation(inode, res->delegation_type);
165 166 167 168 169 170 171 172 173
		} 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

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

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

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

369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
	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)))
386
		goto out;
L
Linus Torvalds 已提交
387

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

393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
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;
}

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

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

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

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

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

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

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

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

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

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

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 544
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);
}

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

	if (clp == NULL)
		return;
557

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

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

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

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

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

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

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

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

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

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

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

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

641 642 643
	nfs_delegation_run_state_manager(clp);
}

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

658 659
	filemap_flush(inode->i_mapping);

660 661
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
662 663
	if (delegation == NULL)
		goto out_enoent;
A
Alexandros Batsakis 已提交
664

665 666
	if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid))
		goto out_enoent;
667
	nfs_mark_return_delegation(server, delegation);
668
	rcu_read_unlock();
669

670 671
	nfs_delegation_run_state_manager(clp);
	return 0;
672 673 674
out_enoent:
	rcu_read_unlock();
	return -ENOENT;
L
Linus Torvalds 已提交
675 676
}

677 678 679
static struct inode *
nfs_delegation_find_inode_server(struct nfs_server *server,
				 const struct nfs_fh *fhandle)
L
Linus Torvalds 已提交
680 681 682
{
	struct nfs_delegation *delegation;
	struct inode *res = NULL;
683 684

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

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

738
	rcu_read_lock();
739 740
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_delegation_mark_reclaim_server(server);
741
	rcu_read_unlock();
L
Linus Torvalds 已提交
742 743
}

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

755 756
restart:
	rcu_read_lock();
757 758 759 760 761 762 763 764 765 766
	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),
767
					delegation, server);
768 769 770 771 772 773 774
			rcu_read_unlock();

			if (delegation != NULL)
				nfs_free_delegation(delegation);
			iput(inode);
			goto restart;
		}
L
Linus Torvalds 已提交
775
	}
776
	rcu_read_unlock();
L
Linus Torvalds 已提交
777
}
778

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

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