Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+9 −2
Original line number Original line Diff line number Diff line
@@ -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);
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,
+28 −17
Original line number Original line Diff line number Diff line
@@ -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,
		.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,
	}
	}


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;
}
}
+3 −2
Original line number Original line Diff line number Diff line
@@ -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;