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 { ...@@ -190,8 +190,16 @@ struct proto_ops {
struct pipe_inode_info *pipe, size_t len, unsigned int flags); struct pipe_inode_info *pipe, size_t len, unsigned int flags);
int (*set_peek_off)(struct sock *sk, int val); int (*set_peek_off)(struct sock *sk, int val);
int (*peek_len)(struct socket *sock); 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, int (*read_sock)(struct sock *sk, read_descriptor_t *desc,
sk_read_actor_t recv_actor); 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) \ #define DECLARE_SOCKADDR(type, dst, src) \
...@@ -279,6 +287,8 @@ do { \ ...@@ -279,6 +287,8 @@ do { \
int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
size_t num, size_t len); 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, int kernel_recvmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec,
size_t num, size_t len, int flags); size_t num, size_t len, int flags);
...@@ -297,6 +307,8 @@ int kernel_setsockopt(struct socket *sock, int level, int optname, char *optval, ...@@ -297,6 +307,8 @@ int kernel_setsockopt(struct socket *sock, int level, int optname, char *optval,
unsigned int optlen); unsigned int optlen);
int kernel_sendpage(struct socket *sock, struct page *page, int offset, int kernel_sendpage(struct socket *sock, struct page *page, int offset,
size_t size, int flags); 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_ioctl(struct socket *sock, int cmd, unsigned long arg);
int kernel_sock_shutdown(struct socket *sock, enum sock_shutdown_cmd how); 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, ...@@ -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, 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);
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); 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,
......
...@@ -1582,11 +1582,14 @@ int sock_no_shutdown(struct socket *, int); ...@@ -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_getsockopt(struct socket *, int , int, char __user *, int __user *);
int sock_no_setsockopt(struct socket *, int, int, char __user *, unsigned int); 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(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_recvmsg(struct socket *, struct msghdr *, size_t, int);
int sock_no_mmap(struct file *file, struct socket *sock, int sock_no_mmap(struct file *file, struct socket *sock,
struct vm_area_struct *vma); struct vm_area_struct *vma);
ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset,
size_t size, int flags); 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 * Functions to fill in entries in struct proto_ops when a protocol
......
...@@ -18,26 +18,26 @@ ...@@ -18,26 +18,26 @@
#define STRP_STATS_INCR(stat) ((stat)++) #define STRP_STATS_INCR(stat) ((stat)++)
struct strp_stats { struct strp_stats {
unsigned long long rx_msgs; unsigned long long msgs;
unsigned long long rx_bytes; unsigned long long bytes;
unsigned int rx_mem_fail; unsigned int mem_fail;
unsigned int rx_need_more_hdr; unsigned int need_more_hdr;
unsigned int rx_msg_too_big; unsigned int msg_too_big;
unsigned int rx_msg_timeouts; unsigned int msg_timeouts;
unsigned int rx_bad_hdr_len; unsigned int bad_hdr_len;
}; };
struct strp_aggr_stats { struct strp_aggr_stats {
unsigned long long rx_msgs; unsigned long long msgs;
unsigned long long rx_bytes; unsigned long long bytes;
unsigned int rx_mem_fail; unsigned int mem_fail;
unsigned int rx_need_more_hdr; unsigned int need_more_hdr;
unsigned int rx_msg_too_big; unsigned int msg_too_big;
unsigned int rx_msg_timeouts; unsigned int msg_timeouts;
unsigned int rx_bad_hdr_len; unsigned int bad_hdr_len;
unsigned int rx_aborts; unsigned int aborts;
unsigned int rx_interrupted; unsigned int interrupted;
unsigned int rx_unrecov_intr; unsigned int unrecov_intr;
}; };
struct strparser; struct strparser;
...@@ -48,16 +48,18 @@ struct strp_callbacks { ...@@ -48,16 +48,18 @@ struct strp_callbacks {
void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb); void (*rcv_msg)(struct strparser *strp, struct sk_buff *skb);
int (*read_sock_done)(struct strparser *strp, int err); int (*read_sock_done)(struct strparser *strp, int err);
void (*abort_parser)(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 full_len;
int offset; 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)); offsetof(struct qdisc_skb_cb, data));
} }
...@@ -65,18 +67,18 @@ static inline struct strp_rx_msg *strp_rx_msg(struct sk_buff *skb) ...@@ -65,18 +67,18 @@ static inline struct strp_rx_msg *strp_rx_msg(struct sk_buff *skb)
struct strparser { struct strparser {
struct sock *sk; struct sock *sk;
u32 rx_stopped : 1; u32 stopped : 1;
u32 rx_paused : 1; u32 paused : 1;
u32 rx_aborted : 1; u32 aborted : 1;
u32 rx_interrupted : 1; u32 interrupted : 1;
u32 rx_unrecov_intr : 1; u32 unrecov_intr : 1;
struct sk_buff **rx_skb_nextp; struct sk_buff **skb_nextp;
struct timer_list rx_msg_timer; struct timer_list msg_timer;
struct sk_buff *rx_skb_head; struct sk_buff *skb_head;
unsigned int rx_need_bytes; unsigned int need_bytes;
struct delayed_work rx_delayed_work; struct delayed_work delayed_work;
struct work_struct rx_work; struct work_struct work;
struct strp_stats stats; struct strp_stats stats;
struct strp_callbacks cb; struct strp_callbacks cb;
}; };
...@@ -84,7 +86,7 @@ struct strparser { ...@@ -84,7 +86,7 @@ struct strparser {
/* Must be called with lock held for attached socket */ /* Must be called with lock held for attached socket */
static inline void strp_pause(struct strparser *strp) static inline void strp_pause(struct strparser *strp)
{ {
strp->rx_paused = 1; strp->paused = 1;
} }
/* May be called without holding lock for attached socket */ /* May be called without holding lock for attached socket */
...@@ -97,37 +99,37 @@ static inline void save_strp_stats(struct strparser *strp, ...@@ -97,37 +99,37 @@ static inline void save_strp_stats(struct strparser *strp,
#define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += \ #define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += \
strp->stats._stat) strp->stats._stat)
SAVE_PSOCK_STATS(rx_msgs); SAVE_PSOCK_STATS(msgs);
SAVE_PSOCK_STATS(rx_bytes); SAVE_PSOCK_STATS(bytes);
SAVE_PSOCK_STATS(rx_mem_fail); SAVE_PSOCK_STATS(mem_fail);
SAVE_PSOCK_STATS(rx_need_more_hdr); SAVE_PSOCK_STATS(need_more_hdr);
SAVE_PSOCK_STATS(rx_msg_too_big); SAVE_PSOCK_STATS(msg_too_big);
SAVE_PSOCK_STATS(rx_msg_timeouts); SAVE_PSOCK_STATS(msg_timeouts);
SAVE_PSOCK_STATS(rx_bad_hdr_len); SAVE_PSOCK_STATS(bad_hdr_len);
#undef SAVE_PSOCK_STATS #undef SAVE_PSOCK_STATS
if (strp->rx_aborted) if (strp->aborted)
agg_stats->rx_aborts++; agg_stats->aborts++;
if (strp->rx_interrupted) if (strp->interrupted)
agg_stats->rx_interrupted++; agg_stats->interrupted++;
if (strp->rx_unrecov_intr) if (strp->unrecov_intr)
agg_stats->rx_unrecov_intr++; agg_stats->unrecov_intr++;
} }
static inline void aggregate_strp_stats(struct strp_aggr_stats *stats, static inline void aggregate_strp_stats(struct strp_aggr_stats *stats,
struct strp_aggr_stats *agg_stats) struct strp_aggr_stats *agg_stats)
{ {
#define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += stats->_stat) #define SAVE_PSOCK_STATS(_stat) (agg_stats->_stat += stats->_stat)
SAVE_PSOCK_STATS(rx_msgs); SAVE_PSOCK_STATS(msgs);
SAVE_PSOCK_STATS(rx_bytes); SAVE_PSOCK_STATS(bytes);
SAVE_PSOCK_STATS(rx_mem_fail); SAVE_PSOCK_STATS(mem_fail);
SAVE_PSOCK_STATS(rx_need_more_hdr); SAVE_PSOCK_STATS(need_more_hdr);
SAVE_PSOCK_STATS(rx_msg_too_big); SAVE_PSOCK_STATS(msg_too_big);
SAVE_PSOCK_STATS(rx_msg_timeouts); SAVE_PSOCK_STATS(msg_timeouts);
SAVE_PSOCK_STATS(rx_bad_hdr_len); SAVE_PSOCK_STATS(bad_hdr_len);
SAVE_PSOCK_STATS(rx_aborts); SAVE_PSOCK_STATS(aborts);
SAVE_PSOCK_STATS(rx_interrupted); SAVE_PSOCK_STATS(interrupted);
SAVE_PSOCK_STATS(rx_unrecov_intr); SAVE_PSOCK_STATS(unrecov_intr);
#undef SAVE_PSOCK_STATS #undef SAVE_PSOCK_STATS
} }
...@@ -135,8 +137,11 @@ static inline void aggregate_strp_stats(struct strp_aggr_stats *stats, ...@@ -135,8 +137,11 @@ static inline void aggregate_strp_stats(struct strp_aggr_stats *stats,
void strp_done(struct strparser *strp); void strp_done(struct strparser *strp);
void strp_stop(struct strparser *strp); void strp_stop(struct strparser *strp);
void strp_check_rcv(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); struct strp_callbacks *cb);
void strp_data_ready(struct strparser *strp); 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_ */ #endif /* __NET_STRPARSER_H_ */
...@@ -350,8 +350,11 @@ int tcp_v4_rcv(struct sk_buff *skb); ...@@ -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_v4_tw_remember_stamp(struct inet_timewait_sock *tw);
int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size); 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 tcp_sendpage(struct sock *sk, struct page *page, int offset, size_t size,
int flags); 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, ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
size_t size, int flags); size_t size, int flags);
void tcp_release_cb(struct sock *sk); 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, ...@@ -1982,6 +1982,107 @@ int skb_splice_bits(struct sk_buff *skb, struct sock *sk, unsigned int offset,
} }
EXPORT_SYMBOL_GPL(skb_splice_bits); 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_store_bits - store bits from kernel buffer to skb
* @skb: destination buffer * @skb: destination buffer
......
...@@ -2500,6 +2500,12 @@ int sock_no_sendmsg(struct socket *sock, struct msghdr *m, size_t len) ...@@ -2500,6 +2500,12 @@ int sock_no_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
} }
EXPORT_SYMBOL(sock_no_sendmsg); 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 sock_no_recvmsg(struct socket *sock, struct msghdr *m, size_t len,
int flags) int flags)
{ {
...@@ -2528,6 +2534,22 @@ ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, siz ...@@ -2528,6 +2534,22 @@ ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, siz
} }
EXPORT_SYMBOL(sock_no_sendpage); 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 * Default Socket Callbacks
*/ */
......
...@@ -944,6 +944,8 @@ const struct proto_ops inet_stream_ops = { ...@@ -944,6 +944,8 @@ const struct proto_ops inet_stream_ops = {
.sendpage = inet_sendpage, .sendpage = inet_sendpage,
.splice_read = tcp_splice_read, .splice_read = tcp_splice_read,
.read_sock = tcp_read_sock, .read_sock = tcp_read_sock,
.sendmsg_locked = tcp_sendmsg_locked,
.sendpage_locked = tcp_sendpage_locked,
.peek_len = tcp_peek_len, .peek_len = tcp_peek_len,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt, .compat_setsockopt = compat_sock_common_setsockopt,
......
...@@ -1046,23 +1046,29 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset, ...@@ -1046,23 +1046,29 @@ ssize_t do_tcp_sendpages(struct sock *sk, struct page *page, int offset,
} }
EXPORT_SYMBOL_GPL(do_tcp_sendpages); EXPORT_SYMBOL_GPL(do_tcp_sendpages);
int tcp_sendpage(struct sock *sk, struct page *page, int offset, int tcp_sendpage_locked(struct sock *sk, struct page *page, int offset,
size_t size, int flags) size_t size, int flags)
{ {
ssize_t res;
if (!(sk->sk_route_caps & NETIF_F_SG) || if (!(sk->sk_route_caps & NETIF_F_SG) ||
!sk_check_csum_caps(sk)) !sk_check_csum_caps(sk))
return sock_no_sendpage(sk->sk_socket, page, offset, size, return sock_no_sendpage(sk->sk_socket, page, offset, size,
flags); flags);
lock_sock(sk);
tcp_rate_check_app_limited(sk); /* is sending application-limited? */ 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); release_sock(sk);
return res;
return ret;
} }
EXPORT_SYMBOL(tcp_sendpage); EXPORT_SYMBOL(tcp_sendpage);
...@@ -1156,7 +1162,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg, ...@@ -1156,7 +1162,7 @@ static int tcp_sendmsg_fastopen(struct sock *sk, struct msghdr *msg,
return err; 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 tcp_sock *tp = tcp_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1167,8 +1173,6 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) ...@@ -1167,8 +1173,6 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
bool sg; bool sg;
long timeo; long timeo;
lock_sock(sk);
flags = msg->msg_flags; flags = msg->msg_flags;
if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect)) { if (unlikely(flags & MSG_FASTOPEN || inet_sk(sk)->defer_connect)) {
err = tcp_sendmsg_fastopen(sk, msg, &copied_syn, size); 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) ...@@ -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); tcp_push(sk, flags, mss_now, tp->nonagle, size_goal);
} }
out_nopush: out_nopush:
release_sock(sk);
return copied + copied_syn; return copied + copied_syn;
do_fault: do_fault:
...@@ -1401,9 +1404,19 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) ...@@ -1401,9 +1404,19 @@ int tcp_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
sk->sk_write_space(sk); sk->sk_write_space(sk);
tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED); tcp_chrono_stop(sk, TCP_CHRONO_SNDBUF_LIMITED);
} }
release_sock(sk);
return err; 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); EXPORT_SYMBOL(tcp_sendmsg);
/* /*
......
...@@ -155,8 +155,8 @@ static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq, ...@@ -155,8 +155,8 @@ static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
seq_printf(seq, seq_printf(seq,
" psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ", " psock-%-5u %-10llu %-16llu %-10llu %-16llu %-8d %-8d %-8d %-8d ",
psock->index, psock->index,
psock->strp.stats.rx_msgs, psock->strp.stats.msgs,
psock->strp.stats.rx_bytes, psock->strp.stats.bytes,
psock->stats.tx_msgs, psock->stats.tx_msgs,
psock->stats.tx_bytes, psock->stats.tx_bytes,
psock->sk->sk_receive_queue.qlen, psock->sk->sk_receive_queue.qlen,
...@@ -170,22 +170,22 @@ static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq, ...@@ -170,22 +170,22 @@ static void kcm_format_psock(struct kcm_psock *psock, struct seq_file *seq,
if (psock->tx_stopped) if (psock->tx_stopped)
seq_puts(seq, "TxStop "); seq_puts(seq, "TxStop ");
if (psock->strp.rx_stopped) if (psock->strp.stopped)
seq_puts(seq, "RxStop "); seq_puts(seq, "RxStop ");
if (psock->tx_kcm) if (psock->tx_kcm)
seq_printf(seq, "Rsvd-%d ", psock->tx_kcm->index); 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->sk->sk_receive_queue.qlen) {
if (psock->strp.rx_need_bytes) if (psock->strp.need_bytes)
seq_printf(seq, "RxWait=%u ", seq_printf(seq, "RxWait=%u ",
psock->strp.rx_need_bytes); psock->strp.need_bytes);
else else
seq_printf(seq, "RxWait "); seq_printf(seq, "RxWait ");
} }
} else { } else {
if (psock->strp.rx_paused) if (psock->strp.paused)
seq_puts(seq, "RxPause "); seq_puts(seq, "RxPause ");
if (psock->ready_rx_msg) if (psock->ready_rx_msg)
...@@ -371,20 +371,20 @@ static int kcm_stats_seq_show(struct seq_file *seq, void *v) ...@@ -371,20 +371,20 @@ static int kcm_stats_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, seq_printf(seq,
"%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n", "%-8s %-10llu %-16llu %-10llu %-16llu %-10llu %-10llu %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u %-10u\n",
"", "",
strp_stats.rx_msgs, strp_stats.msgs,
strp_stats.rx_bytes, strp_stats.bytes,
psock_stats.tx_msgs, psock_stats.tx_msgs,
psock_stats.tx_bytes, psock_stats.tx_bytes,
psock_stats.reserved, psock_stats.reserved,
psock_stats.unreserved, psock_stats.unreserved,
strp_stats.rx_aborts, strp_stats.aborts,
strp_stats.rx_interrupted, strp_stats.interrupted,
strp_stats.rx_unrecov_intr, strp_stats.unrecov_intr,
strp_stats.rx_mem_fail, strp_stats.mem_fail,
strp_stats.rx_need_more_hdr, strp_stats.need_more_hdr,
strp_stats.rx_bad_hdr_len, strp_stats.bad_hdr_len,
strp_stats.rx_msg_too_big, strp_stats.msg_too_big,
strp_stats.rx_msg_timeouts, strp_stats.msg_timeouts,
psock_stats.tx_aborts); psock_stats.tx_aborts);
return 0; return 0;
......
...@@ -96,12 +96,12 @@ static void kcm_update_rx_mux_stats(struct kcm_mux *mux, ...@@ -96,12 +96,12 @@ static void kcm_update_rx_mux_stats(struct kcm_mux *mux,
struct kcm_psock *psock) struct kcm_psock *psock)
{ {
STRP_STATS_ADD(mux->stats.rx_bytes, STRP_STATS_ADD(mux->stats.rx_bytes,
psock->strp.stats.rx_bytes - psock->strp.stats.bytes -
psock->saved_rx_bytes); psock->saved_rx_bytes);
mux->stats.rx_msgs += mux->stats.rx_msgs +=
psock->strp.stats.rx_msgs - psock->saved_rx_msgs; psock->strp.stats.msgs - psock->saved_rx_msgs;
psock->saved_rx_msgs = psock->strp.stats.rx_msgs; psock->saved_rx_msgs = psock->strp.stats.msgs;
psock->saved_rx_bytes = psock->strp.stats.rx_bytes; psock->saved_rx_bytes = psock->strp.stats.bytes;
} }
static void kcm_update_tx_mux_stats(struct kcm_mux *mux, 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, ...@@ -1118,7 +1118,7 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
struct kcm_sock *kcm = kcm_sk(sk); struct kcm_sock *kcm = kcm_sk(sk);
int err = 0; int err = 0;
long timeo; long timeo;
struct strp_rx_msg *rxm; struct strp_msg *stm;
int copied = 0; int copied = 0;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1132,26 +1132,26 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg, ...@@ -1132,26 +1132,26 @@ static int kcm_recvmsg(struct socket *sock, struct msghdr *msg,
/* Okay, have a message on the receive queue */ /* Okay, have a message on the receive queue */
rxm = strp_rx_msg(skb); stm = strp_msg(skb);
if (len > rxm->full_len) if (len > stm->full_len)
len = rxm->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) if (err < 0)
goto out; goto out;
copied = len; copied = len;
if (likely(!(flags & MSG_PEEK))) { if (likely(!(flags & MSG_PEEK))) {
KCM_STATS_ADD(kcm->stats.rx_bytes, copied); KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
if (copied < rxm->full_len) { if (copied < stm->full_len) {
if (sock->type == SOCK_DGRAM) { if (sock->type == SOCK_DGRAM) {
/* Truncated message */ /* Truncated message */
msg->msg_flags |= MSG_TRUNC; msg->msg_flags |= MSG_TRUNC;
goto msg_finished; goto msg_finished;
} }
rxm->offset += copied; stm->offset += copied;
rxm->full_len -= copied; stm->full_len -= copied;
} else { } else {
msg_finished: msg_finished:
/* Finished with message */ /* Finished with message */
...@@ -1175,7 +1175,7 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos, ...@@ -1175,7 +1175,7 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct kcm_sock *kcm = kcm_sk(sk); struct kcm_sock *kcm = kcm_sk(sk);
long timeo; long timeo;
struct strp_rx_msg *rxm; struct strp_msg *stm;
int err = 0; int err = 0;
ssize_t copied; ssize_t copied;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1192,12 +1192,12 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos, ...@@ -1192,12 +1192,12 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
/* Okay, have a message on the receive queue */ /* Okay, have a message on the receive queue */
rxm = strp_rx_msg(skb); stm = strp_msg(skb);
if (len > rxm->full_len) if (len > stm->full_len)
len = rxm->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) { if (copied < 0) {
err = copied; err = copied;
goto err_out; goto err_out;
...@@ -1205,8 +1205,8 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos, ...@@ -1205,8 +1205,8 @@ static ssize_t kcm_splice_read(struct socket *sock, loff_t *ppos,
KCM_STATS_ADD(kcm->stats.rx_bytes, copied); KCM_STATS_ADD(kcm->stats.rx_bytes, copied);
rxm->offset += copied; stm->offset += copied;
rxm->full_len -= copied; stm->full_len -= copied;
/* We have no way to return MSG_EOR. If all the bytes have been /* 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. * read we still leave the message in the receive socket buffer.
......
...@@ -652,6 +652,20 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg, ...@@ -652,6 +652,20 @@ int kernel_sendmsg(struct socket *sock, struct msghdr *msg,
} }
EXPORT_SYMBOL(kernel_sendmsg); 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) static bool skb_is_err_queue(const struct sk_buff *skb)
{ {
/* pkt_type of skbs enqueued on the error queue are set to /* 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, ...@@ -3376,6 +3390,19 @@ int kernel_sendpage(struct socket *sock, struct page *page, int offset,
} }
EXPORT_SYMBOL(kernel_sendpage); 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) int kernel_sock_ioctl(struct socket *sock, int cmd, unsigned long arg)
{ {
mm_segment_t oldfs = get_fs(); 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