summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2006-10-02 02:17:48 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-02 07:57:18 -0700
commitb41b66d63c730cc45a1024e1f1e67439e507e40f (patch)
tree85f623c087a90ccf08a8264c638df5504f972c0d /net
parent80212d59e32a8a8e030c2ddc5861d8ff70542c56 (diff)
[PATCH] knfsd: allow sockets to be passed to nfsd via 'portlist'
Userspace should create and bind a socket (but not connectted) and write the 'fd' to portlist. This will cause the nfs server to listen on that socket. To close a socket, the name of the socket - as read from 'portlist' can be written to 'portlist' with a preceding '-'. Signed-off-by: Neil Brown <neilb@suse.de> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'net')
-rw-r--r--net/sunrpc/svcsock.c49
1 files changed, 45 insertions, 4 deletions
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 3ee4b78742b..c6be67a86ae 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -31,6 +31,7 @@
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
+#include <linux/file.h>
#include <net/sock.h>
#include <net/checksum.h>
#include <net/ip.h>
@@ -451,9 +452,9 @@ static int one_sock_name(char *buf, struct svc_sock *svsk)
}
int
-svc_sock_names(char *buf, struct svc_serv *serv)
+svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
{
- struct svc_sock *svsk;
+ struct svc_sock *svsk, *closesk = NULL;
int len = 0;
if (!serv)
@@ -461,9 +462,14 @@ svc_sock_names(char *buf, struct svc_serv *serv)
spin_lock(&serv->sv_lock);
list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) {
int onelen = one_sock_name(buf+len, svsk);
- len += onelen;
+ if (toclose && strcmp(toclose, buf+len) == 0)
+ closesk = svsk;
+ else
+ len += onelen;
}
spin_unlock(&serv->sv_lock);
+ if (closesk)
+ svc_delete_socket(closesk);
return len;
}
EXPORT_SYMBOL(svc_sock_names);
@@ -1407,6 +1413,38 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
return svsk;
}
+int svc_addsock(struct svc_serv *serv,
+ int fd,
+ char *name_return,
+ int *proto)
+{
+ int err = 0;
+ struct socket *so = sockfd_lookup(fd, &err);
+ struct svc_sock *svsk = NULL;
+
+ if (!so)
+ return err;
+ if (so->sk->sk_family != AF_INET)
+ err = -EAFNOSUPPORT;
+ else if (so->sk->sk_protocol != IPPROTO_TCP &&
+ so->sk->sk_protocol != IPPROTO_UDP)
+ err = -EPROTONOSUPPORT;
+ else if (so->state > SS_UNCONNECTED)
+ err = -EISCONN;
+ else {
+ svsk = svc_setup_socket(serv, so, &err, 1);
+ if (svsk)
+ err = 0;
+ }
+ if (err) {
+ sockfd_put(so);
+ return err;
+ }
+ if (proto) *proto = so->sk->sk_protocol;
+ return one_sock_name(name_return, svsk);
+}
+EXPORT_SYMBOL_GPL(svc_addsock);
+
/*
* Create socket for RPC service.
*/
@@ -1482,7 +1520,10 @@ svc_delete_socket(struct svc_sock *svsk)
if (!svsk->sk_inuse) {
spin_unlock_bh(&serv->sv_lock);
- sock_release(svsk->sk_sock);
+ if (svsk->sk_sock->file)
+ sockfd_put(svsk->sk_sock);
+ else
+ sock_release(svsk->sk_sock);
kfree(svsk);
} else {
spin_unlock_bh(&serv->sv_lock);