delegation.c 18.3 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 nfs_have_delegation(struct inode *inode, fmode_t flags)
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
{
	struct nfs_delegation *delegation;
	int ret = 0;

	flags &= FMODE_READ|FMODE_WRITE;
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
	if (delegation != NULL && (delegation->type & flags) == flags) {
		nfs_mark_delegation_referenced(delegation);
		ret = 1;
	}
	rcu_read_unlock();
	return ret;
}

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

72 73 74
	if (inode->i_flock == NULL)
		goto out;

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

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

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;
108
		if (!nfs4_stateid_match(&state->stateid, stateid))
109
			continue;
L
Linus Torvalds 已提交
110 111
		get_nfs_open_context(ctx);
		spin_unlock(&inode->i_lock);
112
		err = nfs4_open_delegation_recall(ctx, state, stateid);
113 114
		if (err >= 0)
			err = nfs_delegation_claim_locks(ctx, state);
L
Linus Torvalds 已提交
115
		put_nfs_open_context(ctx);
116
		if (err != 0)
117
			return err;
L
Linus Torvalds 已提交
118 119 120
		goto again;
	}
	spin_unlock(&inode->i_lock);
121
	return 0;
L
Linus Torvalds 已提交
122 123
}

124 125 126 127 128 129
/**
 * 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 已提交
130
 */
131 132
void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred,
				  struct nfs_openres *res)
L
Linus Torvalds 已提交
133
{
134 135
	struct nfs_delegation *delegation;
	struct rpc_cred *oldcred = NULL;
L
Linus Torvalds 已提交
136

137 138 139 140 141
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
	if (delegation != NULL) {
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL) {
142
			nfs4_stateid_copy(&delegation->stateid, &res->delegation);
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
			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 已提交
162 163
}

164 165 166 167 168 169 170 171 172
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;
}

173 174 175 176 177 178 179 180 181 182 183
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;
}

184 185
static struct nfs_delegation *
nfs_detach_delegation_locked(struct nfs_inode *nfsi,
186
			     struct nfs_server *server)
187
{
188 189
	struct nfs_delegation *delegation =
		rcu_dereference_protected(nfsi->delegation,
190
				lockdep_is_held(&server->nfs_client->cl_lock));
191 192 193

	if (delegation == NULL)
		goto nomatch;
194

195
	spin_lock(&delegation->lock);
196
	list_del_rcu(&delegation->super_list);
197
	delegation->inode = NULL;
198 199
	nfsi->delegation_state = 0;
	rcu_assign_pointer(nfsi->delegation, NULL);
200
	spin_unlock(&delegation->lock);
201 202 203 204 205
	return delegation;
nomatch:
	return NULL;
}

206
static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi,
207
						    struct nfs_server *server)
208
{
209
	struct nfs_client *clp = server->nfs_client;
210 211 212
	struct nfs_delegation *delegation;

	spin_lock(&clp->cl_lock);
213
	delegation = nfs_detach_delegation_locked(nfsi, server);
214 215 216 217
	spin_unlock(&clp->cl_lock);
	return delegation;
}

218 219 220 221 222 223 224
/**
 * 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 已提交
225 226 227
 */
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
{
228 229
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
230
	struct nfs_inode *nfsi = NFS_I(inode);
231
	struct nfs_delegation *delegation, *old_delegation;
232
	struct nfs_delegation *freeme = NULL;
L
Linus Torvalds 已提交
233 234
	int status = 0;

235
	delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
L
Linus Torvalds 已提交
236 237
	if (delegation == NULL)
		return -ENOMEM;
238
	nfs4_stateid_copy(&delegation->stateid, &res->delegation);
L
Linus Torvalds 已提交
239 240
	delegation->type = res->delegation_type;
	delegation->maxsize = res->maxsize;
241
	delegation->change_attr = inode->i_version;
L
Linus Torvalds 已提交
242 243
	delegation->cred = get_rpccred(cred);
	delegation->inode = inode;
244
	delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
245
	spin_lock_init(&delegation->lock);
L
Linus Torvalds 已提交
246 247

	spin_lock(&clp->cl_lock);
248
	old_delegation = rcu_dereference_protected(nfsi->delegation,
249
					lockdep_is_held(&clp->cl_lock));
250
	if (old_delegation != NULL) {
251 252
		if (nfs4_stateid_match(&delegation->stateid,
					&old_delegation->stateid) &&
253
				delegation->type == old_delegation->type) {
254
			goto out;
L
Linus Torvalds 已提交
255
		}
256 257 258 259 260 261
		/*
		 * Deal with broken servers that hand out two
		 * delegations for the same file.
		 */
		dfprintk(FILE, "%s: server %s handed out "
				"a duplicate delegation!\n",
262
				__func__, clp->cl_hostname);
263
		if (delegation->type <= old_delegation->type) {
264 265 266 267
			freeme = delegation;
			delegation = NULL;
			goto out;
		}
268
		freeme = nfs_detach_delegation_locked(nfsi, server);
L
Linus Torvalds 已提交
269
	}
270
	list_add_rcu(&delegation->super_list, &server->delegations);
271 272 273
	nfsi->delegation_state = delegation->type;
	rcu_assign_pointer(nfsi->delegation, delegation);
	delegation = NULL;
274 275 276 277 278 279

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

280
out:
L
Linus Torvalds 已提交
281
	spin_unlock(&clp->cl_lock);
282 283
	if (delegation != NULL)
		nfs_free_delegation(delegation);
284 285
	if (freeme != NULL)
		nfs_do_return_delegation(inode, freeme, 0);
L
Linus Torvalds 已提交
286 287 288 289 290 291
	return status;
}

/*
 * Basic procedure for returning a delegation to the server
 */
292
static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
L
Linus Torvalds 已提交
293 294
{
	struct nfs_inode *nfsi = NFS_I(inode);
295
	int err;
L
Linus Torvalds 已提交
296

297 298 299 300
	/*
	 * Guard against new delegated open/lock/unlock calls and against
	 * state recovery
	 */
L
Linus Torvalds 已提交
301
	down_write(&nfsi->rwsem);
302
	err = nfs_delegation_claim_opens(inode, &delegation->stateid);
L
Linus Torvalds 已提交
303
	up_write(&nfsi->rwsem);
304 305
	if (err)
		goto out;
L
Linus Torvalds 已提交
306

307 308 309
	err = nfs_do_return_delegation(inode, delegation, issync);
out:
	return err;
310 311
}

312 313 314 315 316
/**
 * nfs_client_return_marked_delegations - return previously marked delegations
 * @clp: nfs_client to process
 *
 * Returns zero on success, or a negative errno value.
317
 */
318
int nfs_client_return_marked_delegations(struct nfs_client *clp)
319 320
{
	struct nfs_delegation *delegation;
321
	struct nfs_server *server;
322
	struct inode *inode;
323
	int err = 0;
324 325 326

restart:
	rcu_read_lock();
327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349
	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;
			delegation = nfs_detach_delegation(NFS_I(inode),
								server);
			rcu_read_unlock();

			if (delegation != NULL) {
				filemap_flush(inode->i_mapping);
				err = __nfs_inode_return_delegation(inode,
								delegation, 0);
			}
			iput(inode);
			if (!err)
				goto restart;
			set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
			return err;
350
		}
351 352
	}
	rcu_read_unlock();
353
	return 0;
354 355
}

356 357 358 359 360 361
/**
 * 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().
362 363 364
 */
void nfs_inode_return_delegation_noreclaim(struct inode *inode)
{
365
	struct nfs_server *server = NFS_SERVER(inode);
366 367 368
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;

369
	if (rcu_access_pointer(nfsi->delegation) != NULL) {
370
		delegation = nfs_detach_delegation(nfsi, server);
371 372 373 374 375
		if (delegation != NULL)
			nfs_do_return_delegation(inode, delegation, 0);
	}
}

376 377 378 379 380 381
/**
 * nfs_inode_return_delegation - synchronously return a delegation
 * @inode: inode to process
 *
 * Returns zero on success, or a negative errno value.
 */
382 383
int nfs_inode_return_delegation(struct inode *inode)
{
384
	struct nfs_server *server = NFS_SERVER(inode);
385 386 387 388
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
	int err = 0;

389
	if (rcu_access_pointer(nfsi->delegation) != NULL) {
390
		delegation = nfs_detach_delegation(nfsi, server);
391
		if (delegation != NULL) {
392
			nfs_wb_all(inode);
393 394
			err = __nfs_inode_return_delegation(inode, delegation, 1);
		}
395 396
	}
	return err;
L
Linus Torvalds 已提交
397 398
}

399 400
static void nfs_mark_return_delegation(struct nfs_server *server,
		struct nfs_delegation *delegation)
401 402
{
	set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
403
	set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
404 405
}

406 407 408 409
/**
 * nfs_super_return_all_delegations - return delegations for one superblock
 * @sb: sb to process
 *
L
Linus Torvalds 已提交
410
 */
411
void nfs_super_return_all_delegations(struct super_block *sb)
L
Linus Torvalds 已提交
412
{
413 414
	struct nfs_server *server = NFS_SB(sb);
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
415 416 417 418
	struct nfs_delegation *delegation;

	if (clp == NULL)
		return;
419

420
	rcu_read_lock();
421
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
422
		spin_lock(&delegation->lock);
423
		set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
424
		spin_unlock(&delegation->lock);
L
Linus Torvalds 已提交
425
	}
426
	rcu_read_unlock();
427

428 429
	if (nfs_client_return_marked_delegations(clp) != 0)
		nfs4_schedule_state_manager(clp);
430 431
}

432 433
static void nfs_mark_return_all_delegation_types(struct nfs_server *server,
						 fmode_t flags)
434 435 436
{
	struct nfs_delegation *delegation;

437
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
438 439 440
		if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
			continue;
		if (delegation->type & flags)
441
			nfs_mark_return_delegation(server, delegation);
442
	}
443 444 445 446 447 448 449 450 451 452
}

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);
453
	rcu_read_unlock();
L
Linus Torvalds 已提交
454 455
}

456 457 458 459 460
static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
{
	nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
}

461
static void nfs_delegation_run_state_manager(struct nfs_client *clp)
462
{
463 464
	if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
		nfs4_schedule_state_manager(clp);
465 466
}

467 468 469 470 471 472 473 474 475 476
void nfs_remove_bad_delegation(struct inode *inode)
{
	struct nfs_delegation *delegation;

	delegation = nfs_detach_delegation(NFS_I(inode), NFS_SERVER(inode));
	if (delegation) {
		nfs_inode_find_state_and_recover(inode, &delegation->stateid);
		nfs_free_delegation(delegation);
	}
}
A
Andy Adamson 已提交
477
EXPORT_SYMBOL_GPL(nfs_remove_bad_delegation);
478

479 480 481 482 483 484
/**
 * nfs_expire_all_delegation_types
 * @clp: client to process
 * @flags: delegation types to expire
 *
 */
485
void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags)
486
{
487
	nfs_client_mark_return_all_delegation_types(clp, flags);
488
	nfs_delegation_run_state_manager(clp);
489 490
}

491 492 493 494 495
/**
 * nfs_expire_all_delegations
 * @clp: client to process
 *
 */
496 497 498 499 500
void nfs_expire_all_delegations(struct nfs_client *clp)
{
	nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
}

501 502 503 504
/**
 * nfs_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
 * @clp: client to process
 *
L
Linus Torvalds 已提交
505
 */
506
void nfs_handle_cb_pathdown(struct nfs_client *clp)
L
Linus Torvalds 已提交
507 508 509
{
	if (clp == NULL)
		return;
510
	nfs_client_mark_return_all_delegations(clp);
L
Linus Torvalds 已提交
511 512
}

513
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
514 515 516
{
	struct nfs_delegation *delegation;

517
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
518 519
		if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
			continue;
520
		nfs_mark_return_delegation(server, delegation);
521 522 523
	}
}

524 525 526 527 528
/**
 * nfs_expire_unreferenced_delegations - Eliminate unused delegations
 * @clp: nfs_client to process
 *
 */
529 530
void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
{
531 532 533 534 535 536 537
	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();

538 539 540
	nfs_delegation_run_state_manager(clp);
}

541 542 543
/**
 * nfs_async_inode_return_delegation - asynchronously return a delegation
 * @inode: inode to process
544
 * @stateid: state ID information
545 546
 *
 * Returns zero on success, or a negative errno value.
L
Linus Torvalds 已提交
547
 */
548 549
int nfs_async_inode_return_delegation(struct inode *inode,
				      const nfs4_stateid *stateid)
L
Linus Torvalds 已提交
550
{
551 552
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
553
	struct nfs_delegation *delegation;
L
Linus Torvalds 已提交
554

555 556
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
A
Alexandros Batsakis 已提交
557

558
	if (!clp->cl_mvops->match_stateid(&delegation->stateid, stateid)) {
559 560 561
		rcu_read_unlock();
		return -ENOENT;
	}
562
	nfs_mark_return_delegation(server, delegation);
563
	rcu_read_unlock();
564

565 566
	nfs_delegation_run_state_manager(clp);
	return 0;
L
Linus Torvalds 已提交
567 568
}

569 570 571
static struct inode *
nfs_delegation_find_inode_server(struct nfs_server *server,
				 const struct nfs_fh *fhandle)
L
Linus Torvalds 已提交
572 573 574
{
	struct nfs_delegation *delegation;
	struct inode *res = NULL;
575 576

	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
577 578 579
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL &&
		    nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
L
Linus Torvalds 已提交
580 581
			res = igrab(delegation->inode);
		}
582 583 584
		spin_unlock(&delegation->lock);
		if (res != NULL)
			break;
L
Linus Torvalds 已提交
585
	}
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
	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;
	}
609
	rcu_read_unlock();
L
Linus Torvalds 已提交
610 611 612
	return res;
}

613 614 615 616 617 618 619 620 621 622 623 624
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 已提交
625
 */
626
void nfs_delegation_mark_reclaim(struct nfs_client *clp)
L
Linus Torvalds 已提交
627
{
628 629
	struct nfs_server *server;

630
	rcu_read_lock();
631 632
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_delegation_mark_reclaim_server(server);
633
	rcu_read_unlock();
L
Linus Torvalds 已提交
634 635
}

636 637 638 639
/**
 * nfs_delegation_reap_unclaimed - reap unclaimed delegations after reboot recovery is done
 * @clp: nfs_client to process
 *
L
Linus Torvalds 已提交
640
 */
641
void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
L
Linus Torvalds 已提交
642
{
643
	struct nfs_delegation *delegation;
644
	struct nfs_server *server;
645
	struct inode *inode;
646

647 648
restart:
	rcu_read_lock();
649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
	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),
								server);
			rcu_read_unlock();

			if (delegation != NULL)
				nfs_free_delegation(delegation);
			iput(inode);
			goto restart;
		}
L
Linus Torvalds 已提交
667
	}
668
	rcu_read_unlock();
L
Linus Torvalds 已提交
669
}
670

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
/**
 * 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
 *
 * Returns one and fills in "dst->data" * if inode had a delegation,
 * otherwise zero is returned.
 */
701 702 703 704
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
705
	int ret = 0;
706

707 708
	rcu_read_lock();
	delegation = rcu_dereference(nfsi->delegation);
709
	if (delegation != NULL) {
710
		nfs4_stateid_copy(dst, &delegation->stateid);
711
		ret = 1;
712
	}
713 714
	rcu_read_unlock();
	return ret;
715
}