diff options
author | Chuck Lever <chuck.lever@oracle.com> | 2008-12-04 14:20:46 -0500 |
---|---|---|
committer | J. Bruce Fields <bfields@citi.umich.edu> | 2009-01-06 11:53:51 -0500 |
commit | 29ed1407ed81086b778ebf12145b048ac3f7e10e (patch) | |
tree | 35523669465a1a37f969054e1c3d7530582701fc | |
parent | f47534f7f0ac7727e05ec4274b764b181df2cf7f (diff) |
NSM: Support IPv6 version of mon_name
The "mon_name" argument of the NSMPROC_MON and NSMPROC_UNMON upcalls
is a string that contains the hostname or IP address of the remote peer
to be notified when this host has rebooted. The sm-notify command uses
this identifier to contact the peer when we reboot, so it must be
either a well-qualified DNS hostname or a presentation format IP
address string.
When the "nsm_use_hostnames" sysctl is set to zero, the kernel's NSM
provides a presentation format IP address in the "mon_name" argument.
Otherwise, the "caller_name" argument from NLM requests is used,
which is usually just the DNS hostname of the peer.
To support IPv6 addresses for the mon_name argument, we use the
nsm_handle's address eye-catcher, which already contains an appropriate
presentation format address string. Using the eye-catcher string
obviates the need to use a large buffer on the stack to form the
presentation address string for the upcall.
This patch also addresses a subtle bug.
An NSMPROC_MON request and the subsequent NSMPROC_UNMON request for the
same peer are required to use the same value for the "mon_name"
argument. Otherwise, rpc.statd's NSMPROC_UNMON processing cannot
locate the database entry for that peer and remove it.
If the setting of nsm_use_hostnames is changed between the time the
kernel sends an NSMPROC_MON request and the time it sends the
NSMPROC_UNMON request for the same peer, the "mon_name" argument for
these two requests may not be the same. This is because the value of
"mon_name" is currently chosen at the moment the call is made based on
the setting of nsm_use_hostnames
To ensure both requests pass identical contents in the "mon_name"
argument, we now select which string to use for the argument in the
nsm_monitor() function. A pointer to this string is saved in the
nsm_handle so it can be used for a subsequent NSMPROC_UNMON upcall.
NB: There are other potential problems, such as how nlm_host_rebooted()
might behave if nsm_use_hostnames were changed while hosts are still
being monitored. This patch does not attempt to address those
problems.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
-rw-r--r-- | fs/lockd/mon.c | 27 | ||||
-rw-r--r-- | include/linux/lockd/lockd.h | 1 |
2 files changed, 9 insertions, 19 deletions
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 497dfea02e8a..a606fbbf804d 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c | |||
@@ -18,8 +18,6 @@ | |||
18 | 18 | ||
19 | #define NLMDBG_FACILITY NLMDBG_MONITOR | 19 | #define NLMDBG_FACILITY NLMDBG_MONITOR |
20 | 20 | ||
21 | #define XDR_ADDRBUF_LEN (20) | ||
22 | |||
23 | static struct rpc_clnt * nsm_create(void); | 21 | static struct rpc_clnt * nsm_create(void); |
24 | 22 | ||
25 | static struct rpc_program nsm_program; | 23 | static struct rpc_program nsm_program; |
@@ -42,7 +40,7 @@ nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) | |||
42 | .prog = NLM_PROGRAM, | 40 | .prog = NLM_PROGRAM, |
43 | .vers = 3, | 41 | .vers = 3, |
44 | .proc = NLMPROC_NSM_NOTIFY, | 42 | .proc = NLMPROC_NSM_NOTIFY, |
45 | .mon_name = nsm->sm_name, | 43 | .mon_name = nsm->sm_mon_name, |
46 | }; | 44 | }; |
47 | struct rpc_message msg = { | 45 | struct rpc_message msg = { |
48 | .rpc_argp = &args, | 46 | .rpc_argp = &args, |
@@ -87,6 +85,12 @@ nsm_monitor(struct nlm_host *host) | |||
87 | if (nsm->sm_monitored) | 85 | if (nsm->sm_monitored) |
88 | return 0; | 86 | return 0; |
89 | 87 | ||
88 | /* | ||
89 | * Choose whether to record the caller_name or IP address of | ||
90 | * this peer in the local rpc.statd's database. | ||
91 | */ | ||
92 | nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; | ||
93 | |||
90 | status = nsm_mon_unmon(nsm, SM_MON, &res); | 94 | status = nsm_mon_unmon(nsm, SM_MON, &res); |
91 | 95 | ||
92 | if (status < 0 || res.status != 0) | 96 | if (status < 0 || res.status != 0) |
@@ -167,25 +171,10 @@ static __be32 *xdr_encode_nsm_string(__be32 *p, char *string) | |||
167 | 171 | ||
168 | /* | 172 | /* |
169 | * "mon_name" specifies the host to be monitored. | 173 | * "mon_name" specifies the host to be monitored. |
170 | * | ||
171 | * Linux uses a text version of the IP address of the remote | ||
172 | * host as the host identifier (the "mon_name" argument). | ||
173 | * | ||
174 | * Linux statd always looks up the canonical hostname first for | ||
175 | * whatever remote hostname it receives, so this works alright. | ||
176 | */ | 174 | */ |
177 | static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) | 175 | static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) |
178 | { | 176 | { |
179 | char buffer[XDR_ADDRBUF_LEN + 1]; | 177 | return xdr_encode_nsm_string(p, argp->mon_name); |
180 | char *name = argp->mon_name; | ||
181 | |||
182 | if (!nsm_use_hostnames) { | ||
183 | snprintf(buffer, XDR_ADDRBUF_LEN, | ||
184 | "%pI4", &argp->addr); | ||
185 | name = buffer; | ||
186 | } | ||
187 | |||
188 | return xdr_encode_nsm_string(p, name); | ||
189 | } | 178 | } |
190 | 179 | ||
191 | /* | 180 | /* |
diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h index 54dbb458e73c..d3c7247d23e8 100644 --- a/include/linux/lockd/lockd.h +++ b/include/linux/lockd/lockd.h | |||
@@ -79,6 +79,7 @@ struct nlm_host { | |||
79 | struct nsm_handle { | 79 | struct nsm_handle { |
80 | struct list_head sm_link; | 80 | struct list_head sm_link; |
81 | atomic_t sm_count; | 81 | atomic_t sm_count; |
82 | char *sm_mon_name; | ||
82 | char *sm_name; | 83 | char *sm_name; |
83 | struct sockaddr_storage sm_addr; | 84 | struct sockaddr_storage sm_addr; |
84 | size_t sm_addrlen; | 85 | size_t sm_addrlen; |