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
static void nfs_do_free_delegation(struct nfs_delegation *delegation)
L
Linus Torvalds 已提交
25
{
26 27
	if (delegation->cred)
		put_rpccred(delegation->cred);
L
Linus Torvalds 已提交
28 29 30
	kfree(delegation);
}

31 32 33 34
static void nfs_free_delegation_callback(struct rcu_head *head)
{
	struct nfs_delegation *delegation = container_of(head, struct nfs_delegation, rcu);

35 36 37 38 39 40
	nfs_do_free_delegation(delegation);
}

static void nfs_free_delegation(struct nfs_delegation *delegation)
{
	call_rcu(&delegation->rcu, nfs_free_delegation_callback);
41 42
}

43 44 45 46 47
/**
 * nfs_mark_delegation_referenced - set delegation's REFERENCED flag
 * @delegation: delegation to process
 *
 */
48 49 50 51 52
void nfs_mark_delegation_referenced(struct nfs_delegation *delegation)
{
	set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags);
}

53 54 55 56 57 58 59
/**
 * 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.
 */
60
int nfs_have_delegation(struct inode *inode, fmode_t flags)
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
{
	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;
}

76 77 78 79
static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state)
{
	struct inode *inode = state->inode;
	struct file_lock *fl;
80
	int status = 0;
81

82 83 84
	if (inode->i_flock == NULL)
		goto out;

85 86
	/* Protect inode->i_flock using the file locks lock */
	lock_flocks();
H
Harvey Harrison 已提交
87
	for (fl = inode->i_flock; fl != NULL; fl = fl->fl_next) {
88 89
		if (!(fl->fl_flags & (FL_POSIX|FL_FLOCK)))
			continue;
90
		if (nfs_file_open_context(fl->fl_file) != ctx)
91
			continue;
92
		unlock_flocks();
93
		status = nfs4_lock_delegation_recall(state, fl);
94
		if (status < 0)
95
			goto out;
96
		lock_flocks();
97
	}
98
	unlock_flocks();
99
out:
100 101 102
	return status;
}

103
static int nfs_delegation_claim_opens(struct inode *inode, const nfs4_stateid *stateid)
L
Linus Torvalds 已提交
104 105 106 107
{
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_open_context *ctx;
	struct nfs4_state *state;
108
	int err;
L
Linus Torvalds 已提交
109 110 111 112 113 114 115 116 117

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;
118 119
		if (memcmp(state->stateid.data, stateid->data, sizeof(state->stateid.data)) != 0)
			continue;
L
Linus Torvalds 已提交
120 121
		get_nfs_open_context(ctx);
		spin_unlock(&inode->i_lock);
122
		err = nfs4_open_delegation_recall(ctx, state, stateid);
123 124
		if (err >= 0)
			err = nfs_delegation_claim_locks(ctx, state);
L
Linus Torvalds 已提交
125
		put_nfs_open_context(ctx);
126
		if (err != 0)
127
			return err;
L
Linus Torvalds 已提交
128 129 130
		goto again;
	}
	spin_unlock(&inode->i_lock);
131
	return 0;
L
Linus Torvalds 已提交
132 133
}

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

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
	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 已提交
173 174
}

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

184 185 186 187 188 189 190 191 192 193 194
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;
}

195 196
static struct nfs_delegation *
nfs_detach_delegation_locked(struct nfs_inode *nfsi,
197
			     struct nfs_server *server)
198
{
199 200
	struct nfs_delegation *delegation =
		rcu_dereference_protected(nfsi->delegation,
201
				lockdep_is_held(&server->nfs_client->cl_lock));
202 203 204

	if (delegation == NULL)
		goto nomatch;
205

206
	spin_lock(&delegation->lock);
207
	list_del_rcu(&delegation->super_list);
208
	delegation->inode = NULL;
209 210
	nfsi->delegation_state = 0;
	rcu_assign_pointer(nfsi->delegation, NULL);
211
	spin_unlock(&delegation->lock);
212 213 214 215 216
	return delegation;
nomatch:
	return NULL;
}

217
static struct nfs_delegation *nfs_detach_delegation(struct nfs_inode *nfsi,
218
						    struct nfs_server *server)
219
{
220
	struct nfs_client *clp = server->nfs_client;
221 222 223
	struct nfs_delegation *delegation;

	spin_lock(&clp->cl_lock);
224
	delegation = nfs_detach_delegation_locked(nfsi, server);
225 226 227 228
	spin_unlock(&clp->cl_lock);
	return delegation;
}

229 230 231 232 233 234 235
/**
 * 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 已提交
236 237 238
 */
int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
{
239 240
	struct nfs_server *server = NFS_SERVER(inode);
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
241
	struct nfs_inode *nfsi = NFS_I(inode);
242
	struct nfs_delegation *delegation, *old_delegation;
243
	struct nfs_delegation *freeme = NULL;
L
Linus Torvalds 已提交
244 245
	int status = 0;

246
	delegation = kmalloc(sizeof(*delegation), GFP_NOFS);
L
Linus Torvalds 已提交
247 248 249 250 251 252
	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;
253
	delegation->change_attr = nfsi->change_attr;
L
Linus Torvalds 已提交
254 255
	delegation->cred = get_rpccred(cred);
	delegation->inode = inode;
256
	delegation->flags = 1<<NFS_DELEGATION_REFERENCED;
257
	spin_lock_init(&delegation->lock);
L
Linus Torvalds 已提交
258 259

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

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

292
out:
L
Linus Torvalds 已提交
293
	spin_unlock(&clp->cl_lock);
294 295
	if (delegation != NULL)
		nfs_free_delegation(delegation);
296 297
	if (freeme != NULL)
		nfs_do_return_delegation(inode, freeme, 0);
L
Linus Torvalds 已提交
298 299 300 301 302 303
	return status;
}

/*
 * Basic procedure for returning a delegation to the server
 */
304
static int __nfs_inode_return_delegation(struct inode *inode, struct nfs_delegation *delegation, int issync)
L
Linus Torvalds 已提交
305 306
{
	struct nfs_inode *nfsi = NFS_I(inode);
307
	int err;
L
Linus Torvalds 已提交
308

309 310 311 312
	/*
	 * Guard against new delegated open/lock/unlock calls and against
	 * state recovery
	 */
L
Linus Torvalds 已提交
313
	down_write(&nfsi->rwsem);
314
	err = nfs_delegation_claim_opens(inode, &delegation->stateid);
L
Linus Torvalds 已提交
315
	up_write(&nfsi->rwsem);
316 317
	if (err)
		goto out;
L
Linus Torvalds 已提交
318

319 320 321
	err = nfs_do_return_delegation(inode, delegation, issync);
out:
	return err;
322 323
}

324 325 326 327 328
/**
 * nfs_client_return_marked_delegations - return previously marked delegations
 * @clp: nfs_client to process
 *
 * Returns zero on success, or a negative errno value.
329
 */
330
int nfs_client_return_marked_delegations(struct nfs_client *clp)
331 332
{
	struct nfs_delegation *delegation;
333
	struct nfs_server *server;
334
	struct inode *inode;
335
	int err = 0;
336 337 338

restart:
	rcu_read_lock();
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361
	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;
362
		}
363 364
	}
	rcu_read_unlock();
365
	return 0;
366 367
}

368 369 370 371 372 373
/**
 * 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().
374 375 376
 */
void nfs_inode_return_delegation_noreclaim(struct inode *inode)
{
377
	struct nfs_server *server = NFS_SERVER(inode);
378 379 380
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;

381
	if (rcu_access_pointer(nfsi->delegation) != NULL) {
382
		delegation = nfs_detach_delegation(nfsi, server);
383 384 385 386 387
		if (delegation != NULL)
			nfs_do_return_delegation(inode, delegation, 0);
	}
}

388 389 390 391 392 393
/**
 * nfs_inode_return_delegation - synchronously return a delegation
 * @inode: inode to process
 *
 * Returns zero on success, or a negative errno value.
 */
394 395
int nfs_inode_return_delegation(struct inode *inode)
{
396
	struct nfs_server *server = NFS_SERVER(inode);
397 398 399 400
	struct nfs_inode *nfsi = NFS_I(inode);
	struct nfs_delegation *delegation;
	int err = 0;

401
	if (rcu_access_pointer(nfsi->delegation) != NULL) {
402
		delegation = nfs_detach_delegation(nfsi, server);
403
		if (delegation != NULL) {
404
			nfs_wb_all(inode);
405 406
			err = __nfs_inode_return_delegation(inode, delegation, 1);
		}
407 408
	}
	return err;
L
Linus Torvalds 已提交
409 410
}

411
static void nfs_mark_return_delegation(struct nfs_delegation *delegation)
412
{
413 414
	struct nfs_client *clp = NFS_SERVER(delegation->inode)->nfs_client;

415 416 417 418
	set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
	set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state);
}

419 420 421 422
/**
 * nfs_super_return_all_delegations - return delegations for one superblock
 * @sb: sb to process
 *
L
Linus Torvalds 已提交
423
 */
424
void nfs_super_return_all_delegations(struct super_block *sb)
L
Linus Torvalds 已提交
425
{
426 427
	struct nfs_server *server = NFS_SB(sb);
	struct nfs_client *clp = server->nfs_client;
L
Linus Torvalds 已提交
428 429 430 431
	struct nfs_delegation *delegation;

	if (clp == NULL)
		return;
432

433
	rcu_read_lock();
434
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
435
		spin_lock(&delegation->lock);
436
		set_bit(NFS_DELEGATION_RETURN, &delegation->flags);
437
		spin_unlock(&delegation->lock);
L
Linus Torvalds 已提交
438
	}
439
	rcu_read_unlock();
440

441 442
	if (nfs_client_return_marked_delegations(clp) != 0)
		nfs4_schedule_state_manager(clp);
443 444
}

445 446
static void nfs_mark_return_all_delegation_types(struct nfs_server *server,
						 fmode_t flags)
447 448 449
{
	struct nfs_delegation *delegation;

450
	list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
451 452 453
		if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE))
			continue;
		if (delegation->type & flags)
454
			nfs_mark_return_delegation(delegation);
455
	}
456 457 458 459 460 461 462 463 464 465
}

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);
466
	rcu_read_unlock();
L
Linus Torvalds 已提交
467 468
}

469 470 471 472 473
static void nfs_client_mark_return_all_delegations(struct nfs_client *clp)
{
	nfs_client_mark_return_all_delegation_types(clp, FMODE_READ|FMODE_WRITE);
}

474
static void nfs_delegation_run_state_manager(struct nfs_client *clp)
475
{
476 477
	if (test_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state))
		nfs4_schedule_state_manager(clp);
478 479
}

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(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_client *clp = NFS_SERVER(inode)->nfs_client;
	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->validate_stateid(delegation, stateid)) {
559 560 561
		rcu_read_unlock();
		return -ENOENT;
	}
562
	nfs_mark_return_delegation(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 710
	if (delegation != NULL) {
		memcpy(dst->data, delegation->stateid.data, sizeof(dst->data));
711
		ret = 1;
712
	}
713 714
	rcu_read_unlock();
	return ret;
715
}