Blame view

fs/lockd/mon.c 14 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
  /*
   * linux/fs/lockd/mon.c
   *
   * The kernel statd client.
   *
   * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
   */
  
  #include <linux/types.h>
  #include <linux/utsname.h>
  #include <linux/kernel.h>
94da7663d   Chuck Lever   NSM: Replace IP a...
12
  #include <linux/ktime.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
13
  #include <linux/slab.h>
94da7663d   Chuck Lever   NSM: Replace IP a...
14

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/sunrpc/clnt.h>
0896a725a   \"Talpey, Thomas\   NFS/SUNRPC: use t...
16
  #include <linux/sunrpc/xprtsock.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include <linux/sunrpc/svc.h>
  #include <linux/lockd/lockd.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19

ad5b365c1   Mans Rullgard   NSM: Fix unaligne...
20
  #include <asm/unaligned.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
  #define NLMDBG_FACILITY		NLMDBG_MONITOR
36e8e668d   Chuck Lever   NSM: Move NSM pro...
22
23
24
25
26
27
28
29
30
31
32
33
  #define NSM_PROGRAM		100024
  #define NSM_VERSION		1
  
  enum {
  	NSMPROC_NULL,
  	NSMPROC_STAT,
  	NSMPROC_MON,
  	NSMPROC_UNMON,
  	NSMPROC_UNMON_ALL,
  	NSMPROC_SIMU_CRASH,
  	NSMPROC_NOTIFY,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

9c1bfd037   Chuck Lever   NSM: Move NSM-rel...
35
  struct nsm_args {
cab2d3c99   Chuck Lever   NSM: Encode the n...
36
  	struct nsm_private	*priv;
9c1bfd037   Chuck Lever   NSM: Move NSM-rel...
37
38
39
40
41
42
43
44
45
46
47
  	u32			prog;		/* RPC callback info */
  	u32			vers;
  	u32			proc;
  
  	char			*mon_name;
  };
  
  struct nsm_res {
  	u32			status;
  	u32			state;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  static struct rpc_program	nsm_program;
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
49
50
  static				LIST_HEAD(nsm_handles);
  static				DEFINE_SPINLOCK(nsm_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
  
  /*
   * Local NSM state
   */
6c9dc4255   Chuck Lever   lockd: Update NSM...
55
  u32	__read_mostly		nsm_local_state;
b7ba597fb   Chuck Lever   NSM: Move nsm_use...
56
  int	__read_mostly		nsm_use_hostnames;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

8529bc51d   Chuck Lever   NSM: Move nsm_add...
58
59
60
61
  static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)
  {
  	return (struct sockaddr *)&nsm->sm_addr;
  }
49b5699b3   Chuck Lever   NSM: Move nsm_cre...
62
63
64
65
66
67
68
69
70
71
72
73
74
75
  static struct rpc_clnt *nsm_create(void)
  {
  	struct sockaddr_in sin = {
  		.sin_family		= AF_INET,
  		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),
  	};
  	struct rpc_create_args args = {
  		.protocol		= XPRT_TRANSPORT_UDP,
  		.address		= (struct sockaddr *)&sin,
  		.addrsize		= sizeof(sin),
  		.servername		= "rpc.statd",
  		.program		= &nsm_program,
  		.version		= NSM_VERSION,
  		.authflavor		= RPC_AUTH_NULL,
0e5c2632e   Chuck Lever   lockd: Don't both...
76
  		.flags			= RPC_CLNT_CREATE_NOPING,
49b5699b3   Chuck Lever   NSM: Move nsm_cre...
77
78
79
80
81
82
  	};
  
  	return rpc_create(&args);
  }
  
  static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
  {
  	struct rpc_clnt	*clnt;
  	int		status;
a4846750f   Chuck Lever   NSM: Use C99 stru...
86
  	struct nsm_args args = {
cab2d3c99   Chuck Lever   NSM: Encode the n...
87
  		.priv		= &nsm->sm_priv,
a4846750f   Chuck Lever   NSM: Use C99 stru...
88
89
90
  		.prog		= NLM_PROGRAM,
  		.vers		= 3,
  		.proc		= NLMPROC_NSM_NOTIFY,
29ed1407e   Chuck Lever   NSM: Support IPv6...
91
  		.mon_name	= nsm->sm_mon_name,
a4846750f   Chuck Lever   NSM: Use C99 stru...
92
  	};
dead28da8   Chuck Lever   SUNRPC: eliminate...
93
94
95
96
  	struct rpc_message msg = {
  		.rpc_argp	= &args,
  		.rpc_resp	= res,
  	};
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
98
99
100
  
  	clnt = nsm_create();
  	if (IS_ERR(clnt)) {
  		status = PTR_ERR(clnt);
5acf43155   Chuck Lever   NSM: convert prin...
101
102
103
  		dprintk("lockd: failed to create NSM upcall transport, "
  				"status=%d
  ", status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  	memset(res, 0, sizeof(*res));
dead28da8   Chuck Lever   SUNRPC: eliminate...
107
108
  	msg.rpc_proc = &clnt->cl_procinfo[proc];
  	status = rpc_call_sync(clnt, &msg, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
109
  	if (status < 0)
5acf43155   Chuck Lever   NSM: convert prin...
110
111
112
  		dprintk("lockd: NSM upcall RPC failed, status=%d
  ",
  				status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  	else
  		status = 0;
90c5755ff   Trond Myklebust   SUNRPC: Kill rpc_...
115
  	rpc_shutdown_client(clnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
117
118
   out:
  	return status;
  }
1e49323c4   Chuck Lever   NLM: Move the pub...
119
120
121
122
123
124
125
126
127
128
  /**
   * nsm_monitor - Notify a peer in case we reboot
   * @host: pointer to nlm_host of peer to notify
   *
   * If this peer is not already monitored, this function sends an
   * upcall to the local rpc.statd to record the name/address of
   * the peer to notify in case we reboot.
   *
   * Returns zero if the peer is monitored by the local rpc.statd;
   * otherwise a negative errno value is returned.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
   */
1e49323c4   Chuck Lever   NLM: Move the pub...
130
  int nsm_monitor(const struct nlm_host *host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  {
8dead0dbd   Olaf Kirch   [PATCH] knfsd: lo...
132
  	struct nsm_handle *nsm = host->h_nsmhandle;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
  	struct nsm_res	res;
  	int		status;
9fee49024   Chuck Lever   NSM: Use sm_name ...
135
136
  	dprintk("lockd: nsm_monitor(%s)
  ", nsm->sm_name);
8dead0dbd   Olaf Kirch   [PATCH] knfsd: lo...
137
138
  
  	if (nsm->sm_monitored)
977faf392   Olaf Kirch   [PATCH] knfsd: hi...
139
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140

29ed1407e   Chuck Lever   NSM: Support IPv6...
141
142
143
144
145
  	/*
  	 * Choose whether to record the caller_name or IP address of
  	 * this peer in the local rpc.statd's database.
  	 */
  	nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
36e8e668d   Chuck Lever   NSM: Move NSM pro...
146
  	status = nsm_mon_unmon(nsm, NSMPROC_MON, &res);
6c9dc4255   Chuck Lever   lockd: Update NSM...
147
  	if (unlikely(res.status != 0))
5d254b119   Chuck Lever   NSM: Make sure to...
148
  		status = -EIO;
6c9dc4255   Chuck Lever   lockd: Update NSM...
149
  	if (unlikely(status < 0)) {
9fee49024   Chuck Lever   NSM: Use sm_name ...
150
151
  		printk(KERN_NOTICE "lockd: cannot monitor %s
  ", nsm->sm_name);
6c9dc4255   Chuck Lever   lockd: Update NSM...
152
153
154
155
156
157
158
159
160
161
  		return status;
  	}
  
  	nsm->sm_monitored = 1;
  	if (unlikely(nsm_local_state != res.state)) {
  		nsm_local_state = res.state;
  		dprintk("lockd: NSM state changed to %d
  ", nsm_local_state);
  	}
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
  }
356c3eb46   Chuck Lever   NLM: Move the pub...
163
164
165
166
167
168
169
  /**
   * nsm_unmonitor - Unregister peer notification
   * @host: pointer to nlm_host of peer to stop monitoring
   *
   * If this peer is monitored, this function sends an upcall to
   * tell the local rpc.statd not to send this peer a notification
   * when we reboot.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
   */
356c3eb46   Chuck Lever   NLM: Move the pub...
171
  void nsm_unmonitor(const struct nlm_host *host)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
172
  {
8dead0dbd   Olaf Kirch   [PATCH] knfsd: lo...
173
  	struct nsm_handle *nsm = host->h_nsmhandle;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
  	struct nsm_res	res;
356c3eb46   Chuck Lever   NLM: Move the pub...
175
  	int status;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176

9502c5225   Olaf Kirch   [PATCH] knfsd: lo...
177
178
  	if (atomic_read(&nsm->sm_count) == 1
  	 && nsm->sm_monitored && !nsm->sm_sticky) {
9fee49024   Chuck Lever   NSM: Use sm_name ...
179
180
  		dprintk("lockd: nsm_unmonitor(%s)
  ", nsm->sm_name);
9502c5225   Olaf Kirch   [PATCH] knfsd: lo...
181

36e8e668d   Chuck Lever   NSM: Move NSM pro...
182
  		status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res);
0c7aef456   Chuck Lever   NSM: Check result...
183
184
  		if (res.status != 0)
  			status = -EIO;
977faf392   Olaf Kirch   [PATCH] knfsd: hi...
185
  		if (status < 0)
9502c5225   Olaf Kirch   [PATCH] knfsd: lo...
186
187
  			printk(KERN_NOTICE "lockd: cannot unmonitor %s
  ",
9fee49024   Chuck Lever   NSM: Use sm_name ...
188
  					nsm->sm_name);
9502c5225   Olaf Kirch   [PATCH] knfsd: lo...
189
190
  		else
  			nsm->sm_monitored = 0;
977faf392   Olaf Kirch   [PATCH] knfsd: hi...
191
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192
  }
3420a8c43   Chuck Lever   NSM: Add nsm_look...
193
194
195
196
197
198
199
200
201
202
203
  static struct nsm_handle *nsm_lookup_hostname(const char *hostname,
  					      const size_t len)
  {
  	struct nsm_handle *nsm;
  
  	list_for_each_entry(nsm, &nsm_handles, sm_link)
  		if (strlen(nsm->sm_name) == len &&
  		    memcmp(nsm->sm_name, hostname, len) == 0)
  			return nsm;
  	return NULL;
  }
77a3ef33e   Chuck Lever   NSM: More clean u...
204
205
206
207
208
  static struct nsm_handle *nsm_lookup_addr(const struct sockaddr *sap)
  {
  	struct nsm_handle *nsm;
  
  	list_for_each_entry(nsm, &nsm_handles, sm_link)
4516fc045   Jeff Layton   sunrpc: add routi...
209
  		if (rpc_cmp_addr(nsm_addr(nsm), sap))
77a3ef33e   Chuck Lever   NSM: More clean u...
210
211
212
  			return nsm;
  	return NULL;
  }
3420a8c43   Chuck Lever   NSM: Add nsm_look...
213
214
215
216
217
218
219
220
221
222
  static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv)
  {
  	struct nsm_handle *nsm;
  
  	list_for_each_entry(nsm, &nsm_handles, sm_link)
  		if (memcmp(nsm->sm_priv.data, priv->data,
  					sizeof(priv->data)) == 0)
  			return nsm;
  	return NULL;
  }
7e44d3bea   Chuck Lever   NSM: Generate NSM...
223
224
225
226
227
228
  /*
   * Construct a unique cookie to match this nsm_handle to this monitored
   * host.  It is passed to the local rpc.statd via NSMPROC_MON, and
   * returned via NLMPROC_SM_NOTIFY, in the "priv" field of these
   * requests.
   *
94da7663d   Chuck Lever   NSM: Replace IP a...
229
230
231
232
233
234
235
236
237
238
   * The NSM protocol requires that these cookies be unique while the
   * system is running.  We prefer a stronger requirement of making them
   * unique across reboots.  If user space bugs cause a stale cookie to
   * be sent to the kernel, it could cause the wrong host to lose its
   * lock state if cookies were not unique across reboots.
   *
   * The cookies are exposed only to local user space via loopback.  They
   * do not appear on the physical network.  If we want greater security
   * for some reason, nsm_init_private() could perform a one-way hash to
   * obscure the contents of the cookie.
7e44d3bea   Chuck Lever   NSM: Generate NSM...
239
240
241
   */
  static void nsm_init_private(struct nsm_handle *nsm)
  {
94da7663d   Chuck Lever   NSM: Replace IP a...
242
243
  	u64 *p = (u64 *)&nsm->sm_priv.data;
  	struct timespec ts;
ad5b365c1   Mans Rullgard   NSM: Fix unaligne...
244
  	s64 ns;
94da7663d   Chuck Lever   NSM: Replace IP a...
245
246
  
  	ktime_get_ts(&ts);
ad5b365c1   Mans Rullgard   NSM: Fix unaligne...
247
248
249
  	ns = timespec_to_ns(&ts);
  	put_unaligned(ns, p);
  	put_unaligned((unsigned long)nsm, p + 1);
7e44d3bea   Chuck Lever   NSM: Generate NSM...
250
  }
b39b897c2   Chuck Lever   NSM: Refactor nsm...
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
  static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
  					    const size_t salen,
  					    const char *hostname,
  					    const size_t hostname_len)
  {
  	struct nsm_handle *new;
  
  	new = kzalloc(sizeof(*new) + hostname_len + 1, GFP_KERNEL);
  	if (unlikely(new == NULL))
  		return NULL;
  
  	atomic_set(&new->sm_count, 1);
  	new->sm_name = (char *)(new + 1);
  	memcpy(nsm_addr(new), sap, salen);
  	new->sm_addrlen = salen;
  	nsm_init_private(new);
c15128c5e   Chuck Lever   lockd: Replace ns...
267
268
269
270
271
  
  	if (rpc_ntop(nsm_addr(new), new->sm_addrbuf,
  					sizeof(new->sm_addrbuf)) == 0)
  		(void)snprintf(new->sm_addrbuf, sizeof(new->sm_addrbuf),
  				"unsupported address family");
b39b897c2   Chuck Lever   NSM: Refactor nsm...
272
273
274
275
276
  	memcpy(new->sm_name, hostname, hostname_len);
  	new->sm_name[hostname_len] = '\0';
  
  	return new;
  }
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
277
  /**
92fd91b99   Chuck Lever   NLM: Remove "crea...
278
   * nsm_get_handle - Find or create a cached nsm_handle
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
279
280
281
282
   * @sap: pointer to socket address of handle to find
   * @salen: length of socket address
   * @hostname: pointer to C string containing hostname to find
   * @hostname_len: length of C string
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
283
   *
92fd91b99   Chuck Lever   NLM: Remove "crea...
284
   * Behavior is modulated by the global nsm_use_hostnames variable.
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
285
   *
92fd91b99   Chuck Lever   NLM: Remove "crea...
286
287
288
289
   * Returns a cached nsm_handle after bumping its ref count, or
   * returns a fresh nsm_handle if a handle that matches @sap and/or
   * @hostname cannot be found in the handle cache.  Returns NULL if
   * an error occurs.
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
290
   */
92fd91b99   Chuck Lever   NLM: Remove "crea...
291
292
293
  struct nsm_handle *nsm_get_handle(const struct sockaddr *sap,
  				  const size_t salen, const char *hostname,
  				  const size_t hostname_len)
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
294
  {
77a3ef33e   Chuck Lever   NSM: More clean u...
295
  	struct nsm_handle *cached, *new = NULL;
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
296

67c6d107a   Chuck Lever   NSM: Move nsm_fin...
297
298
299
300
301
302
303
304
305
306
307
308
  	if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
  		if (printk_ratelimit()) {
  			printk(KERN_WARNING "Invalid hostname \"%.*s\" "
  					    "in NFS lock request
  ",
  				(int)hostname_len, hostname);
  		}
  		return NULL;
  	}
  
  retry:
  	spin_lock(&nsm_lock);
77a3ef33e   Chuck Lever   NSM: More clean u...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
  
  	if (nsm_use_hostnames && hostname != NULL)
  		cached = nsm_lookup_hostname(hostname, hostname_len);
  	else
  		cached = nsm_lookup_addr(sap);
  
  	if (cached != NULL) {
  		atomic_inc(&cached->sm_count);
  		spin_unlock(&nsm_lock);
  		kfree(new);
  		dprintk("lockd: found nsm_handle for %s (%s), "
  				"cnt %d
  ", cached->sm_name,
  				cached->sm_addrbuf,
  				atomic_read(&cached->sm_count));
  		return cached;
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
325
  	}
77a3ef33e   Chuck Lever   NSM: More clean u...
326
327
328
329
  
  	if (new != NULL) {
  		list_add(&new->sm_link, &nsm_handles);
  		spin_unlock(&nsm_lock);
5cf1c4b19   Chuck Lever   NSM: Add dprintk(...
330
331
  		dprintk("lockd: created nsm_handle for %s (%s)
  ",
77a3ef33e   Chuck Lever   NSM: More clean u...
332
333
  				new->sm_name, new->sm_addrbuf);
  		return new;
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
334
  	}
77a3ef33e   Chuck Lever   NSM: More clean u...
335

67c6d107a   Chuck Lever   NSM: Move nsm_fin...
336
  	spin_unlock(&nsm_lock);
77a3ef33e   Chuck Lever   NSM: More clean u...
337
338
  	new = nsm_create_handle(sap, salen, hostname, hostname_len);
  	if (unlikely(new == NULL))
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
339
  		return NULL;
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
340
  	goto retry;
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
341
342
343
  }
  
  /**
3420a8c43   Chuck Lever   NSM: Add nsm_look...
344
345
346
   * nsm_reboot_lookup - match NLMPROC_SM_NOTIFY arguments to an nsm_handle
   * @info: pointer to NLMPROC_SM_NOTIFY arguments
   *
7e469af97   Jeff Layton   lockd: don't clea...
347
348
349
   * Returns a matching nsm_handle if found in the nsm cache. The returned
   * nsm_handle's reference count is bumped. Otherwise returns NULL if some
   * error occurred.
3420a8c43   Chuck Lever   NSM: Add nsm_look...
350
351
352
353
354
355
   */
  struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
  {
  	struct nsm_handle *cached;
  
  	spin_lock(&nsm_lock);
94da7663d   Chuck Lever   NSM: Replace IP a...
356
  	cached = nsm_lookup_priv(&info->priv);
3420a8c43   Chuck Lever   NSM: Add nsm_look...
357
358
359
360
361
362
363
364
365
366
  	if (unlikely(cached == NULL)) {
  		spin_unlock(&nsm_lock);
  		dprintk("lockd: never saw rebooted peer '%.*s' before
  ",
  				info->len, info->mon);
  		return cached;
  	}
  
  	atomic_inc(&cached->sm_count);
  	spin_unlock(&nsm_lock);
3420a8c43   Chuck Lever   NSM: Add nsm_look...
367
368
369
370
371
372
373
374
  	dprintk("lockd: host %s (%s) rebooted, cnt %d
  ",
  			cached->sm_name, cached->sm_addrbuf,
  			atomic_read(&cached->sm_count));
  	return cached;
  }
  
  /**
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
375
376
377
378
379
380
   * nsm_release - Release an NSM handle
   * @nsm: pointer to handle to be released
   *
   */
  void nsm_release(struct nsm_handle *nsm)
  {
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
381
382
383
  	if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
  		list_del(&nsm->sm_link);
  		spin_unlock(&nsm_lock);
5cf1c4b19   Chuck Lever   NSM: Add dprintk(...
384
385
386
  		dprintk("lockd: destroyed nsm_handle for %s (%s)
  ",
  				nsm->sm_name, nsm->sm_addrbuf);
67c6d107a   Chuck Lever   NSM: Move nsm_fin...
387
388
389
  		kfree(nsm);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
   * XDR functions for NSM.
2ca7754d4   Chuck Lever   lockd: Fix up inc...
392
393
394
   *
   * See http://www.opengroup.org/ for details on the Network
   * Status Monitor wire protocol.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
395
   */
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
396
  static int encode_nsm_string(struct xdr_stream *xdr, const char *string)
099bd05f2   Chuck Lever   lockd: Ensure NSM...
397
  {
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
398
399
400
401
402
403
404
405
406
407
  	const u32 len = strlen(string);
  	__be32 *p;
  
  	if (unlikely(len > SM_MAXSTRLEN))
  		return -EIO;
  	p = xdr_reserve_space(xdr, sizeof(u32) + len);
  	if (unlikely(p == NULL))
  		return -EIO;
  	xdr_encode_opaque(p, string, len);
  	return 0;
099bd05f2   Chuck Lever   lockd: Ensure NSM...
408
  }
496951743   Chuck Lever   lockd: refactor S...
409
410
  /*
   * "mon_name" specifies the host to be monitored.
496951743   Chuck Lever   lockd: refactor S...
411
   */
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
412
  static int encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp)
496951743   Chuck Lever   lockd: refactor S...
413
  {
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
414
  	return encode_nsm_string(xdr, argp->mon_name);
496951743   Chuck Lever   lockd: refactor S...
415
  }
850c95fd0   Chuck Lever   lockd: refactor S...
416
417
418
  /*
   * The "my_id" argument specifies the hostname and RPC procedure
   * to be called when the status manager receives notification
36e8e668d   Chuck Lever   NSM: Move NSM pro...
419
   * (via the NLMPROC_SM_NOTIFY call) that the state of host "mon_name"
850c95fd0   Chuck Lever   lockd: refactor S...
420
421
   * has changed.
   */
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
422
  static int encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp)
850c95fd0   Chuck Lever   lockd: refactor S...
423
  {
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
424
425
426
427
428
429
430
431
432
  	int status;
  	__be32 *p;
  
  	status = encode_nsm_string(xdr, utsname()->nodename);
  	if (unlikely(status != 0))
  		return status;
  	p = xdr_reserve_space(xdr, 3 * sizeof(u32));
  	if (unlikely(p == NULL))
  		return -EIO;
850c95fd0   Chuck Lever   lockd: refactor S...
433
434
435
  	*p++ = htonl(argp->prog);
  	*p++ = htonl(argp->vers);
  	*p++ = htonl(argp->proc);
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
436
  	return 0;
850c95fd0   Chuck Lever   lockd: refactor S...
437
  }
ea72a7f17   Chuck Lever   lockd: document u...
438
439
  /*
   * The "mon_id" argument specifies the non-private arguments
36e8e668d   Chuck Lever   NSM: Move NSM pro...
440
   * of an NSMPROC_MON or NSMPROC_UNMON call.
ea72a7f17   Chuck Lever   lockd: document u...
441
   */
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
442
  static int encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp)
ea72a7f17   Chuck Lever   lockd: document u...
443
  {
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
444
  	int status;
ea72a7f17   Chuck Lever   lockd: document u...
445

03eb1dcbb   Chuck Lever   NSM: move to xdr_...
446
447
448
449
  	status = encode_mon_name(xdr, argp);
  	if (unlikely(status != 0))
  		return status;
  	return encode_my_id(xdr, argp);
ea72a7f17   Chuck Lever   lockd: document u...
450
  }
0490a54a0   Chuck Lever   lockd: introduce ...
451
452
  /*
   * The "priv" argument may contain private information required
36e8e668d   Chuck Lever   NSM: Move NSM pro...
453
454
   * by the NSMPROC_MON call. This information will be supplied in the
   * NLMPROC_SM_NOTIFY call.
0490a54a0   Chuck Lever   lockd: introduce ...
455
   */
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
456
  static int encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp)
0490a54a0   Chuck Lever   lockd: introduce ...
457
  {
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
458
459
460
461
462
  	__be32 *p;
  
  	p = xdr_reserve_space(xdr, SM_PRIV_SIZE);
  	if (unlikely(p == NULL))
  		return -EIO;
cab2d3c99   Chuck Lever   NSM: Encode the n...
463
  	xdr_encode_opaque_fixed(p, argp->priv->data, SM_PRIV_SIZE);
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
464
  	return 0;
0490a54a0   Chuck Lever   lockd: introduce ...
465
  }
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
466
467
  static int xdr_enc_mon(struct rpc_rqst *req, __be32 *p,
  		       const struct nsm_args *argp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  {
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
469
470
  	struct xdr_stream xdr;
  	int status;
0490a54a0   Chuck Lever   lockd: introduce ...
471

03eb1dcbb   Chuck Lever   NSM: move to xdr_...
472
473
474
475
476
  	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
  	status = encode_mon_id(&xdr, argp);
  	if (unlikely(status))
  		return status;
  	return encode_priv(&xdr, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
477
  }
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
478
479
  static int xdr_enc_unmon(struct rpc_rqst *req, __be32 *p,
  			 const struct nsm_args *argp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
  {
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
481
482
483
484
  	struct xdr_stream xdr;
  
  	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
  	return encode_mon_id(&xdr, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
485
  }
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
486
487
  static int xdr_dec_stat_res(struct rpc_rqst *rqstp, __be32 *p,
  			    struct nsm_res *resp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
488
  {
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
489
490
491
492
493
494
  	struct xdr_stream xdr;
  
  	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
  	p = xdr_inline_decode(&xdr, 2 * sizeof(u32));
  	if (unlikely(p == NULL))
  		return -EIO;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
  	resp->status = ntohl(*p++);
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
496
497
498
499
  	resp->state = ntohl(*p);
  
  	dprintk("lockd: xdr_dec_stat_res status %d state %d
  ",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
501
502
  			resp->status, resp->state);
  	return 0;
  }
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
503
504
  static int xdr_dec_stat(struct rpc_rqst *rqstp, __be32 *p,
  			struct nsm_res *resp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  {
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
506
507
508
509
510
511
512
513
514
515
  	struct xdr_stream xdr;
  
  	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
  	p = xdr_inline_decode(&xdr, sizeof(u32));
  	if (unlikely(p == NULL))
  		return -EIO;
  	resp->state = ntohl(*p);
  
  	dprintk("lockd: xdr_dec_stat state %d
  ", resp->state);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
518
519
  	return 0;
  }
  
  #define SM_my_name_sz	(1+XDR_QUADLEN(SM_MAXSTRLEN))
2ca7754d4   Chuck Lever   lockd: Fix up inc...
520
521
522
  #define SM_my_id_sz	(SM_my_name_sz+3)
  #define SM_mon_name_sz	(1+XDR_QUADLEN(SM_MAXSTRLEN))
  #define SM_mon_id_sz	(SM_mon_name_sz+SM_my_id_sz)
0490a54a0   Chuck Lever   lockd: introduce ...
523
524
  #define SM_priv_sz	(XDR_QUADLEN(SM_PRIV_SIZE))
  #define SM_mon_sz	(SM_mon_id_sz+SM_priv_sz)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
525
526
  #define SM_monres_sz	2
  #define SM_unmonres_sz	1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
  static struct rpc_procinfo	nsm_procedures[] = {
36e8e668d   Chuck Lever   NSM: Move NSM pro...
528
529
  [NSMPROC_MON] = {
  		.p_proc		= NSMPROC_MON,
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
530
531
  		.p_encode	= (kxdrproc_t)xdr_enc_mon,
  		.p_decode	= (kxdrproc_t)xdr_dec_stat_res,
2bea90d43   Chuck Lever   SUNRPC: RPC buffe...
532
533
  		.p_arglen	= SM_mon_sz,
  		.p_replen	= SM_monres_sz,
36e8e668d   Chuck Lever   NSM: Move NSM pro...
534
  		.p_statidx	= NSMPROC_MON,
cc0175c1d   Chuck Lever   SUNRPC: display h...
535
  		.p_name		= "MONITOR",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
536
  	},
36e8e668d   Chuck Lever   NSM: Move NSM pro...
537
538
  [NSMPROC_UNMON] = {
  		.p_proc		= NSMPROC_UNMON,
03eb1dcbb   Chuck Lever   NSM: move to xdr_...
539
540
  		.p_encode	= (kxdrproc_t)xdr_enc_unmon,
  		.p_decode	= (kxdrproc_t)xdr_dec_stat,
2bea90d43   Chuck Lever   SUNRPC: RPC buffe...
541
542
  		.p_arglen	= SM_mon_id_sz,
  		.p_replen	= SM_unmonres_sz,
36e8e668d   Chuck Lever   NSM: Move NSM pro...
543
  		.p_statidx	= NSMPROC_UNMON,
cc0175c1d   Chuck Lever   SUNRPC: display h...
544
  		.p_name		= "UNMONITOR",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
545
546
547
548
  	},
  };
  
  static struct rpc_version	nsm_version1 = {
e8c96f8c2   Tobias Klauser   [PATCH] fs: Use A...
549
550
  		.number		= 1,
  		.nrprocs	= ARRAY_SIZE(nsm_procedures),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
551
552
553
554
555
556
557
558
559
560
561
  		.procs		= nsm_procedures
  };
  
  static struct rpc_version *	nsm_version[] = {
  	[1] = &nsm_version1,
  };
  
  static struct rpc_stat		nsm_stats;
  
  static struct rpc_program	nsm_program = {
  		.name		= "statd",
36e8e668d   Chuck Lever   NSM: Move NSM pro...
562
  		.number		= NSM_PROGRAM,
e8c96f8c2   Tobias Klauser   [PATCH] fs: Use A...
563
  		.nrvers		= ARRAY_SIZE(nsm_version),
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
566
  		.version	= nsm_version,
  		.stats		= &nsm_stats
  };