delegation.c 18.4 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 475 476 477 478 479
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);
	}
}

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

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

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

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

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

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

539 540 541
	nfs_delegation_run_state_manager(clp);
}

542 543 544 545 546 547
/**
 * 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 已提交
548
 */
549 550
int nfs_async_inode_return_delegation(struct inode *inode,
				      const nfs4_stateid *stateid)
L
Linus Torvalds 已提交
551
{
552 553
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
554
	struct nfs_delegation *delegation;
L
Linus Torvalds 已提交
555

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

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

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

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

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

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

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

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

648 649
restart:
	rcu_read_lock();
650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
	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 已提交
668
	}
669
	rcu_read_unlock();
L
Linus Torvalds 已提交
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 701
/**
 * 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.
 */
702 703 704 705
int nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode)
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
706
	int ret = 0;
707

708 709
	rcu_read_lock();
	delegation = rcu_dereference(nfsi->delegation);
710 711
	if (delegation != NULL) {
		memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
712
		ret = 1;
713
	}
714 715
	rcu_read_unlock();
	return ret;
716
}