* [PATCH 0/7] Register kernel RPC services via rpcbind v4
@ 2008-08-18 23:33 Chuck Lever
[not found] ` <20080818233128.1214.48603.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
0 siblings, 1 reply; 9+ messages in thread
From: Chuck Lever @ 2008-08-18 23:33 UTC (permalink / raw)
To: bfields, trond.myklebust; +Cc: linux-nfs
Hi Bruce, Trond-
Here's the patch series that adds rpcbind v4 support to svc_register(), with
the simplification we discussed last week. I think this looks cleaner.
Please consider these for 2.6.28.
---
Chuck Lever (7):
SUNRPC: Support IPv6 when registering kernel RPC services
SUNRPC: Split portmap unregister API into separate function
SUNRPC: Simplify rpcb_register() API
SUNRPC: Use proper INADDR_ANY when setting up RPC services on IPv6
SUNRPC: Set V6ONLY socket option for RPC listener sockets
SUNRPC: Add address family field to svc_serv data structure
NFS: nfs_parsed_mount_options can use unsigned int
fs/Kconfig | 22 +++++
fs/lockd/svc.c | 2
fs/nfs/callback.c | 3 -
fs/nfs/internal.h | 8 +-
fs/nfsd/nfssvc.c | 3 -
include/linux/sunrpc/clnt.h | 4 -
include/linux/sunrpc/svc.h | 15 ++--
net/sunrpc/rpcb_clnt.c | 65 +++++++---------
net/sunrpc/svc.c | 175 ++++++++++++++++++++++++++++++++++++-------
net/sunrpc/svc_xprt.c | 37 +++++++--
net/sunrpc/svcsock.c | 13 +++
11 files changed, 260 insertions(+), 87 deletions(-)
--
Chuck Lever
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/7] NFS: nfs_parsed_mount_options can use unsigned int
[not found] ` <20080818233128.1214.48603.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
@ 2008-08-18 23:33 ` Chuck Lever
2008-08-18 23:33 ` [PATCH 2/7] SUNRPC: Add address family field to svc_serv data structure Chuck Lever
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Chuck Lever @ 2008-08-18 23:33 UTC (permalink / raw)
To: bfields, trond.myklebust; +Cc: linux-nfs
Eliminate mixed sign comparisons in nfs_compare_remount_options().
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/nfs/internal.h | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h
index 24241fc..275a692 100644
--- a/fs/nfs/internal.h
+++ b/fs/nfs/internal.h
@@ -32,11 +32,11 @@ struct nfs_clone_mount {
*/
struct nfs_parsed_mount_data {
int flags;
- int rsize, wsize;
- int timeo, retrans;
- int acregmin, acregmax,
+ unsigned int rsize, wsize;
+ unsigned int timeo, retrans;
+ unsigned int acregmin, acregmax,
acdirmin, acdirmax;
- int namlen;
+ unsigned int namlen;
unsigned int bsize;
unsigned int auth_flavor_len;
rpc_authflavor_t auth_flavors[1];
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 2/7] SUNRPC: Add address family field to svc_serv data structure
[not found] ` <20080818233128.1214.48603.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-08-18 23:33 ` [PATCH 1/7] NFS: nfs_parsed_mount_options can use unsigned int Chuck Lever
@ 2008-08-18 23:33 ` Chuck Lever
2008-08-18 23:33 ` [PATCH 3/7] SUNRPC: Set V6ONLY socket option for RPC listener sockets Chuck Lever
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Chuck Lever @ 2008-08-18 23:33 UTC (permalink / raw)
To: bfields, trond.myklebust; +Cc: linux-nfs
Introduce and initialize an address family field in the svc_serv structure.
This field will determine what address family to use for the service's
listener sockets and which address family is advertised via the local
rpcbind daemon.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/lockd/svc.c | 2 +-
fs/nfs/callback.c | 3 ++-
fs/nfsd/nfssvc.c | 3 ++-
include/linux/sunrpc/svc.h | 11 +++++++----
net/sunrpc/svc.c | 12 +++++++-----
5 files changed, 19 insertions(+), 12 deletions(-)
diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c
index 5bd9bf0..1553fec 100644
--- a/fs/lockd/svc.c
+++ b/fs/lockd/svc.c
@@ -266,7 +266,7 @@ lockd_up(int proto) /* Maybe add a 'family' option when IPv6 is supported ?? */
"lockd_up: no pid, %d users??\n", nlmsvc_users);
error = -ENOMEM;
- serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, NULL);
+ serv = svc_create(&nlmsvc_program, LOCKD_BUFSIZE, AF_INET, NULL);
if (!serv) {
printk(KERN_WARNING "lockd_up: create service failed\n");
goto out;
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index f447f4b..6a09760 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -105,7 +105,8 @@ int nfs_callback_up(void)
mutex_lock(&nfs_callback_mutex);
if (nfs_callback_info.users++ || nfs_callback_info.task != NULL)
goto out;
- serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE, NULL);
+ serv = svc_create(&nfs4_callback_program, NFS4_CALLBACK_BUFSIZE,
+ AF_INET, NULL);
ret = -ENOMEM;
if (!serv)
goto out_err;
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 80292ff..4eed938 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -229,7 +229,8 @@ int nfsd_create_serv(void)
atomic_set(&nfsd_busy, 0);
nfsd_serv = svc_create_pooled(&nfsd_program, nfsd_max_blksize,
- nfsd_last_thread, nfsd, THIS_MODULE);
+ AF_INET, nfsd_last_thread,
+ nfsd, THIS_MODULE);
if (nfsd_serv == NULL)
err = -ENOMEM;
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index dc69068..a794d4a 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -66,6 +66,7 @@ struct svc_serv {
struct list_head sv_tempsocks; /* all temporary sockets */
int sv_tmpcnt; /* count of temporary sockets */
struct timer_list sv_temptimer; /* timer for aging temporary sockets */
+ sa_family_t sv_family; /* listener's address family */
char * sv_name; /* service name */
@@ -381,14 +382,16 @@ struct svc_procedure {
/*
* Function prototypes.
*/
-struct svc_serv * svc_create(struct svc_program *, unsigned int,
- void (*shutdown)(struct svc_serv*));
+struct svc_serv *svc_create(struct svc_program *, unsigned int,
+ const sa_family_t,
+ void (*shutdown)(struct svc_serv *));
struct svc_rqst *svc_prepare_thread(struct svc_serv *serv,
struct svc_pool *pool);
void svc_exit_thread(struct svc_rqst *);
struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
- void (*shutdown)(struct svc_serv*), svc_thread_fn,
- struct module *);
+ const sa_family_t,
+ void (*shutdown)(struct svc_serv *),
+ svc_thread_fn, struct module *);
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
void svc_destroy(struct svc_serv *);
int svc_process(struct svc_rqst *);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 5a32cb7..2a6649f 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -357,7 +357,7 @@ svc_pool_for_cpu(struct svc_serv *serv, int cpu)
*/
static struct svc_serv *
__svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
- void (*shutdown)(struct svc_serv *serv))
+ const sa_family_t family, void (*shutdown)(struct svc_serv *serv))
{
struct svc_serv *serv;
unsigned int vers;
@@ -366,6 +366,7 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
if (!(serv = kzalloc(sizeof(*serv), GFP_KERNEL)))
return NULL;
+ serv->sv_family = family;
serv->sv_name = prog->pg_name;
serv->sv_program = prog;
serv->sv_nrthreads = 1;
@@ -425,21 +426,22 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
struct svc_serv *
svc_create(struct svc_program *prog, unsigned int bufsize,
- void (*shutdown)(struct svc_serv *serv))
+ const sa_family_t family, void (*shutdown)(struct svc_serv *serv))
{
- return __svc_create(prog, bufsize, /*npools*/1, shutdown);
+ return __svc_create(prog, bufsize, /*npools*/1, family, shutdown);
}
EXPORT_SYMBOL(svc_create);
struct svc_serv *
svc_create_pooled(struct svc_program *prog, unsigned int bufsize,
- void (*shutdown)(struct svc_serv *serv),
+ const sa_family_t family,
+ void (*shutdown)(struct svc_serv *serv),
svc_thread_fn func, struct module *mod)
{
struct svc_serv *serv;
unsigned int npools = svc_pool_map_get();
- serv = __svc_create(prog, bufsize, npools, shutdown);
+ serv = __svc_create(prog, bufsize, npools, family, shutdown);
if (serv != NULL) {
serv->sv_function = func;
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 3/7] SUNRPC: Set V6ONLY socket option for RPC listener sockets
[not found] ` <20080818233128.1214.48603.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-08-18 23:33 ` [PATCH 1/7] NFS: nfs_parsed_mount_options can use unsigned int Chuck Lever
2008-08-18 23:33 ` [PATCH 2/7] SUNRPC: Add address family field to svc_serv data structure Chuck Lever
@ 2008-08-18 23:33 ` Chuck Lever
2008-08-18 23:33 ` [PATCH 4/7] SUNRPC: Use proper INADDR_ANY when setting up RPC services on IPv6 Chuck Lever
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Chuck Lever @ 2008-08-18 23:33 UTC (permalink / raw)
To: bfields, trond.myklebust; +Cc: linux-nfs
My plan is to use an AF_INET listener on systems that support only IPv4,
and an AF_INET6 listener on systems that can support IPv6. Incoming
IPv4 packets will be posted to an AF_INET6 listener with a mapped IPv4
address.
Max Matveev <makc@sgi.com> says:
Creating a single listener can be dangerous - if net.ipv6.bindv6only
is enabled then it's possible to create another listener in v4
namespace on the same port and steal the traffic from the "unifed"
listener. You need to disable V6ONLY explicitly via a sockopt to stop
that.
Set appropriate socket option on RPC server listener sockets to prevent
this.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
net/sunrpc/svcsock.c | 13 +++++++++++++
1 files changed, 13 insertions(+), 0 deletions(-)
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 3e65719..f91377c 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -1114,6 +1114,7 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
struct svc_sock *svsk;
struct sock *inet;
int pmap_register = !(flags & SVC_SOCK_ANONYMOUS);
+ int val;
dprintk("svc: svc_setup_socket %p\n", sock);
if (!(svsk = kzalloc(sizeof(*svsk), GFP_KERNEL))) {
@@ -1146,6 +1147,18 @@ static struct svc_sock *svc_setup_socket(struct svc_serv *serv,
else
svc_tcp_init(svsk, serv);
+ /*
+ * We start one listener per sv_serv. We want AF_INET
+ * requests to be automatically shunted to our AF_INET6
+ * listener using a mapped IPv4 address. Make sure
+ * no-one starts an equivalent IPv4 listener, which
+ * would steal our incoming connections.
+ */
+ val = 0;
+ if (serv->sv_family == AF_INET6)
+ kernel_setsockopt(sock, SOL_IPV6, IPV6_V6ONLY,
+ (char *)&val, sizeof(val));
+
dprintk("svc: svc_setup_socket created %p (inet %p)\n",
svsk, svsk->sk_sk);
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 4/7] SUNRPC: Use proper INADDR_ANY when setting up RPC services on IPv6
[not found] ` <20080818233128.1214.48603.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
` (2 preceding siblings ...)
2008-08-18 23:33 ` [PATCH 3/7] SUNRPC: Set V6ONLY socket option for RPC listener sockets Chuck Lever
@ 2008-08-18 23:33 ` Chuck Lever
2008-08-18 23:34 ` [PATCH 5/7] SUNRPC: Simplify rpcb_register() API Chuck Lever
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Chuck Lever @ 2008-08-18 23:33 UTC (permalink / raw)
To: bfields, trond.myklebust; +Cc: linux-nfs
Choose the correct family for the ANY address when initializing RPC
services.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
net/sunrpc/svc_xprt.c | 37 ++++++++++++++++++++++++++++++-------
1 files changed, 30 insertions(+), 7 deletions(-)
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index e46c825..96eda5f 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -159,16 +159,41 @@ void svc_xprt_init(struct svc_xprt_class *xcl, struct svc_xprt *xprt,
}
EXPORT_SYMBOL_GPL(svc_xprt_init);
-int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
- int flags)
+static struct svc_xprt *__svc_xpo_create(struct svc_xprt_class *xcl,
+ struct svc_serv *serv,
+ unsigned short port, int flags)
{
- struct svc_xprt_class *xcl;
struct sockaddr_in sin = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(INADDR_ANY),
.sin_port = htons(port),
};
- dprintk("svc: creating transport %s[%d]\n", xprt_name, port);
+ struct sockaddr_in6 sin6 = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_ANY_INIT,
+ .sin6_port = htons(port),
+ };
+
+ switch (serv->sv_family) {
+ case AF_INET:
+ return xcl->xcl_ops->xpo_create(serv,
+ (struct sockaddr *)&sin,
+ sizeof(sin), flags);
+ case AF_INET6:
+ return xcl->xcl_ops->xpo_create(serv,
+ (struct sockaddr *)&sin6,
+ sizeof(sin6), flags);
+ }
+
+ return ERR_PTR(-EAFNOSUPPORT);
+}
+
+int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
+ int flags)
+{
+ struct svc_xprt_class *xcl;
+
+ dprintk("svc: creating transport %s[%u]\n", xprt_name, port);
spin_lock(&svc_xprt_class_lock);
list_for_each_entry(xcl, &svc_xprt_class_list, xcl_list) {
struct svc_xprt *newxprt;
@@ -180,9 +205,7 @@ int svc_create_xprt(struct svc_serv *serv, char *xprt_name, unsigned short port,
goto err;
spin_unlock(&svc_xprt_class_lock);
- newxprt = xcl->xcl_ops->
- xpo_create(serv, (struct sockaddr *)&sin, sizeof(sin),
- flags);
+ newxprt = __svc_xpo_create(xcl, serv, port, flags);
if (IS_ERR(newxprt)) {
module_put(xcl->xcl_owner);
return PTR_ERR(newxprt);
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 5/7] SUNRPC: Simplify rpcb_register() API
[not found] ` <20080818233128.1214.48603.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
` (3 preceding siblings ...)
2008-08-18 23:33 ` [PATCH 4/7] SUNRPC: Use proper INADDR_ANY when setting up RPC services on IPv6 Chuck Lever
@ 2008-08-18 23:34 ` Chuck Lever
2008-08-18 23:34 ` [PATCH 6/7] SUNRPC: Split portmap unregister API into separate function Chuck Lever
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Chuck Lever @ 2008-08-18 23:34 UTC (permalink / raw)
To: bfields, trond.myklebust; +Cc: linux-nfs
Bruce suggested there's no need to expose the difference between an error
sending the PMAP_SET request and an error reply from the portmapper to
rpcb_register's callers. The user space equivalent of rpcb_register() is
pmap_set(3), which returns a bool_t : either the PMAP set worked, or it
didn't. Simple.
So let's remove the "*okay" argument from rpcb_register() and
rpcb_v4_register(), and simply return an error if any part of the call
didn't work.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
include/linux/sunrpc/clnt.h | 4 +--
net/sunrpc/rpcb_clnt.c | 65 +++++++++++++++++++------------------------
net/sunrpc/svc.c | 8 +----
3 files changed, 32 insertions(+), 45 deletions(-)
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index e5bfe01..8ac8e75 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -124,10 +124,10 @@ struct rpc_clnt *rpc_clone_client(struct rpc_clnt *);
void rpc_shutdown_client(struct rpc_clnt *);
void rpc_release_client(struct rpc_clnt *);
-int rpcb_register(u32, u32, int, unsigned short, int *);
+int rpcb_register(u32, u32, int, unsigned short);
int rpcb_v4_register(const u32 program, const u32 version,
const struct sockaddr *address,
- const char *netid, int *result);
+ const char *netid);
int rpcb_getport_sync(struct sockaddr_in *, u32, u32, int);
void rpcb_getport_async(struct rpc_task *);
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 24db2b4..cc7250d 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -176,13 +176,12 @@ static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr,
}
static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
- u32 version, struct rpc_message *msg,
- int *result)
+ u32 version, struct rpc_message *msg)
{
struct rpc_clnt *rpcb_clnt;
- int error = 0;
+ int result, error = 0;
- *result = 0;
+ msg->rpc_resp = &result;
rpcb_clnt = rpcb_create_local(addr, addrlen, version);
if (!IS_ERR(rpcb_clnt)) {
@@ -191,12 +190,19 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
} else
error = PTR_ERR(rpcb_clnt);
- if (error < 0)
+ if (error < 0) {
printk(KERN_WARNING "RPC: failed to contact local rpcbind "
"server (errno %d).\n", -error);
- dprintk("RPC: registration status %d/%d\n", error, *result);
+ return error;
+ }
+
+ if (!result) {
+ dprintk("RPC: registration failed\n");
+ return -EACCES;
+ }
- return error;
+ dprintk("RPC: registration succeeded\n");
+ return 0;
}
/**
@@ -205,7 +211,11 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
* @vers: RPC version number to bind
* @prot: transport protocol to register
* @port: port value to register
- * @okay: OUT: result code
+ *
+ * Returns zero if the registration request was dispatched successfully
+ * and the rpcbind daemon returned success. Otherwise, returns an errno
+ * value that reflects the nature of the error (request could not be
+ * dispatched, timed out, or rpcbind returned an error).
*
* RPC services invoke this function to advertise their contact
* information via the system's rpcbind daemon. RPC services
@@ -217,15 +227,6 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
* all registered transports for [program, version] from the local
* rpcbind database.
*
- * Returns zero if the registration request was dispatched
- * successfully and a reply was received. The rpcbind daemon's
- * boolean result code is stored in *okay.
- *
- * Returns an errno value and sets *result to zero if there was
- * some problem that prevented the rpcbind request from being
- * dispatched, or if the rpcbind daemon did not respond within
- * the timeout.
- *
* This function uses rpcbind protocol version 2 to contact the
* local rpcbind daemon.
*
@@ -236,7 +237,7 @@ static int rpcb_register_call(struct sockaddr *addr, size_t addrlen,
* IN6ADDR_ANY (ie available for all AF_INET and AF_INET6
* addresses).
*/
-int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
+int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)
{
struct rpcbind_args map = {
.r_prog = prog,
@@ -246,7 +247,6 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
};
struct rpc_message msg = {
.rpc_argp = &map,
- .rpc_resp = okay,
};
dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
@@ -259,7 +259,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port, int *okay)
return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
sizeof(rpcb_inaddr_loopback),
- RPCBVERS_2, &msg, okay);
+ RPCBVERS_2, &msg);
}
/*
@@ -290,7 +290,7 @@ static int rpcb_register_netid4(struct sockaddr_in *address_to_register,
return rpcb_register_call((struct sockaddr *)&rpcb_inaddr_loopback,
sizeof(rpcb_inaddr_loopback),
- RPCBVERS_4, msg, msg->rpc_resp);
+ RPCBVERS_4, msg);
}
/*
@@ -321,7 +321,7 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
return rpcb_register_call((struct sockaddr *)&rpcb_in6addr_loopback,
sizeof(rpcb_in6addr_loopback),
- RPCBVERS_4, msg, msg->rpc_resp);
+ RPCBVERS_4, msg);
}
/**
@@ -330,7 +330,11 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
* @version: RPC version number of service to (un)register
* @address: address family, IP address, and port to (un)register
* @netid: netid of transport protocol to (un)register
- * @result: result code from rpcbind RPC call
+ *
+ * Returns zero if the registration request was dispatched successfully
+ * and the rpcbind daemon returned success. Otherwise, returns an errno
+ * value that reflects the nature of the error (request could not be
+ * dispatched, timed out, or rpcbind returned an error).
*
* RPC services invoke this function to advertise their contact
* information via the system's rpcbind daemon. RPC services
@@ -342,15 +346,6 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
* to zero. Callers pass a netid of "" to unregister all
* transport netids associated with [program, version, address].
*
- * Returns zero if the registration request was dispatched
- * successfully and a reply was received. The rpcbind daemon's
- * result code is stored in *result.
- *
- * Returns an errno value and sets *result to zero if there was
- * some problem that prevented the rpcbind request from being
- * dispatched, or if the rpcbind daemon did not respond within
- * the timeout.
- *
* This function uses rpcbind protocol version 4 to contact the
* local rpcbind daemon. The local rpcbind daemon must support
* version 4 of the rpcbind protocol in order for these functions
@@ -372,8 +367,7 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register,
* advertises the service on all IPv4 and IPv6 addresses.
*/
int rpcb_v4_register(const u32 program, const u32 version,
- const struct sockaddr *address, const char *netid,
- int *result)
+ const struct sockaddr *address, const char *netid)
{
struct rpcbind_args map = {
.r_prog = program,
@@ -383,11 +377,8 @@ int rpcb_v4_register(const u32 program, const u32 version,
};
struct rpc_message msg = {
.rpc_argp = &map,
- .rpc_resp = result,
};
- *result = 0;
-
switch (address->sa_family) {
case AF_INET:
return rpcb_register_netid4((struct sockaddr_in *)address,
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 2a6649f..c2eb72c 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -731,7 +731,7 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
struct svc_program *progp;
unsigned long flags;
unsigned int i;
- int error = 0, dummy;
+ int error = 0;
if (!port)
clear_thread_flag(TIF_SIGPENDING);
@@ -752,13 +752,9 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
if (progp->pg_vers[i]->vs_hidden)
continue;
- error = rpcb_register(progp->pg_prog, i, proto, port, &dummy);
+ error = rpcb_register(progp->pg_prog, i, proto, port);
if (error < 0)
break;
- if (port && !dummy) {
- error = -EACCES;
- break;
- }
}
}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 6/7] SUNRPC: Split portmap unregister API into separate function
[not found] ` <20080818233128.1214.48603.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
` (4 preceding siblings ...)
2008-08-18 23:34 ` [PATCH 5/7] SUNRPC: Simplify rpcb_register() API Chuck Lever
@ 2008-08-18 23:34 ` Chuck Lever
2008-08-18 23:34 ` [PATCH 7/7] SUNRPC: Support IPv6 when registering kernel RPC services Chuck Lever
2008-08-20 23:20 ` [PATCH 0/7] Register kernel RPC services via rpcbind v4 J. Bruce Fields
7 siblings, 0 replies; 9+ messages in thread
From: Chuck Lever @ 2008-08-18 23:34 UTC (permalink / raw)
To: bfields, trond.myklebust; +Cc: linux-nfs
Create a separate server-level interface for unregistering RPC services.
The mechanics of, and the API for, registering and unregistering RPC
services will diverge further as support for IPv6 is added.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
net/sunrpc/svc.c | 62 ++++++++++++++++++++++++++++++++++++++++++++----------
1 files changed, 50 insertions(+), 12 deletions(-)
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index c2eb72c..3d4c0b0 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -28,6 +28,8 @@
#define RPCDBG_FACILITY RPCDBG_SVCDSP
+static void svc_unregister(const struct svc_serv *serv);
+
#define svc_serv_is_pooled(serv) ((serv)->sv_function)
/*
@@ -417,9 +419,8 @@ __svc_create(struct svc_program *prog, unsigned int bufsize, int npools,
spin_lock_init(&pool->sp_lock);
}
-
/* Remove any stale portmap registrations */
- svc_register(serv, 0, 0);
+ svc_unregister(serv);
return serv;
}
@@ -488,8 +489,7 @@ svc_destroy(struct svc_serv *serv)
if (svc_serv_is_pooled(serv))
svc_pool_map_put();
- /* Unregister service with the portmapper */
- svc_register(serv, 0, 0);
+ svc_unregister(serv);
kfree(serv->sv_pools);
kfree(serv);
}
@@ -729,12 +729,10 @@ int
svc_register(struct svc_serv *serv, int proto, unsigned short port)
{
struct svc_program *progp;
- unsigned long flags;
unsigned int i;
int error = 0;
- if (!port)
- clear_thread_flag(TIF_SIGPENDING);
+ BUG_ON(proto == 0 && port == 0);
for (progp = serv->sv_program; progp; progp = progp->pg_next) {
for (i = 0; i < progp->pg_nvers; i++) {
@@ -758,13 +756,53 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
}
}
- if (!port) {
- spin_lock_irqsave(¤t->sighand->siglock, flags);
- recalc_sigpending();
- spin_unlock_irqrestore(¤t->sighand->siglock, flags);
+ return error;
+}
+
+/*
+ * All transport protocols and ports for this service are removed
+ * from the local rpcbind database if the service is not hidden.
+ *
+ * The result of unregistration is reported via dprintk for those
+ * who want verification of the result, but is otherwise not
+ * important.
+ *
+ * The local rpcbind daemon listens on either only IPv6 or only
+ * IPv4. The kernel can't tell how it's configured. However,
+ * AF_INET addresses are mapped to AF_INET6 in IPv6-only config-
+ * urations, so even an unregistration request on AF_INET will
+ * get to a local rpcbind daemon listening only on AF_INET6. So
+ * we always unregister via AF_INET.
+ *
+ * At this point we don't need rpcbind version 4 for unregis-
+ * tration: A v2 UNSET request will clear all transports (netids),
+ * addresses, and address families for [program, version].
+ */
+static void svc_unregister(const struct svc_serv *serv)
+{
+ struct svc_program *progp;
+ unsigned long flags;
+ unsigned int i;
+ int error;
+
+ clear_thread_flag(TIF_SIGPENDING);
+
+ for (progp = serv->sv_program; progp; progp = progp->pg_next) {
+ for (i = 0; i < progp->pg_nvers; i++) {
+ if (progp->pg_vers[i] == NULL)
+ continue;
+ if (progp->pg_vers[i]->vs_hidden)
+ continue;
+
+ error = rpcb_register(progp->pg_prog, i, 0, 0);
+ dprintk("svc: svc_unregister(%sv%u), error %d\n",
+ progp->pg_name, i, error);
+ }
}
- return error;
+ spin_lock_irqsave(¤t->sighand->siglock, flags);
+ recalc_sigpending();
+ spin_unlock_irqrestore(¤t->sighand->siglock, flags);
}
/*
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH 7/7] SUNRPC: Support IPv6 when registering kernel RPC services
[not found] ` <20080818233128.1214.48603.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
` (5 preceding siblings ...)
2008-08-18 23:34 ` [PATCH 6/7] SUNRPC: Split portmap unregister API into separate function Chuck Lever
@ 2008-08-18 23:34 ` Chuck Lever
2008-08-20 23:20 ` [PATCH 0/7] Register kernel RPC services via rpcbind v4 J. Bruce Fields
7 siblings, 0 replies; 9+ messages in thread
From: Chuck Lever @ 2008-08-18 23:34 UTC (permalink / raw)
To: bfields, trond.myklebust; +Cc: linux-nfs
In order to advertise NFS-related services on IPv6 interfaces via
rpcbind, the kernel RPC server implementation must use
rpcb_v4_register() instead of rpcb_register().
A new kernel build option allows distributions to use the legacy
v2 call until they integrate an appropriate user-space rpcbind
daemon that can support IPv6 RPC services.
I tried adding some automatic logic to fall back if registering
with a v4 protocol request failed, but there are too many corner
cases. So I just made it a compile-time switch that distributions
can throw when they've replaced portmapper with rpcbind.
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
---
fs/Kconfig | 22 ++++++++++
include/linux/sunrpc/svc.h | 4 +-
net/sunrpc/svc.c | 95 +++++++++++++++++++++++++++++++++++++++++---
3 files changed, 113 insertions(+), 8 deletions(-)
diff --git a/fs/Kconfig b/fs/Kconfig
index d387358..949e6d1 100644
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -1765,6 +1765,28 @@ config SUNRPC_XPRT_RDMA
If unsure, say N.
+config SUNRPC_REGISTER_V4
+ bool "Register local RPC services via rpcbind v4 (EXPERIMENTAL)"
+ depends on SUNRPC && EXPERIMENTAL
+ default n
+ help
+ Sun added support for registering RPC services at an IPv6
+ address by creating two new versions of the rpcbind protocol
+ (RFC 1833).
+
+ This option enables support in the kernel RPC server for
+ registering kernel RPC services via version 4 of the rpcbind
+ protocol. If you enable this option, you must run a portmapper
+ daemon that supports rpcbind protocol version 4.
+
+ Serving NFS over IPv6 from knfsd (the kernel's NFS server)
+ requires that you enable this option and use a portmapper that
+ supports rpcbind version 4.
+
+ If unsure, say N to get traditional behavior (register kernel
+ RPC services using only rpcbind version 2). Distributions
+ using the legacy Linux portmapper daemon must say N here.
+
config RPCSEC_GSS_KRB5
tristate "Secure RPC: Kerberos V mechanism (EXPERIMENTAL)"
depends on SUNRPC && EXPERIMENTAL
diff --git a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
index a794d4a..2a41d29 100644
--- a/include/linux/sunrpc/svc.h
+++ b/include/linux/sunrpc/svc.h
@@ -395,7 +395,9 @@ struct svc_serv * svc_create_pooled(struct svc_program *, unsigned int,
int svc_set_num_threads(struct svc_serv *, struct svc_pool *, int);
void svc_destroy(struct svc_serv *);
int svc_process(struct svc_rqst *);
-int svc_register(struct svc_serv *, int, unsigned short);
+int svc_register(const struct svc_serv *, const unsigned short,
+ const unsigned short);
+
void svc_wake_up(struct svc_serv *);
void svc_reserve(struct svc_rqst *rqstp, int space);
struct svc_pool * svc_pool_for_cpu(struct svc_serv *serv, int cpu);
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index 3d4c0b0..c023cb3 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -720,13 +720,92 @@ svc_exit_thread(struct svc_rqst *rqstp)
}
EXPORT_SYMBOL(svc_exit_thread);
+#ifdef CONFIG_SUNRPC_REGISTER_V4
/*
- * Register an RPC service with the local portmapper.
- * To unregister a service, call this routine with
- * proto and port == 0.
+ * Registering kernel RPC services with rpcbind version 2 will work
+ * over either IPv4 or IPv6, since the Linux kernel always registers
+ * services for the "any" address.
+ *
+ * However, the local rpcbind daemon listens on either only AF_INET
+ * or AF_INET6 (never both). When it listens on AF_INET6, an rpcbind
+ * version 2 registration will result in registering the service at
+ * IN6ADDR_ANY, even if the RPC service being registered is not
+ * IPv6-enabled.
+ *
+ * Rpcbind version 4 allows us to be a little more specific. Kernel
+ * RPC services that don't yet support AF_INET6 can register
+ * themselves as IPv4-only with the local rpcbind daemon, even if the
+ * daemon is listening only on AF_INET6.
+ *
+ * And, registering IPv6-enabled kernel RPC services via AF_INET6
+ * verifies that the local user space rpcbind daemon is properly
+ * configured to support remote AF_INET6 rpcbind requests.
+ *
+ * An AF_INET6 registration request will fail if the local rpcbind
+ * daemon is not set up to listen on AF_INET6. Likewise, we fail
+ * AF_INET6 registration requests if svc_register() is configured to
+ * support only rpcbind version 2.
*/
-int
-svc_register(struct svc_serv *serv, int proto, unsigned short port)
+static int __svc_register(const u32 program, const u32 version,
+ const sa_family_t family,
+ const unsigned short protocol,
+ const unsigned short port)
+{
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl(INADDR_ANY),
+ .sin_port = htons(port),
+ };
+ struct sockaddr_in6 sin6 = {
+ .sin6_family = AF_INET6,
+ .sin6_addr = IN6ADDR_ANY_INIT,
+ .sin6_port = htons(port),
+ };
+ struct sockaddr *sap;
+ char *netid;
+
+ switch (family) {
+ case AF_INET:
+ sap = (struct sockaddr *)&sin;
+ netid = RPCBIND_NETID_TCP;
+ if (protocol == IPPROTO_UDP)
+ netid = RPCBIND_NETID_UDP;
+ break;
+ case AF_INET6:
+ sap = (struct sockaddr *)&sin6;
+ netid = RPCBIND_NETID_TCP6;
+ if (protocol == IPPROTO_UDP)
+ netid = RPCBIND_NETID_UDP6;
+ break;
+ default:
+ return -EAFNOSUPPORT;
+ }
+
+ return rpcb_v4_register(program, version, sap, netid);
+}
+#else
+static int __svc_register(const u32 program, const u32 version,
+ sa_family_t family,
+ const unsigned short protocol,
+ const unsigned short port)
+{
+ if (family != AF_INET)
+ return -EAFNOSUPPORT;
+
+ return rpcb_register(program, version, protocol, port);
+}
+#endif
+
+/**
+ * svc_register - register an RPC service with the local portmapper
+ * @serv: svc_serv struct for the service to register
+ * @proto: transport protocol number to advertise
+ * @port: port to advertise
+ *
+ * Service is registered for any address in serv's address family
+ */
+int svc_register(const struct svc_serv *serv, const unsigned short proto,
+ const unsigned short port)
{
struct svc_program *progp;
unsigned int i;
@@ -739,8 +818,9 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
if (progp->pg_vers[i] == NULL)
continue;
- dprintk("svc: svc_register(%s, %s, %d, %d)%s\n",
+ dprintk("svc: svc_register(%s, %u, %s, %u, %d)%s\n",
progp->pg_name,
+ serv->sv_family,
proto == IPPROTO_UDP? "udp" : "tcp",
port,
i,
@@ -750,7 +830,8 @@ svc_register(struct svc_serv *serv, int proto, unsigned short port)
if (progp->pg_vers[i]->vs_hidden)
continue;
- error = rpcb_register(progp->pg_prog, i, proto, port);
+ error = __svc_register(progp->pg_prog, i,
+ serv->sv_family, proto, port);
if (error < 0)
break;
}
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH 0/7] Register kernel RPC services via rpcbind v4
[not found] ` <20080818233128.1214.48603.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
` (6 preceding siblings ...)
2008-08-18 23:34 ` [PATCH 7/7] SUNRPC: Support IPv6 when registering kernel RPC services Chuck Lever
@ 2008-08-20 23:20 ` J. Bruce Fields
7 siblings, 0 replies; 9+ messages in thread
From: J. Bruce Fields @ 2008-08-20 23:20 UTC (permalink / raw)
To: Chuck Lever; +Cc: trond.myklebust, linux-nfs
On Mon, Aug 18, 2008 at 07:33:20PM -0400, Chuck Lever wrote:
> Hi Bruce, Trond-
>
> Here's the patch series that adds rpcbind v4 support to svc_register(), with
> the simplification we discussed last week. I think this looks cleaner.
>
> Please consider these for 2.6.28.
Thanks. I've applied #5, #6, and 37 (#2, #3, and #4 were already
applied--let me know if my versions are out of date--and #1 I'll leave
to Trond):
git://linux-nfs.org/~bfields/linux.git for-2.6.28
Keep sending patches....
--b.
>
> ---
>
> Chuck Lever (7):
> SUNRPC: Support IPv6 when registering kernel RPC services
> SUNRPC: Split portmap unregister API into separate function
> SUNRPC: Simplify rpcb_register() API
> SUNRPC: Use proper INADDR_ANY when setting up RPC services on IPv6
> SUNRPC: Set V6ONLY socket option for RPC listener sockets
> SUNRPC: Add address family field to svc_serv data structure
> NFS: nfs_parsed_mount_options can use unsigned int
>
>
> fs/Kconfig | 22 +++++
> fs/lockd/svc.c | 2
> fs/nfs/callback.c | 3 -
> fs/nfs/internal.h | 8 +-
> fs/nfsd/nfssvc.c | 3 -
> include/linux/sunrpc/clnt.h | 4 -
> include/linux/sunrpc/svc.h | 15 ++--
> net/sunrpc/rpcb_clnt.c | 65 +++++++---------
> net/sunrpc/svc.c | 175 ++++++++++++++++++++++++++++++++++++-------
> net/sunrpc/svc_xprt.c | 37 +++++++--
> net/sunrpc/svcsock.c | 13 +++
> 11 files changed, 260 insertions(+), 87 deletions(-)
>
> --
> Chuck Lever
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-08-20 23:20 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-08-18 23:33 [PATCH 0/7] Register kernel RPC services via rpcbind v4 Chuck Lever
[not found] ` <20080818233128.1214.48603.stgit-meopP2rzCrTwdl/1UfZZQIVfYA8g3rJ/@public.gmane.org>
2008-08-18 23:33 ` [PATCH 1/7] NFS: nfs_parsed_mount_options can use unsigned int Chuck Lever
2008-08-18 23:33 ` [PATCH 2/7] SUNRPC: Add address family field to svc_serv data structure Chuck Lever
2008-08-18 23:33 ` [PATCH 3/7] SUNRPC: Set V6ONLY socket option for RPC listener sockets Chuck Lever
2008-08-18 23:33 ` [PATCH 4/7] SUNRPC: Use proper INADDR_ANY when setting up RPC services on IPv6 Chuck Lever
2008-08-18 23:34 ` [PATCH 5/7] SUNRPC: Simplify rpcb_register() API Chuck Lever
2008-08-18 23:34 ` [PATCH 6/7] SUNRPC: Split portmap unregister API into separate function Chuck Lever
2008-08-18 23:34 ` [PATCH 7/7] SUNRPC: Support IPv6 when registering kernel RPC services Chuck Lever
2008-08-20 23:20 ` [PATCH 0/7] Register kernel RPC services via rpcbind v4 J. Bruce Fields
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox