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

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

33 34 35 36 37
	nfs_do_free_delegation(delegation);
}

static void nfs_free_delegation(struct nfs_delegation *delegation)
{
38 39 40 41
	if (delegation->cred) {
		put_rpccred(delegation->cred);
		delegation->cred = NULL;
	}
42
	call_rcu(&delegation->rcu, nfs_free_delegation_callback);
43 44
}

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

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

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

84 85 86
	if (inode->i_flock == NULL)
		goto out;

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

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

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

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

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

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

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

	if (delegation == NULL)
		goto nomatch;
207

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	if (clp == NULL)
		return;
434

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

443 444
	if (nfs_client_return_marked_delegations(clp) != 0)
		nfs4_schedule_state_manager(clp);
445 446
}

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

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

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

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

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

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

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

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

516
static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
517 518 519
{
	struct nfs_delegation *delegation;

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

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

541 542 543
	nfs_delegation_run_state_manager(clp);
}

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

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

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

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

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

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

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

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

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

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

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