Skip to content

Commit

Permalink
lockd: Start PF_INET6 listener only if IPv6 support is available
Browse files Browse the repository at this point in the history
Apparently a lot of people need to disable IPv6 completely on their
distributor-built systems, which have CONFIG_IPV6_MODULE enabled at
build time.

They do this by blacklisting the ipv6.ko module.  This causes the
creation of the lockd service listener to fail if CONFIG_IPV6_MODULE
is set, but the module cannot be loaded.

Now that the kernel's PF_INET6 RPC listeners are completely separate
from PF_INET listeners, we can always start PF_INET.  Then lockd can
try to start PF_INET6, but it isn't required to be available.

Note this has the added benefit that NLM callbacks from AF_INET6
servers will never come from AF_INET remotes.  We no longer have to
worry about matching mapped IPv4 addresses to AF_INET when comparing
addresses.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
  • Loading branch information
Chuck Lever authored and Trond Myklebust committed Mar 28, 2009
1 parent 9355982 commit eb16e90
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 59 deletions.
51 changes: 1 addition & 50 deletions fs/lockd/clntlock.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,55 +139,6 @@ int nlmclnt_block(struct nlm_wait *block, struct nlm_rqst *req, long timeout)
return 0;
}

#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
static const struct in6_addr *nlmclnt_map_v4addr(const struct sockaddr *sap,
struct in6_addr *addr_mapped)
{
const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;

switch (sap->sa_family) {
case AF_INET6:
return &((const struct sockaddr_in6 *)sap)->sin6_addr;
case AF_INET:
ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, addr_mapped);
return addr_mapped;
}

return NULL;
}

/*
* If lockd is using a PF_INET6 listener, all incoming requests appear
* to come from AF_INET6 remotes. The address of AF_INET remotes are
* mapped to AF_INET6 automatically by the network layer. In case the
* user passed an AF_INET server address at mount time, ensure both
* addresses are AF_INET6 before comparing them.
*/
static int nlmclnt_cmp_addr(const struct nlm_host *host,
const struct sockaddr *sap)
{
const struct in6_addr *addr1;
const struct in6_addr *addr2;
struct in6_addr addr1_mapped;
struct in6_addr addr2_mapped;

addr1 = nlmclnt_map_v4addr(nlm_addr(host), &addr1_mapped);
if (likely(addr1 != NULL)) {
addr2 = nlmclnt_map_v4addr(sap, &addr2_mapped);
if (likely(addr2 != NULL))
return ipv6_addr_equal(addr1, addr2);
}

return 0;
}
#else /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */
static int nlmclnt_cmp_addr(const struct nlm_host *host,
const struct sockaddr *sap)
{
return nlm_cmp_addr(nlm_addr(host), sap);
}
#endif /* !(CONFIG_IPV6 || CONFIG_IPV6_MODULE) */

/*
* The server lockd has called us back to tell us the lock was granted
*/
Expand Down Expand Up @@ -215,7 +166,7 @@ __be32 nlmclnt_grant(const struct sockaddr *addr, const struct nlm_lock *lock)
*/
if (fl_blocked->fl_u.nfs_fl.owner->pid != lock->svid)
continue;
if (!nlmclnt_cmp_addr(block->b_host, addr))
if (!nlm_cmp_addr(nlm_addr(block->b_host), addr))
continue;
if (nfs_compare_fh(NFS_FH(fl_blocked->fl_file->f_path.dentry->d_inode) ,fh) != 0)
continue;
Expand Down
30 changes: 21 additions & 9 deletions fs/lockd/svc.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,20 +193,30 @@ lockd(void *vrqstp)
return 0;
}

static int create_lockd_listener(struct svc_serv *serv, char *name,
unsigned short port)
static int create_lockd_listener(struct svc_serv *serv, const char *name,
const int family, const unsigned short port)
{
struct svc_xprt *xprt;

xprt = svc_find_xprt(serv, name, 0, 0);
xprt = svc_find_xprt(serv, name, family, 0);
if (xprt == NULL)
return svc_create_xprt(serv, name, PF_INET,
port, SVC_SOCK_DEFAULTS);

return svc_create_xprt(serv, name, family, port,
SVC_SOCK_DEFAULTS);
svc_xprt_put(xprt);
return 0;
}

static int create_lockd_family(struct svc_serv *serv, const int family)
{
int err;

err = create_lockd_listener(serv, "udp", family, nlm_udpport);
if (err < 0)
return err;

return create_lockd_listener(serv, "tcp", family, nlm_tcpport);
}

/*
* Ensure there are active UDP and TCP listeners for lockd.
*
Expand All @@ -222,13 +232,15 @@ static int make_socks(struct svc_serv *serv)
static int warned;
int err;

err = create_lockd_listener(serv, "udp", nlm_udpport);
err = create_lockd_family(serv, PF_INET);
if (err < 0)
goto out_err;

err = create_lockd_listener(serv, "tcp", nlm_tcpport);
if (err < 0)
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
err = create_lockd_family(serv, PF_INET6);
if (err < 0 && err != -EAFNOSUPPORT)
goto out_err;
#endif /* CONFIG_IPV6 || CONFIG_IPV6_MODULE */

warned = 0;
return 0;
Expand Down

0 comments on commit eb16e90

Please sign in to comment.