diff options
author | David S. Miller <davem@davemloft.net> | 2010-12-08 16:15:38 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-12-08 16:47:38 -0500 |
commit | fe6c791570efe717946ea7b7dd50aec96b70d551 (patch) | |
tree | 1becb5e8aea7a9c9a7d78f987bd73b0a5d8ee434 /net/unix | |
parent | f8bf5681cf15f77692c8ad8cb95d059ff7c622c9 (diff) | |
parent | f19872575ff7819a3723154657a497d9bca66b33 (diff) |
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
Conflicts:
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
net/llc/af_llc.c
Diffstat (limited to 'net/unix')
-rw-r--r-- | net/unix/af_unix.c | 37 | ||||
-rw-r--r-- | net/unix/garbage.c | 9 |
2 files changed, 40 insertions, 6 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 7ff31c60186a..417d7a6c36cf 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -1344,9 +1344,25 @@ static void unix_destruct_scm(struct sk_buff *skb) | |||
1344 | sock_wfree(skb); | 1344 | sock_wfree(skb); |
1345 | } | 1345 | } |
1346 | 1346 | ||
1347 | #define MAX_RECURSION_LEVEL 4 | ||
1348 | |||
1347 | static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) | 1349 | static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) |
1348 | { | 1350 | { |
1349 | int i; | 1351 | int i; |
1352 | unsigned char max_level = 0; | ||
1353 | int unix_sock_count = 0; | ||
1354 | |||
1355 | for (i = scm->fp->count - 1; i >= 0; i--) { | ||
1356 | struct sock *sk = unix_get_socket(scm->fp->fp[i]); | ||
1357 | |||
1358 | if (sk) { | ||
1359 | unix_sock_count++; | ||
1360 | max_level = max(max_level, | ||
1361 | unix_sk(sk)->recursion_level); | ||
1362 | } | ||
1363 | } | ||
1364 | if (unlikely(max_level > MAX_RECURSION_LEVEL)) | ||
1365 | return -ETOOMANYREFS; | ||
1350 | 1366 | ||
1351 | /* | 1367 | /* |
1352 | * Need to duplicate file references for the sake of garbage | 1368 | * Need to duplicate file references for the sake of garbage |
@@ -1357,9 +1373,11 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) | |||
1357 | if (!UNIXCB(skb).fp) | 1373 | if (!UNIXCB(skb).fp) |
1358 | return -ENOMEM; | 1374 | return -ENOMEM; |
1359 | 1375 | ||
1360 | for (i = scm->fp->count-1; i >= 0; i--) | 1376 | if (unix_sock_count) { |
1361 | unix_inflight(scm->fp->fp[i]); | 1377 | for (i = scm->fp->count - 1; i >= 0; i--) |
1362 | return 0; | 1378 | unix_inflight(scm->fp->fp[i]); |
1379 | } | ||
1380 | return max_level; | ||
1363 | } | 1381 | } |
1364 | 1382 | ||
1365 | static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) | 1383 | static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds) |
@@ -1394,6 +1412,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1394 | struct sk_buff *skb; | 1412 | struct sk_buff *skb; |
1395 | long timeo; | 1413 | long timeo; |
1396 | struct scm_cookie tmp_scm; | 1414 | struct scm_cookie tmp_scm; |
1415 | int max_level; | ||
1397 | 1416 | ||
1398 | if (NULL == siocb->scm) | 1417 | if (NULL == siocb->scm) |
1399 | siocb->scm = &tmp_scm; | 1418 | siocb->scm = &tmp_scm; |
@@ -1432,8 +1451,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1432 | goto out; | 1451 | goto out; |
1433 | 1452 | ||
1434 | err = unix_scm_to_skb(siocb->scm, skb, true); | 1453 | err = unix_scm_to_skb(siocb->scm, skb, true); |
1435 | if (err) | 1454 | if (err < 0) |
1436 | goto out_free; | 1455 | goto out_free; |
1456 | max_level = err + 1; | ||
1437 | unix_get_secdata(siocb->scm, skb); | 1457 | unix_get_secdata(siocb->scm, skb); |
1438 | 1458 | ||
1439 | skb_reset_transport_header(skb); | 1459 | skb_reset_transport_header(skb); |
@@ -1515,6 +1535,8 @@ restart: | |||
1515 | if (sock_flag(other, SOCK_RCVTSTAMP)) | 1535 | if (sock_flag(other, SOCK_RCVTSTAMP)) |
1516 | __net_timestamp(skb); | 1536 | __net_timestamp(skb); |
1517 | skb_queue_tail(&other->sk_receive_queue, skb); | 1537 | skb_queue_tail(&other->sk_receive_queue, skb); |
1538 | if (max_level > unix_sk(other)->recursion_level) | ||
1539 | unix_sk(other)->recursion_level = max_level; | ||
1518 | unix_state_unlock(other); | 1540 | unix_state_unlock(other); |
1519 | other->sk_data_ready(other, len); | 1541 | other->sk_data_ready(other, len); |
1520 | sock_put(other); | 1542 | sock_put(other); |
@@ -1545,6 +1567,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1545 | int sent = 0; | 1567 | int sent = 0; |
1546 | struct scm_cookie tmp_scm; | 1568 | struct scm_cookie tmp_scm; |
1547 | bool fds_sent = false; | 1569 | bool fds_sent = false; |
1570 | int max_level; | ||
1548 | 1571 | ||
1549 | if (NULL == siocb->scm) | 1572 | if (NULL == siocb->scm) |
1550 | siocb->scm = &tmp_scm; | 1573 | siocb->scm = &tmp_scm; |
@@ -1608,10 +1631,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1608 | 1631 | ||
1609 | /* Only send the fds in the first buffer */ | 1632 | /* Only send the fds in the first buffer */ |
1610 | err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); | 1633 | err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); |
1611 | if (err) { | 1634 | if (err < 0) { |
1612 | kfree_skb(skb); | 1635 | kfree_skb(skb); |
1613 | goto out_err; | 1636 | goto out_err; |
1614 | } | 1637 | } |
1638 | max_level = err + 1; | ||
1615 | fds_sent = true; | 1639 | fds_sent = true; |
1616 | 1640 | ||
1617 | err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); | 1641 | err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); |
@@ -1627,6 +1651,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1627 | goto pipe_err_free; | 1651 | goto pipe_err_free; |
1628 | 1652 | ||
1629 | skb_queue_tail(&other->sk_receive_queue, skb); | 1653 | skb_queue_tail(&other->sk_receive_queue, skb); |
1654 | if (max_level > unix_sk(other)->recursion_level) | ||
1655 | unix_sk(other)->recursion_level = max_level; | ||
1630 | unix_state_unlock(other); | 1656 | unix_state_unlock(other); |
1631 | other->sk_data_ready(other, size); | 1657 | other->sk_data_ready(other, size); |
1632 | sent += size; | 1658 | sent += size; |
@@ -1847,6 +1873,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | |||
1847 | unix_state_lock(sk); | 1873 | unix_state_lock(sk); |
1848 | skb = skb_dequeue(&sk->sk_receive_queue); | 1874 | skb = skb_dequeue(&sk->sk_receive_queue); |
1849 | if (skb == NULL) { | 1875 | if (skb == NULL) { |
1876 | unix_sk(sk)->recursion_level = 0; | ||
1850 | if (copied >= target) | 1877 | if (copied >= target) |
1851 | goto unlock; | 1878 | goto unlock; |
1852 | 1879 | ||
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 | ||