Commit 2e674381 authored by David S. Miller's avatar David S. Miller

Merge branch 'kzproxy-next'

Tom Herbert says:

====================
net: Infrastructure changes for [kz]proxy

This patch set contains some general infrastructure enhancements that
will be used by kernel proxy and zero proxy.

The changes are:
  - proto_ops: Add locked versions of sendmsg and sendpage
  - skb_send_sock: Allow sending and skb on a socket within the
    kernel
  - Generalize strparser. Allow it to be used in other contexts than
    just in the read_sock path. This will be used in the transmit
    path of zero proxy.

Some nice future work (which I've been discussing with John Fastabend)
will be to make some of the related functions to allow gifting of skbs
We should be able to do that with skb_send_sock and strp_process. I'd
also like this feature in the read_sock callbeck.

Tested: Ran modified kernel without incident. Tested new functionality
using zero proxy (in development).
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 29fda25a bbb03029
This diff is collapsed.
......@@ -190,8 +190,16 @@ struct proto_ops {
struct pipe_inode_info *pipe, size_t len, unsigned int flags);
int (*set_peek_off)(struct sock *sk, int val);
int (*peek_len)(struct socket *sock);
/* The following functions are called internally by kernel with
* sock lock already held.
*/
int (*read_sock)(struct sock *sk, read_descriptor_t *desc,
sk_read_actor_t recv_actor);
int (*sendpage_locked)(struct sock *sk, struct page *page,
int offset, size_t size, int flags);
int (*sendmsg_locked)(struct sock *sk, struct msghdr *msg,
size_t size);
};
#define DECLARE_SOCKADDR(type, dst, src) \
......@@ -279,6 +287,8 @@ do { \
int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
size_t num, size_t len);
int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
struct kvec *vec, size_t num, size_t len);
int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
size_t num, size_t len, int flags);
......@@ -297,6 +307,8 @@ int kernel_setsockopt(struct socket *sock, int level, int optname, char *optval,
unsigned int optlen);
int kernel_sendpage(struct socket *sock, struct page *page, int offset,
size_t size, int flags);
int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset,
size_t size, int flags);
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg);
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how);
......
......@@ -3113,6 +3113,9 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset, u8 *to,
int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
struct pipe_inode_info *pipe, unsigned int len,
unsigned int flags);
int skb_send_sock_locked(struct sock *sk, struct sk_buff *skb, int offset,
int len);
int skb_send_sock(struct sock *sk, struct sk_buff *skb, int offset, int len);
void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to);
unsigned int skb_zerocopy_headlen(const struct sk_buff *from);
int skb_zerocopy(struct sk_buff *to, struct sk_buff *from,
......
......@@ -1582,11 +1582,14 @@ int sock_no_shutdown(struct socket *, int);
int sock_no_getsockopt(struct socket *, int , int, char __user *, int __user *);
int sock_no_setsockopt(struct socket *, int, int, char __user *, unsigned int);
int sock_no_sendmsg(struct socket *, struct msghdr *, size_t);
int sock_no_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t len);
int sock_no_recvmsg(struct socket *, struct msghdr *, size_t, int);
int sock_no_mmap(struct file *file, struct socket *sock,
struct vm_area_struct *vma);
ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset,
size_t size, int flags);
ssize_t sock_no_sendpage_locked(struct sock *sk, struct page *page,
int offset, size_t size, int flags);
/*
* Functions to fill in entries in struct proto_ops when a protocol
......
......@@ -18,26 +18,26 @@
#define STRP_STATS_INCR(stat) ((stat)++)
struct strp_stats {
unsigned long long rx_msgs;
unsigned long long rx_bytes;
unsigned int rx_mem_fail;
unsigned int rx_need_more_hdr;
unsigned int rx_msg_too_big;
unsigned int rx_msg_timeouts;
unsigned int rx_bad_hdr_len;
unsigned long long msgs;
unsigned long long bytes;
unsigned int mem_fail;
unsigned int need_more_hdr;
unsigned int msg_too_big;
unsigned int msg_timeouts;
unsigned int bad_hdr_len;
};
struct strp_aggr_stats {
unsigned long long rx_msgs;
unsigned long long rx_bytes;
unsigned int rx_mem_fail;
unsigned int rx_need_more_hdr;
unsigned int rx_msg_too_big;
unsigned int rx_msg_timeouts;
unsigned int rx_bad_hdr_len;
unsigned int rx_aborts;
unsigned int rx_interrupted;
unsigned int rx_unrecov_intr;
unsigned long long msgs;
unsigned long long bytes;
unsigned int mem_fail;
unsigned int need_more_hdr;
unsigned int msg_too_big;
unsigned int msg_timeouts;
unsigned int bad_hdr_len;
unsigned int aborts;
unsigned int interrupted;
unsigned int unrecov_intr;
};
struct strparser;
......@@ -48,16 +48,18 @@ struct strp_callbacks {
void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb);
int (*read_sock_done)(struct strparser *strp, int err);
void (*abort_parser)(struct strparser *strp, int err);
void (*lock)(struct strparser *strp);
void (*unlock)(struct strparser *strp);
};
struct strp_rx_msg {
struct strp_msg {
int full_len;
int offset;
};
static inline struct strp_rx_msg *strp_rx_msg(struct sk_buff *skb)
static inline struct strp_msg *strp_msg(struct sk_buff *skb)
{
return (struct strp_rx_msg *)((void *)skb->cb +
return (struct strp_msg *)((void *)skb->cb +
offsetof(struct qdisc_skb_cb, data));
}
......@@ -65,18 +67,18 @@ static inline struct strp_rx_msg *strp_rx_msg(struct sk_buff *skb)
struct strparser {
struct sock *sk;
u32 rx_stopped : 1;
u32 rx_paused : 1;
u32 rx_aborted : 1;
u32 rx_interrupted : 1;
u32 rx_unrecov_intr : 1;
struct sk_buff **rx_skb_nextp;
struct timer_list rx_msg_timer;
struct sk_buff *rx_skb_head;
unsigned int rx_need_bytes;
struct delayed_work rx_delayed_work;
struct work_struct rx_work;
u32 stopped : 1;
u32 paused : 1;
u32 aborted : 1;
u32 interrupted : 1;
u32 unrecov_intr : 1;
struct sk_buff **skb_nextp;
struct timer_list msg_timer;
struct sk_buff *skb_head;
unsigned int need_bytes;
struct delayed_work delayed_work;
struct work_struct work;
struct strp_stats stats;
struct strp_callbacks cb;
};
......@@ -84,7 +86,7 @@ struct strparser {
/* Must be called with lock held for attached socket */
static inline void strp_pause(struct strparser *strp)
{
strp->rx_paused = 1;
strp->paused = 1;
}
/* May be called without holding lock for attached socket */
......@@ -97,37 +99,37 @@ static inline void save_strp_stats(struct strparser *strp,
#define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += \
strp->stats._stat)
SAVE_PSOCK_STATS(rx_msgs);
SAVE_PSOCK_STATS(rx_bytes);
SAVE_PSOCK_STATS(rx_mem_fail);
SAVE_PSOCK_STATS(rx_need_more_hdr);
SAVE_PSOCK_STATS(rx_msg_too_big);
SAVE_PSOCK_STATS(rx_msg_timeouts);
SAVE_PSOCK_STATS(rx_bad_hdr_len);
SAVE_PSOCK_STATS(msgs);
SAVE_PSOCK_STATS(bytes);
SAVE_PSOCK_STATS(mem_fail);
SAVE_PSOCK_STATS(need_more_hdr);
SAVE_PSOCK_STATS(msg_too_big);
SAVE_PSOCK_STATS(msg_timeouts);
SAVE_PSOCK_STATS(bad_hdr_len);
#undef SAVE_PSOCK_STATS
if (strp->rx_aborted)
agg_stats->rx_aborts++;
if (strp->rx_interrupted)
agg_stats->rx_interrupted++;
if (strp->rx_unrecov_intr)
agg_stats->rx_unrecov_intr++;
if (strp->aborted)
agg_stats->aborts++;
if (strp->interrupted)
agg_stats->interrupted++;
if (strp->unrecov_intr)
agg_stats->unrecov_intr++;
}
static inline void aggregate_strp_stats(struct strp_aggr_stats *stats,
struct strp_aggr_stats *agg_stats)
{
#define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += stats->_stat)
SAVE_PSOCK_STATS(rx_msgs);
SAVE_PSOCK_STATS(rx_bytes);
SAVE_PSOCK_STATS(rx_mem_fail);
SAVE_PSOCK_STATS(rx_need_more_hdr);
SAVE_PSOCK_STATS(rx_msg_too_big);
SAVE_PSOCK_STATS(rx_msg_timeouts);
SAVE_PSOCK_STATS(rx_bad_hdr_len);
SAVE_PSOCK_STATS(rx_aborts);
SAVE_PSOCK_STATS(rx_interrupted);
SAVE_PSOCK_STATS(rx_unrecov_intr);
SAVE_PSOCK_STATS(msgs);
SAVE_PSOCK_STATS(bytes);
SAVE_PSOCK_STATS(mem_fail);
SAVE_PSOCK_STATS(need_more_hdr);
SAVE_PSOCK_STATS(msg_too_big);
SAVE_PSOCK_STATS(msg_timeouts);
SAVE_PSOCK_STATS(bad_hdr_len);
SAVE_PSOCK_STATS(aborts);
SAVE_PSOCK_STATS(interrupted);
SAVE_PSOCK_STATS(unrecov_intr);
#undef SAVE_PSOCK_STATS
}
......@@ -135,8 +137,11 @@ static inline void aggregate_strp_stats(struct strp_aggr_stats *stats,
void strp_done(struct strparser *strp);
void strp_stop(struct strparser *strp);
void strp_check_rcv(struct strparser *strp);
int strp_init(struct strparser *strp, struct sock *csk,
int strp_init(struct strparser *strp, struct sock *sk,
struct strp_callbacks *cb);
void strp_data_ready(struct strparser *strp);
int strp_process(struct strparser *strp, struct sk_buff *orig_skb,
unsigned int orig_offset, size_t orig_len,
size_t max_msg_size, long timeo);
#endif /* __NET_STRPARSER_H_ */
......@@ -350,8 +350,11 @@ int tcp_v4_rcv(struct sk_buff *skb);
int tcp_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size);
int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size);
int tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
int flags);
int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset,
size_t size, int flags);
ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
size_t size, int flags);
void tcp_release_cb(struct sock *sk);
......
......@@ -1982,6 +1982,107 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
}
EXPORT_SYMBOL_GPL(skb_splice_bits);
/* Send skb data on a socket. Socket must be locked. */
int skb_send_sock_locked(struct sock *sk, struct sk_buff *skb, int offset,
int len)
{
unsigned int orig_len = len;
struct sk_buff *head = skb;
unsigned short fragidx;
int slen, ret;
do_frag_list:
/* Deal with head data */
while (offset < skb_headlen(skb) && len) {
struct kvec kv;
struct msghdr msg;
slen = min_t(int, len, skb_headlen(skb) - offset);
kv.iov_base = skb->data + offset;
kv.iov_len = len;
memset(&msg, 0, sizeof(msg));
ret = kernel_sendmsg_locked(sk, &msg, &kv, 1, slen);
if (ret <= 0)
goto error;
offset += ret;
len -= ret;
}
/* All the data was skb head? */
if (!len)
goto out;
/* Make offset relative to start of frags */
offset -= skb_headlen(skb);
/* Find where we are in frag list */
for (fragidx = 0; fragidx < skb_shinfo(skb)->nr_frags; fragidx++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[fragidx];
if (offset < frag->size)
break;
offset -= frag->size;
}
for (; len && fragidx < skb_shinfo(skb)->nr_frags; fragidx++) {
skb_frag_t *frag = &skb_shinfo(skb)->frags[fragidx];
slen = min_t(size_t, len, frag->size - offset);
while (slen) {
ret = kernel_sendpage_locked(sk, frag->page.p,
frag->page_offset + offset,
slen, MSG_DONTWAIT);
if (ret <= 0)
goto error;
len -= ret;
offset += ret;
slen -= ret;
}
offset = 0;
}
if (len) {
/* Process any frag lists */
if (skb == head) {
if (skb_has_frag_list(skb)) {
skb = skb_shinfo(skb)->frag_list;
goto do_frag_list;
}
} else if (skb->next) {
skb = skb->next;
goto do_frag_list;
}
}
out:
return orig_len - len;
error:
return orig_len == len ? ret : orig_len - len;
}
EXPORT_SYMBOL_GPL(skb_send_sock_locked);
/* Send skb data on a socket. */
int skb_send_sock(struct sock *sk, struct sk_buff *skb, int offset, int len)
{
int ret = 0;
lock_sock(sk);
ret = skb_send_sock_locked(sk, skb, offset, len);
release_sock(sk);
return ret;
}
EXPORT_SYMBOL_GPL(skb_send_sock);
/**
* skb_store_bits - store bits from kernel buffer to skb
* @skb: destination buffer
......
......@@ -2500,6 +2500,12 @@ int sock_no_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
}
EXPORT_SYMBOL(sock_no_sendmsg);
int sock_no_sendmsg_locked(struct sock *sk, struct msghdr *m, size_t len)
{
return -EOPNOTSUPP;
}
EXPORT_SYMBOL(sock_no_sendmsg_locked);
int sock_no_recvmsg(struct socket *sock, struct msghdr *m, size_t len,
int flags)
{
......@@ -2528,6 +2534,22 @@ ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, siz
}
EXPORT_SYMBOL(sock_no_sendpage);
ssize_t sock_no_sendpage_locked(struct sock *sk, struct page *page,
int offset, size_t size, int flags)
{
ssize_t res;
struct msghdr msg = {.msg_flags = flags};
struct kvec iov;
char *kaddr = kmap(page);
iov.iov_base = kaddr + offset;
iov.iov_len = size;
res = kernel_sendmsg_locked(sk, &msg, &iov, 1, size);
kunmap(page);
return res;
}
EXPORT_SYMBOL(sock_no_sendpage_locked);
/*
* Default Socket Callbacks
*/
......
......@@ -944,6 +944,8 @@ const struct proto_ops inet_stream_ops = {
.sendpage = inet_sendpage,
.splice_read = tcp_splice_read,
.read_sock = tcp_read_sock,
.sendmsg_locked = tcp_sendmsg_locked,
.sendpage_locked = tcp_sendpage_locked,
.peek_len = tcp_peek_len,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt,
......
......@@ -1046,23 +1046,29 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
}
EXPORT_SYMBOL_GPL(do_tcp_sendpages);
int tcp_sendpage(struct sock *sk, struct page *page, int offset,
size_t size, int flags)
int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset,
size_t size, int flags)
{
ssize_t res;
if (!(sk->sk_route_caps & NETIF_F_SG) ||
!sk_check_csum_caps(sk))
return sock_no_sendpage(sk->sk_socket, page, offset, size,
flags);
lock_sock(sk);
tcp_rate_check_app_limited(sk); /* is sending application-limited? */
res = do_tcp_sendpages(sk, page, offset, size, flags);
return do_tcp_sendpages(sk, page, offset, size, flags);
}
int tcp_sendpage(struct sock *sk, struct page *page, int offset,
size_t size, int flags)
{
int ret;
lock_sock(sk);
ret = tcp_sendpage_locked(sk, page, offset, size, flags);
release_sock(sk);
return res;
return ret;
}
EXPORT_SYMBOL(tcp_sendpage);
......@@ -1156,7 +1162,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
return err;
}
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
int tcp_sendmsg_locked(struct sock *sk, struct msghdr *msg, size_t size)
{
struct tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb;
......@@ -1167,8 +1173,6 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
bool sg;
long timeo;
lock_sock(sk);
flags = msg->msg_flags;
if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect)) {
err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size);
......@@ -1377,7 +1381,6 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
tcp_push(sk, flags, mss_now, tp->nonagle, size_goal);
}
out_nopush:
release_sock(sk);
return copied + copied_syn;
do_fault:
......@@ -1401,9 +1404,19 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
sk->sk_write_space(sk);
tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
}
release_sock(sk);
return err;
}
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
{
int ret;
lock_sock(sk);
ret = tcp_sendmsg_locked(sk, msg, size);
release_sock(sk);
return ret;
}
EXPORT_SYMBOL(tcp_sendmsg);
/*
......
......@@ -155,8 +155,8 @@ static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
seq_printf(seq,
" psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ",
psock->index,
psock->strp.stats.rx_msgs,
psock->strp.stats.rx_bytes,
psock->strp.stats.msgs,
psock->strp.stats.bytes,
psock->stats.tx_msgs,
psock->stats.tx_bytes,
psock->sk->sk_receive_queue.qlen,
......@@ -170,22 +170,22 @@ static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
if (psock->tx_stopped)
seq_puts(seq, "TxStop ");
if (psock->strp.rx_stopped)
if (psock->strp.stopped)
seq_puts(seq, "RxStop ");
if (psock->tx_kcm)
seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index);
if (!psock->strp.rx_paused && !psock->ready_rx_msg) {
if (!psock->strp.paused && !psock->ready_rx_msg) {
if (psock->sk->sk_receive_queue.qlen) {
if (psock->strp.rx_need_bytes)
if (psock->strp.need_bytes)
seq_printf(seq, "RxWait=%u ",
psock->strp.rx_need_bytes);
psock->strp.need_bytes);
else
seq_printf(seq, "RxWait ");
}
} else {
if (psock->strp.rx_paused)
if (psock->strp.paused)
seq_puts(seq, "RxPause ");
if (psock->ready_rx_msg)
......@@ -371,20 +371,20 @@ static int kcm_stats_seq_show(struct seq_file *seq, void *v)
seq_printf(seq,
"%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n",
"",
strp_stats.rx_msgs,
strp_stats.rx_bytes,
strp_stats.msgs,
strp_stats.bytes,
psock_stats.tx_msgs,
psock_stats.tx_bytes,
psock_stats.reserved,
psock_stats.unreserved,
strp_stats.rx_aborts,
strp_stats.rx_interrupted,
strp_stats.rx_unrecov_intr,
strp_stats.rx_mem_fail,
strp_stats.rx_need_more_hdr,
strp_stats.rx_bad_hdr_len,
strp_stats.rx_msg_too_big,
strp_stats.rx_msg_timeouts,
strp_stats.aborts,
strp_stats.interrupted,
strp_stats.unrecov_intr,
strp_stats.mem_fail,
strp_stats.need_more_hdr,
strp_stats.bad_hdr_len,
strp_stats.msg_too_big,
strp_stats.msg_timeouts,
psock_stats.tx_aborts);
return 0;
......
......@@ -96,12 +96,12 @@ static void kcm_update_rx_mux_stats(struct kcm_mux *mux,
struct kcm_psock *psock)
{
STRP_STATS_ADD(mux->stats.rx_bytes,
psock->strp.stats.rx_bytes -
psock->strp.stats.bytes -
psock->saved_rx_bytes);
mux->stats.rx_msgs +=
psock->strp.stats.rx_msgs - psock->saved_rx_msgs;
psock->saved_rx_msgs = psock->strp.stats.rx_msgs;
psock->saved_rx_bytes = psock->strp.stats.rx_bytes;
psock->strp.stats.msgs - psock->saved_rx_msgs;
psock->saved_rx_msgs = psock->strp.stats.msgs;
psock->saved_rx_bytes = psock->strp.stats.bytes;
}
static void kcm_update_tx_mux_stats(struct kcm_mux *mux,
......@@ -1118,7 +1118,7 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
struct kcm_sock *kcm = kcm_sk(sk);
int err = 0;
long timeo;
struct strp_rx_msg *rxm;
struct strp_msg *stm;
int copied = 0;
struct sk_buff *skb;
......@@ -1132,26 +1132,26 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
/* Okay, have a message on the receive queue */
rxm = strp_rx_msg(skb);
stm = strp_msg(skb);
if (len > rxm->full_len)
len = rxm->full_len;
if (len > stm->full_len)
len = stm->full_len;
err = skb_copy_datagram_msg(skb, rxm->offset, msg, len);
err = skb_copy_datagram_msg(skb, stm->offset, msg, len);
if (err < 0)
goto out;
copied = len;
if (likely(!(flags & MSG_PEEK))) {
KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
if (copied < rxm->full_len) {
if (copied < stm->full_len) {
if (sock->type == SOCK_DGRAM) {
/* Truncated message */
msg->msg_flags |= MSG_TRUNC;
goto msg_finished;
}
rxm->offset += copied;
rxm->full_len -= copied;
stm->offset += copied;
stm->full_len -= copied;
} else {
msg_finished:
/* Finished with message */
......@@ -1175,7 +1175,7 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
struct sock *sk = sock->sk;
struct kcm_sock *kcm = kcm_sk(sk);
long timeo;
struct strp_rx_msg *rxm;
struct strp_msg *stm;
int err = 0;
ssize_t copied;
struct sk_buff *skb;
......@@ -1192,12 +1192,12 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
/* Okay, have a message on the receive queue */
rxm = strp_rx_msg(skb);
stm = strp_msg(skb);
if (len > rxm->full_len)
len = rxm->full_len;
if (len > stm->full_len)
len = stm->full_len;
copied = skb_splice_bits(skb, sk, rxm->offset, pipe, len, flags);
copied = skb_splice_bits(skb, sk, stm->offset, pipe, len, flags);
if (copied < 0) {
err = copied;
goto err_out;
......@@ -1205,8 +1205,8 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
rxm->offset += copied;
rxm->full_len -= copied;
stm->offset += copied;
stm->full_len -= copied;
/* We have no way to return MSG_EOR. If all the bytes have been
* read we still leave the message in the receive socket buffer.
......
......@@ -652,6 +652,20 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
}
EXPORT_SYMBOL(kernel_sendmsg);
int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg,
struct kvec *vec, size_t num, size_t size)
{
struct socket *sock = sk->sk_socket;
if (!sock->ops->sendmsg_locked)
sock_no_sendmsg_locked(sk, msg, size);
iov_iter_kvec(&msg->msg_iter, WRITE | ITER_KVEC, vec, num, size);
return sock->ops->sendmsg_locked(sk, msg, msg_data_left(msg));
}
EXPORT_SYMBOL(kernel_sendmsg_locked);
static bool skb_is_err_queue(const struct sk_buff *skb)
{
/* pkt_type of skbs enqueued on the error queue are set to
......@@ -3376,6 +3390,19 @@ int kernel_sendpage(struct socket *sock, struct page *page, int offset,
}
EXPORT_SYMBOL(kernel_sendpage);
int kernel_sendpage_locked(struct sock *sk, struct page *page, int offset,
size_t size, int flags)
{
struct socket *sock = sk->sk_socket;
if (sock->ops->sendpage_locked)
return sock->ops->sendpage_locked(sk, page, offset, size,
flags);
return sock_no_sendpage_locked(sk, page, offset, size, flags);
}
EXPORT_SYMBOL(kernel_sendpage_locked);
int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
{
mm_segment_t oldfs = get_fs();
......
This diff is collapsed.
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