Commit c6f04e93 authored by David S. Miller's avatar David S. Miller

Merge branch 'strp-generalization'

Tom Herbert says:

====================
strp: Generalize stream parser to work with other socket types

Add a read_sock protocol operation function that allows something like
tcp_read_sock to be called for other protocol types.

Specific changes in this patch set:
  - Add read_sock function to proto_ops. This has the same signature as
    tcp_read_sock. sk_read_actor_t is also defined in net.h.
  - Set peek_len and read_sock proto_op functions for TCPv4 and TCPv6
    stream ops.
  - Remove references to tcp in strparser.
  - Call peek_len and read_sock operations from strparser instead of
    calling TCP specific functions.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents e19ac157 96a59083
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include <linux/kmemcheck.h> #include <linux/kmemcheck.h>
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/once.h> #include <linux/once.h>
#include <linux/fs.h>
#include <uapi/linux/net.h> #include <uapi/linux/net.h>
...@@ -128,6 +129,9 @@ struct page; ...@@ -128,6 +129,9 @@ struct page;
struct sockaddr; struct sockaddr;
struct msghdr; struct msghdr;
struct module; struct module;
struct sk_buff;
typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *,
unsigned int, size_t);
struct proto_ops { struct proto_ops {
int family; int family;
...@@ -186,6 +190,8 @@ struct proto_ops { ...@@ -186,6 +190,8 @@ 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);
int (*read_sock)(struct sock *sk, read_descriptor_t *desc,
sk_read_actor_t recv_actor);
}; };
#define DECLARE_SOCKADDR(type, dst, src) \ #define DECLARE_SOCKADDR(type, dst, src) \
......
...@@ -137,6 +137,6 @@ void strp_stop(struct strparser *strp); ...@@ -137,6 +137,6 @@ 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 *csk,
struct strp_callbacks *cb); struct strp_callbacks *cb);
void strp_tcp_data_ready(struct strparser *strp); void strp_data_ready(struct strparser *strp);
#endif /* __NET_STRPARSER_H_ */ #endif /* __NET_STRPARSER_H_ */
...@@ -603,8 +603,6 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize) ...@@ -603,8 +603,6 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)
void tcp_get_info(struct sock *, struct tcp_info *); void tcp_get_info(struct sock *, struct tcp_info *);
/* Read 'sendfile()'-style from a TCP socket */ /* Read 'sendfile()'-style from a TCP socket */
typedef int (*sk_read_actor_t)(read_descriptor_t *, struct sk_buff *,
unsigned int, size_t);
int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
sk_read_actor_t recv_actor); sk_read_actor_t recv_actor);
...@@ -1850,6 +1848,8 @@ static inline int tcp_inq(struct sock *sk) ...@@ -1850,6 +1848,8 @@ static inline int tcp_inq(struct sock *sk)
return answ; return answ;
} }
int tcp_peek_len(struct socket *sock);
static inline void tcp_segs_in(struct tcp_sock *tp, const struct sk_buff *skb) static inline void tcp_segs_in(struct tcp_sock *tp, const struct sk_buff *skb)
{ {
u16 segs_in; u16 segs_in;
......
...@@ -916,6 +916,8 @@ const struct proto_ops inet_stream_ops = { ...@@ -916,6 +916,8 @@ const struct proto_ops inet_stream_ops = {
.mmap = sock_no_mmap, .mmap = sock_no_mmap,
.sendpage = inet_sendpage, .sendpage = inet_sendpage,
.splice_read = tcp_splice_read, .splice_read = tcp_splice_read,
.read_sock = tcp_read_sock,
.peek_len = tcp_peek_len,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt, .compat_setsockopt = compat_sock_common_setsockopt,
.compat_getsockopt = compat_sock_common_getsockopt, .compat_getsockopt = compat_sock_common_getsockopt,
......
...@@ -1570,6 +1570,12 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, ...@@ -1570,6 +1570,12 @@ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc,
} }
EXPORT_SYMBOL(tcp_read_sock); EXPORT_SYMBOL(tcp_read_sock);
int tcp_peek_len(struct socket *sock)
{
return tcp_inq(sock->sk);
}
EXPORT_SYMBOL(tcp_peek_len);
/* /*
* This routine copies from a sock struct into the user buffer. * This routine copies from a sock struct into the user buffer.
* *
......
...@@ -545,6 +545,8 @@ const struct proto_ops inet6_stream_ops = { ...@@ -545,6 +545,8 @@ const struct proto_ops inet6_stream_ops = {
.mmap = sock_no_mmap, .mmap = sock_no_mmap,
.sendpage = inet_sendpage, .sendpage = inet_sendpage,
.splice_read = tcp_splice_read, .splice_read = tcp_splice_read,
.read_sock = tcp_read_sock,
.peek_len = tcp_peek_len,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt, .compat_setsockopt = compat_sock_common_setsockopt,
.compat_getsockopt = compat_sock_common_getsockopt, .compat_getsockopt = compat_sock_common_getsockopt,
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <net/kcm.h> #include <net/kcm.h>
#include <net/netns/generic.h> #include <net/netns/generic.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/tcp.h>
#include <uapi/linux/kcm.h> #include <uapi/linux/kcm.h>
unsigned int kcm_net_id; unsigned int kcm_net_id;
...@@ -340,7 +339,7 @@ static void unreserve_rx_kcm(struct kcm_psock *psock, ...@@ -340,7 +339,7 @@ static void unreserve_rx_kcm(struct kcm_psock *psock,
} }
/* Lower sock lock held */ /* Lower sock lock held */
static void psock_tcp_data_ready(struct sock *sk) static void psock_data_ready(struct sock *sk)
{ {
struct kcm_psock *psock; struct kcm_psock *psock;
...@@ -348,7 +347,7 @@ static void psock_tcp_data_ready(struct sock *sk) ...@@ -348,7 +347,7 @@ static void psock_tcp_data_ready(struct sock *sk)
psock = (struct kcm_psock *)sk->sk_user_data; psock = (struct kcm_psock *)sk->sk_user_data;
if (likely(psock)) if (likely(psock))
strp_tcp_data_ready(&psock->strp); strp_data_ready(&psock->strp);
read_unlock_bh(&sk->sk_callback_lock); read_unlock_bh(&sk->sk_callback_lock);
} }
...@@ -392,7 +391,7 @@ static int kcm_read_sock_done(struct strparser *strp, int err) ...@@ -392,7 +391,7 @@ static int kcm_read_sock_done(struct strparser *strp, int err)
return err; return err;
} }
static void psock_tcp_state_change(struct sock *sk) static void psock_state_change(struct sock *sk)
{ {
/* TCP only does a POLLIN for a half close. Do a POLLHUP here /* TCP only does a POLLIN for a half close. Do a POLLHUP here
* since application will normally not poll with POLLIN * since application will normally not poll with POLLIN
...@@ -402,7 +401,7 @@ static void psock_tcp_state_change(struct sock *sk) ...@@ -402,7 +401,7 @@ static void psock_tcp_state_change(struct sock *sk)
report_csk_error(sk, EPIPE); report_csk_error(sk, EPIPE);
} }
static void psock_tcp_write_space(struct sock *sk) static void psock_write_space(struct sock *sk)
{ {
struct kcm_psock *psock; struct kcm_psock *psock;
struct kcm_mux *mux; struct kcm_mux *mux;
...@@ -1383,19 +1382,12 @@ static int kcm_attach(struct socket *sock, struct socket *csock, ...@@ -1383,19 +1382,12 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
struct list_head *head; struct list_head *head;
int index = 0; int index = 0;
struct strp_callbacks cb; struct strp_callbacks cb;
int err;
if (csock->ops->family != PF_INET &&
csock->ops->family != PF_INET6)
return -EINVAL;
csk = csock->sk; csk = csock->sk;
if (!csk) if (!csk)
return -EINVAL; return -EINVAL;
/* Only support TCP for now */
if (csk->sk_protocol != IPPROTO_TCP)
return -EINVAL;
psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL); psock = kmem_cache_zalloc(kcm_psockp, GFP_KERNEL);
if (!psock) if (!psock)
return -ENOMEM; return -ENOMEM;
...@@ -1409,7 +1401,11 @@ static int kcm_attach(struct socket *sock, struct socket *csock, ...@@ -1409,7 +1401,11 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
cb.parse_msg = kcm_parse_func_strparser; cb.parse_msg = kcm_parse_func_strparser;
cb.read_sock_done = kcm_read_sock_done; cb.read_sock_done = kcm_read_sock_done;
strp_init(&psock->strp, csk, &cb); err = strp_init(&psock->strp, csk, &cb);
if (err) {
kmem_cache_free(kcm_psockp, psock);
return err;
}
sock_hold(csk); sock_hold(csk);
...@@ -1418,9 +1414,9 @@ static int kcm_attach(struct socket *sock, struct socket *csock, ...@@ -1418,9 +1414,9 @@ static int kcm_attach(struct socket *sock, struct socket *csock,
psock->save_write_space = csk->sk_write_space; psock->save_write_space = csk->sk_write_space;
psock->save_state_change = csk->sk_state_change; psock->save_state_change = csk->sk_state_change;
csk->sk_user_data = psock; csk->sk_user_data = psock;
csk->sk_data_ready = psock_tcp_data_ready; csk->sk_data_ready = psock_data_ready;
csk->sk_write_space = psock_tcp_write_space; csk->sk_write_space = psock_write_space;
csk->sk_state_change = psock_tcp_state_change; csk->sk_state_change = psock_state_change;
write_unlock_bh(&csk->sk_callback_lock); write_unlock_bh(&csk->sk_callback_lock);
/* Finished initialization, now add the psock to the MUX. */ /* Finished initialization, now add the psock to the MUX. */
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <net/strparser.h> #include <net/strparser.h>
#include <net/netns/generic.h> #include <net/netns/generic.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/tcp.h>
static struct workqueue_struct *strp_wq; static struct workqueue_struct *strp_wq;
...@@ -80,9 +79,16 @@ static void strp_parser_err(struct strparser *strp, int err, ...@@ -80,9 +79,16 @@ static void strp_parser_err(struct strparser *strp, int err,
strp->cb.abort_parser(strp, err); strp->cb.abort_parser(strp, err);
} }
static inline int strp_peek_len(struct strparser *strp)
{
struct socket *sock = strp->sk->sk_socket;
return sock->ops->peek_len(sock);
}
/* Lower socket lock held */ /* Lower socket lock held */
static int strp_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, static int strp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
unsigned int orig_offset, size_t orig_len) unsigned int orig_offset, size_t orig_len)
{ {
struct strparser *strp = (struct strparser *)desc->arg.data; struct strparser *strp = (struct strparser *)desc->arg.data;
struct _strp_rx_msg *rxm; struct _strp_rx_msg *rxm;
...@@ -266,12 +272,12 @@ static int strp_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb, ...@@ -266,12 +272,12 @@ static int strp_tcp_recv(read_descriptor_t *desc, struct sk_buff *orig_skb,
if (extra < 0) { if (extra < 0) {
/* Message not complete yet. */ /* Message not complete yet. */
if (rxm->strp.full_len - rxm->accum_len > if (rxm->strp.full_len - rxm->accum_len >
tcp_inq(strp->sk)) { strp_peek_len(strp)) {
/* Don't have the whole messages in the socket /* Don't have the whole messages in the socket
* buffer. Set strp->rx_need_bytes to wait for * buffer. Set strp->rx_need_bytes to wait for
* the rest of the message. Also, set "early * the rest of the message. Also, set "early
* eaten" since we've already buffered the skb * eaten" since we've already buffered the skb
* but don't consume yet per tcp_read_sock. * but don't consume yet per strp_read_sock.
*/ */
if (!rxm->accum_len) { if (!rxm->accum_len) {
...@@ -329,16 +335,17 @@ static int default_read_sock_done(struct strparser *strp, int err) ...@@ -329,16 +335,17 @@ static int default_read_sock_done(struct strparser *strp, int err)
} }
/* Called with lock held on lower socket */ /* Called with lock held on lower socket */
static int strp_tcp_read_sock(struct strparser *strp) static int strp_read_sock(struct strparser *strp)
{ {
struct socket *sock = strp->sk->sk_socket;
read_descriptor_t desc; read_descriptor_t desc;
desc.arg.data = strp; desc.arg.data = strp;
desc.error = 0; desc.error = 0;
desc.count = 1; /* give more than one skb per call */ desc.count = 1; /* give more than one skb per call */
/* sk should be locked here, so okay to do tcp_read_sock */ /* sk should be locked here, so okay to do read_sock */
tcp_read_sock(strp->sk, &desc, strp_tcp_recv); sock->ops->read_sock(strp->sk, &desc, strp_recv);
desc.error = strp->cb.read_sock_done(strp, desc.error); desc.error = strp->cb.read_sock_done(strp, desc.error);
...@@ -346,10 +353,8 @@ static int strp_tcp_read_sock(struct strparser *strp) ...@@ -346,10 +353,8 @@ static int strp_tcp_read_sock(struct strparser *strp)
} }
/* Lower sock lock held */ /* Lower sock lock held */
void strp_tcp_data_ready(struct strparser *strp) void strp_data_ready(struct strparser *strp)
{ {
struct sock *csk = strp->sk;
if (unlikely(strp->rx_stopped)) if (unlikely(strp->rx_stopped))
return; return;
...@@ -360,7 +365,7 @@ void strp_tcp_data_ready(struct strparser *strp) ...@@ -360,7 +365,7 @@ void strp_tcp_data_ready(struct strparser *strp)
* allows a thread in BH context to safely check if the process * allows a thread in BH context to safely check if the process
* lock is held. In this case, if the lock is held, queue work. * lock is held. In this case, if the lock is held, queue work.
*/ */
if (sock_owned_by_user(csk)) { if (sock_owned_by_user(strp->sk)) {
queue_work(strp_wq, &strp->rx_work); queue_work(strp_wq, &strp->rx_work);
return; return;
} }
...@@ -369,24 +374,24 @@ void strp_tcp_data_ready(struct strparser *strp) ...@@ -369,24 +374,24 @@ void strp_tcp_data_ready(struct strparser *strp)
return; return;
if (strp->rx_need_bytes) { if (strp->rx_need_bytes) {
if (tcp_inq(csk) >= strp->rx_need_bytes) if (strp_peek_len(strp) >= strp->rx_need_bytes)
strp->rx_need_bytes = 0; strp->rx_need_bytes = 0;
else else
return; return;
} }
if (strp_tcp_read_sock(strp) == -ENOMEM) if (strp_read_sock(strp) == -ENOMEM)
queue_work(strp_wq, &strp->rx_work); queue_work(strp_wq, &strp->rx_work);
} }
EXPORT_SYMBOL_GPL(strp_tcp_data_ready); EXPORT_SYMBOL_GPL(strp_data_ready);
static void do_strp_rx_work(struct strparser *strp) static void do_strp_rx_work(struct strparser *strp)
{ {
read_descriptor_t rd_desc; read_descriptor_t rd_desc;
struct sock *csk = strp->sk; struct sock *csk = strp->sk;
/* We need the read lock to synchronize with strp_tcp_data_ready. We /* We need the read lock to synchronize with strp_data_ready. We
* need the socket lock for calling tcp_read_sock. * need the socket lock for calling strp_read_sock.
*/ */
lock_sock(csk); lock_sock(csk);
...@@ -398,7 +403,7 @@ static void do_strp_rx_work(struct strparser *strp) ...@@ -398,7 +403,7 @@ static void do_strp_rx_work(struct strparser *strp)
rd_desc.arg.data = strp; rd_desc.arg.data = strp;
if (strp_tcp_read_sock(strp) == -ENOMEM) if (strp_read_sock(strp) == -ENOMEM)
queue_work(strp_wq, &strp->rx_work); queue_work(strp_wq, &strp->rx_work);
out: out:
...@@ -424,9 +429,14 @@ static void strp_rx_msg_timeout(unsigned long arg) ...@@ -424,9 +429,14 @@ static void strp_rx_msg_timeout(unsigned long arg)
int strp_init(struct strparser *strp, struct sock *csk, int strp_init(struct strparser *strp, struct sock *csk,
struct strp_callbacks *cb) struct strp_callbacks *cb)
{ {
struct socket *sock = csk->sk_socket;
if (!cb || !cb->rcv_msg || !cb->parse_msg) if (!cb || !cb->rcv_msg || !cb->parse_msg)
return -EINVAL; return -EINVAL;
if (!sock->ops->read_sock || !sock->ops->peek_len)
return -EAFNOSUPPORT;
memset(strp, 0, sizeof(*strp)); memset(strp, 0, sizeof(*strp));
strp->sk = csk; strp->sk = csk;
...@@ -456,7 +466,7 @@ void strp_unpause(struct strparser *strp) ...@@ -456,7 +466,7 @@ void strp_unpause(struct strparser *strp)
} }
EXPORT_SYMBOL_GPL(strp_unpause); EXPORT_SYMBOL_GPL(strp_unpause);
/* strp must already be stopped so that strp_tcp_recv will no longer be called. /* strp must already be stopped so that strp_recv will no longer be called.
* Note that strp_done is not called with the lower socket held. * Note that strp_done is not called with the lower socket held.
*/ */
void strp_done(struct strparser *strp) void strp_done(struct strparser *strp)
......
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