mirror of
https://github.com/torvalds/linux
synced 2024-09-20 19:17:24 +00:00
[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>
This commit is contained in:
parent
80212d59e3
commit
b41b66d63c
|
@ -24,9 +24,11 @@
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/string.h>
|
#include <linux/string.h>
|
||||||
#include <linux/smp_lock.h>
|
#include <linux/smp_lock.h>
|
||||||
|
#include <linux/ctype.h>
|
||||||
|
|
||||||
#include <linux/nfs.h>
|
#include <linux/nfs.h>
|
||||||
#include <linux/nfsd_idmap.h>
|
#include <linux/nfsd_idmap.h>
|
||||||
|
#include <linux/lockd/bind.h>
|
||||||
#include <linux/sunrpc/svc.h>
|
#include <linux/sunrpc/svc.h>
|
||||||
#include <linux/sunrpc/svcsock.h>
|
#include <linux/sunrpc/svcsock.h>
|
||||||
#include <linux/nfsd/nfsd.h>
|
#include <linux/nfsd/nfsd.h>
|
||||||
|
@ -426,16 +428,55 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
|
||||||
|
|
||||||
static ssize_t write_ports(struct file *file, char *buf, size_t size)
|
static ssize_t write_ports(struct file *file, char *buf, size_t size)
|
||||||
{
|
{
|
||||||
/* for now, ignore what was written and just
|
if (size == 0) {
|
||||||
* return known ports
|
|
||||||
* AF proto address port
|
|
||||||
*/
|
|
||||||
int len = 0;
|
int len = 0;
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
if (nfsd_serv)
|
if (nfsd_serv)
|
||||||
len = svc_sock_names(buf, nfsd_serv);
|
len = svc_sock_names(buf, nfsd_serv, NULL);
|
||||||
unlock_kernel();
|
unlock_kernel();
|
||||||
return len;
|
return len;
|
||||||
|
}
|
||||||
|
/* Either a single 'fd' number is written, in which
|
||||||
|
* case it must be for a socket of a supported family/protocol,
|
||||||
|
* and we use it as an nfsd socket, or
|
||||||
|
* A '-' followed by the 'name' of a socket in which case
|
||||||
|
* we close the socket.
|
||||||
|
*/
|
||||||
|
if (isdigit(buf[0])) {
|
||||||
|
char *mesg = buf;
|
||||||
|
int fd;
|
||||||
|
int err;
|
||||||
|
err = get_int(&mesg, &fd);
|
||||||
|
if (err)
|
||||||
|
return -EINVAL;
|
||||||
|
if (fd < 0)
|
||||||
|
return -EINVAL;
|
||||||
|
err = nfsd_create_serv();
|
||||||
|
if (!err) {
|
||||||
|
int proto = 0;
|
||||||
|
err = svc_addsock(nfsd_serv, fd, buf, &proto);
|
||||||
|
/* Decrease the count, but don't shutdown the
|
||||||
|
* the service
|
||||||
|
*/
|
||||||
|
if (err >= 0)
|
||||||
|
lockd_up(proto);
|
||||||
|
nfsd_serv->sv_nrthreads--;
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (buf[0] == '-') {
|
||||||
|
char *toclose = kstrdup(buf+1, GFP_KERNEL);
|
||||||
|
int len = 0;
|
||||||
|
if (!toclose)
|
||||||
|
return -ENOMEM;
|
||||||
|
lock_kernel();
|
||||||
|
if (nfsd_serv)
|
||||||
|
len = svc_sock_names(buf, nfsd_serv, toclose);
|
||||||
|
unlock_kernel();
|
||||||
|
kfree(toclose);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_NFSD_V4
|
#ifdef CONFIG_NFSD_V4
|
||||||
|
|
|
@ -195,7 +195,7 @@ void nfsd_reset_versions(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int nfsd_create_serv(void)
|
int nfsd_create_serv(void)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
lock_kernel();
|
lock_kernel();
|
||||||
|
@ -210,8 +210,6 @@ static int nfsd_create_serv(void)
|
||||||
nfsd_last_thread);
|
nfsd_last_thread);
|
||||||
if (nfsd_serv == NULL)
|
if (nfsd_serv == NULL)
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
else
|
|
||||||
nfsd_serv->sv_nrthreads++;
|
|
||||||
unlock_kernel();
|
unlock_kernel();
|
||||||
do_gettimeofday(&nfssvc_boot); /* record boot time */
|
do_gettimeofday(&nfssvc_boot); /* record boot time */
|
||||||
return err;
|
return err;
|
||||||
|
|
|
@ -143,6 +143,7 @@ int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
|
||||||
enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
|
enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
|
||||||
int nfsd_vers(int vers, enum vers_op change);
|
int nfsd_vers(int vers, enum vers_op change);
|
||||||
void nfsd_reset_versions(void);
|
void nfsd_reset_versions(void);
|
||||||
|
int nfsd_create_serv(void);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -61,6 +61,10 @@ int svc_recv(struct svc_serv *, struct svc_rqst *, long);
|
||||||
int svc_send(struct svc_rqst *);
|
int svc_send(struct svc_rqst *);
|
||||||
void svc_drop(struct svc_rqst *);
|
void svc_drop(struct svc_rqst *);
|
||||||
void svc_sock_update_bufs(struct svc_serv *serv);
|
void svc_sock_update_bufs(struct svc_serv *serv);
|
||||||
int svc_sock_names(char *buf, struct svc_serv *serv);
|
int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose);
|
||||||
|
int svc_addsock(struct svc_serv *serv,
|
||||||
|
int fd,
|
||||||
|
char *name_return,
|
||||||
|
int *proto);
|
||||||
|
|
||||||
#endif /* SUNRPC_SVCSOCK_H */
|
#endif /* SUNRPC_SVCSOCK_H */
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/netdevice.h>
|
#include <linux/netdevice.h>
|
||||||
#include <linux/skbuff.h>
|
#include <linux/skbuff.h>
|
||||||
|
#include <linux/file.h>
|
||||||
#include <net/sock.h>
|
#include <net/sock.h>
|
||||||
#include <net/checksum.h>
|
#include <net/checksum.h>
|
||||||
#include <net/ip.h>
|
#include <net/ip.h>
|
||||||
|
@ -451,9 +452,9 @@ static int one_sock_name(char *buf, struct svc_sock *svsk)
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
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;
|
int len = 0;
|
||||||
|
|
||||||
if (!serv)
|
if (!serv)
|
||||||
|
@ -461,9 +462,14 @@ svc_sock_names(char *buf, struct svc_serv *serv)
|
||||||
spin_lock(&serv->sv_lock);
|
spin_lock(&serv->sv_lock);
|
||||||
list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) {
|
list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) {
|
||||||
int onelen = one_sock_name(buf+len, svsk);
|
int onelen = one_sock_name(buf+len, svsk);
|
||||||
|
if (toclose && strcmp(toclose, buf+len) == 0)
|
||||||
|
closesk = svsk;
|
||||||
|
else
|
||||||
len += onelen;
|
len += onelen;
|
||||||
}
|
}
|
||||||
spin_unlock(&serv->sv_lock);
|
spin_unlock(&serv->sv_lock);
|
||||||
|
if (closesk)
|
||||||
|
svc_delete_socket(closesk);
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(svc_sock_names);
|
EXPORT_SYMBOL(svc_sock_names);
|
||||||
|
@ -1407,6 +1413,38 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
|
||||||
return svsk;
|
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.
|
* Create socket for RPC service.
|
||||||
*/
|
*/
|
||||||
|
@ -1482,6 +1520,9 @@ svc_delete_socket(struct svc_sock *svsk)
|
||||||
|
|
||||||
if (!svsk->sk_inuse) {
|
if (!svsk->sk_inuse) {
|
||||||
spin_unlock_bh(&serv->sv_lock);
|
spin_unlock_bh(&serv->sv_lock);
|
||||||
|
if (svsk->sk_sock->file)
|
||||||
|
sockfd_put(svsk->sk_sock);
|
||||||
|
else
|
||||||
sock_release(svsk->sk_sock);
|
sock_release(svsk->sk_sock);
|
||||||
kfree(svsk);
|
kfree(svsk);
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue