aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorChuck Lever <chuck.lever@oracle.com>2008-12-11 17:56:07 -0500
committerJ. Bruce Fields <bfields@citi.umich.edu>2009-01-06 11:53:55 -0500
commit94da7663db26530a8377f7219f8be8bd4d4822c2 (patch)
treea19b8cac6ce9010d58776cae18b96091a2137efb /fs
parent77a3ef33e2de6fc8aabd7cb1700bfef81757c28a (diff)
NSM: Replace IP address as our nlm_reboot lookup key
NLM provides file locking services for NFS files. Part of this service includes a second protocol, known as NSM, which is a reboot notification service. NLM uses this service to determine when to reclaim locks or enter a grace period after a client or server reboots. The NLM service (implemented by lockd in the Linux kernel) contacts the local NSM service (implemented by rpc.statd in Linux user space) via NSM protocol upcalls to register a callback when a particular remote peer reboots. To match the callback to the correct remote peer, the NLM service constructs a cookie that it passes in the request. The NSM service passes that cookie back to the NLM service when it is notified that the given remote peer has indeed rebooted. Currently on Linux, the cookie is the raw 32-bit IPv4 address of the remote peer. To support IPv6 addresses, which are larger, we could use all 16 bytes of the cookie to represent a full IPv6 address, although we still can't represent an IPv6 address with a scope ID in just 16 bytes. Instead, to avoid the need for future changes to support additional address types, we'll use a manufactured value for the cookie, and use that to find the corresponding nsm_handle struct in the kernel during the NLMPROC_SM_NOTIFY callback. This should provide complete support in the kernel's NSM implementation for IPv6 hosts, while remaining backwards compatible with older rpc.statd implementations. Note we also deal with another case where nsm_use_hostnames can change while there are outstanding notifications, possibly resulting in the loss of reboot notifications. After this patch, the priv cookie is always used to lookup rebooted hosts in the kernel. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/lockd/mon.c28
1 files changed, 19 insertions, 9 deletions
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c
index 99aec744474c..8ae4c02d7dfd 100644
--- a/fs/lockd/mon.c
+++ b/fs/lockd/mon.c
@@ -9,6 +9,8 @@
9#include <linux/types.h> 9#include <linux/types.h>
10#include <linux/utsname.h> 10#include <linux/utsname.h>
11#include <linux/kernel.h> 11#include <linux/kernel.h>
12#include <linux/ktime.h>
13
12#include <linux/sunrpc/clnt.h> 14#include <linux/sunrpc/clnt.h>
13#include <linux/sunrpc/xprtsock.h> 15#include <linux/sunrpc/xprtsock.h>
14#include <linux/sunrpc/svc.h> 16#include <linux/sunrpc/svc.h>
@@ -240,13 +242,25 @@ static struct nsm_handle *nsm_lookup_priv(const struct nsm_private *priv)
240 * returned via NLMPROC_SM_NOTIFY, in the "priv" field of these 242 * returned via NLMPROC_SM_NOTIFY, in the "priv" field of these
241 * requests. 243 * requests.
242 * 244 *
243 * Linux provides the raw IP address of the monitored host, 245 * The NSM protocol requires that these cookies be unique while the
244 * left in network byte order. 246 * system is running. We prefer a stronger requirement of making them
247 * unique across reboots. If user space bugs cause a stale cookie to
248 * be sent to the kernel, it could cause the wrong host to lose its
249 * lock state if cookies were not unique across reboots.
250 *
251 * The cookies are exposed only to local user space via loopback. They
252 * do not appear on the physical network. If we want greater security
253 * for some reason, nsm_init_private() could perform a one-way hash to
254 * obscure the contents of the cookie.
245 */ 255 */
246static void nsm_init_private(struct nsm_handle *nsm) 256static void nsm_init_private(struct nsm_handle *nsm)
247{ 257{
248 __be32 *p = (__be32 *)&nsm->sm_priv.data; 258 u64 *p = (u64 *)&nsm->sm_priv.data;
249 *p = nsm_addr_in(nsm)->sin_addr.s_addr; 259 struct timespec ts;
260
261 ktime_get_ts(&ts);
262 *p++ = timespec_to_ns(&ts);
263 *p = (unsigned long)nsm;
250} 264}
251 265
252static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap, 266static struct nsm_handle *nsm_create_handle(const struct sockaddr *sap,
@@ -351,11 +365,7 @@ struct nsm_handle *nsm_reboot_lookup(const struct nlm_reboot *info)
351 365
352 spin_lock(&nsm_lock); 366 spin_lock(&nsm_lock);
353 367
354 if (nsm_use_hostnames && info->mon != NULL) 368 cached = nsm_lookup_priv(&info->priv);
355 cached = nsm_lookup_hostname(info->mon, info->len);
356 else
357 cached = nsm_lookup_priv(&info->priv);
358
359 if (unlikely(cached == NULL)) { 369 if (unlikely(cached == NULL)) {
360 spin_unlock(&nsm_lock); 370 spin_unlock(&nsm_lock);
361 dprintk("lockd: never saw rebooted peer '%.*s' before\n", 371 dprintk("lockd: never saw rebooted peer '%.*s' before\n",