delegation.c 18.1 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 109
		if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0)
			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 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
	if (delegation != NULL) {
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL) {
			memcpy(delegation->stateid.data, res->delegation.data,
			       sizeof(delegation->stateid.data));
			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 已提交
163 164
}

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

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

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

	if (delegation == NULL)
		goto nomatch;
195

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

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

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

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

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

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

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

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

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

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

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

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

restart:
	rcu_read_lock();
329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351
	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;
352
		}
353 354
	}
	rcu_read_unlock();
355
	return 0;
356 357
}

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

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

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

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

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

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

	if (clp == NULL)
		return;
421

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

430 431
	if (nfs_client_return_marked_delegations(clp) != 0)
		nfs4_schedule_state_manager(clp);
432 433
}

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

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

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

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

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

469 470 471 472 473 474
/**
 * nfs_expire_all_delegation_types
 * @clp: client to process
 * @flags: delegation types to expire
 *
 */
475
void nfs_expire_all_delegation_types(struct nfs_client *clp, fmode_t flags)
476
{
477
	nfs_client_mark_return_all_delegation_types(clp, flags);
478
	nfs_delegation_run_state_manager(clp);
479 480
}

481 482 483 484 485
/**
 * nfs_expire_all_delegations
 * @clp: client to process
 *
 */
486 487 488 489 490
void nfs_expire_all_delegations(struct nfs_client *clp)
{
	nfs_expire_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
}

491 492 493 494
/**
 * nfs_handle_cb_pathdown - return all delegations after NFS4ERR_CB_PATH_DOWN
 * @clp: client to process
 *
L
Linus Torvalds 已提交
495
 */
496
void nfs_handle_cb_pathdown(struct nfs_client *clp)
L
Linus Torvalds 已提交
497 498 499
{
	if (clp == NULL)
		return;
500
	nfs_client_mark_return_all_delegations(clp);
L
Linus Torvalds 已提交
501 502
}

503
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
504 505 506
{
	struct nfs_delegation *delegation;

507
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
508 509
		if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
			continue;
510
		nfs_mark_return_delegation(server, delegation);
511 512 513
	}
}

514 515 516 517 518
/**
 * nfs_expire_unreferenced_delegations - Eliminate unused delegations
 * @clp: nfs_client to process
 *
 */
519 520
void nfs_expire_unreferenced_delegations(struct nfs_client *clp)
{
521 522 523 524 525 526 527
	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();

528 529 530
	nfs_delegation_run_state_manager(clp);
}

531 532 533 534 535 536
/**
 * nfs_async_inode_return_delegation - asynchronously return a delegation
 * @inode: inode to process
 * @stateid: state ID information from CB_RECALL arguments
 *
 * Returns zero on success, or a negative errno value.
L
Linus Torvalds 已提交
537
 */
538 539
int nfs_async_inode_return_delegation(struct inode *inode,
				      const nfs4_stateid *stateid)
L
Linus Torvalds 已提交
540
{
541 542
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
543
	struct nfs_delegation *delegation;
L
Linus Torvalds 已提交
544

545 546
	rcu_read_lock();
	delegation = rcu_dereference(NFS_I(inode)->delegation);
A
Alexandros Batsakis 已提交
547

548
	if (!clp->cl_mvops->validate_stateid(delegation, stateid)) {
549 550 551
		rcu_read_unlock();
		return -ENOENT;
	}
552
	nfs_mark_return_delegation(server, delegation);
553
	rcu_read_unlock();
554

555 556
	nfs_delegation_run_state_manager(clp);
	return 0;
L
Linus Torvalds 已提交
557 558
}

559 560 561
static struct inode *
nfs_delegation_find_inode_server(struct nfs_server *server,
				 const struct nfs_fh *fhandle)
L
Linus Torvalds 已提交
562 563 564
{
	struct nfs_delegation *delegation;
	struct inode *res = NULL;
565 566

	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
567 568 569
		spin_lock(&delegation->lock);
		if (delegation->inode != NULL &&
		    nfs_compare_fh(fhandle, &NFS_I(delegation->inode)->fh) == 0) {
L
Linus Torvalds 已提交
570 571
			res = igrab(delegation->inode);
		}
572 573 574
		spin_unlock(&delegation->lock);
		if (res != NULL)
			break;
L
Linus Torvalds 已提交
575
	}
576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
	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;
	}
599
	rcu_read_unlock();
L
Linus Torvalds 已提交
600 601 602
	return res;
}

603 604 605 606 607 608 609 610 611 612 613 614
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 已提交
615
 */
616
void nfs_delegation_mark_reclaim(struct nfs_client *clp)
L
Linus Torvalds 已提交
617
{
618 619
	struct nfs_server *server;

620
	rcu_read_lock();
621 622
	list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link)
		nfs_delegation_mark_reclaim_server(server);
623
	rcu_read_unlock();
L
Linus Torvalds 已提交
624 625
}

626 627 628 629
/**
 * nfs_delegation_reap_unclaimed - reap unclaimed delegations after reboot recovery is done
 * @clp: nfs_client to process
 *
L
Linus Torvalds 已提交
630
 */
631
void nfs_delegation_reap_unclaimed(struct nfs_client *clp)
L
Linus Torvalds 已提交
632
{
633
	struct nfs_delegation *delegation;
634
	struct nfs_server *server;
635
	struct inode *inode;
636

637 638
restart:
	rcu_read_lock();
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
	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 已提交
657
	}
658
	rcu_read_unlock();
L
Linus Torvalds 已提交
659
}
660

661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
/**
 * 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.
 */
691 692 693 694
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
695
	int ret = 0;
696

697 698
	rcu_read_lock();
	delegation = rcu_dereference(nfsi->delegation);
699 700
	if (delegation != NULL) {
		memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
701
		ret = 1;
702
	}
703 704
	rcu_read_unlock();
	return ret;
705
}