2008-06-30 23:00:29

by Chuck Lever

[permalink] [raw]
Subject: [PATCH 15/16] lockd: Adjust nlmsvc_lookup_host() to accomodate non-AF_INET

Fix up nlmsvc_lookup_host() to pass non-AF_INET source addresses to
nlm_lookup_host().

Signed-off-by: Chuck Lever <[email protected]>
---

fs/lockd/host.c | 51 +++++++++++++++++++++++++++++++++++--------
include/linux/lockd/lockd.h | 5 +++-
2 files changed, 44 insertions(+), 12 deletions(-)


diff --git a/fs/lockd/host.c b/fs/lockd/host.c
index 3c7916d..73e234a 100644
--- a/fs/lockd/host.c
+++ b/fs/lockd/host.c
@@ -305,29 +305,60 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
return nlm_lookup_host(&ni);
}

-/*
- * Find an NLM client handle in the cache. If there is none, create it.
+/**
+ * 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.
+ *
+ * Manufacture a specific source address in case the local system
+ * services clients from multiple IP 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 and
+ * length for our manufactured source address.
*/
-struct nlm_host *
-nlmsvc_lookup_host(struct svc_rqst *rqstp,
- const char *hostname, unsigned int hostname_len)
+struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
+ const char *hostname,
+ const size_t hostname_len)
{
- const struct sockaddr_in source = {
- .sin_family = AF_INET,
- .sin_addr = rqstp->rq_daddr.addr,
+ const struct sockaddr *sap = svc_addr(rqstp);
+ struct sockaddr_storage source = {
+ .ss_family = sap->sa_family,
};
+ struct sockaddr_in *sin = (struct sockaddr_in *)&source;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&source;
struct nlm_lookup_host_info ni = {
.server = NLM_CLIENT,
- .sap = svc_addr(rqstp),
+ .sap = sap,
.salen = rqstp->rq_addrlen,
.protocol = rqstp->rq_prot,
.version = rqstp->rq_vers,
.hostname = hostname,
.hostname_len = hostname_len,
.src_sap = (struct sockaddr *)&source,
- .src_len = sizeof(source),
+ .src_len = rqstp->rq_addrlen,
};

+ dprintk("lockd: %s(host='%.*s', vers=%u, proto=%s)\n", __func__,
+ hostname_len, hostname, rqstp->rq_vers,
+ (rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
+
+ switch (sap->sa_family) {
+ case AF_INET:
+ sin->sin_addr.s_addr = rqstp->rq_daddr.addr.s_addr;
+ break;
+ case AF_INET6:
+ ipv6_addr_copy(&sin6->sin6_addr, &rqstp->rq_daddr.addr6);
+ break;
+ default:
+ return NULL;
+ }
+
return nlm_lookup_host(&ni);
}

diff --git a/include/linux/lockd/lockd.h b/include/linux/lockd/lockd.h
index 6e8909d..e327914 100644
--- a/include/linux/lockd/lockd.h
+++ b/include/linux/lockd/lockd.h
@@ -219,8 +219,9 @@ struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
const unsigned short protocol,
const u32 version,
const char *hostname);
-struct nlm_host *nlmsvc_lookup_host(struct svc_rqst *, const char *,
- unsigned int);
+struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
+ const char *hostname,
+ const size_t hostname_len);
struct rpc_clnt * nlm_bind_host(struct nlm_host *);
void nlm_rebind_host(struct nlm_host *);
struct nlm_host * nlm_get_host(struct nlm_host *);