Commit a60e3cc7 authored by Hannes Frederic Sowa's avatar Hannes Frederic Sowa Committed by David S. Miller

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: default avatarHannes Frederic Sowa <hannes@stressinduktion.org>
Acked-by: default avatarEric Dumazet <edumazet@google.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 869e7c62
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#include <linux/netdev_features.h> #include <linux/netdev_features.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <net/flow_dissector.h> #include <net/flow_dissector.h>
#include <linux/splice.h>
/* A. Checksumming of received packets by device. /* A. Checksumming of received packets by device.
* *
...@@ -2699,9 +2700,15 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len); ...@@ -2699,9 +2700,15 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len); int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
__wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to, __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
int len, __wsum csum); int len, __wsum csum);
int skb_splice_bits(struct sk_buff *skb, unsigned int offset, ssize_t skb_socket_splice(struct sock *sk,
struct pipe_inode_info *pipe,
struct splice_pipe_desc *spd);
int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
struct pipe_inode_info *pipe, unsigned int len, struct pipe_inode_info *pipe, unsigned int len,
unsigned int flags); unsigned int flags,
ssize_t (*splice_cb)(struct sock *,
struct pipe_inode_info *,
struct splice_pipe_desc *));
void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
unsigned int skb_zerocopy_headlen(const struct sk_buff *from); unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
int skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
......
...@@ -1870,15 +1870,39 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe, ...@@ -1870,15 +1870,39 @@ static bool __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe,
return false; return false;
} }
ssize_t skb_socket_splice(struct sock *sk,
struct pipe_inode_info *pipe,
struct splice_pipe_desc *spd)
{
int ret;
/* Drop the socket lock, otherwise we have reverse
* locking dependencies between sk_lock and i_mutex
* here as compared to sendfile(). We enter here
* with the socket lock held, and splice_to_pipe() will
* grab the pipe inode lock. For sendfile() emulation,
* we call into ->sendpage() with the i_mutex lock held
* and networking will grab the socket lock.
*/
release_sock(sk);
ret = splice_to_pipe(pipe, spd);
lock_sock(sk);
return ret;
}
/* /*
* Map data from the skb to a pipe. Should handle both the linear part, * Map data from the skb to a pipe. Should handle both the linear part,
* the fragments, and the frag list. It does NOT handle frag lists within * the fragments, and the frag list. It does NOT handle frag lists within
* the frag list, if such a thing exists. We'd probably need to recurse to * the frag list, if such a thing exists. We'd probably need to recurse to
* handle that cleanly. * handle that cleanly.
*/ */
int skb_splice_bits(struct sk_buff *skb, unsigned int offset, int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
struct pipe_inode_info *pipe, unsigned int tlen, struct pipe_inode_info *pipe, unsigned int tlen,
unsigned int flags) unsigned int flags,
ssize_t (*splice_cb)(struct sock *,
struct pipe_inode_info *,
struct splice_pipe_desc *))
{ {
struct partial_page partial[MAX_SKB_FRAGS]; struct partial_page partial[MAX_SKB_FRAGS];
struct page *pages[MAX_SKB_FRAGS]; struct page *pages[MAX_SKB_FRAGS];
...@@ -1891,7 +1915,6 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, ...@@ -1891,7 +1915,6 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
.spd_release = sock_spd_release, .spd_release = sock_spd_release,
}; };
struct sk_buff *frag_iter; struct sk_buff *frag_iter;
struct sock *sk = skb->sk;
int ret = 0; int ret = 0;
/* /*
...@@ -1914,20 +1937,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset, ...@@ -1914,20 +1937,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,
} }
done: done:
if (spd.nr_pages) { if (spd.nr_pages)
/* ret = splice_cb(sk, pipe, &spd);
* Drop the socket lock, otherwise we have reverse
* locking dependencies between sk_lock and i_mutex
* here as compared to sendfile(). We enter here
* with the socket lock held, and splice_to_pipe() will
* grab the pipe inode lock. For sendfile() emulation,
* we call into ->sendpage() with the i_mutex lock held
* and networking will grab the socket lock.
*/
release_sock(sk);
ret = splice_to_pipe(pipe, &spd);
lock_sock(sk);
}
return ret; return ret;
} }
......
...@@ -695,8 +695,9 @@ static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, ...@@ -695,8 +695,9 @@ static int tcp_splice_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb,
struct tcp_splice_state *tss = rd_desc->arg.data; struct tcp_splice_state *tss = rd_desc->arg.data;
int ret; int ret;
ret = skb_splice_bits(skb, offset, tss->pipe, min(rd_desc->count, len), ret = skb_splice_bits(skb, skb->sk, offset, tss->pipe,
tss->flags); min(rd_desc->count, len), tss->flags,
skb_socket_splice);
if (ret > 0) if (ret > 0)
rd_desc->count -= ret; rd_desc->count -= ret;
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment