host.c 16.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13
/*
 * linux/fs/lockd/host.c
 *
 * Management for NLM peer hosts. The nlm_host struct is shared
 * between client and server implementation. The only reason to
 * do so is to reduce code bloat.
 *
 * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
 */

#include <linux/types.h>
#include <linux/slab.h>
#include <linux/in.h>
14
#include <linux/in6.h>
L
Linus Torvalds 已提交
15 16 17
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svc.h>
#include <linux/lockd/lockd.h>
I
Ingo Molnar 已提交
18
#include <linux/mutex.h>
L
Linus Torvalds 已提交
19

20 21
#include <linux/sunrpc/svc_xprt.h>

22
#include <net/ipv6.h>
L
Linus Torvalds 已提交
23 24 25 26

#define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
#define NLM_HOST_NRHASH		32
#define NLM_HOST_REBIND		(60 * HZ)
27 28
#define NLM_HOST_EXPIRE		(300 * HZ)
#define NLM_HOST_COLLECT	(120 * HZ)
L
Linus Torvalds 已提交
29

C
Chuck Lever 已提交
30
static struct hlist_head	nlm_server_hosts[NLM_HOST_NRHASH];
31
static struct hlist_head	nlm_client_hosts[NLM_HOST_NRHASH];
32 33 34 35 36 37 38 39 40 41 42 43

#define for_each_host(host, pos, chain, table) \
	for ((chain) = (table); \
	     (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
		hlist_for_each_entry((host), (pos), (chain), h_hash)

#define for_each_host_safe(host, pos, next, chain, table) \
	for ((chain) = (table); \
	     (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
		hlist_for_each_entry_safe((host), (pos), (next), \
						(chain), h_hash)

L
Linus Torvalds 已提交
44
static unsigned long		next_gc;
C
Chuck Lever 已提交
45
static unsigned long		nrhosts;
I
Ingo Molnar 已提交
46
static DEFINE_MUTEX(nlm_host_mutex);
L
Linus Torvalds 已提交
47 48 49

static void			nlm_gc_hosts(void);

50 51
struct nlm_lookup_host_info {
	const int		server;		/* search for server|client */
52 53
	const struct sockaddr	*sap;		/* address to search for */
	const size_t		salen;		/* it's length */
54 55 56 57
	const unsigned short	protocol;	/* transport to search for*/
	const u32		version;	/* NLM version to search for */
	const char		*hostname;	/* remote's hostname */
	const size_t		hostname_len;	/* it's length */
58
	const int		noresvport;	/* use non-priv port */
59
	struct net		*net;		/* network namespace to bind */
60 61
};

62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
/*
 * Hash function must work well on big- and little-endian platforms
 */
static unsigned int __nlm_hash32(const __be32 n)
{
	unsigned int hash = (__force u32)n ^ ((__force u32)n >> 16);
	return hash ^ (hash >> 8);
}

static unsigned int __nlm_hash_addr4(const struct sockaddr *sap)
{
	const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
	return __nlm_hash32(sin->sin_addr.s_addr);
}

static unsigned int __nlm_hash_addr6(const struct sockaddr *sap)
{
	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
	const struct in6_addr addr = sin6->sin6_addr;
	return __nlm_hash32(addr.s6_addr32[0]) ^
	       __nlm_hash32(addr.s6_addr32[1]) ^
	       __nlm_hash32(addr.s6_addr32[2]) ^
	       __nlm_hash32(addr.s6_addr32[3]);
}

static unsigned int nlm_hash_address(const struct sockaddr *sap)
{
	unsigned int hash;

	switch (sap->sa_family) {
	case AF_INET:
		hash = __nlm_hash_addr4(sap);
		break;
	case AF_INET6:
		hash = __nlm_hash_addr6(sap);
		break;
	default:
		hash = 0;
	}
	return hash & (NLM_HOST_NRHASH - 1);
}

C
Chuck Lever 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 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
/*
 * Allocate and initialize an nlm_host.  Common to both client and server.
 */
static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
				       struct nsm_handle *nsm)
{
	struct nlm_host *host = NULL;
	unsigned long now = jiffies;

	if (nsm != NULL)
		atomic_inc(&nsm->sm_count);
	else {
		host = NULL;
		nsm = nsm_get_handle(ni->sap, ni->salen,
					ni->hostname, ni->hostname_len);
		if (unlikely(nsm == NULL)) {
			dprintk("lockd: %s failed; no nsm handle\n",
				__func__);
			goto out;
		}
	}

	host = kmalloc(sizeof(*host), GFP_KERNEL);
	if (unlikely(host == NULL)) {
		dprintk("lockd: %s failed; no memory\n", __func__);
		nsm_release(nsm);
		goto out;
	}

	memcpy(nlm_addr(host), ni->sap, ni->salen);
	host->h_addrlen    = ni->salen;
	rpc_set_port(nlm_addr(host), 0);
	host->h_srcaddrlen = 0;

	host->h_rpcclnt    = NULL;
	host->h_name	   = nsm->sm_name;
	host->h_version    = ni->version;
	host->h_proto      = ni->protocol;
	host->h_reclaiming = 0;
	host->h_server     = ni->server;
	host->h_noresvport = ni->noresvport;
	host->h_inuse      = 0;
	init_waitqueue_head(&host->h_gracewait);
	init_rwsem(&host->h_rwsem);
	host->h_state      = 0;
	host->h_nsmstate   = 0;
	host->h_pidcount   = 0;
	atomic_set(&host->h_count, 1);
	mutex_init(&host->h_mutex);
	host->h_nextrebind = now + NLM_HOST_REBIND;
	host->h_expires    = now + NLM_HOST_EXPIRE;
	INIT_LIST_HEAD(&host->h_lockowners);
	spin_lock_init(&host->h_lock);
	INIT_LIST_HEAD(&host->h_granted);
	INIT_LIST_HEAD(&host->h_reclaim);
	host->h_nsmhandle  = nsm;
	host->h_addrbuf    = nsm->sm_addrbuf;
161
	host->net	   = ni->net;
C
Chuck Lever 已提交
162 163 164 165 166

out:
	return host;
}

167
/*
C
Chuck Lever 已提交
168 169 170
 * Destroy an nlm_host and free associated resources
 *
 * Caller must hold nlm_host_mutex.
171
 */
C
Chuck Lever 已提交
172
static void nlm_destroy_host_locked(struct nlm_host *host)
173 174 175
{
	struct rpc_clnt	*clnt;

C
Chuck Lever 已提交
176 177
	dprintk("lockd: destroy host %s\n", host->h_name);

178 179 180
	BUG_ON(!list_empty(&host->h_lockowners));
	BUG_ON(atomic_read(&host->h_count));

C
Chuck Lever 已提交
181 182
	hlist_del_init(&host->h_hash);

183
	nsm_unmonitor(host);
184
	nsm_release(host->h_nsmhandle);
185

186 187 188
	clnt = host->h_rpcclnt;
	if (clnt != NULL)
		rpc_shutdown_client(clnt);
189
	kfree(host);
C
Chuck Lever 已提交
190 191

	nrhosts--;
192 193
}

194 195 196 197 198 199 200
/**
 * nlmclnt_lookup_host - Find an NLM host handle matching a remote server
 * @sap: network address of server
 * @salen: length of server address
 * @protocol: transport protocol to use
 * @version: NLM protocol version
 * @hostname: '\0'-terminated hostname of server
201
 * @noresvport: 1 if non-privileged port should be used
202 203 204 205 206
 *
 * Returns an nlm_host structure that matches the passed-in
 * [server address, transport protocol, NLM version, server hostname].
 * If one doesn't already exist in the host cache, a new handle is
 * created and returned.
207
 */
208 209 210
struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
				     const size_t salen,
				     const unsigned short protocol,
211 212
				     const u32 version,
				     const char *hostname,
213 214
				     int noresvport,
				     struct net *net)
215
{
216 217
	struct nlm_lookup_host_info ni = {
		.server		= 0,
218 219 220
		.sap		= sap,
		.salen		= salen,
		.protocol	= protocol,
221 222
		.version	= version,
		.hostname	= hostname,
223
		.hostname_len	= strlen(hostname),
224
		.noresvport	= noresvport,
225
		.net		= net,
226
	};
227 228 229 230
	struct hlist_head *chain;
	struct hlist_node *pos;
	struct nlm_host	*host;
	struct nsm_handle *nsm = NULL;
231

232 233
	dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
			(hostname ? hostname : "<none>"), version,
234
			(protocol == IPPROTO_UDP ? "udp" : "tcp"));
235

236 237 238 239
	mutex_lock(&nlm_host_mutex);

	chain = &nlm_client_hosts[nlm_hash_address(sap)];
	hlist_for_each_entry(host, pos, chain, h_hash) {
240 241
		if (host->net != net)
			continue;
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298
		if (!rpc_cmp_addr(nlm_addr(host), sap))
			continue;

		/* Same address. Share an NSM handle if we already have one */
		if (nsm == NULL)
			nsm = host->h_nsmhandle;

		if (host->h_proto != protocol)
			continue;
		if (host->h_version != version)
			continue;

		nlm_get_host(host);
		dprintk("lockd: %s found host %s (%s)\n", __func__,
			host->h_name, host->h_addrbuf);
		goto out;
	}

	host = nlm_alloc_host(&ni, nsm);
	if (unlikely(host == NULL))
		goto out;

	hlist_add_head(&host->h_hash, chain);
	nrhosts++;

	dprintk("lockd: %s created host %s (%s)\n", __func__,
		host->h_name, host->h_addrbuf);

out:
	mutex_unlock(&nlm_host_mutex);
	return host;
}

/**
 * nlmclnt_release_host - release client nlm_host
 * @host: nlm_host to release
 *
 */
void nlmclnt_release_host(struct nlm_host *host)
{
	if (host == NULL)
		return;

	dprintk("lockd: release client host %s\n", host->h_name);

	BUG_ON(atomic_read(&host->h_count) < 0);
	BUG_ON(host->h_server);

	if (atomic_dec_and_test(&host->h_count)) {
		BUG_ON(!list_empty(&host->h_lockowners));
		BUG_ON(!list_empty(&host->h_granted));
		BUG_ON(!list_empty(&host->h_reclaim));

		mutex_lock(&nlm_host_mutex);
		nlm_destroy_host_locked(host);
		mutex_unlock(&nlm_host_mutex);
	}
299 300
}

301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317
/**
 * nlmsvc_lookup_host - Find an NLM host handle matching a remote client
 * @rqstp: incoming NLM request
 * @hostname: name of client host
 * @hostname_len: length of client hostname
 *
 * Returns an nlm_host structure that matches the [client address,
 * transport protocol, NLM version, client hostname] of the passed-in
 * NLM request.  If one doesn't already exist in the host cache, a
 * new handle is created and returned.
 *
 * Before possibly creating a new nlm_host, construct a sockaddr
 * for a specific source address in case the local system has
 * multiple network addresses.  The family of the address in
 * rq_daddr is guaranteed to be the same as the family of the
 * address in rq_addr, so it's safe to use the same family for
 * the source address.
318
 */
319 320 321
struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
				    const char *hostname,
				    const size_t hostname_len)
322
{
C
Chuck Lever 已提交
323 324 325 326
	struct hlist_head *chain;
	struct hlist_node *pos;
	struct nlm_host	*host = NULL;
	struct nsm_handle *nsm = NULL;
327 328
	struct sockaddr *src_sap = svc_daddr(rqstp);
	size_t src_len = rqstp->rq_daddrlen;
329
	struct net *net = rqstp->rq_xprt->xpt_net;
330 331
	struct nlm_lookup_host_info ni = {
		.server		= 1,
332 333
		.sap		= svc_addr(rqstp),
		.salen		= rqstp->rq_addrlen,
334 335 336 337
		.protocol	= rqstp->rq_prot,
		.version	= rqstp->rq_vers,
		.hostname	= hostname,
		.hostname_len	= hostname_len,
338
		.net		= net,
339 340 341 342 343
	};

	dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
			(int)hostname_len, hostname, rqstp->rq_vers,
			(rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
344

C
Chuck Lever 已提交
345 346 347 348 349
	mutex_lock(&nlm_host_mutex);

	if (time_after_eq(jiffies, next_gc))
		nlm_gc_hosts();

C
Chuck Lever 已提交
350
	chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
C
Chuck Lever 已提交
351
	hlist_for_each_entry(host, pos, chain, h_hash) {
352 353
		if (host->net != net)
			continue;
C
Chuck Lever 已提交
354 355 356 357 358 359 360 361 362 363 364
		if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
			continue;

		/* Same address. Share an NSM handle if we already have one */
		if (nsm == NULL)
			nsm = host->h_nsmhandle;

		if (host->h_proto != ni.protocol)
			continue;
		if (host->h_version != ni.version)
			continue;
365
		if (!rpc_cmp_addr(nlm_srcaddr(host), src_sap))
C
Chuck Lever 已提交
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381
			continue;

		/* Move to head of hash chain. */
		hlist_del(&host->h_hash);
		hlist_add_head(&host->h_hash, chain);

		nlm_get_host(host);
		dprintk("lockd: %s found host %s (%s)\n",
			__func__, host->h_name, host->h_addrbuf);
		goto out;
	}

	host = nlm_alloc_host(&ni, nsm);
	if (unlikely(host == NULL))
		goto out;

382 383
	memcpy(nlm_srcaddr(host), src_sap, src_len);
	host->h_srcaddrlen = src_len;
C
Chuck Lever 已提交
384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410
	hlist_add_head(&host->h_hash, chain);
	nrhosts++;

	dprintk("lockd: %s created host %s (%s)\n",
		__func__, host->h_name, host->h_addrbuf);

out:
	mutex_unlock(&nlm_host_mutex);
	return host;
}

/**
 * nlmsvc_release_host - release server nlm_host
 * @host: nlm_host to release
 *
 * Host is destroyed later in nlm_gc_host().
 */
void nlmsvc_release_host(struct nlm_host *host)
{
	if (host == NULL)
		return;

	dprintk("lockd: release server host %s\n", host->h_name);

	BUG_ON(atomic_read(&host->h_count) < 0);
	BUG_ON(!host->h_server);
	atomic_dec(&host->h_count);
411 412
}

L
Linus Torvalds 已提交
413 414 415 416 417 418 419 420
/*
 * Create the NLM RPC client for an NLM peer
 */
struct rpc_clnt *
nlm_bind_host(struct nlm_host *host)
{
	struct rpc_clnt	*clnt;

421 422
	dprintk("lockd: nlm_bind_host %s (%s)\n",
			host->h_name, host->h_addrbuf);
L
Linus Torvalds 已提交
423 424

	/* Lock host handle */
T
Trond Myklebust 已提交
425
	mutex_lock(&host->h_mutex);
L
Linus Torvalds 已提交
426 427 428 429 430

	/* If we've already created an RPC client, check whether
	 * RPC rebind is required
	 */
	if ((clnt = host->h_rpcclnt) != NULL) {
431
		if (time_after_eq(jiffies, host->h_nextrebind)) {
432
			rpc_force_rebind(clnt);
L
Linus Torvalds 已提交
433
			host->h_nextrebind = jiffies + NLM_HOST_REBIND;
434
			dprintk("lockd: next rebind in %lu jiffies\n",
L
Linus Torvalds 已提交
435 436 437
					host->h_nextrebind - jiffies);
		}
	} else {
438
		unsigned long increment = nlmsvc_timeout;
439 440 441 442 443 444 445
		struct rpc_timeout timeparms = {
			.to_initval	= increment,
			.to_increment	= increment,
			.to_maxval	= increment * 6UL,
			.to_retries	= 5U,
		};
		struct rpc_create_args args = {
446
			.net		= host->net,
447
			.protocol	= host->h_proto,
448 449
			.address	= nlm_addr(host),
			.addrsize	= host->h_addrlen,
450 451 452 453 454
			.timeout	= &timeparms,
			.servername	= host->h_name,
			.program	= &nlm_program,
			.version	= host->h_version,
			.authflavor	= RPC_AUTH_UNIX,
455
			.flags		= (RPC_CLNT_CREATE_NOPING |
456 457 458
					   RPC_CLNT_CREATE_AUTOBIND),
		};

459 460 461 462 463 464 465
		/*
		 * lockd retries server side blocks automatically so we want
		 * those to be soft RPC calls. Client side calls need to be
		 * hard RPC tasks.
		 */
		if (!host->h_server)
			args.flags |= RPC_CLNT_CREATE_HARDRTRY;
466 467
		if (host->h_noresvport)
			args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
T
Trond Myklebust 已提交
468 469
		if (host->h_srcaddrlen)
			args.saddress = nlm_srcaddr(host);
470

471 472 473 474 475 476 477
		clnt = rpc_create(&args);
		if (!IS_ERR(clnt))
			host->h_rpcclnt = clnt;
		else {
			printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
			clnt = NULL;
		}
L
Linus Torvalds 已提交
478 479
	}

T
Trond Myklebust 已提交
480
	mutex_unlock(&host->h_mutex);
L
Linus Torvalds 已提交
481 482 483 484 485 486 487 488 489 490 491
	return clnt;
}

/*
 * Force a portmap lookup of the remote lockd port
 */
void
nlm_rebind_host(struct nlm_host *host)
{
	dprintk("lockd: rebind host %s\n", host->h_name);
	if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
492
		rpc_force_rebind(host->h_rpcclnt);
L
Linus Torvalds 已提交
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
		host->h_nextrebind = jiffies + NLM_HOST_REBIND;
	}
}

/*
 * Increment NLM host count
 */
struct nlm_host * nlm_get_host(struct nlm_host *host)
{
	if (host) {
		dprintk("lockd: get host %s\n", host->h_name);
		atomic_inc(&host->h_count);
		host->h_expires = jiffies + NLM_HOST_EXPIRE;
	}
	return host;
}

510 511 512 513
static struct nlm_host *next_host_state(struct hlist_head *cache,
					struct nsm_handle *nsm,
					const struct nlm_reboot *info)
{
514
	struct nlm_host *host;
515 516 517 518 519 520 521 522 523 524 525
	struct hlist_head *chain;
	struct hlist_node *pos;

	mutex_lock(&nlm_host_mutex);
	for_each_host(host, pos, chain, cache) {
		if (host->h_nsmhandle == nsm
		    && host->h_nsmstate != info->state) {
			host->h_nsmstate = info->state;
			host->h_state++;

			nlm_get_host(host);
526 527
			mutex_unlock(&nlm_host_mutex);
			return host;
528 529
		}
	}
530

531
	mutex_unlock(&nlm_host_mutex);
532
	return NULL;
533 534
}

535 536 537 538 539 540
/**
 * nlm_host_rebooted - Release all resources held by rebooted host
 * @info: pointer to decoded results of NLM_SM_NOTIFY call
 *
 * We were notified that the specified host has rebooted.  Release
 * all resources held by that peer.
541
 */
542
void nlm_host_rebooted(const struct nlm_reboot *info)
543
{
544
	struct nsm_handle *nsm;
545
	struct nlm_host	*host;
546

547 548
	nsm = nsm_reboot_lookup(info);
	if (unlikely(nsm == NULL))
549
		return;
550 551 552 553 554 555

	/* Mark all hosts tied to this NSM state as having rebooted.
	 * We run the loop repeatedly, because we drop the host table
	 * lock for this.
	 * To avoid processing a host several times, we match the nsmstate.
	 */
C
Chuck Lever 已提交
556
	while ((host = next_host_state(nlm_server_hosts, nsm, info)) != NULL) {
557
		nlmsvc_free_host_resources(host);
C
Chuck Lever 已提交
558
		nlmsvc_release_host(host);
559
	}
560 561 562 563 564
	while ((host = next_host_state(nlm_client_hosts, nsm, info)) != NULL) {
		nlmclnt_recovery(host);
		nlmclnt_release_host(host);
	}

565
	nsm_release(nsm);
566 567
}

L
Linus Torvalds 已提交
568
void
569
nlm_shutdown_hosts_net(struct net *net)
L
Linus Torvalds 已提交
570
{
571 572
	struct hlist_head *chain;
	struct hlist_node *pos;
L
Linus Torvalds 已提交
573 574 575
	struct nlm_host	*host;

	dprintk("lockd: shutting down host module\n");
I
Ingo Molnar 已提交
576
	mutex_lock(&nlm_host_mutex);
L
Linus Torvalds 已提交
577 578 579

	/* First, make all hosts eligible for gc */
	dprintk("lockd: nuking all hosts...\n");
C
Chuck Lever 已提交
580
	for_each_host(host, pos, chain, nlm_server_hosts) {
581 582
		if (net && host->net != net)
			continue;
583 584 585 586
		host->h_expires = jiffies - 1;
		if (host->h_rpcclnt) {
			rpc_shutdown_client(host->h_rpcclnt);
			host->h_rpcclnt = NULL;
587
		}
L
Linus Torvalds 已提交
588 589 590 591
	}

	/* Then, perform a garbage collection pass */
	nlm_gc_hosts();
I
Ingo Molnar 已提交
592
	mutex_unlock(&nlm_host_mutex);
593 594 595 596 597 598 599 600 601 602 603 604 605 606
}

/*
 * Shut down the hosts module.
 * Note that this routine is called only at server shutdown time.
 */
void
nlm_shutdown_hosts(void)
{
	struct hlist_head *chain;
	struct hlist_node *pos;
	struct nlm_host	*host;

	nlm_shutdown_hosts_net(NULL);
L
Linus Torvalds 已提交
607 608

	/* complain if any hosts are left */
C
Chuck Lever 已提交
609
	if (nrhosts != 0) {
L
Linus Torvalds 已提交
610
		printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
C
Chuck Lever 已提交
611
		dprintk("lockd: %lu hosts left:\n", nrhosts);
C
Chuck Lever 已提交
612
		for_each_host(host, pos, chain, nlm_server_hosts) {
613
			dprintk("       %s (cnt %d use %d exp %ld net %p)\n",
614
				host->h_name, atomic_read(&host->h_count),
615
				host->h_inuse, host->h_expires, host->net);
L
Linus Torvalds 已提交
616 617 618 619 620 621 622 623 624 625 626 627
		}
	}
}

/*
 * Garbage collect any unused NLM hosts.
 * This GC combines reference counting for async operations with
 * mark & sweep for resources held by remote clients.
 */
static void
nlm_gc_hosts(void)
{
628 629 630
	struct hlist_head *chain;
	struct hlist_node *pos, *next;
	struct nlm_host	*host;
L
Linus Torvalds 已提交
631 632

	dprintk("lockd: host garbage collection\n");
C
Chuck Lever 已提交
633
	for_each_host(host, pos, chain, nlm_server_hosts)
634
		host->h_inuse = 0;
L
Linus Torvalds 已提交
635 636 637 638

	/* Mark all hosts that hold locks, blocks or shares */
	nlmsvc_mark_resources();

C
Chuck Lever 已提交
639
	for_each_host_safe(host, pos, next, chain, nlm_server_hosts) {
640 641 642 643 644 645 646
		if (atomic_read(&host->h_count) || host->h_inuse
		 || time_before(jiffies, host->h_expires)) {
			dprintk("nlm_gc_hosts skipping %s "
				"(cnt %d use %d exp %ld)\n",
				host->h_name, atomic_read(&host->h_count),
				host->h_inuse, host->h_expires);
			continue;
L
Linus Torvalds 已提交
647
		}
C
Chuck Lever 已提交
648
		nlm_destroy_host_locked(host);
L
Linus Torvalds 已提交
649 650 651 652
	}

	next_gc = jiffies + NLM_HOST_COLLECT;
}