Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b41b66d6 authored by NeilBrown's avatar NeilBrown Committed by Linus Torvalds
Browse files

[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: default avatarNeil Brown <neilb@suse.de>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 80212d59
Loading
Loading
Loading
Loading
+50 −9
Original line number Original line Diff line number Diff line
@@ -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,17 +428,56 @@ 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
		int len = 0;
	 * AF proto address port
		lock_kernel();
		if (nfsd_serv)
			len = svc_sock_names(buf, nfsd_serv, NULL);
		unlock_kernel();
		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;
		int len = 0;
		if (!toclose)
			return -ENOMEM;
		lock_kernel();
		lock_kernel();
		if (nfsd_serv)
		if (nfsd_serv)
		len = svc_sock_names(buf, nfsd_serv);
			len = svc_sock_names(buf, nfsd_serv, toclose);
		unlock_kernel();
		unlock_kernel();
		kfree(toclose);
		return len;
		return len;
	}
	}
	return -EINVAL;
}


#ifdef CONFIG_NFSD_V4
#ifdef CONFIG_NFSD_V4
extern time_t nfs4_leasetime(void);
extern time_t nfs4_leasetime(void);
+1 −3
Original line number Original line Diff line number Diff line
@@ -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;
+1 −0
Original line number Original line Diff line number Diff line
@@ -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);




/* 
/* 
+5 −1
Original line number Original line Diff line number Diff line
@@ -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 */
+45 −4
Original line number Original line Diff line number Diff line
@@ -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 {