diff options
author | Hannes Frederic Sowa <hannes@stressinduktion.org> | 2015-05-21 11:00:00 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2015-05-25 00:06:59 -0400 |
commit | a60e3cc7c92973a31fad0fd04dc5cf4355d3d1ef (patch) | |
tree | fccece19424d49db1c03ef8f204f3c7ca3478a4a | |
parent | 869e7c62486ec0e170a9771acaa251d1a33b5871 (diff) |
net: make skb_splice_bits more configureable
Prepare skb_splice_bits to be able to deal with AF_UNIX sockets.
AF_UNIX sockets don't use lock_sock/release_sock and thus we have to
use a callback to make the locking and unlocking configureable.
Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org>
Acked-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | include/linux/skbuff.h | 11 | ||||
-rw-r--r-- | net/core/skbuff.c | 45 | ||||
-rw-r--r-- | net/ipv4/tcp.c | 5 |
3 files changed, 40 insertions, 21 deletions
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index f708936cdd23..6b41c15efa27 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h | |||
@@ -35,6 +35,7 @@ | |||
35 | #include <linux/netdev_features.h> | 35 | #include <linux/netdev_features.h> |
36 | #include <linux/sched.h> | 36 | #include <linux/sched.h> |
37 | #include <net/flow_dissector.h> | 37 | #include <net/flow_dissector.h> |
38 | #include <linux/splice.h> | ||
38 | 39 | ||
39 | /* A. Checksumming of received packets by device. | 40 | /* A. Checksumming of received packets by device. |
40 | * | 41 | * |
@@ -2699,9 +2700,15 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); | |||
2699 | int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len); | 2700 | int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len); |
2700 | __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, | 2701 | __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, |
2701 | int len, __wsum csum); | 2702 | int len, __wsum csum); |
2702 | int skb_splice_bits(struct sk_buff *skb, unsigned int offset, | 2703 | ssize_t skb_socket_splice(struct sock *sk, |
2704 | struct pipe_inode_info *pipe, | ||
2705 | struct splice_pipe_desc *spd); | ||
2706 | int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, | ||
2703 | struct pipe_inode_info *pipe, unsigned int len, | 2707 | struct pipe_inode_info *pipe, unsigned int len, |
2704 | unsigned int flags); | 2708 | unsigned int flags, |
2709 | ssize_t (*splice_cb)(struct sock *, | ||
2710 | struct pipe_inode_info *, | ||
2711 | struct splice_pipe_desc *)); | ||
2705 | void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); | 2712 | void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); |
2706 | unsigned int skb_zerocopy_headlen(const struct sk_buff *from); | 2713 | unsigned int skb_zerocopy_headlen(const struct sk_buff *from); |
2707 | int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, | 2714 | int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 4f2babeaf18d..02769fa4f5c8 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -1870,15 +1870,39 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe, | |||
1870 | return false; | 1870 | return false; |
1871 | } | 1871 | } |
1872 | 1872 | ||
1873 | ssize_t skb_socket_splice(struct sock *sk, | ||
1874 | struct pipe_inode_info *pipe, | ||
1875 | struct splice_pipe_desc *spd) | ||
1876 | { | ||
1877 | int ret; | ||
1878 | |||
1879 | /* Drop the socket lock, otherwise we have reverse | ||
1880 | * locking dependencies between sk_lock and i_mutex | ||
1881 | * here as compared to sendfile(). We enter here | ||
1882 | * with the socket lock held, and splice_to_pipe() will | ||
1883 | * grab the pipe inode lock. For sendfile() emulation, | ||
1884 | * we call into ->sendpage() with the i_mutex lock held | ||
1885 | * and networking will grab the socket lock. | ||
1886 | */ | ||
1887 | release_sock(sk); | ||
1888 | ret = splice_to_pipe(pipe, spd); | ||
1889 | lock_sock(sk); | ||
1890 | |||
1891 | return ret; | ||
1892 | } | ||
1893 | |||
1873 | /* | 1894 | /* |
1874 | * Map data from the skb to a pipe. Should handle both the linear part, | 1895 | * Map data from the skb to a pipe. Should handle both the linear part, |
1875 | * the fragments, and the frag list. It does NOT handle frag lists within | 1896 | * the fragments, and the frag list. It does NOT handle frag lists within |
1876 | * the frag list, if such a thing exists. We'd probably need to recurse to | 1897 | * the frag list, if such a thing exists. We'd probably need to recurse to |
1877 | * handle that cleanly. | 1898 | * handle that cleanly. |
1878 | */ | 1899 | */ |
1879 | int skb_splice_bits(struct sk_buff *skb, unsigned int offset, | 1900 | int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset, |
1880 | struct pipe_inode_info *pipe, unsigned int tlen, | 1901 | struct pipe_inode_info *pipe, unsigned int tlen, |
1881 | unsigned int flags) | 1902 | unsigned int flags, |
1903 | ssize_t (*splice_cb)(struct sock *, | ||
1904 | struct pipe_inode_info *, | ||
1905 | struct splice_pipe_desc *)) | ||
1882 | { | 1906 | { |
1883 | struct partial_page partial[MAX_SKB_FRAGS]; | 1907 | struct partial_page partial[MAX_SKB_FRAGS]; |
1884 | struct page *pages[MAX_SKB_FRAGS]; | 1908 | struct page *pages[MAX_SKB_FRAGS]; |
@@ -1891,7 +1915,6 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, | |||
1891 | .spd_release = sock_spd_release, | 1915 | .spd_release = sock_spd_release, |
1892 | }; | 1916 | }; |
1893 | struct sk_buff *frag_iter; | 1917 | struct sk_buff *frag_iter; |
1894 | struct sock *sk = skb->sk; | ||
1895 | int ret = 0; | 1918 | int ret = 0; |
1896 | 1919 | ||
1897 | /* | 1920 | /* |
@@ -1914,20 +1937,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, | |||
1914 | } | 1937 | } |
1915 | 1938 | ||
1916 | done: | 1939 | done: |
1917 | if (spd.nr_pages) { | 1940 | if (spd.nr_pages) |
1918 | /* | 1941 | ret = splice_cb(sk, pipe, &spd); |
1919 | * Drop the socket lock, otherwise we have reverse | ||
1920 | * locking dependencies between sk_lock and i_mutex | ||
1921 | * here as compared to sendfile(). We enter here | ||
1922 | * with the socket lock held, and splice_to_pipe() will | ||
1923 | * grab the pipe inode lock. For sendfile() emulation, | ||
1924 | * we call into ->sendpage() with the i_mutex lock held | ||
1925 | * and networking will grab the socket lock. | ||
1926 | */ | ||
1927 | release_sock(sk); | ||
1928 | ret = splice_to_pipe(pipe, &spd); | ||
1929 | lock_sock(sk); | ||
1930 | } | ||
1931 | 1942 | ||
1932 | return ret; | 1943 | return ret; |
1933 | } | 1944 | } |
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 90afcec3f427..65f791f74845 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c | |||
@@ -695,8 +695,9 @@ static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, | |||
695 | struct tcp_splice_state *tss = rd_desc->arg.data; | 695 | struct tcp_splice_state *tss = rd_desc->arg.data; |
696 | int ret; | 696 | int ret; |
697 | 697 | ||
698 | ret = skb_splice_bits(skb, offset, tss->pipe, min(rd_desc->count, len), | 698 | ret = skb_splice_bits(skb, skb->sk, offset, tss->pipe, |
699 | tss->flags); | 699 | min(rd_desc->count, len), tss->flags, |
700 | skb_socket_splice); | ||
700 | if (ret > 0) | 701 | if (ret > 0) |
701 | rd_desc->count -= ret; | 702 | rd_desc->count -= ret; |
702 | return ret; | 703 | return ret; |