Blame view

fs/lockd/host.c 17.5 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
  /*
   * 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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
14
  #include <linux/slab.h>
  #include <linux/in.h>
1b333c54a   Chuck Lever   lockd: address-fa...
15
  #include <linux/in6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
  #include <linux/sunrpc/clnt.h>
5976687a2   Jeff Layton   sunrpc: move addr...
17
  #include <linux/sunrpc/addr.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
19
  #include <linux/sunrpc/svc.h>
  #include <linux/lockd/lockd.h>
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
20
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21

66697bfd6   Stanislav Kinsbursky   LockD: make nlm h...
22
  #include <linux/sunrpc/svc_xprt.h>
1b333c54a   Chuck Lever   lockd: address-fa...
23
  #include <net/ipv6.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24

3cf7fb07e   Stanislav Kinsbursky   LockD: manage gar...
25
  #include "netns.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  #define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
  #define NLM_HOST_NRHASH		32
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
  #define NLM_HOST_REBIND		(60 * HZ)
1447d25eb   NeilBrown   knfsd: Remove NLM...
29
30
  #define NLM_HOST_EXPIRE		(300 * HZ)
  #define NLM_HOST_COLLECT	(120 * HZ)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31

d2df0484b   Chuck Lever   lockd: Rename nlm...
32
  static struct hlist_head	nlm_server_hosts[NLM_HOST_NRHASH];
8ea6ecc8b   Chuck Lever   lockd: Create cli...
33
  static struct hlist_head	nlm_client_hosts[NLM_HOST_NRHASH];
b11374688   J. Bruce Fields   lockd: define hos...
34

b67bfe0d4   Sasha Levin   hlist: drop the n...
35
  #define for_each_host(host, chain, table) \
b11374688   J. Bruce Fields   lockd: define hos...
36
37
  	for ((chain) = (table); \
  	     (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
b67bfe0d4   Sasha Levin   hlist: drop the n...
38
  		hlist_for_each_entry((host), (chain), h_hash)
b11374688   J. Bruce Fields   lockd: define hos...
39

b67bfe0d4   Sasha Levin   hlist: drop the n...
40
  #define for_each_host_safe(host, next, chain, table) \
b11374688   J. Bruce Fields   lockd: define hos...
41
42
  	for ((chain) = (table); \
  	     (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
b67bfe0d4   Sasha Levin   hlist: drop the n...
43
  		hlist_for_each_entry_safe((host), (next), \
b11374688   J. Bruce Fields   lockd: define hos...
44
  						(chain), h_hash)
fcc072c78   Chuck Lever   lockd: Make nrhos...
45
  static unsigned long		nrhosts;
353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
46
  static DEFINE_MUTEX(nlm_host_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

27adaddc8   Stanislav Kinsbursky   LockD: make garba...
48
  static void			nlm_gc_hosts(struct net *net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49

7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
50
51
  struct nlm_lookup_host_info {
  	const int		server;		/* search for server|client */
88541c848   Chuck Lever   lockd: Support no...
52
53
  	const struct sockaddr	*sap;		/* address to search for */
  	const size_t		salen;		/* it's length */
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
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 */
0cb2659b8   Chuck Lever   NLM: allow lockd ...
58
  	const int		noresvport;	/* use non-priv port */
66697bfd6   Stanislav Kinsbursky   LockD: make nlm h...
59
  	struct net		*net;		/* network namespace to bind */
b422df915   Trond Myklebust   lockd: Store the ...
60
  	const struct cred	*cred;
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
61
  };
ede2fea09   Chuck Lever   lockd: Support AF...
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
  /*
   * 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);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
103
  /*
a7952f405   Chuck Lever   lockd: Add nlm_al...
104
105
106
107
108
109
110
111
112
   * 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)
c751082ce   Elena Reshetova   lockd: convert ns...
113
  		refcount_inc(&nsm->sm_count);
a7952f405   Chuck Lever   lockd: Add nlm_al...
114
115
  	else {
  		host = NULL;
0ad95472b   Andrey Ryabinin   lockd: create NSM...
116
  		nsm = nsm_get_handle(ni->net, ni->sap, ni->salen,
a7952f405   Chuck Lever   lockd: Add nlm_al...
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
  					ni->hostname, ni->hostname_len);
  		if (unlikely(nsm == NULL)) {
  			dprintk("lockd: %s failed; no nsm handle
  ",
  				__func__);
  			goto out;
  		}
  	}
  
  	host = kmalloc(sizeof(*host), GFP_KERNEL);
  	if (unlikely(host == NULL)) {
  		dprintk("lockd: %s failed; no memory
  ", __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;
fee21fb58   Elena Reshetova   lockd: convert nl...
152
  	refcount_set(&host->h_count, 1);
a7952f405   Chuck Lever   lockd: Add nlm_al...
153
154
155
156
157
158
159
160
161
  	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;
66697bfd6   Stanislav Kinsbursky   LockD: make nlm h...
162
  	host->net	   = ni->net;
b422df915   Trond Myklebust   lockd: Store the ...
163
  	host->h_cred	   = get_cred(ni->cred),
0d0f4aab4   Andrey Ryabinin   lockd: get rid of...
164
  	strlcpy(host->nodename, utsname()->nodename, sizeof(host->nodename));
a7952f405   Chuck Lever   lockd: Add nlm_al...
165
166
167
168
169
170
  
  out:
  	return host;
  }
  
  /*
723bb5b50   Chuck Lever   lockd: Add nlm_de...
171
172
173
   * Destroy an nlm_host and free associated resources
   *
   * Caller must hold nlm_host_mutex.
c53c1bb94   Olaf Kirch   [PATCH] knfsd: lo...
174
   */
723bb5b50   Chuck Lever   lockd: Add nlm_de...
175
  static void nlm_destroy_host_locked(struct nlm_host *host)
c53c1bb94   Olaf Kirch   [PATCH] knfsd: lo...
176
177
  {
  	struct rpc_clnt	*clnt;
caa4e76b6   Stanislav Kinsbursky   LockD: manage use...
178
  	struct lockd_net *ln = net_generic(host->net, lockd_net_id);
c53c1bb94   Olaf Kirch   [PATCH] knfsd: lo...
179

723bb5b50   Chuck Lever   lockd: Add nlm_de...
180
181
  	dprintk("lockd: destroy host %s
  ", host->h_name);
723bb5b50   Chuck Lever   lockd: Add nlm_de...
182
  	hlist_del_init(&host->h_hash);
c53c1bb94   Olaf Kirch   [PATCH] knfsd: lo...
183
  	nsm_unmonitor(host);
c8c23c423   Chuck Lever   NSM: Release nsmh...
184
  	nsm_release(host->h_nsmhandle);
c53c1bb94   Olaf Kirch   [PATCH] knfsd: lo...
185

34f52e359   Trond Myklebust   SUNRPC: Convert r...
186
187
188
  	clnt = host->h_rpcclnt;
  	if (clnt != NULL)
  		rpc_shutdown_client(clnt);
b422df915   Trond Myklebust   lockd: Store the ...
189
  	put_cred(host->h_cred);
c53c1bb94   Olaf Kirch   [PATCH] knfsd: lo...
190
  	kfree(host);
723bb5b50   Chuck Lever   lockd: Add nlm_de...
191

caa4e76b6   Stanislav Kinsbursky   LockD: manage use...
192
  	ln->nrhosts--;
723bb5b50   Chuck Lever   lockd: Add nlm_de...
193
  	nrhosts--;
c53c1bb94   Olaf Kirch   [PATCH] knfsd: lo...
194
  }
d7d204403   Chuck Lever   lockd: Adjust nlm...
195
196
197
198
199
200
201
  /**
   * 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
0cb2659b8   Chuck Lever   NLM: allow lockd ...
202
   * @noresvport: 1 if non-privileged port should be used
b422df915   Trond Myklebust   lockd: Store the ...
203
204
   * @net: pointer to net namespace
   * @cred: pointer to cred
d7d204403   Chuck Lever   lockd: Adjust nlm...
205
206
207
208
209
   *
   * 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.
c585646dd   Adrian Bunk   [PATCH] fs/lockd/...
210
   */
d7d204403   Chuck Lever   lockd: Adjust nlm...
211
212
213
  struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
  				     const size_t salen,
  				     const unsigned short protocol,
0cb2659b8   Chuck Lever   NLM: allow lockd ...
214
215
  				     const u32 version,
  				     const char *hostname,
66697bfd6   Stanislav Kinsbursky   LockD: make nlm h...
216
  				     int noresvport,
b422df915   Trond Myklebust   lockd: Store the ...
217
218
  				     struct net *net,
  				     const struct cred *cred)
c585646dd   Adrian Bunk   [PATCH] fs/lockd/...
219
  {
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
220
221
  	struct nlm_lookup_host_info ni = {
  		.server		= 0,
d7d204403   Chuck Lever   lockd: Adjust nlm...
222
223
224
  		.sap		= sap,
  		.salen		= salen,
  		.protocol	= protocol,
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
225
226
  		.version	= version,
  		.hostname	= hostname,
d7d204403   Chuck Lever   lockd: Adjust nlm...
227
  		.hostname_len	= strlen(hostname),
0cb2659b8   Chuck Lever   NLM: allow lockd ...
228
  		.noresvport	= noresvport,
66697bfd6   Stanislav Kinsbursky   LockD: make nlm h...
229
  		.net		= net,
b422df915   Trond Myklebust   lockd: Store the ...
230
  		.cred		= cred,
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
231
  	};
8ea6ecc8b   Chuck Lever   lockd: Create cli...
232
  	struct hlist_head *chain;
8ea6ecc8b   Chuck Lever   lockd: Create cli...
233
234
  	struct nlm_host	*host;
  	struct nsm_handle *nsm = NULL;
caa4e76b6   Stanislav Kinsbursky   LockD: manage use...
235
  	struct lockd_net *ln = net_generic(net, lockd_net_id);
c98451bdb   Frank van Maarseveen   NLM: fix source a...
236

7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
237
238
239
  	dprintk("lockd: %s(host='%s', vers=%u, proto=%s)
  ", __func__,
  			(hostname ? hostname : "<none>"), version,
d7d204403   Chuck Lever   lockd: Adjust nlm...
240
  			(protocol == IPPROTO_UDP ? "udp" : "tcp"));
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
241

8ea6ecc8b   Chuck Lever   lockd: Create cli...
242
243
244
  	mutex_lock(&nlm_host_mutex);
  
  	chain = &nlm_client_hosts[nlm_hash_address(sap)];
b67bfe0d4   Sasha Levin   hlist: drop the n...
245
  	hlist_for_each_entry(host, chain, h_hash) {
66697bfd6   Stanislav Kinsbursky   LockD: make nlm h...
246
247
  		if (host->net != net)
  			continue;
8ea6ecc8b   Chuck Lever   lockd: Create cli...
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
  		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)
  ", __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);
caa4e76b6   Stanislav Kinsbursky   LockD: manage use...
272
  	ln->nrhosts++;
8ea6ecc8b   Chuck Lever   lockd: Create cli...
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
  	nrhosts++;
  
  	dprintk("lockd: %s created host %s (%s)
  ", __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
  ", host->h_name);
a2d30a54d   Trond Myklebust   lockd: Remove BUG...
296
  	WARN_ON_ONCE(host->h_server);
8ea6ecc8b   Chuck Lever   lockd: Create cli...
297

4a9be28c4   NeilBrown   NFS: fix mount/um...
298
  	if (refcount_dec_and_mutex_lock(&host->h_count, &nlm_host_mutex)) {
a2d30a54d   Trond Myklebust   lockd: Remove BUG...
299
300
301
  		WARN_ON_ONCE(!list_empty(&host->h_lockowners));
  		WARN_ON_ONCE(!list_empty(&host->h_granted));
  		WARN_ON_ONCE(!list_empty(&host->h_reclaim));
8ea6ecc8b   Chuck Lever   lockd: Create cli...
302

8ea6ecc8b   Chuck Lever   lockd: Create cli...
303
304
305
  		nlm_destroy_host_locked(host);
  		mutex_unlock(&nlm_host_mutex);
  	}
c585646dd   Adrian Bunk   [PATCH] fs/lockd/...
306
  }
6bfbe8af4   Chuck Lever   lockd: Adjust nlm...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
  /**
   * 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.
c585646dd   Adrian Bunk   [PATCH] fs/lockd/...
324
   */
6bfbe8af4   Chuck Lever   lockd: Adjust nlm...
325
326
327
  struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
  				    const char *hostname,
  				    const size_t hostname_len)
c585646dd   Adrian Bunk   [PATCH] fs/lockd/...
328
  {
67216b94d   Chuck Lever   lockd: Clean up n...
329
  	struct hlist_head *chain;
67216b94d   Chuck Lever   lockd: Clean up n...
330
331
  	struct nlm_host	*host = NULL;
  	struct nsm_handle *nsm = NULL;
849a1cf13   Mi Jinlong   SUNRPC: Replace s...
332
333
  	struct sockaddr *src_sap = svc_daddr(rqstp);
  	size_t src_len = rqstp->rq_daddrlen;
9695c7057   Stanislav Kinsbursky   SUNRPC: service r...
334
  	struct net *net = SVC_NET(rqstp);
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
335
336
  	struct nlm_lookup_host_info ni = {
  		.server		= 1,
88541c848   Chuck Lever   lockd: Support no...
337
338
  		.sap		= svc_addr(rqstp),
  		.salen		= rqstp->rq_addrlen,
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
339
340
341
342
  		.protocol	= rqstp->rq_prot,
  		.version	= rqstp->rq_vers,
  		.hostname	= hostname,
  		.hostname_len	= hostname_len,
66697bfd6   Stanislav Kinsbursky   LockD: make nlm h...
343
  		.net		= net,
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
344
  	};
3cf7fb07e   Stanislav Kinsbursky   LockD: manage gar...
345
  	struct lockd_net *ln = net_generic(net, lockd_net_id);
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
346

93f38b6fa   Amir Goldstein   lockd: fix access...
347
348
  	dprintk("lockd: %s(host='%.*s', vers=%u, proto=%s)
  ", __func__,
7f1ed18bd   Chuck Lever   NLM: Convert nlm_...
349
350
  			(int)hostname_len, hostname, rqstp->rq_vers,
  			(rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
c98451bdb   Frank van Maarseveen   NLM: fix source a...
351

67216b94d   Chuck Lever   lockd: Clean up n...
352
  	mutex_lock(&nlm_host_mutex);
3cf7fb07e   Stanislav Kinsbursky   LockD: manage gar...
353
  	if (time_after_eq(jiffies, ln->next_gc))
27adaddc8   Stanislav Kinsbursky   LockD: make garba...
354
  		nlm_gc_hosts(net);
67216b94d   Chuck Lever   lockd: Clean up n...
355

d2df0484b   Chuck Lever   lockd: Rename nlm...
356
  	chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
b67bfe0d4   Sasha Levin   hlist: drop the n...
357
  	hlist_for_each_entry(host, chain, h_hash) {
66697bfd6   Stanislav Kinsbursky   LockD: make nlm h...
358
359
  		if (host->net != net)
  			continue;
67216b94d   Chuck Lever   lockd: Clean up n...
360
361
362
363
364
365
366
367
368
369
370
  		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;
796918366   Chuck Lever   lockd: Remove src...
371
  		if (!rpc_cmp_addr(nlm_srcaddr(host), src_sap))
67216b94d   Chuck Lever   lockd: Clean up n...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
  			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)
  ",
  			__func__, host->h_name, host->h_addrbuf);
  		goto out;
  	}
  
  	host = nlm_alloc_host(&ni, nsm);
  	if (unlikely(host == NULL))
  		goto out;
796918366   Chuck Lever   lockd: Remove src...
388
389
  	memcpy(nlm_srcaddr(host), src_sap, src_len);
  	host->h_srcaddrlen = src_len;
67216b94d   Chuck Lever   lockd: Clean up n...
390
  	hlist_add_head(&host->h_hash, chain);
caa4e76b6   Stanislav Kinsbursky   LockD: manage use...
391
  	ln->nrhosts++;
67216b94d   Chuck Lever   lockd: Clean up n...
392
  	nrhosts++;
535cb8f31   Trond Myklebust   lockd: Fix server...
393
  	refcount_inc(&host->h_count);
67216b94d   Chuck Lever   lockd: Clean up n...
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
  	dprintk("lockd: %s created host %s (%s)
  ",
  		__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
  ", host->h_name);
a2d30a54d   Trond Myklebust   lockd: Remove BUG...
416
  	WARN_ON_ONCE(!host->h_server);
fee21fb58   Elena Reshetova   lockd: convert nl...
417
  	refcount_dec(&host->h_count);
c585646dd   Adrian Bunk   [PATCH] fs/lockd/...
418
419
420
  }
  
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
426
   * Create the NLM RPC client for an NLM peer
   */
  struct rpc_clnt *
  nlm_bind_host(struct nlm_host *host)
  {
  	struct rpc_clnt	*clnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
427

1df40b609   Chuck Lever   NLM: Remove addre...
428
429
430
  	dprintk("lockd: nlm_bind_host %s (%s)
  ",
  			host->h_name, host->h_addrbuf);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
431
432
  
  	/* Lock host handle */
504679141   Trond Myklebust   NLM: sem to mutex...
433
  	mutex_lock(&host->h_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
  
  	/* If we've already created an RPC client, check whether
  	 * RPC rebind is required
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
  	 */
  	if ((clnt = host->h_rpcclnt) != NULL) {
0e1c02e4e   Calum Mackay   lockd: don't use ...
439
  		nlm_rebind_host(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
440
  	} else {
21051ba62   Trond Myklebust   NLM: Fix locking ...
441
  		unsigned long increment = nlmsvc_timeout;
e1ec78928   Chuck Lever   LOCKD: Convert to...
442
443
444
445
446
447
448
  		struct rpc_timeout timeparms = {
  			.to_initval	= increment,
  			.to_increment	= increment,
  			.to_maxval	= increment * 6UL,
  			.to_retries	= 5U,
  		};
  		struct rpc_create_args args = {
66697bfd6   Stanislav Kinsbursky   LockD: make nlm h...
449
  			.net		= host->net,
e1ec78928   Chuck Lever   LOCKD: Convert to...
450
  			.protocol	= host->h_proto,
b4ed58fd3   Chuck Lever   lockd: Use sockad...
451
452
  			.address	= nlm_addr(host),
  			.addrsize	= host->h_addrlen,
e1ec78928   Chuck Lever   LOCKD: Convert to...
453
454
455
456
457
  			.timeout	= &timeparms,
  			.servername	= host->h_name,
  			.program	= &nlm_program,
  			.version	= host->h_version,
  			.authflavor	= RPC_AUTH_UNIX,
90bd17c87   Jeff Layton   NLM: have server-...
458
  			.flags		= (RPC_CLNT_CREATE_NOPING |
e6237b6fe   Trond Myklebust   NFSv4.1: Don't re...
459
460
  					   RPC_CLNT_CREATE_AUTOBIND |
  					   RPC_CLNT_CREATE_REUSEPORT),
b422df915   Trond Myklebust   lockd: Store the ...
461
  			.cred		= host->h_cred,
e1ec78928   Chuck Lever   LOCKD: Convert to...
462
  		};
90bd17c87   Jeff Layton   NLM: have server-...
463
464
465
466
467
468
469
  		/*
  		 * 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;
0cb2659b8   Chuck Lever   NLM: allow lockd ...
470
471
  		if (host->h_noresvport)
  			args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
8e35f8e7c   Trond Myklebust   NLM: Fix a regres...
472
473
  		if (host->h_srcaddrlen)
  			args.saddress = nlm_srcaddr(host);
90bd17c87   Jeff Layton   NLM: have server-...
474

e1ec78928   Chuck Lever   LOCKD: Convert to...
475
476
477
478
479
480
481
482
  		clnt = rpc_create(&args);
  		if (!IS_ERR(clnt))
  			host->h_rpcclnt = clnt;
  		else {
  			printk("lockd: couldn't create RPC handle for %s
  ", host->h_name);
  			clnt = NULL;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
  	}
504679141   Trond Myklebust   NLM: sem to mutex...
484
  	mutex_unlock(&host->h_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
  	return clnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
  }
0e1c02e4e   Calum Mackay   lockd: don't use ...
487
488
489
490
491
492
493
  /**
   * nlm_rebind_host - If needed, force a portmap lookup of the peer's lockd port
   * @host: NLM host handle for peer
   *
   * This is not needed when using a connection-oriented protocol, such as TCP.
   * The existing autobind mechanism is sufficient to force a rebind when
   * required, e.g. on connection state transitions.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
   */
  void
  nlm_rebind_host(struct nlm_host *host)
  {
0e1c02e4e   Calum Mackay   lockd: don't use ...
498
499
  	if (host->h_proto != IPPROTO_UDP)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
  	if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
35f5a422c   Chuck Lever   SUNRPC: new inter...
501
  		rpc_force_rebind(host->h_rpcclnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
502
503
504
505
506
507
508
509
510
511
512
513
  		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
  ", host->h_name);
fee21fb58   Elena Reshetova   lockd: convert nl...
514
  		refcount_inc(&host->h_count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
516
517
518
  		host->h_expires = jiffies + NLM_HOST_EXPIRE;
  	}
  	return host;
  }
b10e30f65   J. Bruce Fields   lockd: reorganize...
519
520
521
522
  static struct nlm_host *next_host_state(struct hlist_head *cache,
  					struct nsm_handle *nsm,
  					const struct nlm_reboot *info)
  {
80c30e8de   Chuck Lever   NLM: Fix "kernel ...
523
  	struct nlm_host *host;
b10e30f65   J. Bruce Fields   lockd: reorganize...
524
  	struct hlist_head *chain;
b10e30f65   J. Bruce Fields   lockd: reorganize...
525
526
  
  	mutex_lock(&nlm_host_mutex);
b67bfe0d4   Sasha Levin   hlist: drop the n...
527
  	for_each_host(host, chain, cache) {
b10e30f65   J. Bruce Fields   lockd: reorganize...
528
529
530
531
532
533
  		if (host->h_nsmhandle == nsm
  		    && host->h_nsmstate != info->state) {
  			host->h_nsmstate = info->state;
  			host->h_state++;
  
  			nlm_get_host(host);
80c30e8de   Chuck Lever   NLM: Fix "kernel ...
534
535
  			mutex_unlock(&nlm_host_mutex);
  			return host;
b10e30f65   J. Bruce Fields   lockd: reorganize...
536
537
  		}
  	}
80c30e8de   Chuck Lever   NLM: Fix "kernel ...
538

b10e30f65   J. Bruce Fields   lockd: reorganize...
539
  	mutex_unlock(&nlm_host_mutex);
80c30e8de   Chuck Lever   NLM: Fix "kernel ...
540
  	return NULL;
b10e30f65   J. Bruce Fields   lockd: reorganize...
541
  }
7fefc9cb9   Chuck Lever   NLM: Change nlm_h...
542
543
  /**
   * nlm_host_rebooted - Release all resources held by rebooted host
0ad95472b   Andrey Ryabinin   lockd: create NSM...
544
   * @net:  network namespace
7fefc9cb9   Chuck Lever   NLM: Change nlm_h...
545
546
547
548
   * @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.
cf712c24d   Olaf Kirch   [PATCH] knfsd: co...
549
   */
0ad95472b   Andrey Ryabinin   lockd: create NSM...
550
  void nlm_host_rebooted(const struct net *net, const struct nlm_reboot *info)
cf712c24d   Olaf Kirch   [PATCH] knfsd: co...
551
  {
5c8dd29ca   Olaf Kirch   [PATCH] knfsd: lo...
552
  	struct nsm_handle *nsm;
0cea32761   Olaf Kirch   [PATCH] knfsd: lo...
553
  	struct nlm_host	*host;
cf712c24d   Olaf Kirch   [PATCH] knfsd: co...
554

0ad95472b   Andrey Ryabinin   lockd: create NSM...
555
  	nsm = nsm_reboot_lookup(net, info);
8c7378fd2   Chuck Lever   NLM: Call nsm_reb...
556
  	if (unlikely(nsm == NULL))
db4e4c9a9   Olaf Kirch   [PATCH] knfsd: wh...
557
  		return;
5c8dd29ca   Olaf Kirch   [PATCH] knfsd: lo...
558
559
560
561
562
563
  
  	/* 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.
  	 */
d2df0484b   Chuck Lever   lockd: Rename nlm...
564
  	while ((host = next_host_state(nlm_server_hosts, nsm, info)) != NULL) {
8ea6ecc8b   Chuck Lever   lockd: Create cli...
565
  		nlmsvc_free_host_resources(host);
67216b94d   Chuck Lever   lockd: Clean up n...
566
  		nlmsvc_release_host(host);
cf712c24d   Olaf Kirch   [PATCH] knfsd: co...
567
  	}
8ea6ecc8b   Chuck Lever   lockd: Create cli...
568
569
570
571
  	while ((host = next_host_state(nlm_client_hosts, nsm, info)) != NULL) {
  		nlmclnt_recovery(host);
  		nlmclnt_release_host(host);
  	}
cdd30fa16   Jeff Layton   lockd: release re...
572
  	nsm_release(nsm);
cf712c24d   Olaf Kirch   [PATCH] knfsd: co...
573
  }
d5850ff9e   Stanislav Kinsbursky   Lockd: host compl...
574
575
576
  static void nlm_complain_hosts(struct net *net)
  {
  	struct hlist_head *chain;
d5850ff9e   Stanislav Kinsbursky   Lockd: host compl...
577
578
579
580
581
582
583
  	struct nlm_host	*host;
  
  	if (net) {
  		struct lockd_net *ln = net_generic(net, lockd_net_id);
  
  		if (ln->nrhosts == 0)
  			return;
e919b0765   Vasily Averin   lockd: remove net...
584
585
586
587
588
589
  		pr_warn("lockd: couldn't shutdown host module for net %x!
  ",
  			net->ns.inum);
  		dprintk("lockd: %lu hosts left in net %x:
  ", ln->nrhosts,
  			net->ns.inum);
d5850ff9e   Stanislav Kinsbursky   Lockd: host compl...
590
591
592
593
594
595
596
597
  	} else {
  		if (nrhosts == 0)
  			return;
  		printk(KERN_WARNING "lockd: couldn't shutdown host module!
  ");
  		dprintk("lockd: %lu hosts left:
  ", nrhosts);
  	}
b67bfe0d4   Sasha Levin   hlist: drop the n...
598
  	for_each_host(host, chain, nlm_server_hosts) {
d5850ff9e   Stanislav Kinsbursky   Lockd: host compl...
599
600
  		if (net && host->net != net)
  			continue;
e919b0765   Vasily Averin   lockd: remove net...
601
602
  		dprintk("       %s (cnt %d use %d exp %ld net %x)
  ",
fee21fb58   Elena Reshetova   lockd: convert nl...
603
  			host->h_name, refcount_read(&host->h_count),
e919b0765   Vasily Averin   lockd: remove net...
604
  			host->h_inuse, host->h_expires, host->net->ns.inum);
d5850ff9e   Stanislav Kinsbursky   Lockd: host compl...
605
606
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
  void
3b64739fb   Stanislav Kinsbursky   Lockd: shutdown N...
608
  nlm_shutdown_hosts_net(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
  {
0cea32761   Olaf Kirch   [PATCH] knfsd: lo...
610
  	struct hlist_head *chain;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
  	struct nlm_host	*host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612

353ab6e97   Ingo Molnar   [PATCH] sem2mutex...
613
  	mutex_lock(&nlm_host_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
614
615
  
  	/* First, make all hosts eligible for gc */
e919b0765   Vasily Averin   lockd: remove net...
616
617
618
  	dprintk("lockd: nuking all hosts in net %x...
  ",
  		net ? net->ns.inum : 0);
b67bfe0d4   Sasha Levin   hlist: drop the n...
619
  	for_each_host(host, chain, nlm_server_hosts) {
3b64739fb   Stanislav Kinsbursky   Lockd: shutdown N...
620
621
  		if (net && host->net != net)
  			continue;
b11374688   J. Bruce Fields   lockd: define hos...
622
623
624
625
  		host->h_expires = jiffies - 1;
  		if (host->h_rpcclnt) {
  			rpc_shutdown_client(host->h_rpcclnt);
  			host->h_rpcclnt = NULL;
d801b8616   Jeff Layton   NLM: tear down RP...
626
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
627
628
629
  	}
  
  	/* Then, perform a garbage collection pass */
27adaddc8   Stanislav Kinsbursky   LockD: make garba...
630
  	nlm_gc_hosts(net);
d5850ff9e   Stanislav Kinsbursky   Lockd: host compl...
631
  	nlm_complain_hosts(net);
9e137ed5a   Vasily Averin   nlm_shutdown_host...
632
  	mutex_unlock(&nlm_host_mutex);
3b64739fb   Stanislav Kinsbursky   Lockd: shutdown N...
633
634
635
636
637
638
639
640
641
  }
  
  /*
   * Shut down the hosts module.
   * Note that this routine is called only at server shutdown time.
   */
  void
  nlm_shutdown_hosts(void)
  {
e2edaa98c   Stanislav Kinsbursky   Lockd: add more d...
642
643
  	dprintk("lockd: shutting down host module
  ");
3b64739fb   Stanislav Kinsbursky   Lockd: shutdown N...
644
  	nlm_shutdown_hosts_net(NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
649
650
651
652
  }
  
  /*
   * 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
27adaddc8   Stanislav Kinsbursky   LockD: make garba...
653
  nlm_gc_hosts(struct net *net)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
  {
0cea32761   Olaf Kirch   [PATCH] knfsd: lo...
655
  	struct hlist_head *chain;
b67bfe0d4   Sasha Levin   hlist: drop the n...
656
  	struct hlist_node *next;
0cea32761   Olaf Kirch   [PATCH] knfsd: lo...
657
  	struct nlm_host	*host;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658

e919b0765   Vasily Averin   lockd: remove net...
659
660
661
  	dprintk("lockd: host garbage collection for net %x
  ",
  		net ? net->ns.inum : 0);
b67bfe0d4   Sasha Levin   hlist: drop the n...
662
  	for_each_host(host, chain, nlm_server_hosts) {
27adaddc8   Stanislav Kinsbursky   LockD: make garba...
663
664
  		if (net && host->net != net)
  			continue;
b11374688   J. Bruce Fields   lockd: define hos...
665
  		host->h_inuse = 0;
27adaddc8   Stanislav Kinsbursky   LockD: make garba...
666
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
667
668
  
  	/* Mark all hosts that hold locks, blocks or shares */
b26411f85   Stanislav Kinsbursky   LockD: mark host ...
669
  	nlmsvc_mark_resources(net);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670

b67bfe0d4   Sasha Levin   hlist: drop the n...
671
  	for_each_host_safe(host, next, chain, nlm_server_hosts) {
27adaddc8   Stanislav Kinsbursky   LockD: make garba...
672
673
  		if (net && host->net != net)
  			continue;
535cb8f31   Trond Myklebust   lockd: Fix server...
674
  		if (host->h_inuse || time_before(jiffies, host->h_expires)) {
b11374688   J. Bruce Fields   lockd: define hos...
675
  			dprintk("nlm_gc_hosts skipping %s "
e919b0765   Vasily Averin   lockd: remove net...
676
677
  				"(cnt %d use %d exp %ld net %x)
  ",
fee21fb58   Elena Reshetova   lockd: convert nl...
678
  				host->h_name, refcount_read(&host->h_count),
e919b0765   Vasily Averin   lockd: remove net...
679
680
  				host->h_inuse, host->h_expires,
  				host->net->ns.inum);
b11374688   J. Bruce Fields   lockd: define hos...
681
  			continue;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
682
  		}
535cb8f31   Trond Myklebust   lockd: Fix server...
683
684
  		if (refcount_dec_if_one(&host->h_count))
  			nlm_destroy_host_locked(host);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
685
  	}
3cf7fb07e   Stanislav Kinsbursky   LockD: manage gar...
686
687
688
689
690
  	if (net) {
  		struct lockd_net *ln = net_generic(net, lockd_net_id);
  
  		ln->next_gc = jiffies + NLM_HOST_COLLECT;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
691
  }