kevent: network notifications.
Subsystems (4)
RFC 2/4 kevent: network notifications.
This patchset includes socket notifications and network asynchronous IO.
Signed-off-by Evgeniy Polyakov <[email protected]>
include/asm-i386/socket.h +2 -0
@@ -49,4 +49,6 @@ #define SO_ACCEPTCONN 30#define SO_PEERSEC 31 +#define SO_ASYNC_SOCK 34 +#endif /* _ASM_SOCKET_H */
include/linux/skbuff.h +2 -0
@@ -1269,6 +1269,8 @@ extern struct sk_buff *skb_recv_datagram int noblock, int *err);extern unsigned int datagram_poll (struct file *file,struct socket *sock,struct poll_table_struct *wait); +extern int skb_copy_datagram (const struct sk_buff *from, +int offset,void *dst,int size);extern int skb_copy_datagram_iovec (const struct sk_buff *from,int offset,struct iovec *to,int size);
include/net/sock.h +25 -15
@@ -47,6 +47,7 @@ #include <linux/module.h>#include <linux/netdevice.h> #include <linux/skbuff.h> /* struct sk_buff */ #include <linux/security.h> +#include <linux/kevent.h> #include <linux/filter.h>
@@ -386,6 +387,8 @@ enum sock_flags {SOCK_NO_LARGESEND ,/* whether to sent large segments or not */ SOCK_LOCALROUTE ,/* route locally only, %SO_DONTROUTE setting */ SOCK_QUEUE_SHRUNK ,/* write queue has been shrunk recently */ +SOCK_ASYNC , + SOCK_ASYNC_INUSE, };static inline void sock_copy_flags (struct sock *nsk,struct sock *osk)
@@ -445,6 +448,21 @@ static inline int sk_stream_memory_free(extern void sk_stream_rfree (struct sk_buff *skb); +struct socket_alloc { +struct socket socket; +struct inode vfs_inode; +}; + +static inline struct socket *SOCKET_I (struct inode *inode) +{ + return &container_of(inode, struct socket_alloc, vfs_inode)->socket; +} + +static inline struct inode *SOCK_INODE (struct socket *socket) +{ + return &container_of(socket, struct socket_alloc, socket)->vfs_inode; +} +static inline void sk_stream_set_owner_r (struct sk_buff *skb,struct sock *sk) { skb->sk = sk;
@@ -472,6 +490,7 @@ static inline void sk_add_backlog(struct sk->sk_backlog.tail = skb; } skb->next =NULL ; +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); }#define sk_wait_event (__sk, __timeo, __condition) \
@@ -543,6 +562,12 @@ struct proto {int (*backlog_rcv) (struct sock *sk,struct sk_buff *skb); + +int (*async_recv) (struct sock *sk, +void *dst,size_t size); +int (*async_send) (struct sock *sk, +struct page **pages,unsigned int poffset, +size_t size);/* Keeping track of sk's, looking them up, and port selection methods. */ void (*hash)(struct sock *sk);
@@ -674,21 +699,6 @@ static inline struct kiocb *siocb_to_kioreturn si->kiocb; } -struct socket_alloc { -struct socket socket; -struct inode vfs_inode; -}; - -static inline struct socket *SOCKET_I (struct inode *inode) -{ - return &container_of(inode, struct socket_alloc, vfs_inode)->socket; -} - -static inline struct inode *SOCK_INODE (struct socket *socket) -{ - return &container_of(socket, struct socket_alloc, socket)->vfs_inode; -} -extern void __sk_stream_mem_reclaim (struct sock *sk);extern int sk_stream_mem_schedule (struct sock *sk,int size,int kind);
include/net/tcp.h +3 -0
@@ -364,6 +364,8 @@ extern int compat_tcp_setsockopt(struc int level, int optname, char __user *optval, int optlen);extern void tcp_set_keepalive (struct sock *sk,int val); +extern int tcp_async_recv (struct sock *sk,void *dst,size_t size); +extern int tcp_async_send (struct sock *sk,struct page **pages,unsigned int poffset,size_t size); extern int tcp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int nonblock,
@@ -857,6 +859,7 @@ static inline int tcp_prequeue(struct so tp->ucopy.memory =0 ; }else if (skb_queue_len (&tp->ucopy.prequeue) ==1 ) {wake_up_interruptible (sk->sk_sleep); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND );if (!inet_csk_ack_scheduled (sk)) inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK, (3 * TCP_RTO_MIN) / 4,
kernel/kevent/kevent_naio.c new file +239 -0
239 lines not on this page · raw message
kernel/kevent/kevent_socket.c new file +125 -0
125 lines not on this page · raw message
net/core/datagram.c +55 -0
67 lines not on this page · raw message
net/core/sock.c +17 -1
@@ -564,6 +564,16 @@ #endifspin_unlock_bh (&sk->sk_lock.slock); ret = -ENONET ;break ; +#ifdef CONFIG_KEVENT_SOCKET +case SO_ASYNC_SOCK : +spin_lock_bh (&sk->sk_lock.slock); +if (valbool) +sock_set_flag (sk,SOCK_ASYNC ); +else +sock_reset_flag (sk,SOCK_ASYNC ); +spin_unlock_bh (&sk->sk_lock.slock); +break ; +#endif /* We implement the SO_SNDLOWAT etc to not be settable (1003.1g 5.3) */
@@ -1313,6 +1323,7 @@ static void sock_def_wakeup(struct sockif (sk->sk_sleep &&waitqueue_active (sk->sk_sleep))wake_up_interruptible_all (sk->sk_sleep);read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_error_report (struct sock *sk)
@@ -1322,6 +1333,7 @@ static void sock_def_error_report(structwake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,0 ,POLL_ERR );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_readable (struct sock *sk,int len)
@@ -1331,6 +1343,7 @@ static void sock_def_readable(struct socwake_up_interruptible (sk->sk_sleep);sk_wake_async (sk,1 ,POLL_IN );read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); }static void sock_def_write_space (struct sock *sk)
@@ -1350,6 +1363,7 @@ static void sock_def_write_space(struct }read_unlock (&sk->sk_callback_lock); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); }static void sock_def_destruct (struct sock *sk)
@@ -1454,8 +1468,10 @@ void fastcall release_sock(struct sock *if (sk->sk_backlog.tail)__release_sock (sk); sk->sk_lock.owner =NULL ; -if (waitqueue_active (&(sk->sk_lock.wq))) +if (waitqueue_active (&(sk->sk_lock.wq))) {wake_up (&(sk->sk_lock.wq)); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV |KEVENT_SOCKET_SEND ); + }spin_unlock_bh (&(sk->sk_lock.slock)); }EXPORT_SYMBOL (release_sock);
net/core/stream.c +1 -0
@@ -36,6 +36,7 @@ void sk_stream_write_space(struct sock *wake_up_interruptible (sk->sk_sleep);if (sock->fasync_list && !(sk->sk_shutdown &SEND_SHUTDOWN ))sock_wake_async (sock,2 ,POLL_OUT ); +kevent_socket_notify (sk,KEVENT_SOCKET_SEND |KEVENT_SOCKET_RECV ); } }
net/ipv4/tcp.c +272 -0
290 lines not on this page · raw message
net/ipv4/tcp_input.c +3 -1
@@ -3113,6 +3113,7 @@ static void tcp_ofo_queue(struct sock *s__skb_unlink (skb, &tp->out_of_order_queue);__skb_queue_tail (&sk->sk_receive_queue, skb); +kevent_socket_notify (sk,KEVENT_SOCKET_RECV ); tp->rcv_nxt =TCP_SKB_CB (skb)->end_seq;if (skb->h.th->fin)tcp_fin (skb, sk, skb->h.th);
@@ -3956,7 +3957,8 @@ int tcp_rcv_established(struct sock *sk,int copied_early =0 ;if (tp->copied_seq == tp->rcv_nxt && - len - tcp_header_len <= tp->ucopy.len) { + len - tcp_header_len <= tp->ucopy.len && + !sock_async (sk)) {#ifdef CONFIG_NET_DMA if (tcp_dma_try_early_copy (sk, skb, tcp_header_len)) { copied_early =1 ;
net/ipv4/tcp_ipv4.c +25 -15
@@ -62,6 +62,7 @@ #include <linux/cache.h>#include <linux/jhash.h> #include <linux/init.h> #include <linux/times.h> +#include <linux/kevent.h> #include <net/icmp.h> #include <net/inet_hashtables.h>
@@ -850,6 +851,7 @@ #endifreqsk_free (req); }else {inet_csk_reqsk_queue_hash_add (sk, req,TCP_TIMEOUT_INIT ); +kevent_socket_notify (sk,KEVENT_SOCKET_ACCEPT ); }return 0 ;
@@ -1089,24 +1091,30 @@ process: skb->dev =NULL ; -bh_lock_sock (sk); ret =0 ; -if (!sock_owned_by_user (sk)) { +if (sock_async (sk)) { +spin_lock_bh (&sk->sk_lock.slock); + ret =tcp_v4_do_rcv (sk, skb); +spin_unlock_bh (&sk->sk_lock.slock); + }else { +bh_lock_sock (sk); +if (!sock_owned_by_user (sk)) {#ifdef CONFIG_NET_DMA -struct tcp_sock *tp =tcp_sk (sk); -if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) - tp->ucopy.dma_chan =get_softnet_dma (); -if (tp->ucopy.dma_chan) - ret =tcp_v4_do_rcv (sk, skb); - else +struct tcp_sock *tp =tcp_sk (sk); +if (!tp->ucopy.dma_chan && tp->ucopy.pinned_list) + tp->ucopy.dma_chan =get_softnet_dma (); +if (tp->ucopy.dma_chan) + ret =tcp_v4_do_rcv (sk, skb); + else#endif - { -if (!tcp_prequeue (sk, skb)) - ret =tcp_v4_do_rcv (sk, skb); - } - }else -sk_add_backlog (sk, skb); -bh_unlock_sock (sk); + { +if (!tcp_prequeue (sk, skb)) + ret =tcp_v4_do_rcv (sk, skb); + } + }else +sk_add_backlog (sk, skb); +bh_unlock_sock (sk); + }sock_put (sk);
@@ -1830,6 +1838,8 @@ struct proto tcp_prot = { .getsockopt = tcp_getsockopt, .sendmsg = tcp_sendmsg, .recvmsg = tcp_recvmsg, + .async_recv = tcp_async_recv, + .async_send = tcp_async_send, .backlog_rcv = tcp_v4_do_rcv, .hash = tcp_v4_hash, .unhash = tcp_unhash,
net/ipv6/tcp_ipv6.c +21 -13
@@ -1215,22 +1215,28 @@ process: skb->dev =NULL ; -bh_lock_sock (sk); ret =0 ; -if (!sock_owned_by_user (sk)) { +if (sock_async (sk)) { +spin_lock_bh (&sk->sk_lock.slock); + ret =tcp_v4_do_rcv (sk, skb); +spin_unlock_bh (&sk->sk_lock.slock); + }else { +bh_lock_sock (sk); +if (!sock_owned_by_user (sk)) {#ifdef CONFIG_NET_DMA -struct tcp_sock *tp =tcp_sk (sk); -if (tp->ucopy.dma_chan) - ret =tcp_v6_do_rcv (sk, skb); - else -#endif - { -if (!tcp_prequeue (sk, skb)) +struct tcp_sock *tp =tcp_sk (sk); +if (tp->ucopy.dma_chan) ret =tcp_v6_do_rcv (sk, skb); - } - }else -sk_add_backlog (sk, skb); -bh_unlock_sock (sk); + else +#endif + { +if (!tcp_prequeue (sk, skb)) + ret =tcp_v6_do_rcv (sk, skb); + } + }else +sk_add_backlog (sk, skb); +bh_unlock_sock (sk); + }sock_put (sk);return ret ?-1 :0 ;
@@ -1580,6 +1586,8 @@ struct proto tcpv6_prot = { .getsockopt = tcp_getsockopt, .sendmsg = tcp_sendmsg, .recvmsg = tcp_recvmsg, + .async_recv = tcp_async_recv, + .async_send = tcp_async_send, .backlog_rcv = tcp_v6_do_rcv, .hash = tcp_v6_hash, .unhash = tcp_unhash,
Signature · 1 line
Evgeniy Polyakov