diff options
author | David S. Miller <davem@davemloft.net> | 2018-09-05 00:33:03 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2018-09-05 00:33:03 -0400 |
commit | 36302685f59345959de96d0d70a5ad20a3a3451b (patch) | |
tree | 778b3170acd1131840823520a4664f2bba343dbe /kernel/bpf/sockmap.c | |
parent | 2fc4aa59ab470f1d5124b33c05680e2b2f2c6f65 (diff) | |
parent | 28619527b8a712590c93d0a9e24b4425b9376a8c (diff) |
Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net
Diffstat (limited to 'kernel/bpf/sockmap.c')
-rw-r--r-- | kernel/bpf/sockmap.c | 64 |
1 files changed, 36 insertions, 28 deletions
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index cf5195c7c331..488ef9663c01 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c | |||
@@ -236,7 +236,7 @@ static int bpf_tcp_init(struct sock *sk) | |||
236 | } | 236 | } |
237 | 237 | ||
238 | static void smap_release_sock(struct smap_psock *psock, struct sock *sock); | 238 | static void smap_release_sock(struct smap_psock *psock, struct sock *sock); |
239 | static int free_start_sg(struct sock *sk, struct sk_msg_buff *md); | 239 | static int free_start_sg(struct sock *sk, struct sk_msg_buff *md, bool charge); |
240 | 240 | ||
241 | static void bpf_tcp_release(struct sock *sk) | 241 | static void bpf_tcp_release(struct sock *sk) |
242 | { | 242 | { |
@@ -248,7 +248,7 @@ static void bpf_tcp_release(struct sock *sk) | |||
248 | goto out; | 248 | goto out; |
249 | 249 | ||
250 | if (psock->cork) { | 250 | if (psock->cork) { |
251 | free_start_sg(psock->sock, psock->cork); | 251 | free_start_sg(psock->sock, psock->cork, true); |
252 | kfree(psock->cork); | 252 | kfree(psock->cork); |
253 | psock->cork = NULL; | 253 | psock->cork = NULL; |
254 | } | 254 | } |
@@ -330,14 +330,14 @@ static void bpf_tcp_close(struct sock *sk, long timeout) | |||
330 | close_fun = psock->save_close; | 330 | close_fun = psock->save_close; |
331 | 331 | ||
332 | if (psock->cork) { | 332 | if (psock->cork) { |
333 | free_start_sg(psock->sock, psock->cork); | 333 | free_start_sg(psock->sock, psock->cork, true); |
334 | kfree(psock->cork); | 334 | kfree(psock->cork); |
335 | psock->cork = NULL; | 335 | psock->cork = NULL; |
336 | } | 336 | } |
337 | 337 | ||
338 | list_for_each_entry_safe(md, mtmp, &psock->ingress, list) { | 338 | list_for_each_entry_safe(md, mtmp, &psock->ingress, list) { |
339 | list_del(&md->list); | 339 | list_del(&md->list); |
340 | free_start_sg(psock->sock, md); | 340 | free_start_sg(psock->sock, md, true); |
341 | kfree(md); | 341 | kfree(md); |
342 | } | 342 | } |
343 | 343 | ||
@@ -369,7 +369,7 @@ static void bpf_tcp_close(struct sock *sk, long timeout) | |||
369 | /* If another thread deleted this object skip deletion. | 369 | /* If another thread deleted this object skip deletion. |
370 | * The refcnt on psock may or may not be zero. | 370 | * The refcnt on psock may or may not be zero. |
371 | */ | 371 | */ |
372 | if (l) { | 372 | if (l && l == link) { |
373 | hlist_del_rcu(&link->hash_node); | 373 | hlist_del_rcu(&link->hash_node); |
374 | smap_release_sock(psock, link->sk); | 374 | smap_release_sock(psock, link->sk); |
375 | free_htab_elem(htab, link); | 375 | free_htab_elem(htab, link); |
@@ -570,14 +570,16 @@ static void free_bytes_sg(struct sock *sk, int bytes, | |||
570 | md->sg_start = i; | 570 | md->sg_start = i; |
571 | } | 571 | } |
572 | 572 | ||
573 | static int free_sg(struct sock *sk, int start, struct sk_msg_buff *md) | 573 | static int free_sg(struct sock *sk, int start, |
574 | struct sk_msg_buff *md, bool charge) | ||
574 | { | 575 | { |
575 | struct scatterlist *sg = md->sg_data; | 576 | struct scatterlist *sg = md->sg_data; |
576 | int i = start, free = 0; | 577 | int i = start, free = 0; |
577 | 578 | ||
578 | while (sg[i].length) { | 579 | while (sg[i].length) { |
579 | free += sg[i].length; | 580 | free += sg[i].length; |
580 | sk_mem_uncharge(sk, sg[i].length); | 581 | if (charge) |
582 | sk_mem_uncharge(sk, sg[i].length); | ||
581 | if (!md->skb) | 583 | if (!md->skb) |
582 | put_page(sg_page(&sg[i])); | 584 | put_page(sg_page(&sg[i])); |
583 | sg[i].length = 0; | 585 | sg[i].length = 0; |
@@ -594,9 +596,9 @@ static int free_sg(struct sock *sk, int start, struct sk_msg_buff *md) | |||
594 | return free; | 596 | return free; |
595 | } | 597 | } |
596 | 598 | ||
597 | static int free_start_sg(struct sock *sk, struct sk_msg_buff *md) | 599 | static int free_start_sg(struct sock *sk, struct sk_msg_buff *md, bool charge) |
598 | { | 600 | { |
599 | int free = free_sg(sk, md->sg_start, md); | 601 | int free = free_sg(sk, md->sg_start, md, charge); |
600 | 602 | ||
601 | md->sg_start = md->sg_end; | 603 | md->sg_start = md->sg_end; |
602 | return free; | 604 | return free; |
@@ -604,7 +606,7 @@ static int free_start_sg(struct sock *sk, struct sk_msg_buff *md) | |||
604 | 606 | ||
605 | static int free_curr_sg(struct sock *sk, struct sk_msg_buff *md) | 607 | static int free_curr_sg(struct sock *sk, struct sk_msg_buff *md) |
606 | { | 608 | { |
607 | return free_sg(sk, md->sg_curr, md); | 609 | return free_sg(sk, md->sg_curr, md, true); |
608 | } | 610 | } |
609 | 611 | ||
610 | static int bpf_map_msg_verdict(int _rc, struct sk_msg_buff *md) | 612 | static int bpf_map_msg_verdict(int _rc, struct sk_msg_buff *md) |
@@ -718,7 +720,7 @@ static int bpf_tcp_ingress(struct sock *sk, int apply_bytes, | |||
718 | list_add_tail(&r->list, &psock->ingress); | 720 | list_add_tail(&r->list, &psock->ingress); |
719 | sk->sk_data_ready(sk); | 721 | sk->sk_data_ready(sk); |
720 | } else { | 722 | } else { |
721 | free_start_sg(sk, r); | 723 | free_start_sg(sk, r, true); |
722 | kfree(r); | 724 | kfree(r); |
723 | } | 725 | } |
724 | 726 | ||
@@ -752,14 +754,10 @@ static int bpf_tcp_sendmsg_do_redirect(struct sock *sk, int send, | |||
752 | release_sock(sk); | 754 | release_sock(sk); |
753 | } | 755 | } |
754 | smap_release_sock(psock, sk); | 756 | smap_release_sock(psock, sk); |
755 | if (unlikely(err)) | 757 | return err; |
756 | goto out; | ||
757 | return 0; | ||
758 | out_rcu: | 758 | out_rcu: |
759 | rcu_read_unlock(); | 759 | rcu_read_unlock(); |
760 | out: | 760 | return 0; |
761 | free_bytes_sg(NULL, send, md, false); | ||
762 | return err; | ||
763 | } | 761 | } |
764 | 762 | ||
765 | static inline void bpf_md_init(struct smap_psock *psock) | 763 | static inline void bpf_md_init(struct smap_psock *psock) |
@@ -822,7 +820,7 @@ more_data: | |||
822 | case __SK_PASS: | 820 | case __SK_PASS: |
823 | err = bpf_tcp_push(sk, send, m, flags, true); | 821 | err = bpf_tcp_push(sk, send, m, flags, true); |
824 | if (unlikely(err)) { | 822 | if (unlikely(err)) { |
825 | *copied -= free_start_sg(sk, m); | 823 | *copied -= free_start_sg(sk, m, true); |
826 | break; | 824 | break; |
827 | } | 825 | } |
828 | 826 | ||
@@ -845,16 +843,17 @@ more_data: | |||
845 | lock_sock(sk); | 843 | lock_sock(sk); |
846 | 844 | ||
847 | if (unlikely(err < 0)) { | 845 | if (unlikely(err < 0)) { |
848 | free_start_sg(sk, m); | 846 | int free = free_start_sg(sk, m, false); |
847 | |||
849 | psock->sg_size = 0; | 848 | psock->sg_size = 0; |
850 | if (!cork) | 849 | if (!cork) |
851 | *copied -= send; | 850 | *copied -= free; |
852 | } else { | 851 | } else { |
853 | psock->sg_size -= send; | 852 | psock->sg_size -= send; |
854 | } | 853 | } |
855 | 854 | ||
856 | if (cork) { | 855 | if (cork) { |
857 | free_start_sg(sk, m); | 856 | free_start_sg(sk, m, true); |
858 | psock->sg_size = 0; | 857 | psock->sg_size = 0; |
859 | kfree(m); | 858 | kfree(m); |
860 | m = NULL; | 859 | m = NULL; |
@@ -912,6 +911,8 @@ static int bpf_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, | |||
912 | 911 | ||
913 | if (unlikely(flags & MSG_ERRQUEUE)) | 912 | if (unlikely(flags & MSG_ERRQUEUE)) |
914 | return inet_recv_error(sk, msg, len, addr_len); | 913 | return inet_recv_error(sk, msg, len, addr_len); |
914 | if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
915 | return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len); | ||
915 | 916 | ||
916 | rcu_read_lock(); | 917 | rcu_read_lock(); |
917 | psock = smap_psock_sk(sk); | 918 | psock = smap_psock_sk(sk); |
@@ -922,9 +923,6 @@ static int bpf_tcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, | |||
922 | goto out; | 923 | goto out; |
923 | rcu_read_unlock(); | 924 | rcu_read_unlock(); |
924 | 925 | ||
925 | if (!skb_queue_empty(&sk->sk_receive_queue)) | ||
926 | return tcp_recvmsg(sk, msg, len, nonblock, flags, addr_len); | ||
927 | |||
928 | lock_sock(sk); | 926 | lock_sock(sk); |
929 | bytes_ready: | 927 | bytes_ready: |
930 | while (copied != len) { | 928 | while (copied != len) { |
@@ -1122,7 +1120,7 @@ wait_for_memory: | |||
1122 | err = sk_stream_wait_memory(sk, &timeo); | 1120 | err = sk_stream_wait_memory(sk, &timeo); |
1123 | if (err) { | 1121 | if (err) { |
1124 | if (m && m != psock->cork) | 1122 | if (m && m != psock->cork) |
1125 | free_start_sg(sk, m); | 1123 | free_start_sg(sk, m, true); |
1126 | goto out_err; | 1124 | goto out_err; |
1127 | } | 1125 | } |
1128 | } | 1126 | } |
@@ -1464,10 +1462,16 @@ static void smap_destroy_psock(struct rcu_head *rcu) | |||
1464 | schedule_work(&psock->gc_work); | 1462 | schedule_work(&psock->gc_work); |
1465 | } | 1463 | } |
1466 | 1464 | ||
1465 | static bool psock_is_smap_sk(struct sock *sk) | ||
1466 | { | ||
1467 | return inet_csk(sk)->icsk_ulp_ops == &bpf_tcp_ulp_ops; | ||
1468 | } | ||
1469 | |||
1467 | static void smap_release_sock(struct smap_psock *psock, struct sock *sock) | 1470 | static void smap_release_sock(struct smap_psock *psock, struct sock *sock) |
1468 | { | 1471 | { |
1469 | if (refcount_dec_and_test(&psock->refcnt)) { | 1472 | if (refcount_dec_and_test(&psock->refcnt)) { |
1470 | tcp_cleanup_ulp(sock); | 1473 | if (psock_is_smap_sk(sock)) |
1474 | tcp_cleanup_ulp(sock); | ||
1471 | write_lock_bh(&sock->sk_callback_lock); | 1475 | write_lock_bh(&sock->sk_callback_lock); |
1472 | smap_stop_sock(psock, sock); | 1476 | smap_stop_sock(psock, sock); |
1473 | write_unlock_bh(&sock->sk_callback_lock); | 1477 | write_unlock_bh(&sock->sk_callback_lock); |
@@ -1581,13 +1585,13 @@ static void smap_gc_work(struct work_struct *w) | |||
1581 | bpf_prog_put(psock->bpf_tx_msg); | 1585 | bpf_prog_put(psock->bpf_tx_msg); |
1582 | 1586 | ||
1583 | if (psock->cork) { | 1587 | if (psock->cork) { |
1584 | free_start_sg(psock->sock, psock->cork); | 1588 | free_start_sg(psock->sock, psock->cork, true); |
1585 | kfree(psock->cork); | 1589 | kfree(psock->cork); |
1586 | } | 1590 | } |
1587 | 1591 | ||
1588 | list_for_each_entry_safe(md, mtmp, &psock->ingress, list) { | 1592 | list_for_each_entry_safe(md, mtmp, &psock->ingress, list) { |
1589 | list_del(&md->list); | 1593 | list_del(&md->list); |
1590 | free_start_sg(psock->sock, md); | 1594 | free_start_sg(psock->sock, md, true); |
1591 | kfree(md); | 1595 | kfree(md); |
1592 | } | 1596 | } |
1593 | 1597 | ||
@@ -1894,6 +1898,10 @@ static int __sock_map_ctx_update_elem(struct bpf_map *map, | |||
1894 | * doesn't update user data. | 1898 | * doesn't update user data. |
1895 | */ | 1899 | */ |
1896 | if (psock) { | 1900 | if (psock) { |
1901 | if (!psock_is_smap_sk(sock)) { | ||
1902 | err = -EBUSY; | ||
1903 | goto out_progs; | ||
1904 | } | ||
1897 | if (READ_ONCE(psock->bpf_parse) && parse) { | 1905 | if (READ_ONCE(psock->bpf_parse) && parse) { |
1898 | err = -EBUSY; | 1906 | err = -EBUSY; |
1899 | goto out_progs; | 1907 | goto out_progs; |