diff options
author | Grant Likely <grant.likely@secretlab.ca> | 2010-12-30 00:20:30 -0500 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2010-12-30 00:21:47 -0500 |
commit | d392da5207352f09030e95d9ea335a4225667ec0 (patch) | |
tree | 7d6cd1932afcad0a5619a5c504a6d93ca318187c /net/unix | |
parent | e39d5ef678045d61812c1401f04fe8edb14d6359 (diff) | |
parent | 387c31c7e5c9805b0aef8833d1731a5fe7bdea14 (diff) |
Merge v2.6.37-rc8 into powerpc/next
Diffstat (limited to 'net/unix')
-rw-r--r-- | net/unix/af_unix.c | 76 | ||||
-rw-r--r-- | net/unix/garbage.c | 9 |
2 files changed, 66 insertions, 19 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 4414a18c63b4..2268e6798124 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -117,7 +117,7 @@ | |||
117 | 117 | ||
118 | static struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1]; | 118 | static struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1]; |
119 | static DEFINE_SPINLOCK(unix_table_lock); | 119 | static DEFINE_SPINLOCK(unix_table_lock); |
120 | static atomic_t unix_nr_socks = ATOMIC_INIT(0); | 120 | static atomic_long_t unix_nr_socks; |
121 | 121 | ||
122 | #define unix_sockets_unbound (&unix_socket_table[UNIX_HASH_SIZE]) | 122 | #define unix_sockets_unbound (&unix_socket_table[UNIX_HASH_SIZE]) |
123 | 123 | ||
@@ -360,13 +360,13 @@ static void unix_sock_destructor(struct sock *sk) | |||
360 | if (u->addr) | 360 | if (u->addr) |
361 | unix_release_addr(u->addr); | 361 | unix_release_addr(u->addr); |
362 | 362 | ||
363 | atomic_dec(&unix_nr_socks); | 363 | atomic_long_dec(&unix_nr_socks); |
364 | local_bh_disable(); | 364 | local_bh_disable(); |
365 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); | 365 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); |
366 | local_bh_enable(); | 366 | local_bh_enable(); |
367 | #ifdef UNIX_REFCNT_DEBUG | 367 | #ifdef UNIX_REFCNT_DEBUG |
368 | printk(KERN_DEBUG "UNIX %p is destroyed, %d are still alive.\n", sk, | 368 | printk(KERN_DEBUG "UNIX %p is destroyed, %ld are still alive.\n", sk, |
369 | atomic_read(&unix_nr_socks)); | 369 | atomic_long_read(&unix_nr_socks)); |
370 | #endif | 370 | #endif |
371 | } | 371 | } |
372 | 372 | ||
@@ -606,8 +606,8 @@ static struct sock *unix_create1(struct net *net, struct socket *sock) | |||
606 | struct sock *sk = NULL; | 606 | struct sock *sk = NULL; |
607 | struct unix_sock *u; | 607 | struct unix_sock *u; |
608 | 608 | ||
609 | atomic_inc(&unix_nr_socks); | 609 | atomic_long_inc(&unix_nr_socks); |
610 | if (atomic_read(&unix_nr_socks) > 2 * get_max_files()) | 610 | if (atomic_long_read(&unix_nr_socks) > 2 * get_max_files()) |
611 | goto out; | 611 | goto out; |
612 | 612 | ||
613 | sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto); | 613 | sk = sk_alloc(net, PF_UNIX, GFP_KERNEL, &unix_proto); |
@@ -632,7 +632,7 @@ static struct sock *unix_create1(struct net *net, struct socket *sock) | |||
632 | unix_insert_socket(unix_sockets_unbound, sk); | 632 | unix_insert_socket(unix_sockets_unbound, sk); |
633 | out: | 633 | out: |
634 | if (sk == NULL) | 634 | if (sk == NULL) |
635 | atomic_dec(&unix_nr_socks); | 635 | atomic_long_dec(&unix_nr_socks); |
636 | else { | 636 | else { |
637 | local_bh_disable(); | 637 | local_bh_disable(); |
638 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); | 638 | sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); |
@@ -692,6 +692,7 @@ static int unix_autobind(struct socket *sock) | |||
692 | static u32 ordernum = 1; | 692 | static u32 ordernum = 1; |
693 | struct unix_address *addr; | 693 | struct unix_address *addr; |
694 | int err; | 694 | int err; |
695 | unsigned int retries = 0; | ||
695 | 696 | ||
696 | mutex_lock(&u->readlock); | 697 | mutex_lock(&u->readlock); |
697 | 698 | ||
@@ -717,9 +718,17 @@ retry: | |||
717 | if (__unix_find_socket_byname(net, addr->name, addr->len, sock->type, | 718 | if (__unix_find_socket_byname(net, addr->name, addr->len, sock->type, |
718 | addr->hash)) { | 719 | addr->hash)) { |
719 | spin_unlock(&unix_table_lock); | 720 | spin_unlock(&unix_table_lock); |
720 | /* Sanity yield. It is unusual case, but yet... */ | 721 | /* |
721 | if (!(ordernum&0xFF)) | 722 | * __unix_find_socket_byname() may take long time if many names |
722 | yield(); | 723 | * are already in use. |
724 | */ | ||
725 | cond_resched(); | ||
726 | /* Give up if all names seems to be in use. */ | ||
727 | if (retries++ == 0xFFFFF) { | ||
728 | err = -ENOSPC; | ||
729 | kfree(addr); | ||
730 | goto out; | ||
731 | } | ||
723 | goto retry; | 732 | goto retry; |
724 | } | 733 | } |
725 | addr->hash ^= sk->sk_type; | 734 | addr->hash ^= sk->sk_type; |
@@ -1334,9 +1343,25 @@ static void unix_destruct_scm(struct sk_buff *skb) | |||
1334 | sock_wfree(skb); | 1343 | sock_wfree(skb); |
1335 | } | 1344 | } |
1336 | 1345 | ||
1346 | #define MAX_RECURSION_LEVEL 4 | ||
1347 | |||
1337 | static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) | 1348 | static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) |
1338 | { | 1349 | { |
1339 | int i; | 1350 | int i; |
1351 | unsigned char max_level = 0; | ||
1352 | int unix_sock_count = 0; | ||
1353 | |||
1354 | for (i = scm->fp->count - 1; i >= 0; i--) { | ||
1355 | struct sock *sk = unix_get_socket(scm->fp->fp[i]); | ||
1356 | |||
1357 | if (sk) { | ||
1358 | unix_sock_count++; | ||
1359 | max_level = max(max_level, | ||
1360 | unix_sk(sk)->recursion_level); | ||
1361 | } | ||
1362 | } | ||
1363 | if (unlikely(max_level > MAX_RECURSION_LEVEL)) | ||
1364 | return -ETOOMANYREFS; | ||
1340 | 1365 | ||
1341 | /* | 1366 | /* |
1342 | * Need to duplicate file references for the sake of garbage | 1367 | * Need to duplicate file references for the sake of garbage |
@@ -1347,9 +1372,11 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) | |||
1347 | if (!UNIXCB(skb).fp) | 1372 | if (!UNIXCB(skb).fp) |
1348 | return -ENOMEM; | 1373 | return -ENOMEM; |
1349 | 1374 | ||
1350 | for (i = scm->fp->count-1; i >= 0; i--) | 1375 | if (unix_sock_count) { |
1351 | unix_inflight(scm->fp->fp[i]); | 1376 | for (i = scm->fp->count - 1; i >= 0; i--) |
1352 | return 0; | 1377 | unix_inflight(scm->fp->fp[i]); |
1378 | } | ||
1379 | return max_level; | ||
1353 | } | 1380 | } |
1354 | 1381 | ||
1355 | static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) | 1382 | static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) |
@@ -1384,6 +1411,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1384 | struct sk_buff *skb; | 1411 | struct sk_buff *skb; |
1385 | long timeo; | 1412 | long timeo; |
1386 | struct scm_cookie tmp_scm; | 1413 | struct scm_cookie tmp_scm; |
1414 | int max_level; | ||
1387 | 1415 | ||
1388 | if (NULL == siocb->scm) | 1416 | if (NULL == siocb->scm) |
1389 | siocb->scm = &tmp_scm; | 1417 | siocb->scm = &tmp_scm; |
@@ -1422,8 +1450,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1422 | goto out; | 1450 | goto out; |
1423 | 1451 | ||
1424 | err = unix_scm_to_skb(siocb->scm, skb, true); | 1452 | err = unix_scm_to_skb(siocb->scm, skb, true); |
1425 | if (err) | 1453 | if (err < 0) |
1426 | goto out_free; | 1454 | goto out_free; |
1455 | max_level = err + 1; | ||
1427 | unix_get_secdata(siocb->scm, skb); | 1456 | unix_get_secdata(siocb->scm, skb); |
1428 | 1457 | ||
1429 | skb_reset_transport_header(skb); | 1458 | skb_reset_transport_header(skb); |
@@ -1502,7 +1531,11 @@ restart: | |||
1502 | goto restart; | 1531 | goto restart; |
1503 | } | 1532 | } |
1504 | 1533 | ||
1534 | if (sock_flag(other, SOCK_RCVTSTAMP)) | ||
1535 | __net_timestamp(skb); | ||
1505 | skb_queue_tail(&other->sk_receive_queue, skb); | 1536 | skb_queue_tail(&other->sk_receive_queue, skb); |
1537 | if (max_level > unix_sk(other)->recursion_level) | ||
1538 | unix_sk(other)->recursion_level = max_level; | ||
1506 | unix_state_unlock(other); | 1539 | unix_state_unlock(other); |
1507 | other->sk_data_ready(other, len); | 1540 | other->sk_data_ready(other, len); |
1508 | sock_put(other); | 1541 | sock_put(other); |
@@ -1533,6 +1566,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1533 | int sent = 0; | 1566 | int sent = 0; |
1534 | struct scm_cookie tmp_scm; | 1567 | struct scm_cookie tmp_scm; |
1535 | bool fds_sent = false; | 1568 | bool fds_sent = false; |
1569 | int max_level; | ||
1536 | 1570 | ||
1537 | if (NULL == siocb->scm) | 1571 | if (NULL == siocb->scm) |
1538 | siocb->scm = &tmp_scm; | 1572 | siocb->scm = &tmp_scm; |
@@ -1596,10 +1630,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1596 | 1630 | ||
1597 | /* Only send the fds in the first buffer */ | 1631 | /* Only send the fds in the first buffer */ |
1598 | err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); | 1632 | err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); |
1599 | if (err) { | 1633 | if (err < 0) { |
1600 | kfree_skb(skb); | 1634 | kfree_skb(skb); |
1601 | goto out_err; | 1635 | goto out_err; |
1602 | } | 1636 | } |
1637 | max_level = err + 1; | ||
1603 | fds_sent = true; | 1638 | fds_sent = true; |
1604 | 1639 | ||
1605 | err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); | 1640 | err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); |
@@ -1615,6 +1650,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1615 | goto pipe_err_free; | 1650 | goto pipe_err_free; |
1616 | 1651 | ||
1617 | skb_queue_tail(&other->sk_receive_queue, skb); | 1652 | skb_queue_tail(&other->sk_receive_queue, skb); |
1653 | if (max_level > unix_sk(other)->recursion_level) | ||
1654 | unix_sk(other)->recursion_level = max_level; | ||
1618 | unix_state_unlock(other); | 1655 | unix_state_unlock(other); |
1619 | other->sk_data_ready(other, size); | 1656 | other->sk_data_ready(other, size); |
1620 | sent += size; | 1657 | sent += size; |
@@ -1713,6 +1750,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1713 | if (err) | 1750 | if (err) |
1714 | goto out_free; | 1751 | goto out_free; |
1715 | 1752 | ||
1753 | if (sock_flag(sk, SOCK_RCVTSTAMP)) | ||
1754 | __sock_recv_timestamp(msg, sk, skb); | ||
1755 | |||
1716 | if (!siocb->scm) { | 1756 | if (!siocb->scm) { |
1717 | siocb->scm = &tmp_scm; | 1757 | siocb->scm = &tmp_scm; |
1718 | memset(&tmp_scm, 0, sizeof(tmp_scm)); | 1758 | memset(&tmp_scm, 0, sizeof(tmp_scm)); |
@@ -1831,6 +1871,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1831 | unix_state_lock(sk); | 1871 | unix_state_lock(sk); |
1832 | skb = skb_dequeue(&sk->sk_receive_queue); | 1872 | skb = skb_dequeue(&sk->sk_receive_queue); |
1833 | if (skb == NULL) { | 1873 | if (skb == NULL) { |
1874 | unix_sk(sk)->recursion_level = 0; | ||
1834 | if (copied >= target) | 1875 | if (copied >= target) |
1835 | goto unlock; | 1876 | goto unlock; |
1836 | 1877 | ||
@@ -2024,11 +2065,10 @@ static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table | |||
2024 | if (sk->sk_shutdown == SHUTDOWN_MASK) | 2065 | if (sk->sk_shutdown == SHUTDOWN_MASK) |
2025 | mask |= POLLHUP; | 2066 | mask |= POLLHUP; |
2026 | if (sk->sk_shutdown & RCV_SHUTDOWN) | 2067 | if (sk->sk_shutdown & RCV_SHUTDOWN) |
2027 | mask |= POLLRDHUP; | 2068 | mask |= POLLRDHUP | POLLIN | POLLRDNORM; |
2028 | 2069 | ||
2029 | /* readable? */ | 2070 | /* readable? */ |
2030 | if (!skb_queue_empty(&sk->sk_receive_queue) || | 2071 | if (!skb_queue_empty(&sk->sk_receive_queue)) |
2031 | (sk->sk_shutdown & RCV_SHUTDOWN)) | ||
2032 | mask |= POLLIN | POLLRDNORM; | 2072 | mask |= POLLIN | POLLRDNORM; |
2033 | 2073 | ||
2034 | /* Connection-based need to check for termination and startup */ | 2074 | /* Connection-based need to check for termination and startup */ |
diff --git a/net/unix/garbage.c b/net/unix/garbage.c index c8df6fda0b1f..f89f83bf828e 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c | |||
@@ -96,7 +96,7 @@ static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait); | |||
96 | unsigned int unix_tot_inflight; | 96 | unsigned int unix_tot_inflight; |
97 | 97 | ||
98 | 98 | ||
99 | static struct sock *unix_get_socket(struct file *filp) | 99 | struct sock *unix_get_socket(struct file *filp) |
100 | { | 100 | { |
101 | struct sock *u_sock = NULL; | 101 | struct sock *u_sock = NULL; |
102 | struct inode *inode = filp->f_path.dentry->d_inode; | 102 | struct inode *inode = filp->f_path.dentry->d_inode; |
@@ -259,9 +259,16 @@ static void inc_inflight_move_tail(struct unix_sock *u) | |||
259 | } | 259 | } |
260 | 260 | ||
261 | static bool gc_in_progress = false; | 261 | static bool gc_in_progress = false; |
262 | #define UNIX_INFLIGHT_TRIGGER_GC 16000 | ||
262 | 263 | ||
263 | void wait_for_unix_gc(void) | 264 | void wait_for_unix_gc(void) |
264 | { | 265 | { |
266 | /* | ||
267 | * If number of inflight sockets is insane, | ||
268 | * force a garbage collect right now. | ||
269 | */ | ||
270 | if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress) | ||
271 | unix_gc(); | ||
265 | wait_event(unix_gc_wait, gc_in_progress == false); | 272 | wait_event(unix_gc_wait, gc_in_progress == false); |
266 | } | 273 | } |
267 | 274 | ||