aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeilBrown <neilb@suse.de>2006-10-02 05:17:48 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-02 10:57:18 -0400
commitb41b66d63c730cc45a1024e1f1e67439e507e40f (patch)
tree85f623c087a90ccf08a8264c638df5504f972c0d
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>
-rw-r--r--fs/nfsd/nfsctl.c59
-rw-r--r--fs/nfsd/nfssvc.c4
-rw-r--r--include/linux/nfsd/nfsd.h1
-rw-r--r--include/linux/sunrpc/svcsock.h6
-rw-r--r--net/sunrpc/svcsock.c49
5 files changed, 102 insertions, 17 deletions
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index d4041a05bc19..80e97a5ffc3f 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -24,9 +24,11 @@
24#include <linux/init.h> 24#include <linux/init.h>
25#include <linux/string.h> 25#include <linux/string.h>
26#include <linux/smp_lock.h> 26#include <linux/smp_lock.h>
27#include <linux/ctype.h>
27 28
28#include <linux/nfs.h> 29#include <linux/nfs.h>
29#include <linux/nfsd_idmap.h> 30#include <linux/nfsd_idmap.h>
31#include <linux/lockd/bind.h>
30#include <linux/sunrpc/svc.h> 32#include <linux/sunrpc/svc.h>
31#include <linux/sunrpc/svcsock.h> 33#include <linux/sunrpc/svcsock.h>
32#include <linux/nfsd/nfsd.h> 34#include <linux/nfsd/nfsd.h>
@@ -426,16 +428,55 @@ static ssize_t write_versions(struct file *file, char *buf, size_t size)
426 428
427static ssize_t write_ports(struct file *file, char *buf, size_t size) 429static ssize_t write_ports(struct file *file, char *buf, size_t size)
428{ 430{
429 /* for now, ignore what was written and just 431 if (size == 0) {
430 * return known ports 432 int len = 0;
431 * AF proto address port 433 lock_kernel();
434 if (nfsd_serv)
435 len = svc_sock_names(buf, nfsd_serv, NULL);
436 unlock_kernel();
437 return len;
438 }
439 /* Either a single 'fd' number is written, in which
440 * case it must be for a socket of a supported family/protocol,
441 * and we use it as an nfsd socket, or
442 * A '-' followed by the 'name' of a socket in which case
443 * we close the socket.
432 */ 444 */
433 int len = 0; 445 if (isdigit(buf[0])) {
434 lock_kernel(); 446 char *mesg = buf;
435 if (nfsd_serv) 447 int fd;
436 len = svc_sock_names(buf, nfsd_serv); 448 int err;
437 unlock_kernel(); 449 err = get_int(&mesg, &fd);
438 return len; 450 if (err)
451 return -EINVAL;
452 if (fd < 0)
453 return -EINVAL;
454 err = nfsd_create_serv();
455 if (!err) {
456 int proto = 0;
457 err = svc_addsock(nfsd_serv, fd, buf, &proto);
458 /* Decrease the count, but don't shutdown the
459 * the service
460 */
461 if (err >= 0)
462 lockd_up(proto);
463 nfsd_serv->sv_nrthreads--;
464 }
465 return err;
466 }
467 if (buf[0] == '-') {
468 char *toclose = kstrdup(buf+1, GFP_KERNEL);
469 int len = 0;
470 if (!toclose)
471 return -ENOMEM;
472 lock_kernel();
473 if (nfsd_serv)
474 len = svc_sock_names(buf, nfsd_serv, toclose);
475 unlock_kernel();
476 kfree(toclose);
477 return len;
478 }
479 return -EINVAL;
439} 480}
440 481
441#ifdef CONFIG_NFSD_V4 482#ifdef CONFIG_NFSD_V4
diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
index 5d473d8f0630..784f94fbebf3 100644
--- a/fs/nfsd/nfssvc.c
+++ b/fs/nfsd/nfssvc.c
@@ -195,7 +195,7 @@ void nfsd_reset_versions(void)
195 } 195 }
196} 196}
197 197
198static int nfsd_create_serv(void) 198int nfsd_create_serv(void)
199{ 199{
200 int err = 0; 200 int err = 0;
201 lock_kernel(); 201 lock_kernel();
@@ -210,8 +210,6 @@ static int nfsd_create_serv(void)
210 nfsd_last_thread); 210 nfsd_last_thread);
211 if (nfsd_serv == NULL) 211 if (nfsd_serv == NULL)
212 err = -ENOMEM; 212 err = -ENOMEM;
213 else
214 nfsd_serv->sv_nrthreads++;
215 unlock_kernel(); 213 unlock_kernel();
216 do_gettimeofday(&nfssvc_boot); /* record boot time */ 214 do_gettimeofday(&nfssvc_boot); /* record boot time */
217 return err; 215 return err;
diff --git a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
index 46f1dc5b96dd..e1dbc86c270b 100644
--- a/include/linux/nfsd/nfsd.h
+++ b/include/linux/nfsd/nfsd.h
@@ -143,6 +143,7 @@ int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
143enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; 143enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL };
144int nfsd_vers(int vers, enum vers_op change); 144int nfsd_vers(int vers, enum vers_op change);
145void nfsd_reset_versions(void); 145void nfsd_reset_versions(void);
146int nfsd_create_serv(void);
146 147
147 148
148/* 149/*
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h
index 3caf92d72a81..b8a9652b8755 100644
--- a/include/linux/sunrpc/svcsock.h
+++ b/include/linux/sunrpc/svcsock.h
@@ -61,6 +61,10 @@ int svc_recv(struct svc_serv *, struct svc_rqst *, long);
61int svc_send(struct svc_rqst *); 61int svc_send(struct svc_rqst *);
62void svc_drop(struct svc_rqst *); 62void svc_drop(struct svc_rqst *);
63void svc_sock_update_bufs(struct svc_serv *serv); 63void svc_sock_update_bufs(struct svc_serv *serv);
64int svc_sock_names(char *buf, struct svc_serv *serv); 64int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose);
65int svc_addsock(struct svc_serv *serv,
66 int fd,
67 char *name_return,
68 int *proto);
65 69
66#endif /* SUNRPC_SVCSOCK_H */ 70#endif /* SUNRPC_SVCSOCK_H */
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
index 3ee4b78742b1..c6be67a86ae7 100644
--- a/net/sunrpc/svcsock.c
+++ b/net/sunrpc/svcsock.c
@@ -31,6 +31,7 @@
31#include <linux/slab.h> 31#include <linux/slab.h>
32#include <linux/netdevice.h> 32#include <linux/netdevice.h>
33#include <linux/skbuff.h> 33#include <linux/skbuff.h>
34#include <linux/file.h>
34#include <net/sock.h> 35#include <net/sock.h>
35#include <net/checksum.h> 36#include <net/checksum.h>
36#include <net/ip.h> 37#include <net/ip.h>
@@ -451,9 +452,9 @@ static int one_sock_name(char *buf, struct svc_sock *svsk)
451} 452}
452 453
453int 454int
454svc_sock_names(char *buf, struct svc_serv *serv) 455svc_sock_names(char *buf, struct svc_serv *serv, char *toclose)
455{ 456{
456 struct svc_sock *svsk; 457 struct svc_sock *svsk, *closesk = NULL;
457 int len = 0; 458 int len = 0;
458 459
459 if (!serv) 460 if (!serv)
@@ -461,9 +462,14 @@ svc_sock_names(char *buf, struct svc_serv *serv)
461 spin_lock(&serv->sv_lock); 462 spin_lock(&serv->sv_lock);
462 list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) { 463 list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) {
463 int onelen = one_sock_name(buf+len, svsk); 464 int onelen = one_sock_name(buf+len, svsk);
464 len += onelen; 465 if (toclose && strcmp(toclose, buf+len) == 0)
466 closesk = svsk;
467 else
468 len += onelen;
465 } 469 }
466 spin_unlock(&serv->sv_lock); 470 spin_unlock(&serv->sv_lock);
471 if (closesk)
472 svc_delete_socket(closesk);
467 return len; 473 return len;
468} 474}
469EXPORT_SYMBOL(svc_sock_names); 475EXPORT_SYMBOL(svc_sock_names);
@@ -1407,6 +1413,38 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock,
1407 return svsk; 1413 return svsk;
1408} 1414}
1409 1415
1416int svc_addsock(struct svc_serv *serv,
1417 int fd,
1418 char *name_return,
1419 int *proto)
1420{
1421 int err = 0;
1422 struct socket *so = sockfd_lookup(fd, &err);
1423 struct svc_sock *svsk = NULL;
1424
1425 if (!so)
1426 return err;
1427 if (so->sk->sk_family != AF_INET)
1428 err = -EAFNOSUPPORT;
1429 else if (so->sk->sk_protocol != IPPROTO_TCP &&
1430 so->sk->sk_protocol != IPPROTO_UDP)
1431 err = -EPROTONOSUPPORT;
1432 else if (so->state > SS_UNCONNECTED)
1433 err = -EISCONN;
1434 else {
1435 svsk = svc_setup_socket(serv, so, &err, 1);
1436 if (svsk)
1437 err = 0;
1438 }
1439 if (err) {
1440 sockfd_put(so);
1441 return err;
1442 }
1443 if (proto) *proto = so->sk->sk_protocol;
1444 return one_sock_name(name_return, svsk);
1445}
1446EXPORT_SYMBOL_GPL(svc_addsock);
1447
1410/* 1448/*
1411 * Create socket for RPC service. 1449 * Create socket for RPC service.
1412 */ 1450 */
@@ -1482,7 +1520,10 @@ svc_delete_socket(struct svc_sock *svsk)
1482 1520
1483 if (!svsk->sk_inuse) { 1521 if (!svsk->sk_inuse) {
1484 spin_unlock_bh(&serv->sv_lock); 1522 spin_unlock_bh(&serv->sv_lock);
1485 sock_release(svsk->sk_sock); 1523 if (svsk->sk_sock->file)
1524 sockfd_put(svsk->sk_sock);
1525 else
1526 sock_release(svsk->sk_sock);
1486 kfree(svsk); 1527 kfree(svsk);
1487 } else { 1528 } else {
1488 spin_unlock_bh(&serv->sv_lock); 1529 spin_unlock_bh(&serv->sv_lock);