diff options
author | NeilBrown <neilb@suse.de> | 2006-10-02 05:17:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-10-02 10:57:18 -0400 |
commit | b41b66d63c730cc45a1024e1f1e67439e507e40f (patch) | |
tree | 85f623c087a90ccf08a8264c638df5504f972c0d | |
parent | 80212d59e32a8a8e030c2ddc5861d8ff70542c56 (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.c | 59 | ||||
-rw-r--r-- | fs/nfsd/nfssvc.c | 4 | ||||
-rw-r--r-- | include/linux/nfsd/nfsd.h | 1 | ||||
-rw-r--r-- | include/linux/sunrpc/svcsock.h | 6 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 49 |
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 | ||
427 | static ssize_t write_ports(struct file *file, char *buf, size_t size) | 429 | static 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 | ||
198 | static int nfsd_create_serv(void) | 198 | int 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 *); | |||
143 | enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; | 143 | enum vers_op {NFSD_SET, NFSD_CLEAR, NFSD_TEST, NFSD_AVAIL }; |
144 | int nfsd_vers(int vers, enum vers_op change); | 144 | int nfsd_vers(int vers, enum vers_op change); |
145 | void nfsd_reset_versions(void); | 145 | void nfsd_reset_versions(void); |
146 | int 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); | |||
61 | int svc_send(struct svc_rqst *); | 61 | int svc_send(struct svc_rqst *); |
62 | void svc_drop(struct svc_rqst *); | 62 | void svc_drop(struct svc_rqst *); |
63 | void svc_sock_update_bufs(struct svc_serv *serv); | 63 | void svc_sock_update_bufs(struct svc_serv *serv); |
64 | int svc_sock_names(char *buf, struct svc_serv *serv); | 64 | int svc_sock_names(char *buf, struct svc_serv *serv, char *toclose); |
65 | int 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 | ||
453 | int | 454 | int |
454 | svc_sock_names(char *buf, struct svc_serv *serv) | 455 | svc_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 | } |
469 | EXPORT_SYMBOL(svc_sock_names); | 475 | EXPORT_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 | ||
1416 | int 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 | } | ||
1446 | EXPORT_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); |