async network I/O, event channels, etc
Subsystems (8)
I was very much surprised by the reactions I got after my OLS talk. Lots of people declared interest and even agreed with the approach and asked me to do further ahead with all this. For those who missed it, the paper and the slides are available on my home page:
http://people.redhat.com/drepper/
As for the next steps I see a number of possible ways. The discussions can be held on the usual mailing lists (i.e., lkml and netdev) but due to the raw nature of the current proposal I would imagine that would be mainly perceived as noise.
So the second proposal is the I can create an appropriate mailing list here. Alternatively possibly two lists, one for the event channel stuff and one for the DMA/AIO part since the two parts are very much unrelated.
I'd appreciate input from those who feel responsible for these lists. I don't mind either way. If there is strong interest right now (let me know, don't pollute the list) I can create mailing lists now and then if necessary close them down and redirect traffic to lkml/netdev.
Waiting for input...
Signature · 1 line
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Quoted 17 lines · On Tue, 25 Jul 2006 12:23:53 -0700 Ulrich Drepper <[email protected]> wrote:
I was very much surprised by the reactions I got after my OLS talk. Lots of people declared interest and even agreed with the approach and asked me to do further ahead with all this. For those who missed it, the paper and the slides are available on my home page:
http://people.redhat.com/drepper/
As for the next steps I see a number of possible ways. The discussions can be held on the usual mailing lists (i.e., lkml and netdev) but due to the raw nature of the current proposal I would imagine that would be mainly perceived as noise.
So the second proposal is the I can create an appropriate mailing list here. Alternatively possibly two lists, one for the event channel stuff and one for the DMA/AIO part since the two parts are very much unrelated.
Quoted 7 lines
I'd appreciate input from those who feel responsible for these lists. I don't mind either way. If there is strong interest right now (let me know, don't pollute the list) I can create mailing lists now and then if necessary close them down and redirect traffic to lkml/netdev.
Waiting for input...
I would prefer directing the API discussion to [email protected]
Quoted 1 line · Stephen Hemminger
I would prefer directing the API discussion to [email protected]
This is for the actual async network I/O. I certainly can agree with this. The other parts are not exclusively or even mainly interesting for networking and likely should be discussed elsewhere. And the net aio stuff depends on the other two parts. netdev would certainly be my last choice but if this is what people want, so be it.
Signature · 1 line
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
David Miller
maintainerFrom: Ulrich Drepper <[email protected]>
Date: Tue, 25 Jul 2006 12:23:53 -0700
Quoted 11 lines
I was very much surprised by the reactions I got after my OLS talk. Lots of people declared interest and even agreed with the approach and asked me to do further ahead with all this. For those who missed it, the paper and the slides are available on my home page:
http://people.redhat.com/drepper/
As for the next steps I see a number of possible ways. The discussions can be held on the usual mailing lists (i.e., lkml and netdev) but due to the raw nature of the current proposal I would imagine that would be mainly perceived as noise.
Since I gave a big thumbs up for Evgivny's kevent work yesterday on linux-kernel, you might want to start by comparing your work to his. Because his has the advantage that 1) we have code now and 2) he has written many test applications and performed many benchmarks against his code which has flushed out most of the major implementation issues.
I think most of the people who have encouraged your work are unaware of Evgivny's kevent stuff, which is extremely unfortunate, the two works are more similar than they are different.
I do not think discussing all of this on netdev would be perceived as noise. :)
Quoted 22 lines · David Miller
From: Ulrich Drepper <[email protected]>
Date: Tue, 25 Jul 2006 12:23:53 -0700Quoted 11 lines
I was very much surprised by the reactions I got after my OLS talk. Lots of people declared interest and even agreed with the approach and asked me to do further ahead with all this. For those who missed it, the paper and the slides are available on my home page:
http://people.redhat.com/drepper/
As for the next steps I see a number of possible ways. The discussions can be held on the usual mailing lists (i.e., lkml and netdev) but due to the raw nature of the current proposal I would imagine that would be mainly perceived as noise.
Since I gave a big thumbs up for Evgivny's kevent work yesterday on linux-kernel, you might want to start by comparing your work to his. Because his has the advantage that 1) we have code now and 2) he has written many test applications and performed many benchmarks against his code which has flushed out most of the major implementation issues.
Quoted 6 lines
I think most of the people who have encouraged your work are unaware of Evgivny's kevent stuff, which is extremely unfortunate, the two works are more similar than they are different.
I do not think discussing all of this on netdev would be perceived as noise. :)
While the comparing is going on, how does this compare to Solaris's ports interface? It's documented at
http://docs.sun.com/app/docs/doc/816-5168/6mbb3hrir?a=view
Also, since we're on the subject, why a whole new interface for event queuing instead of extending the existing io_getevents(2) and friends?
Signature · 1 line
Nicholas Miell <[email protected]>
Quoted 22 lines · David Miller
From: Ulrich Drepper <[email protected]>
Date: Tue, 25 Jul 2006 12:23:53 -0700Quoted 11 lines
I was very much surprised by the reactions I got after my OLS talk. Lots of people declared interest and even agreed with the approach and asked me to do further ahead with all this. For those who missed it, the paper and the slides are available on my home page:
http://people.redhat.com/drepper/
As for the next steps I see a number of possible ways. The discussions can be held on the usual mailing lists (i.e., lkml and netdev) but due to the raw nature of the current proposal I would imagine that would be mainly perceived as noise.
Since I gave a big thumbs up for Evgivny's kevent work yesterday on linux-kernel, you might want to start by comparing your work to his. Because his has the advantage that 1) we have code now and 2) he has written many test applications and performed many benchmarks against his code which has flushed out most of the major implementation issues.
Quoted 6 lines
I think most of the people who have encouraged your work are unaware of Evgivny's kevent stuff, which is extremely unfortunate, the two works are more similar than they are different.
I do not think discussing all of this on netdev would be perceived as noise. :)
Hello David, Ulrich.
Here is brief description of what is kevent and how it works.
Kevent subsystem incorporates several AIO/kqueue design notes and ideas. Kevent can be used both for edge and level notifications. It supports socket notifications (accept, send, recv), network AIO (aio_send(), aio_recv() and aio_sendfile()), inode notifications (create/remove), generic poll()/select() notifications and timer notifications.
There are several object in the kevent system:
storage - each source of events (socket, inode, timer, aio, anything) has
structure kevent_storage incorporated into it, which is basically a list of registered interests for this source of events.
user - it is abstraction which holds all requested kevents. It is
similar to FreeBSD's kqueue.
kevent - set of interests for given source of events or storage.
When kevent is queued into storage, it will live there until removed by kevent_dequeue(). When some activity is noticed in given storage, it scans it's kevent_storage->list for kevents which match activity event. If kevents are found and they are not already in the kevent_user->ready_list, they will be added there at the end.
ioctl(WAIT) (or appropriate syscall) will wait until either requested number of kevents are ready or timeout elapsed or at least one kevent is ready, it's behaviour depends on parameters.
It is possible to have one-shot kevents, which are automatically removed when are ready.
Any event can be added/removed/modified by ioctl or special controlling syscall.
Network AIO is based on kevent and works as usual kevent storage on top of inode.
When new socket is created it is associated with that inode and when some activity is detected appropriate notifications are generated and kevent_naio_callback() is called.
When new kevent is being registered, network AIO ->enqueue() callback simply marks itself like usual socket event watcher. It also locks physical userspace pages in memory and stores appropriate pointers in private kevent structure. I have not created additional DMA memory allocation methods, like Ulrich described in his article, so I handle it inside NAIO which has some overhead (I posted get_user_pages() sclability graph some time ago).
Network AIO callback gets pointers to userspace pages and tries to copy data from receiving skb queue into them using protocol specific callback. This callback is very similar to ->recvmsg(), so they could share a lot in future (as far as I recall it worked only with hardware capable to do checksumming, I'm a bit lazy).
Both network and aio implementation work on top of hooks inside appropriate state machines, but not as repeated call design (curect AIO) or special thread (SGI AIO). AIO work was stopped, since I was unable to achieve the same speed as synchronous read
(maximum speeds were 2Gb/sec vs. 2.1 GB/sec for aio and sync IO accordingly when reading data from the cache).
Network aio_sendfile() works lazily - it asynchronously populates pages into the VFS cache (which can be used for various tricks with adaptive readahead) and then uses usual ->sendfile() callback.
I have not created an interface for userspace events (like Solaris), since right now I do not see it's usefullness, but if there is requirements for that it is quite easy with kevents.
I'm preparing set of kevent patches resend (with cleanups mentioned in previous e-mails), which will be ready in a couple of moments.
1. kevent homepage.
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
2. network aio homepage.
http://tservice.net.ru/~s0mbre/old/?section=projects&item=naio
3. LWN.net published a very good article about kevent.
http://lwn.net/Articles/172844/
Thank you.
Signature · 1 line
Evgeniy Polyakov
cover kevent: generic event processing subsystem.
Kevent subsystem incorporates several AIO/kqueue design notes and ideas. Kevent can be used both for edge and level notifications. It supports socket notifications (accept, send, recv), network AIO (aio_send(), aio_recv() and aio_sendfile()), inode notifications (create/remove), generic poll()/select() notifications and timer notifications.
There are several object in the kevent system:
storage - each source of events (socket, inode, timer, aio, anything) has
structure kevent_storage incorporated into it, which is basically a list of registered interests for this source of events.
user - it is abstraction which holds all requested kevents. It is
similar to FreeBSD's kqueue.
kevent - set of interests for given source of events or storage.
When kevent is queued into storage, it will live there until removed by kevent_dequeue(). When some activity is noticed in given storage, it scans it's kevent_storage->list for kevents which match activity event. If kevents are found and they are not already in the kevent_user->ready_list, they will be added there at the end.
ioctl(WAIT) (or appropriate syscall) will wait until either requested number of kevents are ready or timeout elapsed or at least one kevent is ready, it's behaviour depends on parameters.
It is possible to have one-shot kevents, which are automatically removed when are ready.
Any event can be added/removed/modified by ioctl or special controlling syscall.
Network AIO is based on kevent and works as usual kevent storage on top of inode.
When new socket is created it is associated with that inode and when some activity is detected appropriate notifications are generated and kevent_naio_callback() is called.
When new kevent is being registered, network AIO ->enqueue() callback simply marks itself like usual socket event watcher. It also locks physical userspace pages in memory and stores appropriate pointers in private kevent structure. I have not created additional DMA memory allocation methods, like Ulrich described in his article, so I handle it inside NAIO which has some overhead (I posted get_user_pages() sclability graph some time ago).
Network AIO callback gets pointers to userspace pages and tries to copy data from receiving skb queue into them using protocol specific callback. This callback is very similar to ->recvmsg(), so they could share a lot in future (as far as I recall it worked only with hardware capable to do checksumming, I'm a bit lazy).
Both network and aio implementation work on top of hooks inside appropriate state machines, but not as repeated call design (curect AIO) or special thread (SGI AIO). AIO work was stopped, since I was unable to achieve the same speed as synchronous read
(maximum speeds were 2Gb/sec vs. 2.1 GB/sec for aio and sync IO accordingly when reading data from the cache).
Network aio_sendfile() works lazily - it asynchronously populates pages into the VFS cache (which can be used for various tricks with adaptive readahead) and then uses usual ->sendfile() callback.
I have not created an interface for userspace events (like Solaris), since right now I do not see it's usefullness, but if there is requirements for that it is quite easy with kevents.
Patches currently include ifdefs and kevent can be disabled in config, when things are settled that can be removed.
1. kevent homepage.
http://tservice.net.ru/~s0mbre/old/?section=projects&item=kevent
2. network aio homepage.
http://tservice.net.ru/~s0mbre/old/?section=projects&item=naio
3. LWN.net published a very good article about kevent.
http://lwn.net/Articles/172844/
Thank you.
PATCH 1/4 kevent: core files.
This patch includes core kevent files:
- userspace controlling
- kernelspace interfaces
- initialization
- notification state machines
It might also inlclude parts from other subsystem (like network related syscalls, so it is possible that it will not compile without other patches applied).
arch/i386/kernel/syscall_table.S +4 -0
@@ -316,3 +316,7 @@ ENTRY(sys_call_table) .long sys_sync_file_range .long sys_tee /* 315 */ .long sys_vmsplice + .long sys_aio_recv + .long sys_aio_send + .long sys_aio_sendfile + .long sys_kevent_ctl
arch/x86_64/ia32/ia32entry.S +4 -0
@@ -696,4 +696,8 @@ #endif .quad sys_sync_file_range .quad sys_tee .quad compat_sys_vmsplice + .quad sys_aio_recv + .quad sys_aio_send + .quad sys_aio_sendfile + .quad sys_kevent_ctl ia32_syscall_end:
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/asm-i386/unistd.h +5 -1
@@ -322,10 +322,14 @@ #define __NR_splice 313#define __NR_sync_file_range 314#define __NR_tee 315#define __NR_vmsplice 316 +#define __NR_aio_recv 317 +#define __NR_aio_send 318 +#define __NR_aio_sendfile 319 +#define __NR_kevent_ctl 320#ifdef __KERNEL__ -#define NR_syscalls 317 +#define NR_syscalls 321/* * user-visible error numbers are in the range -1 - -128: see
include/asm-x86_64/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/asm-x86_64/unistd.h +9 -2
@@ -617,11 +617,18 @@ #define __NR_sync_file_range 277 __SYSCALL(__NR_sync_file_range, sys_sync_file_range)#define __NR_vmsplice 278 __SYSCALL(__NR_vmsplice, sys_vmsplice) +#define __NR_aio_recv 279 +__SYSCALL(__NR_aio_recv, sys_aio_recv) +#define __NR_aio_send 280 +__SYSCALL(__NR_aio_send, sys_aio_send) +#define __NR_aio_sendfile 281 +__SYSCALL(__NR_aio_sendfile, sys_aio_sendfile) +#define __NR_kevent_ctl 282 +__SYSCALL(__NR_kevent_ctl, sys_kevent_ctl)#ifdef __KERNEL__ -#define __NR_syscall_max __NR_vmsplice - +#define __NR_syscall_max __NR_kevent_ctl#ifndef __NO_STUBS/* user-visible error numbers are in the range -1 - -4095 */
include/linux/kevent.h new file +263 -0
263 lines not on this page · raw message
include/linux/kevent_storage.h new file +12 -0
@@ -0,0 +1,12 @@ +#ifndef __KEVENT_STORAGE_H +#define __KEVENT_STORAGE_H + +struct kevent_storage +{ +void *origin;/* Originator's pointer, e.g. struct sock or struct file. Can be NULL. */ +struct list_head list;/* List of queued kevents. */ +unsigned int qlen;/* Number of queued kevents. */ +spinlock_t lock;/* Protects users queue. */ +}; + +#endif /* __KEVENT_STORAGE_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/linux/syscalls.h +4 -0
@@ -587,4 +587,8 @@ asmlinkage long sys_get_robust_list(intasmlinkage long sys_set_robust_list (struct robust_list_head __user *head,size_t len); +asmlinkage long sys_aio_recv (int ctl_fd,int s,void __user *buf,size_t size,unsigned flags); +asmlinkage long sys_aio_send (int ctl_fd,int s,void __user *buf,size_t size,unsigned flags); +asmlinkage long sys_aio_sendfile (int ctl_fd,int fd,int s,size_t size,unsigned flags); +asmlinkage long sys_kevent_ctl (int ctl_fd,void __user *buf);#endif
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,
init/Kconfig +2 -0
@@ -185,6 +185,8 @@ config AUDITSYSCALL such as SELinux. To use audit's filesystem watch feature, please ensure that INOTIFY is configured. +source "kernel/kevent/Kconfig" + config IKCONFIG bool "Kernel .config support" ---help---
kernel/Makefile +1 -0
@@ -36,6 +36,7 @@ obj-$(CONFIG_DETECT_SOFTLOCKUP) += softl obj-$(CONFIG_GENERIC_HARDIRQS) += irq/ obj-$(CONFIG_SECCOMP) += seccomp.o obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o +obj-$(CONFIG_KEVENT) += kevent/ obj-$(CONFIG_RELAY) += relay.o ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
kernel/kevent/Kconfig new file +57 -0
57 lines not on this page · raw message
kernel/kevent/Makefile new file +7 -0
@@ -0,0 +1,7 @@ +obj-y := kevent.o kevent_user.o kevent_init.o +obj-$(CONFIG_KEVENT_SOCKET) += kevent_socket.o +obj-$(CONFIG_KEVENT_INODE) += kevent_inode.o +obj-$(CONFIG_KEVENT_TIMER) += kevent_timer.o +obj-$(CONFIG_KEVENT_POLL) += kevent_poll.o +obj-$(CONFIG_KEVENT_NAIO) += kevent_naio.o +obj-$(CONFIG_KEVENT_AIO) += kevent_aio.o
kernel/kevent/kevent.c new file +260 -0
260 lines not on this page · raw message
kernel/kevent/kevent_init.c new file +85 -0
85 lines not on this page · raw message
kernel/kevent/kevent_user.c new file +728 -0
728 lines not on this page · raw message
kernel/sys_ni.c +5 -0
@@ -121,6 +121,11 @@ cond_syscall(ppc_rtas);cond_syscall (sys_spu_run);cond_syscall (sys_spu_create); +cond_syscall (sys_aio_recv); +cond_syscall (sys_aio_send); +cond_syscall (sys_aio_sendfile); +cond_syscall (sys_kevent_ctl); +/* mmu depending weak syscall entries */ cond_syscall (sys_mprotect);cond_syscall (sys_msync);
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,
PATCH 2/4 kevent: network AIO, socket notifications.
This patchset includes socket notifications and network asynchronous IO. Network AIO is based on kevent and works as usual kevent storage on top of inode.
When new socket is created it is associated with inode (to save some space, since inode already has kevent_storage embedded) and when some activity is detected appropriate notifications are generated and kevent_naio_callback() is called.
When new kevent is being registered, network AIO ->enqueue() callback simply marks itself like usual socket event watcher. It also locks physical userspace pages in memory and stores appropriate pointers in private kevent structure. I have not created additional DMA memory allocation methods, like Ulrich described in his article, so I handle it inside NAIO which has some overhead (I posted get_user_pages() sclability graph some time ago). New set of syscalls to allocate DMAable memory is in TODO.
Network AIO callback gets pointers to userspace pages and tries to copy data from receiving skb queue into them using protocol specific callback. This callback is very similar to ->recvmsg(), so they could share a lot in future (as far as I recall it worked only with hardware capable to do checksumming, I'm a bit lazy, it is in TODO)
kernel/kevent/kevent_socket.c new file +125 -0
@@ -0,0 +1,125 @@ +/* +* kevent_socket.c +* +* 2006 Copyright (c) Evgeniy Polyakov <[email protected]> +* All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/timer.h> +#include <linux/file.h> +#include <linux/tcp.h> +#include <linux/kevent.h> + +#include <net/sock.h> +#include <net/request_sock.h> +#include <net/inet_connection_sock.h> + +static int kevent_socket_callback (struct kevent *k) +{ +struct inode *inode = k->st->origin; +struct sock *sk =SOCKET_I (inode)->sk; +int rmem; + +if (k->event.event &KEVENT_SOCKET_RECV ) { +int ret =0 ; + +if ((rmem =atomic_read (&sk->sk_rmem_alloc)) >0 || + !skb_queue_empty (&sk->sk_receive_queue)) + ret =1 ; +if (sk->sk_shutdown &RCV_SHUTDOWN ) + ret =1 ; +if (ret) +return ret; + } +if ((k->event.event &KEVENT_SOCKET_ACCEPT ) && + (!reqsk_queue_empty (&inet_csk (sk)->icsk_accept_queue) || +reqsk_queue_len_young (&inet_csk (sk)->icsk_accept_queue))) { + k->event.ret_data[1 ] =reqsk_queue_len (&inet_csk (sk)->icsk_accept_queue); +return 1 ; + } + +return 0 ; +} + +int kevent_socket_enqueue (struct kevent *k) +{ +struct file *file; +struct inode *inode; +int err, fput_needed; + + file =fget_light (k->event.id.raw[0 ], &fput_needed); +if (!file) +return -ENODEV ; + + err = -EINVAL ; +if (!file->f_dentry || !file->f_dentry->d_inode) + goto err_out_fput; + + inode =igrab (file->f_dentry->d_inode); +if (!inode) + goto err_out_fput; + + err =kevent_storage_enqueue (&inode->st, k); +if (err) + goto err_out_iput; + + err = k->callback (k); +if (err) + goto err_out_dequeue; + +fput_light (file, fput_needed); +return err; + +err_out_dequeue: +kevent_storage_dequeue (k->st, k); +err_out_iput: +iput (inode); +err_out_fput: +fput_light (file, fput_needed); +return err; +} + +int kevent_socket_dequeue (struct kevent *k) +{ +struct inode *inode = k->st->origin; + +kevent_storage_dequeue (k->st, k); +iput (inode); + +return 0 ; +} + +int kevent_init_socket (struct kevent *k) +{ + k->enqueue = &kevent_socket_enqueue; + k->dequeue = &kevent_socket_dequeue; + k->callback = &kevent_socket_callback; +return 0 ; +} + +void kevent_socket_notify (struct sock *sk,u32 event) +{ +if (sk->sk_socket && !test_and_set_bit (SOCK_ASYNC_INUSE , &sk->sk_flags)) { +kevent_storage_ready (&SOCK_INODE (sk->sk_socket)->st,NULL , event); +sock_reset_flag (sk,SOCK_ASYNC_INUSE ); + } +}
kernel/kevent/kevent_naio.c new file +239 -0
239 lines not on this page · raw message
PATCH 3/4 kevent: AIO, aio_sendfile() implementation.
This patch includes asynchronous propagation of file's data into VFS cache and aio_sendfile() implementation.
Network aio_sendfile() works lazily - it asynchronously populates pages into the VFS cache (which can be used for various tricks with adaptive readahead) and then uses usual ->sendfile() callback.
fs/bio.c +1 -1
@@ -119,7 +119,7 @@ void bio_free(struct bio *bio, struct bi/* * default destructor for a bio allocated with bio_alloc_bioset() */ -static void bio_fs_destructor (struct bio *bio) +void bio_fs_destructor (struct bio *bio) {bio_free (bio, fs_bio_set); }
fs/ext2/inode.c +1 -0
@@ -685,6 +685,7 @@ ext2_writepages(struct address_space *ma }struct address_space_operations ext2_aops = { + .get_block = ext2_get_block, .readpage = ext2_readpage, .readpages = ext2_readpages, .writepage = ext2_writepage,
fs/ext3/inode.c +1 -0
@@ -1700,6 +1700,7 @@ static int ext3_journalled_set_page_dirt }static struct address_space_operations ext3_ordered_aops = { + .get_block = ext3_get_block, .readpage = ext3_readpage, .readpages = ext3_readpages, .writepage = ext3_ordered_writepage,
fs/file_table.c +6 -0
@@ -113,6 +113,9 @@ struct file *get_empty_filp(void)if (security_file_alloc (f)) goto fail_sec; +#ifdef CONFIG_KEVENT_POLL +kevent_storage_init (f, &f->st); +#endif tsk = current;INIT_LIST_HEAD (&f->f_u.fu_list);atomic_set (&f->f_count,1 );
@@ -160,6 +163,9 @@ void fastcall __fput(struct file *file)might_sleep ();fsnotify_close (file); +#ifdef CONFIG_KEVENT_POLL +kevent_storage_fini (&file->st); +#endif /* * The function eventpoll_release() should be the first called * in the file cleanup chain.
fs/inode.c +7 -0
@@ -22,6 +22,7 @@ #include <linux/pagemap.h>#include <linux/cdev.h> #include <linux/bootmem.h> #include <linux/inotify.h> +#include <linux/kevent.h> #include <linux/mount.h> /*
@@ -166,12 +167,18 @@ #endif }memset (&inode->u,0 ,sizeof (inode->u)); inode->i_mapping = mapping; +#if definedCONFIG_KEVENT +kevent_storage_init (inode, &inode->st); +#endif }return inode; }void destroy_inode (struct inode *inode) { +#if definedCONFIG_KEVENT_INODE || definedCONFIG_KEVENT_SOCKET +kevent_storage_fini (&inode->st); +#endif BUG_ON (inode_has_buffers (inode));security_inode_free (inode);if (inode->i_sb->s_op->destroy_inode)
fs/reiserfs/inode.c +1 -0
@@ -2997,6 +2997,7 @@ int reiserfs_setattr(struct dentry *dent }struct address_space_operations reiserfs_address_space_operations = { + .get_block = reiserfs_get_block, .writepage = reiserfs_writepage, .readpage = reiserfs_readpage, .readpages = reiserfs_readpages,
include/linux/fs.h +12 -0
@@ -236,6 +236,9 @@ #include <linux/mutex.h>#include <asm/atomic.h> #include <asm/semaphore.h> #include <asm/byteorder.h> +#ifdef CONFIG_KEVENT +#include <linux/kevent_storage.h> +#endif struct hd_geometry ;struct iovec ;
@@ -348,6 +351,8 @@ struct address_space;struct writeback_control ;struct address_space_operations { +int (*get_block)(struct inode *inode,sector_t iblock, +struct buffer_head *bh_result,int create);int (*writepage)(struct page *page,struct writeback_control *wbc);int (*readpage)(struct file *,struct page *);void (*sync_page)(struct page *);
@@ -526,6 +531,10 @@ #ifdef CONFIG_INOTIFYstruct mutex inotify_mutex;/* protects the watches list */ #endif +#ifdef CONFIG_KEVENT_INODE +struct kevent_storage st; +#endif +unsigned long i_state;unsigned long dirtied_when;/* jiffies of first dirtying */
@@ -659,6 +668,9 @@ #ifdef CONFIG_EPOLLstruct list_head f_ep_links;spinlock_t f_ep_lock;#endif /* #ifdef CONFIG_EPOLL */ +#ifdef CONFIG_KEVENT_POLL +struct kevent_storage st; +#endif struct address_space *f_mapping; };extern spinlock_t files_lock;
include/linux/fsnotify.h +5 -0
@@ -15,6 +15,7 @@ #ifdef __KERNEL__#include <linux/dnotify.h> #include <linux/inotify.h> +#include <linux/kevent.h> #include <linux/audit.h> /*
@@ -79,6 +80,7 @@ static inline void fsnotify_nameremove(s isdir =IN_ISDIR ;dnotify_parent (dentry,DN_DELETE );inotify_dentry_parent_queue_event (dentry,IN_DELETE |isdir,0 , dentry->d_name.name); +kevent_inode_notify_parent (dentry,KEVENT_INODE_REMOVE ); }/*
@@ -88,6 +90,7 @@ static inline void fsnotify_inoderemove( {inotify_inode_queue_event (inode,IN_DELETE_SELF ,0 ,NULL ,NULL );inotify_inode_is_dead (inode); +kevent_inode_remove (inode); }/*
@@ -96,6 +99,7 @@ static inline void fsnotify_inoderemove(static inline void fsnotify_create (struct inode *inode,struct dentry *dentry) {inode_dir_notify (inode,DN_CREATE ); +kevent_inode_notify (inode,KEVENT_INODE_CREATE );inotify_inode_queue_event (inode,IN_CREATE ,0 , dentry->d_name.name, dentry->d_inode);audit_inode_child (dentry->d_name.name, dentry->d_inode, inode->i_ino);
@@ -107,6 +111,7 @@ static inline void fsnotify_create(strucstatic inline void fsnotify_mkdir (struct inode *inode,struct dentry *dentry) {inode_dir_notify (inode,DN_CREATE ); +kevent_inode_notify (inode,KEVENT_INODE_CREATE );inotify_inode_queue_event (inode,IN_CREATE |IN_ISDIR ,0 , dentry->d_name.name, dentry->d_inode);audit_inode_child (dentry->d_name.name, dentry->d_inode, inode->i_ino);
kernel/kevent/kevent_inode.c new file +110 -0
110 lines not on this page · raw message
kernel/kevent/kevent_aio.c new file +580 -0
580 lines not on this page · raw message
PATCH 4/4 kevent: poll/select() notifications. Timer notifications.
This patch includes generic poll/select and timer notifications.
kevent_poll works simialr to epoll and has the same issues (callback is invoked not from internal state machine of the caller, but through process awake).
Timer notifications can be used for fine grained per-process time management, since iteractive timers are very inconveniently to use, and they are limited.
kernel/kevent/kevent_poll.c new file +223 -0
@@ -0,0 +1,223 @@ +/* +* kevent_poll.c +* +* 2006 Copyright (c) Evgeniy Polyakov <[email protected]> +* All rights reserved. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2 of the License, or +* (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +*/ + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/timer.h> +#include <linux/file.h> +#include <linux/kevent.h> +#include <linux/poll.h> +#include <linux/fs.h> + +static kmem_cache_t *kevent_poll_container_cache; +static kmem_cache_t *kevent_poll_priv_cache; + +struct kevent_poll_ctl +{ +struct poll_table_struct pt; +struct kevent *k; +}; + +struct kevent_poll_wait_container +{ +struct list_head container_entry; +wait_queue_head_t *whead; +wait_queue_t wait; +struct kevent *k; +}; + +struct kevent_poll_private +{ +struct list_head container_list; +spinlock_t container_lock; +}; + +static int kevent_poll_enqueue (struct kevent *k); +static int kevent_poll_dequeue (struct kevent *k); +static int kevent_poll_callback (struct kevent *k); + +static int kevent_poll_wait_callback (wait_queue_t *wait, +unsigned mode,int sync,void *key) +{ +struct kevent_poll_wait_container *cont = + container_of(wait, struct kevent_poll_wait_container, wait); +struct kevent *k = cont->k; +struct file *file = k->st->origin; +unsigned long flags; +u32 revents, event; + + revents = file->f_op->poll (file,NULL ); +spin_lock_irqsave (&k->lock, flags); + event = k->event.event; +spin_unlock_irqrestore (&k->lock, flags); + +kevent_storage_ready (k->st,NULL , revents); + +return 0 ; +} + +static void kevent_poll_qproc (struct file *file,wait_queue_head_t *whead, +struct poll_table_struct *poll_table) +{ +struct kevent *k = + container_of(poll_table, struct kevent_poll_ctl, pt)->k; +struct kevent_poll_private *priv = k->priv; +struct kevent_poll_wait_container *cont; +unsigned long flags; + + cont =kmem_cache_alloc (kevent_poll_container_cache,SLAB_KERNEL ); +if (!cont) { +kevent_break (k); +return ; + } + + cont->k = k; +init_waitqueue_func_entry (&cont->wait, kevent_poll_wait_callback); + cont->whead = whead; + +spin_lock_irqsave (&priv->container_lock, flags); +list_add_tail (&cont->container_entry, &priv->container_list); +spin_unlock_irqrestore (&priv->container_lock, flags); + +add_wait_queue (whead, &cont->wait); +} + +static int kevent_poll_enqueue (struct kevent *k) +{ +struct file *file; +int err, ready =0 ; +unsigned int revents; +struct kevent_poll_ctl ctl; +struct kevent_poll_private *priv; + + file =fget (k->event.id.raw[0 ]); +if (!file) +return -ENODEV ; + + err = -EINVAL ; +if (!file->f_op || !file->f_op->poll) + goto err_out_fput; + + err = -ENOMEM ; + priv =kmem_cache_alloc (kevent_poll_priv_cache,SLAB_KERNEL ); +if (!priv) + goto err_out_fput; + +spin_lock_init (&priv->container_lock); +INIT_LIST_HEAD (&priv->container_list); + + k->priv = priv; + + ctl.k = k; +init_poll_funcptr (&ctl.pt, &kevent_poll_qproc); + + err =kevent_storage_enqueue (&file->st, k); +if (err) + goto err_out_free; + + revents = file->f_op->poll (file, &ctl.pt); +if (revents & k->event.event) { + ready =1 ; +kevent_poll_dequeue (k); + } + +return ready; + +err_out_free: +kmem_cache_free (kevent_poll_priv_cache, priv); +err_out_fput: +fput (file); +return err; +} + +static int kevent_poll_dequeue (struct kevent *k) +{ +struct file *file = k->st->origin; +struct kevent_poll_private *priv = k->priv; +struct kevent_poll_wait_container *w, *n; +unsigned long flags; + +kevent_storage_dequeue (k->st, k); + +spin_lock_irqsave (&priv->container_lock, flags); +list_for_each_entry_safe (w, n, &priv->container_list, container_entry) { +list_del (&w->container_entry); +remove_wait_queue (w->whead, &w->wait); +kmem_cache_free (kevent_poll_container_cache, w); + } +spin_unlock_irqrestore (&priv->container_lock, flags); + +kmem_cache_free (kevent_poll_priv_cache, priv); + k->priv =NULL ; + +fput (file); + +return 0 ; +} + +static int kevent_poll_callback (struct kevent *k) +{ +struct file *file = k->st->origin; +unsigned int revents = file->f_op->poll (file,NULL ); +return (revents & k->event.event); +} + +int kevent_init_poll (struct kevent *k) +{ +if (!kevent_poll_container_cache || !kevent_poll_priv_cache) +return -ENOMEM ; + + k->enqueue = &kevent_poll_enqueue; + k->dequeue = &kevent_poll_dequeue; + k->callback = &kevent_poll_callback; +return 0 ; +} + + +static int __init kevent_poll_sys_init (void ) +{ + kevent_poll_container_cache =kmem_cache_create ("kevent_poll_container_cache" , +sizeof (struct kevent_poll_wait_container ),0 ,0 ,NULL ,NULL ); +if (!kevent_poll_container_cache) { +printk (KERN_ERR "Failed to create kevent poll container cache.\n" ); +return -ENOMEM ; + } + + kevent_poll_priv_cache =kmem_cache_create ("kevent_poll_priv_cache" , +sizeof (struct kevent_poll_private ),0 ,0 ,NULL ,NULL ); +if (!kevent_poll_priv_cache) { +printk (KERN_ERR "Failed to create kevent poll private data cache.\n" ); +kmem_cache_destroy (kevent_poll_container_cache); + kevent_poll_container_cache =NULL ; +return -ENOMEM ; + } + +printk (KERN_INFO "Kevent poll()/select() subsystem has been initialized.\n" ); +return 0 ; +} + +static void __exit kevent_poll_sys_fini(void) +{ +kmem_cache_destroy (kevent_poll_priv_cache); +kmem_cache_destroy (kevent_poll_container_cache); +} + +module_init (kevent_poll_sys_init); +module_exit (kevent_poll_sys_fini);
kernel/kevent/kevent_timer.c new file +112 -0
112 lines not on this page · raw message
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
In reply to Evgeniy PolyakovQuoted 27 lines · Evgeniy Polyakov
This patch includes asynchronous propagation of file's data into VFS cache and
aio_sendfile()implementation.
Networkaio_sendfile()works lazily - it asynchronously populates pages into the VFS cache (which can be used for various tricks with adaptive readahead) and then uses usual ->sendfile() callback.Signed-off-by Evgeniy Polyakov <[email protected]>fs/bio.c +1
-1@@ -119,7 +119,7 @@ void bio_free(struct bio *bio, struct bi/* * default destructor for a bio allocated with bio_alloc_bioset() */ -static void bio_fs_destructor (struct bio *bio) +void bio_fs_destructor (struct bio *bio) {bio_free (bio, fs_bio_set); }fs/ext2/inode.c +0
-0
fs/ext2/inode.c ext2_writepages(struct address_space *ma · line 688
Quoted 4 lines
fs/ext2/inode.c +1
-0@@ -685,6 +685,7 @@ ext2_writepages(struct address_space *ma }struct address_space_operations ext2_aops = { + .get_block = ext2_get_block,
No way in hell. For whatever you do please provide a interface at the readpage/writepage/sendfile/etc abstraction layer. get_block is nothing that can be exposed to the common code.
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 6 lines · Christoph Hellwig
fs/ext2/inode.c ext2_writepages(struct address_space *ma · line 688
Quoted 2 lines
struct
address_space_operationsext2_aops= {fs/ext2/inode.c +1
-0+ .get_block = ext2_get_block,No way in hell. For whatever you do please provide a interface at the readpage/writepage/sendfile/etc abstraction layer.
get_blockis nothing that can be exposed to the common code.
Compare this with sync read methods - all they do is exactly the same operations with low-level blocks, which are combined into nice exported function, so there is _no_ readpage layer - it calls only one function which works with blocks.
I would create the same, i.e. async_readpage(), which called kevent's functions and processed low-level blocks, just like sync code does, but that requires kevent to be deep part of the FS tree.
So I prefer to have kevent/some_function_which_works_with_blocks_and_kevents()
instead of fs/some_function_which_works_with_block_and_kevents() kevent/call_that_function_like_all_readpage_callbacks_do().
So it is not a technical problem, but political one.
Signature · 1 line
Evgeniy Polyakov
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 8 lines · Evgeniy Polyakov
Quoted 6 lines · Christoph Hellwig
fs/ext2/inode.c ext2_writepages(struct address_space *ma · line 688
Quoted 2 lines
struct
address_space_operationsext2_aops= {fs/ext2/inode.c +1
-0+ .get_block = ext2_get_block,No way in hell. For whatever you do please provide a interface at the readpage/writepage/sendfile/etc abstraction layer.
get_blockis nothing that can be exposed to the common code.
Quoted 4 lines
Compare this with sync read methods - all they do is exactly the same operations with low-level blocks, which are combined into nice exported function, so there is _no_ readpage layer - it calls only one function which works with blocks.
No. The abtraction layer there is ->readpage(s). _A_ common implementation works with a get_block callback from the filesystem, but there are various others. We've been there before, up to mid-2.3.x we had a get_block inode operation and we got rid of it because it is the wrong abstraction.
Quoted 1 line
So it is not a technical problem, but political one.
It's a technical problem, and it's called get you abstractions right. And ontop of that a political one and that's called get your abstraction coherent. If you managed to argue all of us into accept that get_block is the right abstraction (and as I mentioned above that's technically not true) you'd still have the burden to update everything to use the same abstraction.
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 14 lines · Christoph Hellwig
Quoted 8 lines · Evgeniy Polyakov
Quoted 6 lines · Christoph Hellwig
fs/ext2/inode.c ext2_writepages(struct address_space *ma · line 688
Quoted 2 lines
struct
address_space_operationsext2_aops= {fs/ext2/inode.c +1
-0+ .get_block = ext2_get_block,No way in hell. For whatever you do please provide a interface at the readpage/writepage/sendfile/etc abstraction layer.
get_blockis nothing that can be exposed to the common code.Quoted 4 lines
Compare this with sync read methods - all they do is exactly the same operations with low-level blocks, which are combined into nice exported function, so there is _no_ readpage layer - it calls only one function which works with blocks.
Quoted 4 lines
No. The abtraction layer there is ->readpage(s). _A_ common implementation works with a
get_blockcallback from the filesystem, but there are various others. We've been there before, up to mid-2.3.x we had aget_blockinode operation and we got rid of it because it is the wrong abstraction.
Well, kevent can work not from it's own, but with common implementation, which works with get_block(). No problem here.
Quoted 7 lines
Quoted 1 line
So it is not a technical problem, but political one.
It's a technical problem, and it's called get you abstractions right. And ontop of that a political one and that's called get your abstraction coherent. If you managed to argue all of us into accept that
get_blockis the right abstraction (and as I mentioned above that's technically not true) you'd still have the burden to update everything to use the same abstraction.
Christoph, I completely understand your point of view.
There is absolutely no technical problem to create common async implementation, and place it where existing sync lives and call from readpage() level.
It just requires to allow to change BIO callbacks instead of default one, and (probably) event sync readpage can be used.
Signature · 1 line
Evgeniy Polyakov
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
In reply to Evgeniy PolyakovQuoted 6 lines · Evgeniy Polyakov
This patch includes asynchronous propagation of file's data into VFS cache and
aio_sendfile()implementation.
Networkaio_sendfile()works lazily - it asynchronously populates pages into the VFS cache (which can be used for various tricks with adaptive readahead) and then uses usual ->sendfile() callback.
And please don't base this on sendfile. Please make the splice infrastructure aynschronous without duplicating all the code but rather make the existing code aynch and the existing synchronous call wait on them to finish, similar to how we handle async/sync direct I/O. And to be honest, I don't think adding all this code is acceptable if it can't replace the existing aio code while keeping the interface. So while you interface looks pretty sane the implementation needs a lot of work still :)
David Miller
maintainerRe: [3/4] kevent: AIO, aio_sendfile() implementation.
From: Christoph Hellwig <[email protected]>
Date: Wed, 26 Jul 2006 11:04:31 +0100
Quoted 4 lines
And to be honest, I don't think adding all this code is acceptable if it can't replace the existing aio code while keeping the interface. So while you interface looks pretty sane the implementation needs a lot of work still :)
Networking and disk AIO have significantly different needs.
Therefore, I really don't see it as reasonable to expect a merge of these two things. It doesn't make any sense.
I do agree that this stuff needs to be cleaned up, all the get_block etc. hacks have to be pulled out and abstracted properly. That part of the kevent changes are indeed still crap :)
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 8 lines · David Miller
From: Christoph Hellwig <[email protected]>
Date: Wed, 26 Jul 2006 11:04:31 +0100Quoted 4 lines
And to be honest, I don't think adding all this code is acceptable if it can't replace the existing aio code while keeping the interface. So while you interface looks pretty sane the implementation needs a lot of work still :)
Quoted 4 lines
Networking and disk AIO have significantly different needs.
Therefore, I really don't see it as reasonable to expect a merge of these two things. It doesn't make any sense.
I'm not sure about that. The current aio interface isn't exactly nice for disk I/O either. I'm more than happy to have a discussion about that aspect.
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 9 lines · Christoph Hellwig
Quoted 4 lines
Networking and disk AIO have significantly different needs.
Therefore, I really don't see it as reasonable to expect a merge of these two things. It doesn't make any sense.
I'm not sure about that. The current aio interface isn't exactly nice for disk I/O either. I'm more than happy to have a discussion about that aspect.
I agree that it makes perfect sense for a merger because aio and networking have very similar needs. In both cases, the caller hands the kernel a buffer and wants the kernel to either fill it or consume it, and to be able to do so asynchronously. You also want to maximize performance in both cases by taking advantage of zero copy IO.
I wonder though, why do you say the current aio interface isn't nice for disk IO? It seems to work rather nicely to me, and is much better than the posix aio interface.
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
In reply to David MillerQuoted 11 lines · David Miller
From: Christoph Hellwig <[email protected]>
Date: Wed, 26 Jul 2006 11:04:31 +0100Quoted 4 lines
And to be honest, I don't think adding all this code is acceptable if it can't replace the existing aio code while keeping the interface. So while you interface looks pretty sane the implementation needs a lot of work still :)
Networking and disk AIO have significantly different needs.
Surely, there needs to be a unified polling interface to support single threaded designs.
Signature · 1 line
error compiling committee.c: too many arguments to function
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
In reply to Christoph HellwigQuoted 8 lines · Christoph Hellwig
Quoted 6 lines · Evgeniy Polyakov
This patch includes asynchronous propagation of file's data into VFS cache and
aio_sendfile()implementation.
Networkaio_sendfile()works lazily - it asynchronously populates pages into the VFS cache (which can be used for various tricks with adaptive readahead) and then uses usual ->sendfile() callback.
Quoted 7 lines
And please don't base this on sendfile. Please make the splice infrastructure aynschronous without duplicating all the code but rather make the existing code aynch and the existing synchronous call wait on them to finish, similar to how we handle async/sync direct I/O. And to be honest, I don't think adding all this code is acceptable if it can't replace the existing aio code while keeping the interface. So while you interface looks pretty sane the implementation needs a lot of work still :)
Kevent was created quite before splice and friends, so I used what there were :)
I stopped to work on AIO, since neither existing, nor mine implementation were able to outperform sync speeds (one of the major problems in my implementation is get_user_pages() overhead, which can be completely eliminated with physical memory allocation being done in advance in userspace, like Ulrich described).
My personal opinion on existing AIO is that it is not the right design. Benjamin LaHaise agree with me (if I understood him right), but he failed to move AIO outside repeated-call model (2.4 had state machine based one, and out-of-the tree 2.6 patches have that design too). In theory existing AIO (with all posix userspace API) can be replaced with kevent (it will even take less space), but I would present it as a TODO item, since kevent itself has nothing to do with AIO.
Kevent is a generic event processing mechanism, AIO, network AIO and all others are just kernel users of it's functionality.
Signature · 1 line
Evgeniy Polyakov
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 7 lines · Evgeniy Polyakov
I stopped to work on AIO, since neither existing, nor mine implementation were able to outperform sync speeds (one of the major problems in my implementation is
get_user_pages()overhead, which can be completely eliminated with physical memory allocation being done in advance in userspace, like Ulrich described).
My personal opinion on existing AIO is that it is not the right design. Benjamin LaHaise agree with me (if I understood him right),
I completely agree with that aswell.
Quoted 6 lines
but he
failed to move AIO outside repeated-call model (2.4 had state machine based one, and out-of-the tree 2.6 patches have that design too). In theory existing AIO (with all posix userspace API) can be replaced with kevent (it will even take less space), but I would present it as a TODO item, since kevent itself has nothing to do with AIO.
And replacing the existing aio code is exactly we I want you to do. We can't keep adding more and more code without getting rid of old mess forever.
And yes, the asynchronous pagecache population bit in your patchkit has a lot to do with aio. It's same variant of aio done right (or at least less bad).
I suspect the right way to go ahead is to drop that bit for now (it's the by far worst code in the patchkit anyway) and then we can redo it later to not get abstractions wrong and duplicate lots of code but also replace the aio code. I don't expect you to do that alone, you'll probably need quite a bit help from us FS and VM people.
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 4 lines · Christoph Hellwig
Quoted 2 lines
My personal opinion on existing AIO is that it is not the right design. Benjamin LaHaise agree with me (if I understood him right),
I completely agree with that aswell.
I agree, too, but the current code is not the last of the line. Suparna has a st of patches which make the current kernel aio code work much better and especially make it really usable to implement POSIX AIO.
In Ottawa we were talking about submitting it and Suparna will. We just thought about a little longer timeframe. I guess it could be accelerated since he mostly has the patch done. But I don't know her schedule.
Important here is, don't base any decision on the current aio implementation.
Signature · 1 line
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 12 lines · Ulrich Drepper
Quoted 5 lines · Christoph Hellwig
Quoted 3 lines
My personal opinion on existing AIO is that it is not the right design. Benjamin LaHaise agree with me (if I understood him right),
I completely agree with that aswell.
I agree, too, but the current code is not the last of the line. Suparna has a st of patches which make the current kernel aio code work much better and especially make it really usable to implement POSIX AIO.
Quoted 8 lines
In Ottawa we were talking about submitting it and Suparna will. We just thought about a little longer timeframe. I guess it could be accelerated since he mostly has the patch done. But I don't know her schedule.
Important here is, don't base any decision on the current aio implementation.
Ulrich,
Suparna mentioned your interest in making POSIX glibc aio work with kernel-aio at OLS. We thought taking a re-look at the (kernel side) work BULL did, would be a nice starting point. I re-based those patches to 2.6.18-rc2 and sent it to Zach Brown for review before sending them out to list.
These patches does NOT make AIO any cleaner. All they do is add functionality to support POSIX AIO easier. These are
[ PATCH 1/3 ] Adding signal notification for event completion
[ PATCH 2/3 ] lio (listio) completion semantics
[ PATCH 3/3 ] cancel_fd support
Suparna explained these in the following article:
http://lwn.net/Articles/148755/
If you think, this is a reasonable direction/approach for the kernel and you would take care of glibc side of things - I can spend time on these patches, getting them to reasonable shape and push for inclusion.
Please let us know.
Thanks,
Badari
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 35 lines · Badari Pulavarty
Quoted 12 lines · Ulrich Drepper
Quoted 5 lines · Christoph Hellwig
Quoted 3 lines
My personal opinion on existing AIO is that it is not the right design. Benjamin LaHaise agree with me (if I understood him right),
I completely agree with that aswell.
I agree, too, but the current code is not the last of the line. Suparna has a st of patches which make the current kernel aio code work much better and especially make it really usable to implement POSIX AIO.
Quoted 8 lines
In Ottawa we were talking about submitting it and Suparna will. We just thought about a little longer timeframe. I guess it could be accelerated since he mostly has the patch done. But I don't know her schedule.
Important here is, don't base any decision on the current aio implementation.
Ulrich,
Suparna mentioned your interest in making POSIX glibc aio work with kernel-aio at OLS.
We thought taking a re-look at the (kernel side) work BULL did, would be a nice starting
point. I re-based those patches to 2.6.18-rc2 and sent it to Zach Brown for review before
sending them out to list.These patches does NOT make AIO any cleaner. All they do is add functionality to support
POSIX AIO easier. These are
Quoted 5 lines
[ PATCH 1/3 ] Adding signal notification for event completion
[ PATCH 2/3 ] lio (listio) completion semantics
[ PATCH 3/3 ]
cancel_fdsupport
Badari,
Thanks for refreshing those patches, they have been sitting here
for quite some time now and collected dust.
I also think Suparna's patchset for doing buffered AIO would be
a real plus here.
Quoted 10 lines
Suparna explained these in the following article:
http://lwn.net/Articles/148755/
If you think, this is a reasonable direction/approach for the kernel and you would take care
of glibc side of things - I can spend time on these patches, getting them to reasonable shape
and push for inclusion.
Ulrich, I you want to have a look at how those patches are put to
use in libposix-aio, have a look at http://sourceforge.net/projects/paiol.
It could be a starting point for glibc.
Thanks,
Sébastien.
Signature · 11 lines
----------------------------------------------------- Sébastien Dugué BULL/FREC:B1-247 phone: (+33) 476 29 77 70 Bullcom: 229-7770 mailto:[email protected] Linux POSIX AIO: http://www.bullopensource.org/posix http://sourceforge.net/projects/paiol -----------------------------------------------------
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 62 lines · Sébastien Dugué
Quoted 32 lines · Badari Pulavarty
Quoted 14 lines · Ulrich Drepper
Quoted 7 lines · Christoph Hellwig
Quoted 4 lines
My personal opinion on existing AIO is that it is not the right design. Benjamin LaHaise agree with me (if I understood him right),
I completely agree with that aswell.
I agree, too, but the current code is not the last of the line. Suparna has a st of patches which make the current kernel aio code work much better and especially make it really usable to implement POSIX AIO.
Quoted 9 lines
In Ottawa we were talking about submitting it and Suparna will. We just thought about a little longer timeframe. I guess it could be accelerated since he mostly has the patch done. But I don't know her schedule.
Important here is, don't base any decision on the current aio implementation.
Ulrich,
Suparna mentioned your interest in making POSIX glibc aio work with kernel-aio at OLS. We thought taking a re-look at the (kernel side) work BULL did, would be a nice starting point. I re-based those patches to 2.6.18-rc2 and sent it to Zach Brown for review before sending them out to list.
Quoted 9 lines
These patches does NOT make AIO any cleaner. All they do is add functionality to support POSIX AIO easier. These are
[ PATCH 1/3 ] Adding signal notification for event completion
[ PATCH 2/3 ] lio (listio) completion semantics
[ PATCH 3/3 ]
cancel_fdsupportBadari,
Thanks for refreshing those patches, they have been sitting here
for quite some time now and collected dust.I also think Suparna's patchset for doing buffered AIO would be
a real plus here.Quoted 8 lines
Suparna explained these in the following article:
http://lwn.net/Articles/148755/
If you think, this is a reasonable direction/approach for the kernel and you would take care of glibc side of things - I can spend time on these patches, getting them to reasonable shape and push for inclusion.
Quoted 10 lines
Ulrich, I you want to have a look at how those patches are put to
use in libposix-aio, have a look at http://sourceforge.net/projects/paiol.It could be a starting point for glibc.
Thanks,
Sébastien.
Sebastien,
Suparna mentioned at Ulrich wants us to concentrate on kernel-side support, so that he can look at glibc side of things (along with other work he is already doing). So, if we can get an agreement on what kind of kernel support is needed - we can focus our efforts on kernel side first and leave glibc enablement to capable hands of Uli :)
Thanks,
Badari
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 7 lines
Suparna mentioned at Ulrich wants us to concentrate on kernel-side support, so that he can look at glibc side of things (along with other work he is already doing). So, if we can get an agreement on what kind of kernel support is needed - we can focus our efforts on kernel side first and leave glibc enablement to capable hands of Uli :)
Yeah, and the existing patches still need some cleanup. Badari, did you still want me to look into that?
We need someone to claim ultimate responsibility for getting these patches suitable for merging :). I'm happy to do that if Suparna isn't already on it.
- z
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 7 lines · Zach Brown
Quoted 6 lines
Suparna mentioned at Ulrich wants us to concentrate on kernel-side support, so that he can look at glibc side of things (along with other work he is already doing). So, if we can get an agreement on what kind of kernel support is needed - we can focus our efforts on kernel side first and leave glibc enablement to capable hands of Uli :)
Quoted 6 lines
Yeah, and the existing patches still need some cleanup. Badari, did you still want me to look into that?
We need someone to claim ultimate responsibility for getting these patches suitable for merging :). I'm happy to do that if Suparna isn't already on it.
Zach,
Thanks for volunteering !! Sebastien & I should be able to help you.
Before we spend too much time cleaning up and merging into mainline - I would like an agreement that what we add is good enough for glibc POSIX AIO. I hate to waste everyone's time and add complexity to the kernel - if glibc side is not going to happen :(
Thanks,
Badari
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 3 lines · Badari Pulavarty
Before we spend too much time cleaning up and merging into mainline - I would like an agreement that what we add is good enough for glibc POSIX AIO.
I haven't seen a description of the interface so far. Would be good if it existed. But I briefly mentioned one quirk in the interface about which Suparna wasn't sure whether it's implemented/implementable in the current interface.
If a lio_listio call is made the individual requests are handle just as if they'd be issue separately. I.e., the notification specified in the individual aiocb is performed when the specific request is done. Then, once all requests are done, another notification is made, this time controlled by the sigevent parameter if lio_listio.
Another feature which I always wanted: the current lio_listio call returns in blocking mode only if all requests are done. In non-blocking mode it returns immediately and the program needs to poll the aiocbs. What is needed is something in the middle. For instance, if multiple read requests are issued the program might be able to start working as soon as one request is satisfied. I.e., a call similar to lio_listio would be nice which also takes another parameter specifying how many of the NENT aiocbs have to finish before the call returns.
Signature · 1 line
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 9 lines · Ulrich Drepper
Quoted 3 lines · Badari Pulavarty
Before we spend too much time cleaning up and merging into mainline - I would like an agreement that what we add is good enough for glibc POSIX AIO.
I haven't seen a description of the interface so far. Would be good if it existed. But I briefly mentioned one quirk in the interface about which Suparna wasn't sure whether it's implemented/implementable in the current interface.
Sebastien, could you provide a description of interfaces you are adding ? Since you did all the work, it would be appropriate for you to do it :)
Quoted 7 lines
If a
lio_listiocall is made the individual requests are handle just as if they'd be issue separately. I.e., the notification specified in the individual aiocb is performed when the specific request is done. Then, once all requests are done, another notification is made, this time controlled by the sigevent parameter iflio_listio.
Quoted 8 lines
Another feature which I always wanted: the current
lio_listiocall returns in blocking mode only if all requests are done. In non-blocking mode it returns immediately and the program needs to poll the aiocbs. What is needed is something in the middle. For instance, if multiple read requests are issued the program might be able to start working as soon as one request is satisfied. I.e., a call similar tolio_listiowould be nice which also takes another parameter specifying how many of the NENT aiocbs have to finish before the call returns.
Looks reasonable.
Thanks,
Badari
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 6 lines · Badari Pulavarty
Quoted 5 lines · Ulrich Drepper
Quoted 3 lines · Badari Pulavarty
Before we spend too much time cleaning up and merging into mainline - I would like an agreement that what we add is good enough for glibc POSIX AIO.
Quoted 9 lines
Quoted 4 lines
I haven't seen a description of the interface so far. Would be good if it existed. But I briefly mentioned one quirk in the interface about which Suparna wasn't sure whether it's implemented/implementable in the current interface.
Sebastien, could you provide a description of interfaces you are adding ? Since you did all the work, it would be appropriate for you to do it :)
I will clean up what description I have and send it soon.
Sébastien.
Signature · 11 lines
----------------------------------------------------- Sébastien Dugué BULL/FREC:B1-247 phone: (+33) 476 29 77 70 Bullcom: 229-7770 mailto:[email protected] Linux POSIX AIO: http://www.bullopensource.org/posix http://sourceforge.net/projects/paiol -----------------------------------------------------
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
In reply to Badari PulavartyQuoted 6 lines · Badari Pulavarty
Quoted 5 lines · Ulrich Drepper
Quoted 3 lines · Badari Pulavarty
Before we spend too much time cleaning up and merging into mainline - I would like an agreement that what we add is good enough for glibc POSIX AIO.
Quoted 9 lines
Quoted 4 lines
I haven't seen a description of the interface so far. Would be good if it existed. But I briefly mentioned one quirk in the interface about which Suparna wasn't sure whether it's implemented/implementable in the current interface.
Sebastien, could you provide a description of interfaces you are adding ? Since you did all the work, it would be appropriate for you to do it :)
Here are the descriptions for the AIO completion notification and
listio patches. Hope I did not leave out too much.
Sébastien.
Signature · 11 lines
----------------------------------------------------- Sébastien Dugué BULL/FREC:B1-247 phone: (+33) 476 29 77 70 Bullcom: 229-7770 mailto:[email protected] Linux POSIX AIO: http://www.bullopensource.org/posix http://sourceforge.net/projects/paiol -----------------------------------------------------
aio completion notification
Summary:
-------
The current 2.6 kernel does not support notification of user space via
an RT signal upon an asynchronous IO completion. The POSIX specification states that when an AIO request completes, a signal can be delivered to the application as notification.
The aioevent patch adds a struct sigevent *aio_sigeventp to the iocb.
The relevant fields (pid, signal number and value) are stored in the kiocb for use when the request completes.
That sigevent structure is filled by the application as part of the AIO
request preparation. Upon request completion, the kernel notifies the application using those sigevent parameters. If SIGEV_NONE has been specified, then the old behaviour is retained and the application must rely on polling the completion queue using io_getevents().
Details:
-------
A struct sigevent *aio_sigeventp is added to struct iocb ininclude/linux/aio_abi.h
An enum {IO_NOTIFY_SIGNAL = 0, IO_NOTIFY_THREAD_ID = 1} is added ininclude/linux/aio.h:
- IO_NOTIFY_SIGNAL means that the signal is to be sent to the requesting thread
- IO_NOTIFY_THREAD_ID means that the signal is to be sent to a specifi thread.
The following fields are added to struct kiocb in include/linux/aio.h:
- pid_t ki_pid: target of the signal
- __u16 ki_signo: signal number
- __u16 ki_notify: kind of notification, IO_NOTIFY_SIGNAL or IO_NOTIFY_THREAD_ID
- uid_t ki_uid, ki_euid: filled with the submitter credentials
- sigval_t ki_sigev_value: value stuffed in siginfo
these fields are only valid if ki_signo != 0.
In io_submit_one(), if the application provided a sigevent theniocb_setup_sigevent() is called which does the following:
- save current->uid and current->euid in the kiocb fields ki_uid and ki_euid for use in the completion path to check permissions
- check access to the user sigevent
- extract the needed fields from the sigevent (pid, signo, and value). If the signal number passed from userspace is 0 then no notification is to occur and ki_signo is set to 0
- check whether the submitting thread wants to be notified directly (sigevent->sigev_notify_thread_id is 0) or wants the signal to be sent to another thread.
In the latter case a check is made to assert that the target thread is in the same thread group
- fill in the kiocb fields (ki_pid, ki_signo, ki_notify and ki_sigev_value) for that request.
Upon request completion, in aio_complete(), if ki_signo is not 0, then__aio_send_signal() is called which sends the signal as follows:
- fill in the siginfo struct to be sent to the application
- check whether we have permission to signal the given thread
- send the signal
listio support
Summary:
-------
The lio patch adds POSIX listio completion notification support. It builds
on support provided by the aio event patch and adds an IOCB_CMD_GROUP command to sys_io_submit().
The purpose of IOCB_CMD_GROUP is to group together the following requests in
the list up to the end of the list.
As part of listio submission, the user process prepends to a list of requests
an empty special aiocb with an aio_lio_opcode of IOCB_CMD_GROUP, filling only the aio_sigevent fields.
Details:
-------
An IOCB_CMD_GROUP is added to the IOCB_CMD enum in include/linux/aio_abi.h
A struct lio_event is added in include/linux/aio.h
A struct lio_event *ki_lio is added to struct iocb in include/linux/aio.h
In sys_io_submit(), upon detecting such an IOCB_CMD_GROUP marker iocb, anlio_event is created in lio_create() which contains the necessary information for signaling a thread (signal number, pid, notify type and value) along with a count of requests attached to this event.
The following depicts the lio_event structure:
struct lio_event {
atomic_t lio_users;
int lio_wait;
__s32 lio_pid;
__u16 lio_signo;
__u16 lio_notify;
__u64 lio_value;
uid_t lio_uid, lio_euid;
}; lio_users holds a count of the number of requests attached to this lio. It
is incremented with each request submitted and decremented at each request completion. Thread notification occurs when this count reaches 0.
Each subsequent submitted request is attached to this lio_event by setting
the request kiocb->*ki_lio to that lio_event (in io_submit_one()) and incrementing the lio_users count.
In aio_complete(), if the request is attached to an lio (ki_lio <> 0), thenlio_check() is called to decrement the lio_users count and eventually signal the user process when all the requests in the group have completed.
The IOCB_CMD_GROUP command semantic is as follows:
- if the associated aiocb sigevent is NULL then we want to group requests for the purpose of blocking on the group completion (LIO_WAIT sync behavior).
- if the associated sigevent is valid (not NULL) then we want to group requests for the purpose of being notified upon that group of requests completion (LIO_NOWAIT async behaviour).
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
Quoted 1 line · Sébastien Dugué
aio completion notification
I looked over this now but I don't think I understand everything. Or I don't see how it all is integrated. And no, I'm not looking at the proposed glibc code since would mean being tainted.
Quoted 6 lines
Details:
-------A struct sigevent
*aio_sigeventpis added to struct iocb ininclude/linux/aio_abi.h
Quoted 8 lines
An enum {
IO_NOTIFY_SIGNAL= 0,IO_NOTIFY_THREAD_ID= 1} is added ininclude/linux/aio.h:-
IO_NOTIFY_SIGNALmeans that the signal is to be sent to the requesting thread-
IO_NOTIFY_THREAD_IDmeans that the signal is to be sent to a specifi thread.
This has been proved to be sufficient in the timer code which basically has the same problem. But why do you need separate constants? We have the various SIGEV_* constants, among them SIGEV_THREAD_ID. Just use these constants for the values of ki_notify.
Quoted 10 lines
The following fields are added to struct kiocb in
include/linux/aio.h:-
pid_tki_pid: target of the signal-
__u16ki_signo: signal number-
__u16ki_notify: kind of notification,IO_NOTIFY_SIGNALorIO_NOTIFY_THREAD_ID-
uid_tki_uid,ki_euid: filled with the submitter credentials
These two fields aren't needed for the POSIX interfaces. Where does the requirement come from? I don't say they should be removed, they might be useful, but if the costs are non-negligible then they could go away.
Quoted 5 lines
- check whether the submitting thread wants to be notified directly (
sigevent->sigev_notify_thread_idis 0) or wants the signal to be sent to another thread.
In the latter case a check is made to assert that the target thread is in the same thread group
Is this really how it's implemented? This is not how it should be. Either a signal is sent to a specific thread in the same process (this is what SIGEV_THREAD_ID is for) or the signal is sent to a calling process. Sending a signal to the process means that from the kernel's POV any thread which doesn't have the signal blocked can receive it. The final decision is made by the kernel. There is no mechanism to send the signal to another process.
So, for the purpose of the POSIX AIO code the ki_pid value is only needed when the SIGEV_THREAD_ID bit is set.
It could be an extension and I don't mind it being introduced. But again, it's not necessary and if it adds costs then it could be left out. It is something which could easily be introduced later if the need arises.
Quoted 2 lines
listio support
I really don't understand the kernel interface for this feature.
Quoted 8 lines
Details:
-------An
IOCB_CMD_GROUPis added to theIOCB_CMDenum ininclude/linux/aio_abi.hA struct
lio_eventis added ininclude/linux/aio.hA struct
lio_event*ki_liois added to struct iocb ininclude/linux/aio.h
So you have a pointer in the structure for the individual requests. I assume you use the atomic counter to trigger the final delivery. I further assume that if lio_wait is set the calling thread is suspended until all requests are handled and that the final notification in this case means that thread gets woken.
This is all fine.
But how do you pass the requests to the kernel? If you have a new lio_listio-like syscall it'll be easy. But I haven't seen anything like this mentioned.
The alternative is to pass the requests one-by-one in which case I don't see how you create the reference to the lio_listio control block. This approach seems to be slower.
If all requests are passed at once, do you have the equivalent of LIO_NOP entries?
How can we support the extension where we wait for a number of requests which need not be all of them. I.e., I submit N requests and want to be notified when at least M (M <= N) notified. I am not yet clear about the actual semantics we should implement (e.g., do we send another notification after the first one?) but it's something which IMO should be taken into account in the design.
Finally, and this is very important, does you code send out the individual requests notification and then in the end the lio_listio completion? I think Suparna wrote this is the case but I want to make sure.
Overall, this looks much better than the old code. If the answers to my questions show that the behavior is compatible with the POSIX AIO code I'm certainly very much in favor of adding the kernel code.
Signature · 1 line
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)
BTW, if anyone would like to be dropped off this growing cc list, please let us know.
Quoted 6 lines · Ulrich Drepper
Quoted 1 line · Sébastien Dugué
aio completion notification
I looked over this now but I don't think I understand everything. Or I don't see how it all is integrated. And no, I'm not looking at the proposed glibc code since would mean being tainted.
Oh, I didn't realise that.
I'll make an attempt to clarify parts that I understand based on what I have gleaned from my reading of the code and intent, but hopefully Sebastien, Ben, Zach et al will be able to pitch in for a more accurate and complete picture.
Quoted 14 lines
Quoted 14 lines
Details:
-------A struct sigevent
*aio_sigeventpis added to struct iocb ininclude/linux/aio_abi.hAn enum {
IO_NOTIFY_SIGNAL= 0,IO_NOTIFY_THREAD_ID= 1} is added ininclude/linux/aio.h:-
IO_NOTIFY_SIGNALmeans that the signal is to be sent to the requesting thread
Quoted 8 lines
Quoted 2 lines
-
IO_NOTIFY_THREAD_IDmeans that the signal is to be sent to a specifi thread.This has been proved to be sufficient in the timer code which basically has the same problem. But why do you need separate constants? We have the various SIGEV_* constants, among them
SIGEV_THREAD_ID. Just use these constants for the values ofki_notify.
I am wondering about that too. IIRC, the IO_NOTIFY_* constants are not part of the ABI, but only internal to the kernel implementation. I think Zach had suggested inferring THREAD_ID notification if the pid specified is not zero. But, I don't see why ->sigev_notify couldn't used directly (just like the POSIX timers code does) thus doing away with the new constants altogether. Sebestian/Laurent, do you recall?
Quoted 7 lines
Quoted 7 lines
The following fields are added to struct kiocb in
include/linux/aio.h:-
pid_tki_pid: target of the signal-
__u16ki_signo: signal number
Quoted 8 lines
Quoted 4 lines
-
__u16ki_notify: kind of notification,IO_NOTIFY_SIGNALorIO_NOTIFY_THREAD_ID-
uid_tki_uid,ki_euid: filled with the submitter credentialsThese two fields aren't needed for the POSIX interfaces. Where does the requirement come from? I don't say they should be removed, they might be useful, but if the costs are non-negligible then they could go away.
I'm guessing they are being used for validation of permissions at the time of sending the signal, but maybe saving the task pointer in the iocb instead of the pid would suffice ?
Quoted 8 lines
Quoted 7 lines
- check whether the submitting thread wants to be notified directly (
sigevent->sigev_notify_thread_idis 0) or wants the signal to be sent to another thread.
In the latter case a check is made to assert that the target thread is in the same thread group
Quoted 7 lines
Is this really how it's implemented? This is not how it should be. Either a signal is sent to a specific thread in the same process (this is what
SIGEV_THREAD_IDis for) or the signal is sent to a calling process. Sending a signal to the process means that from the kernel's POV any thread which doesn't have the signal blocked can receive it. The final decision is made by the kernel. There is no mechanism to send the signal to another process.
The code seems to be set up to call specific_send_sig_info() in the case of *_THREAD_ID , and __group_send_sig_info() otherwise. So I think the intended behaviour is as you describe it should be (__group_send_sig_info does the equivalent of sending a signal to the process and so any thread which doesn't have signals blocked can receive it, while specific_send_sig_info sends it to a particular thread).
But, I should really leave it to Sebestian to confirm that.
Quoted 10 lines
So, for the purpose of the POSIX AIO code the
ki_pidvalue is only needed when theSIGEV_THREAD_IDbit is set.It could be an extension and I don't mind it being introduced. But again, it's not necessary and if it adds costs then it could be left out. It is something which could easily be introduced later if the need arises.
Quoted 4 lines
Quoted 2 lines
listio support
I really don't understand the kernel interface for this feature.
I'm sorry this is confusing. This probably means that we need to separate the external interface description more clearly and completely from the internals.
Quoted 19 lines
Quoted 10 lines
Details:
-------An
IOCB_CMD_GROUPis added to theIOCB_CMDenum ininclude/linux/aio_abi.hA struct
lio_eventis added ininclude/linux/aio.hA struct
lio_event*ki_liois added to struct iocb ininclude/linux/aio.hSo you have a pointer in the structure for the individual requests. I assume you use the atomic counter to trigger the final delivery. I further assume that if
lio_waitis set the calling thread is suspended until all requests are handled and that the final notification in this case means that thread gets woken.This is all fine.
Quoted 7 lines
But how do you pass the requests to the kernel? If you have a new lio_listio-like syscall it'll be easy. But I haven't seen anything like this mentioned.
The alternative is to pass the requests one-by-one in which case I don't see how you create the reference to the
lio_listiocontrol block. This approach seems to be slower.
The way it works (and better ideas are welcome) is that, since the io_submit() syscall already accepts an array of iocbs[], no new syscall was introduced. To implement lio_listio, one has to set up such an array, with the first iocb in the array having the special (new) grouping opcode of IOCB_CMD_GROUP which specifies the sigev notification to be associated with group completion (a NULL value of the sigev notification pointer would imply equivalent of LIO_WAIT). The following iocbs in the array should correspond to the set of listio aiocbs. Whenever it encounters an IOCB_CMD_GROUP iocb opcode, the kernel would interpret all subsequent iocbs[] submitted in the same io_submit() call to be associated with the same lio control block.
Does that clarify ?
Would an example help ?
Quoted 4 lines
If all requests are passed at once, do you have the equivalent of
LIO_NOPentries?
Good question - we do have an IOCB_CMD_NOOP defined, and I seem to even recall a patch that implemented it, but am wondering if it ever got merged. Ben/Zach ?
Quoted 8 lines
How can we support the extension where we wait for a number of requests which need not be all of them. I.e., I submit N requests and want to be notified when at least M (M <= N) notified. I am not yet clear about the actual semantics we should implement (e.g., do we send another notification after the first one?) but it's something which IMO should be taken into account in the design.
My thought here was that it should be possible to include M as a parameter to the IOCB_CMD_GROUP opcode iocb, and thus incorporated in the lio control block ... then whatever semantics are agreed upon can be implemented.
Quoted 4 lines
Finally, and this is very important, does you code send out the individual requests notification and then in the end the
lio_listiocompletion? I think Suparna wrote this is the case but I want to make sure.
Sebestian, could you confirm ?
Quoted 5 lines
Overall, this looks much better than the old code. If the answers to my questions show that the behavior is compatible with the POSIX AIO code I'm certainly very much in favor of adding the kernel code.
Thanks a lot for looking through this !
Let us know what you think about the listio interface ... hopefully the other issues are mostly simple to resolve.
Regards
Suparna
Quoted 4 lines
Signature · 2 lines
-- ➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Signature · 3 lines
Suparna Bhattacharya ([email protected]) Linux Technology Center IBM Software Lab, India
Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)
Quoted 6 lines · Suparna Bhattacharya
I am wondering about that too. IIRC, the IO_NOTIFY_* constants are not part of the ABI, but only internal to the kernel implementation. I think Zach had suggested inferring
THREAD_IDnotification if the pid specified is not zero. But, I don't see why ->sigev_notify couldn't used directly (just like the POSIX timers code does) thus doing away with the new constants altogether. Sebestian/Laurent, do you recall?
I suggest to model the implementation after the timer code which does exactly what we need.
Quoted 3 lines
I'm guessing they are being used for validation of permissions at the time of sending the signal, but maybe saving the task pointer in the iocb instead of the pid would suffice ?
Why should any verification be necessary? The requests are generated in the same process which will receive the notification. Even if the POSIX process (aka, kernel process group) changes the IDs the notifications should be set. The key is that notifications cannot be sent to another POSIX process.
Adding this as a feature just makes things so much more complicated.
Quoted 2 lines
So I think the
intended behaviour is as you describe it should be
Then the documentation needs to be adjusted.
Quoted 7 lines
The way it works (and better ideas are welcome) is that, since the
io_submit()syscall already accepts an array of iocbs[], no new syscall was introduced. To implementlio_listio, one has to set up such an array, with the first iocb in the array having the special (new) grouping opcode ofIOCB_CMD_GROUPwhich specifies the sigev notification to be associated with group completion (a NULL value of the sigev notification pointer would imply equivalent ofLIO_WAIT).
OK, this seems OK. We have to construct the iocb arrays dynamically anyway.
Quoted 3 lines
My thought here was that it should be possible to include M as a parameter to the
IOCB_CMD_GROUPopcode iocb, and thus incorporated in the lio control block ... then whatever semantics are agreed upon can be implemented.
If you have room for the parameter this is fine. For the beginning we can enforce the number to be the same as the total number of requests.
Quoted 2 lines
Let us know what you think about the listio interface ... hopefully the other issues are mostly simple to resolve.
It should be fine and I would support adding all this assuming the normal file support (as opposed to direct I/O only) is added, too.
But I have one last question: sockets, pipes and the like are already supported, right? If this is not the case we have a problem with the currently proposed lio_listio interface.
Signature · 1 line
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)
Quoted 9 lines · Ulrich Drepper
Quoted 6 lines
I am wondering about that too. IIRC, the IO_NOTIFY_* constants are not part of the ABI, but only internal to the kernel implementation. I think Zach had suggested inferring
THREAD_IDnotification if the pid specified is not zero. But, I don't see why ->sigev_notify couldn't used directly (just like the POSIX timers code does) thus doing away with the new constants altogether. Sebestian/Laurent, do you recall?I suggest to model the implementation after the timer code which does exactly what we need.
Yeah, and if at all possible we want to use just one helper thread for SIGEV_THREAD notification of timers/aio/etc., so it really should behave the same as timer thread notification.
Jakub
Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)
Quoted 8 lines · Jakub Jelinek
Quoted 7 lines · Ulrich Drepper
Quoted 6 lines
I am wondering about that too. IIRC, the IO_NOTIFY_* constants are not part of the ABI, but only internal to the kernel implementation. I think Zach had suggested inferring
THREAD_IDnotification if the pid specified is not zero. But, I don't see why ->sigev_notify couldn't used directly (just like the POSIX timers code does) thus doing away with the new constants altogether. Sebestian/Laurent, do you recall?
Quoted 7 lines
Quoted 2 lines
I suggest to model the implementation after the timer code which does exactly what we need.
Yeah, and if at all possible we want to use just one helper thread for
SIGEV_THREADnotification of timers/aio/etc., so it really should behave the same as timer thread notification.
That's exactly what is done in libposix-aio.
Sébastien.
Signature · 11 lines
----------------------------------------------------- Sébastien Dugué BULL/FREC:B1-247 phone: (+33) 476 29 77 70 Bullcom: 229-7770 mailto:[email protected] Linux POSIX AIO: http://www.bullopensource.org/posix http://sourceforge.net/projects/paiol -----------------------------------------------------
Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)
In reply to Ulrich DrepperQuoted 10 lines · Ulrich Drepper
Quoted 6 lines · Suparna Bhattacharya
I am wondering about that too. IIRC, the IO_NOTIFY_* constants are not part of the ABI, but only internal to the kernel implementation. I think Zach had suggested inferring
THREAD_IDnotification if the pid specified is not zero. But, I don't see why ->sigev_notify couldn't used directly (just like the POSIX timers code does) thus doing away with the new constants altogether. Sebestian/Laurent, do you recall?I suggest to model the implementation after the timer code which does exactly what we need.
Agreed.
Quoted 11 lines
Quoted 5 lines
I'm guessing they are being used for validation of permissions at the time of sending the signal, but maybe saving the task pointer in the iocb instead of the pid would suffice ?
Why should any verification be necessary? The requests are generated in the same process which will receive the notification. Even if the POSIX process (aka, kernel process group) changes the IDs the notifications should be set. The key is that notifications cannot be sent to another POSIX process.
Is there a (remote) possibility that the thread could have died and its pid got reused by a new thread in another process ? Or is there a mechanism that prevents such a possibility from arising (not just in NPTL library, but at the kernel level) ?
I think the timer code saves a reference to the task pointer instead of the pid, which is what I was suggesting above (instead of the euid checks), as way to avoid the above situation.
Quoted 8 lines
Adding this as a feature just makes things so much more complicated.
Quoted 2 lines
So I think the
intended behaviour is as you describe it should beThen the documentation needs to be adjusted.
*Nod*
Quoted 13 lines
Quoted 9 lines
The way it works (and better ideas are welcome) is that, since the
io_submit()syscall already accepts an array of iocbs[], no new syscall was introduced. To implementlio_listio, one has to set up such an array, with the first iocb in the array having the special (new) grouping opcode ofIOCB_CMD_GROUPwhich specifies the sigev notification to be associated with group completion (a NULL value of the sigev notification pointer would imply equivalent ofLIO_WAIT).OK, this seems OK. We have to construct the iocb arrays dynamically anyway.
Quoted 7 lines
Quoted 3 lines
My thought here was that it should be possible to include M as a parameter to the
IOCB_CMD_GROUPopcode iocb, and thus incorporated in the lio control block ... then whatever semantics are agreed upon can be implemented.If you have room for the parameter this is fine. For the beginning we can enforce the number to be the same as the total number of requests.
Sounds good.
Quoted 6 lines
Quoted 3 lines
Let us know what you think about the listio interface ... hopefully the other issues are mostly simple to resolve.
It should be fine and I would support adding all this assuming the normal file support (as opposed to direct I/O only) is added, too.
OK. I updated my patchset against 2618-rc3 just after OLS.
Quoted 5 lines
But I have one last question: sockets, pipes and the like are already supported, right? If this is not the case we have a problem with the currently proposed
lio_listiointerface.
AIO for pipes should not be a problem - Chris Mason had a patch, so we can just bring it up to the current levels, possibly with some additional improvements.
I'm not sure what would be the right thing to do for the sockets case. While we could put together a patch for basic aio_read/write (based on the same model used for files), given the whole ongoing kevent effort, its not yet clear to me what would make the most sense ...
Ben had a patch to do a fallback to kernel threads for AIO operations that are not yet supported natively. I had some concerns about the approach, but I guess he had intended it as an interim path for cases like this.
Suggestions would be much appreciated ? DaveM, Ingo, Andrew ?
Regards
Suparna
Quoted 4 lines
Signature · 2 lines
-- ➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Signature · 3 lines
Suparna Bhattacharya ([email protected]) Linux Technology Center IBM Software Lab, India
Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)
Quoted 4 lines · Suparna Bhattacharya
Is there a (remote) possibility that the thread could have died and its pid got reused by a new thread in another process ? Or is there a mechanism that prevents such a possibility from arising (not just in NPTL library, but at the kernel level) ?
The UID/GID won't help you with dying processes. What if the same user creates a process with the same PID? That process will not expect the notification and mustn't receive it. If you cannot detect whether the issuing process died you have problems which cannot be solved with a uid/gid pair.
Quoted 3 lines
AIO for pipes should not be a problem - Chris Mason had a patch, so we can just bring it up to the current levels, possibly with some additional improvements.
Good.
Quoted 8 lines
I'm not sure what would be the right thing to do for the sockets case. While we could put together a patch for basic aio_read/write (based on the same model used for files), given the whole ongoing kevent effort, its not yet clear to me what would make the most sense ...
Ben had a patch to do a fallback to kernel threads for AIO operations that are not yet supported natively. I had some concerns about the approach, but I guess he had intended it as an interim path for cases like this.
A fallback solution would be sufficient. Nobody _should_ use POSIX AIO for networking but people do and just giving them something that works is good enough. It cannot really be worse than the userlevel emulation we have know.
The alternative, separately and sequentially handling network sockets at userlevel is horrible. We'd have to go over every file descriptor and check whether it's a socket and then take if out of the request list for the kernel. Then they need to be handled separately before or after the kernel AIO code. This would punish unduly all the 99.9% of the programs which don't use POSIX AIO for network I/O.
Signature · 1 line
➧ Ulrich Drepper ➧ Red Hat, Inc. ➧ 444 Castro St ➧ Mountain View, CA ❖
Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)
Quoted 6 lines · Ulrich Drepper
Quoted 4 lines · Suparna Bhattacharya
Is there a (remote) possibility that the thread could have died and its pid got reused by a new thread in another process ? Or is there a mechanism that prevents such a possibility from arising (not just in NPTL library, but at the kernel level) ?
Quoted 7 lines
The UID/GID won't help you with dying processes. What if the same user creates a process with the same PID? That process will not expect the notification and mustn't receive it. If you cannot detect whether the issuing process died you have problems which cannot be solved with a uid/gid pair.
Eric W. Biederman sent a series of patches that introduced a struct task_ref specifically to solve this sort of problem on January 28 of this year, but I don't think it went anywhere.
Signature · 1 line
Nicholas Miell <[email protected]>
Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)
In reply to Ulrich DrepperQuoted 11 lines · Ulrich Drepper
Quoted 6 lines · Suparna Bhattacharya
I am wondering about that too. IIRC, the IO_NOTIFY_* constants are not part of the ABI, but only internal to the kernel implementation. I think Zach had suggested inferring
THREAD_IDnotification if the pid specified is not zero. But, I don't see why ->sigev_notify couldn't used directly (just like the POSIX timers code does) thus doing away with the new constants altogether. Sebestian/Laurent, do you recall?I suggest to model the implementation after the timer code which does exactly what we need.
Will do.
Quoted 5 lines
Quoted 4 lines
I'm guessing they are being used for validation of permissions at the time of sending the signal, but maybe saving the task pointer in the iocb instead of the pid would suffice ?
Quoted 8 lines
Why should any verification be necessary? The requests are generated in the same process which will receive the notification. Even if the POSIX process (aka, kernel process group) changes the IDs the notifications should be set. The key is that notifications cannot be sent to another POSIX process.
Adding this as a feature just makes things so much more complicated.
Agreed.
Sébastien.
Signature · 11 lines
----------------------------------------------------- Sébastien Dugué BULL/FREC:B1-247 phone: (+33) 476 29 77 70 Bullcom: 229-7770 mailto:[email protected] Linux POSIX AIO: http://www.bullopensource.org/posix http://sourceforge.net/projects/paiol -----------------------------------------------------
Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)
In reply to Suparna BhattacharyaHi,
just came back from vacation, sorry for the delay.
Quoted 40 lines · Suparna Bhattacharya
BTW, if anyone would like to be dropped off this growing cc list, please let us know.
Quoted 6 lines · Ulrich Drepper
Quoted 1 line · Sébastien Dugué
aio completion notification
I looked over this now but I don't think I understand everything. Or I don't see how it all is integrated. And no, I'm not looking at the proposed glibc code since would mean being tainted.
Oh, I didn't realise that.
I'll make an attempt to clarify parts that I understand based on what I have gleaned from my reading of the code and intent, but hopefully Sebastien, Ben, Zach et al will be able to pitch in for a more accurate and complete picture.Quoted 14 lines
Quoted 14 lines
Details:
-------A struct sigevent
*aio_sigeventpis added to struct iocb ininclude/linux/aio_abi.hAn enum {
IO_NOTIFY_SIGNAL= 0,IO_NOTIFY_THREAD_ID= 1} is added ininclude/linux/aio.h:-
IO_NOTIFY_SIGNALmeans that the signal is to be sent to the requesting threadQuoted 8 lines
Quoted 2 lines
-
IO_NOTIFY_THREAD_IDmeans that the signal is to be sent to a specifi thread.This has been proved to be sufficient in the timer code which basically has the same problem. But why do you need separate constants? We have the various SIGEV_* constants, among them
SIGEV_THREAD_ID. Just use these constants for the values ofki_notify.
Quoted 6 lines
I am wondering about that too. IIRC, the IO_NOTIFY_* constants are not part of the ABI, but only internal to the kernel implementation. I think Zach had suggested inferring
THREAD_IDnotification if the pid specified is not zero. But, I don't see why ->sigev_notify couldn't used directly (just like the POSIX timers code does) thus doing away with the new constants altogether. Sebestian/Laurent, do you recall?
As I see it, those IO_NOTIFY_* constants are uneeded and we could use
->sigev_notify directly. I will change this so that we use the same mechanism as the POSIX timers code.
Quoted 13 lines
Quoted 13 lines
Quoted 12 lines
The following fields are added to struct kiocb in
include/linux/aio.h:-
pid_tki_pid: target of the signal-
__u16ki_signo: signal number-
__u16ki_notify: kind of notification,IO_NOTIFY_SIGNALorIO_NOTIFY_THREAD_ID-
uid_tki_uid,ki_euid: filled with the submitter credentials
Quoted 7 lines
Quoted 3 lines
These two fields aren't needed for the POSIX interfaces. Where does the requirement come from? I don't say they should be removed, they might be useful, but if the costs are non-negligible then they could go away.
I'm guessing they are being used for validation of permissions at the time of sending the signal, but maybe saving the task pointer in the iocb instead of the pid would suffice ?
IIRC, Ben added these for that exact reason. Is this really needed?
Ben?
Quoted 17 lines
Quoted 9 lines
Quoted 8 lines
- check whether the submitting thread wants to be notified directly (
sigevent->sigev_notify_thread_idis 0) or wants the signal to be sent to another thread.
In the latter case a check is made to assert that the target thread is in the same thread groupQuoted 7 lines
Is this really how it's implemented? This is not how it should be. Either a signal is sent to a specific thread in the same process (this is what
SIGEV_THREAD_IDis for) or the signal is sent to a calling process. Sending a signal to the process means that from the kernel's POV any thread which doesn't have the signal blocked can receive it. The final decision is made by the kernel. There is no mechanism to send the signal to another process.
Quoted 8 lines
The code seems to be set up to call
specific_send_sig_info()in the case of*_THREAD_ID, and__group_send_sig_info()otherwise. So I think the intended behaviour is as you describe it should be (__group_send_sig_infodoes the equivalent of sending a signal to the process and so any thread which doesn't have signals blocked can receive it, whilespecific_send_sig_infosends it to a particular thread).But, I should really leave it to Sebestian to confirm that.
That's right, but I think that part needs to be reworked to follow
the same logic as the POSIX timers.
Quoted 47 lines
Quoted 4 lines
Quoted 2 lines
listio support
I really don't understand the kernel interface for this feature.
I'm sorry this is confusing. This probably means that we need to separate the external interface description more clearly and completely from the internals.
Quoted 19 lines
Quoted 10 lines
Details:
-------An
IOCB_CMD_GROUPis added to theIOCB_CMDenum ininclude/linux/aio_abi.hA struct
lio_eventis added ininclude/linux/aio.hA struct
lio_event*ki_liois added to struct iocb ininclude/linux/aio.hSo you have a pointer in the structure for the individual requests. I assume you use the atomic counter to trigger the final delivery. I further assume that if
lio_waitis set the calling thread is suspended until all requests are handled and that the final notification in this case means that thread gets woken.This is all fine.
Quoted 7 lines
But how do you pass the requests to the kernel? If you have a new lio_listio-like syscall it'll be easy. But I haven't seen anything like this mentioned.
The alternative is to pass the requests one-by-one in which case I don't see how you create the reference to the
lio_listiocontrol block. This approach seems to be slower.The way it works (and better ideas are welcome) is that, since the
io_submit()syscall already accepts an array of iocbs[], no new syscall was introduced. To implementlio_listio, one has to set up such an array, with the first iocb in the array having the special (new) grouping opcode ofIOCB_CMD_GROUPwhich specifies the sigev notification to be associated with group completion (a NULL value of the sigev notification pointer would imply equivalent ofLIO_WAIT). The following iocbs in the array should correspond to the set of listio aiocbs. Whenever it encounters anIOCB_CMD_GROUPiocb opcode, the kernel would interpret all subsequent iocbs[] submitted in the sameio_submit()call to be associated with the same lio control block.
Quoted 7 lines
Does that clarify ?
Would an example help ?
Quoted 3 lines
If all requests are passed at once, do you have the equivalent of
LIO_NOPentries?
So far, LIO_NOP entries are pruned by the support library
(libposix-aio) and never sent to the kernel.
Quoted 20 lines
Quoted 1 line
Good question - we do have an
IOCB_CMD_NOOPdefined, and I seem to even recall a patch that implemented it, but am wondering if it ever got merged. Ben/Zach ?Quoted 8 lines
How can we support the extension where we wait for a number of requests which need not be all of them. I.e., I submit N requests and want to be notified when at least M (M <= N) notified. I am not yet clear about the actual semantics we should implement (e.g., do we send another notification after the first one?) but it's something which IMO should be taken into account in the design.
My thought here was that it should be possible to include M as a parameter to the
IOCB_CMD_GROUPopcode iocb, and thus incorporated in the lio control block ... then whatever semantics are agreed upon can be implemented.Quoted 1 line
Quoted 5 lines
Quoted 3 lines
Finally, and this is very important, does you code send out the individual requests notification and then in the end the
lio_listiocompletion? I think Suparna wrote this is the case but I want to make sure.Sebestian, could you confirm ?
If (and only if) the user did setup a sigevent for one or more
individual requests then those requests completion will trigger a notification and in the end the list completion notification is sent. Otherwise, only the list completion notification is sent.
Signature · 11 lines
----------------------------------------------------- Sébastien Dugué BULL/FREC:B1-247 phone: (+33) 476 29 77 70 Bullcom: 229-7770 mailto:[email protected] Linux POSIX AIO: http://www.bullopensource.org/posix http://sourceforge.net/projects/paiol -----------------------------------------------------
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
In reply to Ulrich DrepperQuoted 17 lines · Ulrich Drepper
Quoted 3 lines · Badari Pulavarty
Before we spend too much time cleaning up and merging into mainline - I would like an agreement that what we add is good enough for glibc POSIX AIO.
I haven't seen a description of the interface so far. Would be good if it existed. But I briefly mentioned one quirk in the interface about which Suparna wasn't sure whether it's implemented/implementable in the current interface.
If a
lio_listiocall is made the individual requests are handle just as if they'd be issue separately. I.e., the notification specified in the individual aiocb is performed when the specific request is done. Then, once all requests are done, another notification is made, this time controlled by the sigevent parameter iflio_listio.
Quoted 8 lines
Another feature which I always wanted: the current
lio_listiocall returns in blocking mode only if all requests are done. In non-blocking mode it returns immediately and the program needs to poll the aiocbs. What is needed is something in the middle. For instance, if multiple read requests are issued the program might be able to start working as soon as one request is satisfied. I.e., a call similar tolio_listiowould be nice which also takes another parameter specifying how many of the NENT aiocbs have to finish before the call returns.
You're right here, that definitely would be a plus.
Signature · 11 lines
----------------------------------------------------- Sébastien Dugué BULL/FREC:B1-247 phone: (+33) 476 29 77 70 Bullcom: 229-7770 mailto:[email protected] Linux POSIX AIO: http://www.bullopensource.org/posix http://sourceforge.net/projects/paiol -----------------------------------------------------
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
In reply to Ulrich DrepperQuoted 6 lines · Ulrich Drepper
Quoted 3 lines · Badari Pulavarty
Before we spend too much time cleaning up and merging into mainline - I would like an agreement that what we add is good enough for glibc POSIX AIO.
I haven't seen a description of the interface so far. Would be good if
Did Sébastien's mail with the description help ?
Quoted 9 lines
it existed. But I briefly mentioned one quirk in the interface about which Suparna wasn't sure whether it's implemented/implementable in the current interface.
If a
lio_listiocall is made the individual requests are handle just as if they'd be issue separately. I.e., the notification specified in the individual aiocb is performed when the specific request is done. Then, once all requests are done, another notification is made, this time controlled by the sigevent parameter iflio_listio.
Looking at the code in lio kernel patch, this should be already covered:
if (iocb->ki_signo)
__aio_send_signal(iocb);+ if (iocb->ki_lio)
+ lio_check(iocb->ki_lio);
That is, it first checks the notification in the individual iocb, and then the one for the LIO.
Quoted 10 lines
Another feature which I always wanted: the current
lio_listiocall returns in blocking mode only if all requests are done. In non-blocking mode it returns immediately and the program needs to poll the aiocbs. What is needed is something in the middle. For instance, if multiple read requests are issued the program might be able to start working as soon as one request is satisfied. I.e., a call similar tolio_listiowould be nice which also takes another parameter specifying how many of the NENT aiocbs have to finish before the call returns.
I imagine the kernel could enable this by incorporating this additional parameter for IOCB_CMD_GROUP in the ABI (in the default case this should be the same as the total number of iocbs submitted to lio_listio). Now should the at least NENT check apply only to LIO_WAIT or also to the LIO_NOWAIT notification case ?
BTW, the native io_getevents does support a min_nr wakeup already, except that it applies to any iocb on the io_context, and not just a given lio_listio call.
Regards
Suparna
Signature · 3 lines
Suparna Bhattacharya ([email protected]) Linux Technology Center IBM Software Lab, India
Re: [3/4] kevent: AIO, aio_sendfile() implementation.
In reply to Badari PulavartyQuoted 81 lines · Badari Pulavarty
Quoted 68 lines · Sébastien Dugué
Quoted 39 lines · Badari Pulavarty
Quoted 14 lines · Ulrich Drepper
Quoted 7 lines · Christoph Hellwig
Quoted 4 lines
My personal opinion on existing AIO is that it is not the right design. Benjamin LaHaise agree with me (if I understood him right),
I completely agree with that aswell.
I agree, too, but the current code is not the last of the line. Suparna has a st of patches which make the current kernel aio code work much better and especially make it really usable to implement POSIX AIO.
Quoted 9 lines
In Ottawa we were talking about submitting it and Suparna will. We just thought about a little longer timeframe. I guess it could be accelerated since he mostly has the patch done. But I don't know her schedule.
Important here is, don't base any decision on the current aio implementation.
Ulrich,
Suparna mentioned your interest in making POSIX glibc aio work with kernel-aio at OLS.
We thought taking a re-look at the (kernel side) work BULL did, would be a nice starting
point. I re-based those patches to 2.6.18-rc2 and sent it to Zach Brown for review before
sending them out to list.These patches does NOT make AIO any cleaner. All they do is add functionality to support
POSIX AIO easier. These areQuoted 6 lines
[ PATCH 1/3 ] Adding signal notification for event completion
[ PATCH 2/3 ] lio (listio) completion semantics
[ PATCH 3/3 ]
cancel_fdsupportBadari,
Thanks for refreshing those patches, they have been sitting here
for quite some time now and collected dust.I also think Suparna's patchset for doing buffered AIO would be
a real plus here.Quoted 10 lines
Suparna explained these in the following article:
http://lwn.net/Articles/148755/
If you think, this is a reasonable direction/approach for the kernel and you would take care
of glibc side of things - I can spend time on these patches, getting them to reasonable shape
and push for inclusion.Quoted 10 lines
Ulrich, I you want to have a look at how those patches are put to
use in libposix-aio, have a look at http://sourceforge.net/projects/paiol.It could be a starting point for glibc.
Thanks,
Sébastien.
Sebastien,
Quoted 9 lines
Suparna mentioned at Ulrich wants us to concentrate on kernel-side support, so that he
can look at glibc side of things (along with other work he is already doing). So, if we
can get an agreement on what kind of kernel support is needed - we can focus our
efforts on kernel side first and leave glibc enablement to capable hands of Uli :)
That's fine with me.
Sébastien.
Signature · 11 lines
----------------------------------------------------- Sébastien Dugué BULL/FREC:B1-247 phone: (+33) 476 29 77 70 Bullcom: 229-7770 mailto:[email protected] Linux POSIX AIO: http://www.bullopensource.org/posix http://sourceforge.net/projects/paiol -----------------------------------------------------
Re: [1/4] kevent: core files.
In reply to Evgeniy PolyakovQuoted 24 lines · On Wed, 26 Jul 2006 13:18:15 +0400 Evgeniy Polyakov <[email protected]> wrote:
kernel/kevent/kevent_user.c new file +24
-0+static int kevent_ctl_process (struct file *file, +struct kevent_user_control *ctl,void __user *arg) +{ +int err; +struct kevent_user *u = file->private_data; + +if (!u) +return -EINVAL ; + +switch (ctl->cmd) { +case KEVENT_CTL_ADD : + err =kevent_user_ctl_add (u, ctl, + arg+sizeof (struct kevent_user_control )); +break ; +case KEVENT_CTL_REMOVE : + err =kevent_user_ctl_remove (u, ctl, + arg+sizeof (struct kevent_user_control )); +break ; +case KEVENT_CTL_MODIFY : + err =kevent_user_ctl_modify (u, ctl, + arg+sizeof (struct kevent_user_control )); +break ; +case KEVENT_CTL_WAIT : + err =kevent_user_wait (file, u, ctl, arg);
kernel/kevent/kevent_user.c line 618
Quoted 10 lines
kernel/kevent/kevent_user.c new file +10
-0+break ; +case KEVENT_CTL_INIT : + err =kevent_ctl_init (); +default : + err = -EINVAL ; +break ; + } + +return err; +}
Please indent the body of the switch one tabstop to the left.
Quoted 11 lines
kernel/kevent/kevent_user.c new file +11
-0+asmlinkage long sys_kevent_ctl (int fd,void __user *arg) +{ +int err, fput_needed; +struct kevent_user_control ctl; +struct file *file; + +if (copy_from_user (&ctl, arg,sizeof (struct kevent_user_control ))) +return -EINVAL ; + +if (ctl.cmd ==KEVENT_CTL_INIT ) +return kevent_ctl_init ();
kernel/kevent/kevent_user.c line 640
Quoted 10 lines
kernel/kevent/kevent_user.c new file +10
-0+ + file =fget_light (fd, &fput_needed); +if (!file) +return -ENODEV ; + + err =kevent_ctl_process (file, &ctl, arg); + +fput_light (file, fput_needed); +return err; +}
If the user passes this an fd which was obtained via means other than kevent_ctl_init(), the kernel will explode. Do
if (file->f_fop != &kevent_user_fops) return -EINVAL;
Re: [1/4] kevent: core files.
Quoted 1 line · Andrew Morton
Please indent the body of the switch one tabstop to the left.
..
Quoted 5 lines
If the user passes this an fd which was obtained via means other than
kevent_ctl_init(), the kernel will explode. Doif (file->f_fop != &kevent_user_fops) return -EINVAL;
Thanks, I will implement both.
Signature · 1 line
Evgeniy Polyakov
Re: [1/4] kevent: core files.
In reply to Evgeniy Polyakovkernel/kevent/kevent.c line 237
Quoted 12 lines · Evgeniy Polyakov
kernel/kevent/kevent.c new file +12
-0+struct kevent *kevent_alloc (gfp_t mask) +{ +struct kevent *k; + +if (kevent_cache) + k =kmem_cache_alloc (kevent_cache, mask); +else + k =kzalloc (sizeof (struct kevent ), mask); + +return k; +} +
Sorry for that.
It is fixed already to always use cache, but I forget to commit that change before I created pachset.
Signature · 1 line
Evgeniy Polyakov
David Miller
maintainerFrom: Evgeniy Polyakov <[email protected]>
Date: Wed, 26 Jul 2006 10:28:17 +0400
Quoted 4 lines
I have not created additional DMA memory allocation methods, like Ulrich described in his article, so I handle it inside NAIO which has some overhead (I posted
get_user_pages()sclability graph some time ago).
I've been thinking about this aspect, and I think it's very interesting. Let's be clear what the ramifications of this are first.
Using the terminology of Network Algorithmics, this is an instance of Principle 2, "Shift computation in time".
Instead of using get_user_pages() at AIO setup, we instead map the thing to userspace later when the user wants it. Pinning pages is a pain because both user and kernel refer to the buffer at the same time. We get more flexibility when the user has to map the thing explicitly.
I want us to think about how a user might want to use this. What I anticipate is that users will want to organize a pool of AIO buffers for themselves using this DMA interface. So the events they are truly interested in are of a finer granularity than you might expect. They want to know when pieces of a buffer are available for reuse.
And here is the core dilemma.
If you make the event granularity too coarse, a larger AIO buffer pool is necessary. If you make the event granuliary too fine, event processing begins to dominate, and costs too much. This is true even for something as light weight as kevent.
Quoted 12 lines · David Miller
From: Evgeniy Polyakov <[email protected]>
Date: Wed, 26 Jul 2006 10:28:17 +0400Quoted 4 lines
I have not created additional DMA memory allocation methods, like Ulrich described in his article, so I handle it inside NAIO which has some overhead (I posted
get_user_pages()sclability graph some time ago).I've been thinking about this aspect, and I think it's very interesting. Let's be clear what the ramifications of this are first.
Quoted 8 lines
Using the terminology of Network Algorithmics, this is an instance of Principle 2, "Shift computation in time".
Instead of using
get_user_pages()at AIO setup, we instead map the thing to userspace later when the user wants it. Pinning pages is a pain because both user and kernel refer to the buffer at the same time. We get more flexibility when the user has to map the thing explicitly.
I.e. map skb's data to userspace? Not a good idea especially with it's tricky lifetime and unability for userspace to inform kernel when it finished and skb can be freed (without additional syscall). I did it with af_tlb zero-copy sniffer (but I substitute mapped pages with physical skb->data pages), and it was not very good.
Quoted 6 lines
I want us to think about how a user might want to use this. What I anticipate is that users will want to organize a pool of AIO buffers for themselves using this DMA interface. So the events they are truly interested in are of a finer granularity than you might expect. They want to know when pieces of a buffer are available for reuse.
Ah, I see.
Well, I think preallocate some buffers and use that in AIO setup is a plus, since in that case user does not care about when it is possible to reuse the same buffer - when appropriate kevent is completed, that means that provided buffer is no longer in use by kernel, and user can reuse it.
Signature · 1 line
Evgeniy Polyakov
David Miller
maintainerFrom: Evgeniy Polyakov <[email protected]>
Date: Thu, 27 Jul 2006 11:49:02 +0400
Quoted 3 lines
I.e. map skb's data to userspace? Not a good idea especially with it's tricky lifetime and unability for userspace to inform kernel when it finished and skb can be freed (without additional syscall).
Hmmm...
If it is paged based, I do not see the problem. Events and calls to AIO I/O routines make transfer of buffer ownership. The fact that while kernel (and thus networking stack) "owns" the buffer for an AIO call, the user can have a valid mapping to it is a unimportant detail.
If the user will scramble a piece of data that is in flight to or from the network card, it is his problem.
If we are using a primitive network card that does not support scatter-gather I/O and thus not page based SKBs, we will make copies. But this is transparent to the user.
The idea is that DMA mappings have page granularity.
At least on transmit it should work well. Receive side is more difficult and initial implementation will need to copy.
Quoted 2 lines
I did it with
af_tlbzero-copy sniffer (but I substitute mapped pages with physicalskb->datapages), and it was not very good.
Trying to be too clever with skb->data has always been catastrophic. :)
Quoted 5 lines
Well, I think preallocate some buffers and use that in AIO setup is a plus, since in that case user does not care about when it is possible to reuse the same buffer - when appropriate kevent is completed, that means that provided buffer is no longer in use by kernel, and user can reuse it.
We now enter the most interesting topic of AIO buffer pool management and where it belongs. :-) We are assuming up to this point that the user manages this stuff with explicit DMA calls for allocation, then passes the key based references to those buffers as arguments to the AIO I/O calls.
But I want to suggest another possibility. What if the kernel managed the AIO buffer pool for a task? It could grow this dynamically based upon need. The only implementation road block is how large to we allow this to grow, but I think normal VM mechanisms can take care of it.
On transmit this is not straightforward, but for receive it has really nice possibilities. :)
Quoted 7 lines · David Miller
From: Evgeniy Polyakov <[email protected]>
Date: Thu, 27 Jul 2006 11:49:02 +0400Quoted 3 lines
I.e. map skb's data to userspace? Not a good idea especially with it's tricky lifetime and unability for userspace to inform kernel when it finished and skb can be freed (without additional syscall).
Quoted 6 lines
Hmmm...
If it is paged based, I do not see the problem. Events and calls to AIO I/O routines make transfer of buffer ownership. The fact that while kernel (and thus networking stack) "owns" the buffer for an AIO call, the user can have a valid mapping to it is a unimportant detail.
Ownership may be clear, but "when can I reuse" is tricky. The same issue comes up for vmsplice -> splice to socket.
Signature · 1 line
Jens Axboe
Quoted 10 lines · Jens Axboe
Quoted 9 lines · David Miller
From: Evgeniy Polyakov <[email protected]>
Date: Thu, 27 Jul 2006 11:49:02 +0400Quoted 3 lines
I.e. map skb's data to userspace? Not a good idea especially with it's tricky lifetime and unability for userspace to inform kernel when it finished and skb can be freed (without additional syscall).
Hmmm...
Quoted 7 lines
Quoted 4 lines
If it is paged based, I do not see the problem. Events and calls to AIO I/O routines make transfer of buffer ownership. The fact that while kernel (and thus networking stack) "owns" the buffer for an AIO call, the user can have a valid mapping to it is a unimportant detail.
Ownership may be clear, but "when can I reuse" is tricky. The same issue comes up for vmsplice -> splice to socket.
Ownership transition from user -> kernel that is, what I'm trying to say that returning ownership to the user again is the tricky part.
Signature · 1 line
Jens Axboe
David Miller
maintainerFrom: Jens Axboe <[email protected]>
Date: Thu, 27 Jul 2006 10:11:15 +0200
Quoted 2 lines
Ownership transition from user -> kernel that is, what I'm trying to say that returning ownership to the user again is the tricky part.
Yes, it is important that for TCP, for example, we don't give the user the event until the data is acknowledged and the skb's referencing that data are fully freed.
This is further complicated by the fact that packetization boundaries are going to be different from AIO buffer boundaries.
I think this is what you are alluding to.
Quoted 6 lines · David Miller
From: Jens Axboe <[email protected]>
Date: Thu, 27 Jul 2006 10:11:15 +0200Quoted 2 lines
Ownership transition from user -> kernel that is, what I'm trying to say that returning ownership to the user again is the tricky part.
Quoted 8 lines
Yes, it is important that for TCP, for example, we don't give the user the event until the data is acknowledged and the skb's referencing that data are fully freed.
This is further complicated by the fact that packetization boundaries are going to be different from AIO buffer boundaries.
I think this is what you are alluding to.
Precisely. And this is the bit that is currently still broken for splice-to-socket, since it gives that ack right after ->sendpage() has been called. But that's a known deficiency right now, I think Alexey is currently looking at that (as well as receive side support).
Signature · 1 line
Jens Axboe
David Miller
maintainerFrom: Jens Axboe <[email protected]>
Date: Thu, 27 Jul 2006 10:29:24 +0200
Quoted 4 lines
Precisely. And this is the bit that is currently still broken for splice-to-socket, since it gives that ack right after ->sendpage() has been called. But that's a known deficiency right now, I think Alexey is currently looking at that (as well as receive side support).
That's right, I was discussing this with him just a few days ago.
It's good to hear that he's looking at those patches you were working on several months ago.
Quoted 8 lines · David Miller
From: Jens Axboe <[email protected]>
Date: Thu, 27 Jul 2006 10:29:24 +0200Quoted 4 lines
Precisely. And this is the bit that is currently still broken for splice-to-socket, since it gives that ack right after ->sendpage() has been called. But that's a known deficiency right now, I think Alexey is currently looking at that (as well as receive side support).
Quoted 4 lines
That's right, I was discussing this with him just a few days ago.
It's good to hear that he's looking at those patches you were working on several months ago.
It is. I never ventured much into the networking part, just noted that as a current limitation with the ->sendpage() based approach. Basically we need to pass more info in, which also gets rid of the limitation of passing a single page at the time.
Signature · 1 line
Jens Axboe
Quoted 17 lines · David Miller
From: Evgeniy Polyakov <[email protected]>
Date: Thu, 27 Jul 2006 11:49:02 +0400Quoted 3 lines
I.e. map skb's data to userspace? Not a good idea especially with it's tricky lifetime and unability for userspace to inform kernel when it finished and skb can be freed (without additional syscall).
Hmmm...
If it is paged based, I do not see the problem. Events and calls to AIO I/O routines make transfer of buffer ownership. The fact that while kernel (and thus networking stack) "owns" the buffer for an AIO call, the user can have a valid mapping to it is a unimportant detail.
If the user will scramble a piece of data that is in flight to or from the network card, it is his problem.
Quoted 8 lines
If we are using a primitive network card that does not support scatter-gather I/O and thus not page based SKBs, we will make copies. But this is transparent to the user.
The idea is that DMA mappings have page granularity.
At least on transmit it should work well. Receive side is more difficult and initial implementation will need to copy.
And what if several skb->data are placed on the same page? Or do we want to allocate at least one page for one skb? Even if it is an 40 bytes ack?
Quoted 4 lines
Quoted 2 lines
I did it with
af_tlbzero-copy sniffer (but I substitute mapped pages with physicalskb->datapages), and it was not very good.Trying to be too clever with
skb->datahas always been catastrophic. :)
Yep :)
Quoted 12 lines
Quoted 5 lines
Well, I think preallocate some buffers and use that in AIO setup is a plus, since in that case user does not care about when it is possible to reuse the same buffer - when appropriate kevent is completed, that means that provided buffer is no longer in use by kernel, and user can reuse it.
We now enter the most interesting topic of AIO buffer pool management and where it belongs. :-) We are assuming up to this point that the user manages this stuff with explicit DMA calls for allocation, then passes the key based references to those buffers as arguments to the AIO I/O calls.
Quoted 8 lines
But I want to suggest another possibility. What if the kernel managed the AIO buffer pool for a task? It could grow this dynamically based upon need. The only implementation road block is how large to we allow this to grow, but I think normal VM mechanisms can take care of it.
On transmit this is not straightforward, but for receive it has really nice possibilities. :)
Btw, according to DMA allocations - there are some problems here too. Some pieces of the world can not dma behind 16mb, and someone can do it over 4gb. If only 16mb are used, it is just 8k packets with 1500 MTU, and actually userspace does not know which NIC receives it's data, so it is impossible in advance to allocate some pool, which will be used for dma transfer, so we just need to allocate physical pages and use them with memcpy() from skb->data.
Those physical pages can be managed within kernel and userspace can map them. But there is another possibility - replace slab allocation for network devices with allocation from premapped pool.
That naturally allows to manage that pool for AIO needs and have zero-copy sending and receiving support. That is what I talked in netchannel topic when question about allocation/freeing cost in atomic context arised. I work on that solution, which can be used both for netchannels (and full userspace processing) and usual networking code.
Signature · 1 line
Evgeniy Polyakov
David Miller
maintainerFrom: Evgeniy Polyakov <[email protected]>
Date: Thu, 27 Jul 2006 12:58:13 +0400
Quoted 3 lines
Btw, according to DMA allocations - there are some problems here too. Some pieces of the world can not dma behind 16mb, and someone can do it over 4gb.
I think people take this "DMA" in Ulrich's interface names too literally. It is logically something different, although it could be used directly for this purpose.
View it rather as memory you have by some key based ID, but need to explicitly map to access directly.
Quoted 8 lines
Those physical pages can be managed within kernel and userspace can map them. But there is another possibility - replace slab allocation for network devices with allocation from premapped pool.
That naturally allows to manage that pool for AIO needs and have zero-copy sending and receiving support. That is what I talked in netchannel topic when question about allocation/freeing cost in atomic context arised. I work on that solution, which can be used both for netchannels (and full userspace processing) and usual networking code.
Interesting idea, and yes I have been watching you stress test your AVL tree code :))
Quoted 7 lines · David Miller
From: Evgeniy Polyakov <[email protected]>
Date: Thu, 27 Jul 2006 12:58:13 +0400Quoted 3 lines
Btw, according to DMA allocations - there are some problems here too. Some pieces of the world can not dma behind 16mb, and someone can do it over 4gb.
Quoted 6 lines
I think people take this "DMA" in Ulrich's interface names too literally. It is logically something different, although it could be used directly for this purpose.
View it rather as memory you have by some key based ID, but need to explicitly map to access directly.
I mean here, that it is possible to have those Ulrich's dma regions to be used as a real dma regions, and showed that it is not a good idea.
Quoted 11 lines
Quoted 8 lines
Those physical pages can be managed within kernel and userspace can map them. But there is another possibility - replace slab allocation for network devices with allocation from premapped pool.
That naturally allows to manage that pool for AIO needs and have zero-copy sending and receiving support. That is what I talked in netchannel topic when question about allocation/freeing cost in atomic context arised. I work on that solution, which can be used both for netchannels (and full userspace processing) and usual networking code.Interesting idea, and yes I have been watching you stress test your AVL tree code :))
Tests are completed - actually it required 12 a4 papers filled with small circles and numbers to prove it is correct, overnight run was just for clarifications :)
Signature · 1 line
Evgeniy Polyakov