diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/svcsock.c | 49 |
1 files changed, 45 insertions, 4 deletions
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); |