Skip to contentSkip to conversation

async network I/O, event channels, etc

PATCH In review Ulrich Drepper 15 participants 60 messages Jul 25, 2006 – Sep 4, 2006

Subsystems (8)
Networking Network drivers VFS TCP +4 more subsystems
lore
Share & tools
lore
#0 lore raw

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 ❖
#1 lore raw
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]

#2 lore raw
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 ❖
maintainer
#3 lore raw
In reply to Ulrich Drepper

From: 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. :)

#4 lore raw
Quoted 22 lines · David Miller

From: 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.

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]>
#5 lore raw
In reply to David Miller
Quoted 22 lines · David Miller

From: 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.

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
#6 lore raw

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.

#7 lore raw

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
index af56987..93e23ff 100644
@@ -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
index 5a92fed..534d516 100644
@@ -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
index 802ae76..3473f5c 100644
@@ -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
index de2ccc1..52f8642 100644
@@ -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
index f2cdbea..1f31f86 100644
@@ -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
index 0aff22b..352c34b 100644
@@ -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
new file mode 100644
index 0000000..bd891f0
@@ -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
index 66f8819..ea914c3 100644
@@ -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
index bd67a44..33d436e 100644
@@ -587,4 +587,8 @@ asmlinkage long sys_get_robust_list(int 
 asmlinkage 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
index d10dfec..7a2bee3 100644
@@ -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_kio
 	return 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
index 5f4eb5c..820cd5a 100644
@@ -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
index df864a3..6135afc 100644
@@ -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
index f6ef00f..eb057ea 100644
@@ -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
new file mode 100644
index 0000000..7dcd651
@@ -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
index 5433195..dcbacf5 100644
@@ -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
index 5d820c3..3345048 100644
@@ -564,6 +564,16 @@ #endif
 			spin_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 sock 
 	if (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(struct
 		wake_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 soc
 		wake_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
index e948969..91e2e07 100644
@@ -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
index e08245b..5655b1e 100644
@@ -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
index 25ecc6e..05d7086 100644
@@ -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 @@ #endif
 	   	reqsk_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
index a50eb30..e27e231 100644
@@ -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,
#8 lore raw

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
new file mode 100644
index 0000000..c230aaa
@@ -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

#9 lore raw

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
index 6a0b9ad..a3ee530 100644
@@ -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
index 04af9c4..295fce9 100644
@@ -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
index 2edd7ee..e44f5ad 100644
@@ -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
index bcea199..8759479 100644
@@ -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
index 3a2446a..0493935 100644
@@ -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 defined CONFIG_KEVENT
+		kevent_storage_init(inode, &inode->st);
+#endif
 	}
 	return inode;
 }
 
 void destroy_inode(struct inode *inode) 
 {
+#if defined CONFIG_KEVENT_INODE || defined CONFIG_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
index 9857e50..bbbb578 100644
@@ -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
index ecc8c2c..248f6a1 100644
@@ -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_INOTIFY
 	struct 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_EPOLL
 	struct 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
index cc5dec7..0acc8db 100644
@@ -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(struc
 static 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

#10 lore raw

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
new file mode 100644
index 0000000..4950e7c
@@ -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

#11 lore raw

Re: [3/4] kevent: AIO, aio_sendfile() implementation.

In reply to Evgeniy Polyakov
Quoted 27 lines · Evgeniy Polyakov

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
index 6a0b9ad..a3ee530 100644
@@ -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
index 04af9c4..295fce9 100644

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.

#12 lore raw

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_operations ext2_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_block is 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
#13 lore raw

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_operations ext2_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_block is 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.

#14 lore raw

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_operations ext2_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_block is 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_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.

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_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.

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
#15 lore raw

Re: [3/4] kevent: AIO, aio_sendfile() implementation.

In reply to Evgeniy Polyakov
Quoted 6 lines · Evgeniy Polyakov

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.

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 :)

maintainer
#16 lore raw

Re: [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 :)

#17 lore raw

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 +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 :)

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.

#18 lore raw

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.

#19 lore raw

Re: [3/4] kevent: AIO, aio_sendfile() implementation.

In reply to David Miller
Quoted 11 lines · David Miller

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.

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
#20 lore raw

Re: [3/4] kevent: AIO, aio_sendfile() implementation.

In reply to Christoph Hellwig
Quoted 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.
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.

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
#21 lore raw

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.

#22 lore raw

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 ❖
#23 lore raw

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

#24 lore raw

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_fd support

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

-----------------------------------------------------
#25 lore raw

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_fd support

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 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

#26 lore raw

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

#27 lore raw

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

#28 lore raw

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 ❖
#29 lore raw

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_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.

Quoted 8 lines

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.

Looks reasonable.

Thanks,
Badari

#30 lore raw

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

-----------------------------------------------------
#31 lore raw

Re: [3/4] kevent: AIO, aio_sendfile() implementation.

In reply to Badari Pulavarty
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 :)

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 in
include/linux/aio_abi.h

An enum {IO_NOTIFY_SIGNAL = 0, IO_NOTIFY_THREAD_ID = 1} is added in
include/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 then
iocb_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, an
lio_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), then
lio_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).

#32 lore raw

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_sigeventp is added to struct iocb in
include/linux/aio_abi.h

Quoted 8 lines

An enum {IO_NOTIFY_SIGNAL = 0, IO_NOTIFY_THREAD_ID = 1} is added in
include/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.

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_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

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_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

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_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

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 ❖
#33 lore raw

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_sigeventp is added to struct iocb in
include/linux/aio_abi.h

An enum {IO_NOTIFY_SIGNAL = 0, IO_NOTIFY_THREAD_ID = 1} is added in
include/linux/aio.h:

- IO_NOTIFY_SIGNAL means that the signal is to be sent to the requesting thread

Quoted 8 lines
Quoted 2 lines

- IO_NOTIFY_THREAD_ID means 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.

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_t ki_pid: target of the signal

- __u16 ki_signo: signal number

Quoted 8 lines
Quoted 4 lines

- __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

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 ?

Quoted 8 lines
Quoted 7 lines

- 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

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_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.

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_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 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_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

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.

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_listio control 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_NOP entries?

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_listio completion? 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
#34 lore raw

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_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?

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 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).

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_GROUP opcode 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 ❖
#35 lore raw

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_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?

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

#36 lore raw

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_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 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_THREAD notification 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

-----------------------------------------------------
#37 lore raw

Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)

In reply to Ulrich Drepper
Quoted 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_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?

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 be

Then 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 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).

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_GROUP opcode 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_listio interface.

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
#38 lore raw

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 ❖
#39 lore raw

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]>
#40 lore raw

Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)

In reply to Ulrich Drepper
Quoted 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_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?

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

-----------------------------------------------------
#41 lore raw

Re: Kernel patches enabling better POSIX AIO (Was Re: [3/4] kevent: AIO, aio_sendfile)

In reply to Suparna Bhattacharya

Hi,

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_sigeventp is added to struct iocb in
include/linux/aio_abi.h

An enum {IO_NOTIFY_SIGNAL = 0, IO_NOTIFY_THREAD_ID = 1} is added in
include/linux/aio.h:

- IO_NOTIFY_SIGNAL means that the signal is to be sent to the requesting thread

Quoted 8 lines
Quoted 2 lines

- IO_NOTIFY_THREAD_ID means 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 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_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?

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_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

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_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

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_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.

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_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.

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_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

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.

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_listio control 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.

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_NOP entries?

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_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 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_listio completion? 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

-----------------------------------------------------
#42 lore raw

Re: [3/4] kevent: AIO, aio_sendfile() implementation.

In reply to Ulrich Drepper
Quoted 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_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.

Quoted 8 lines

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.

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

-----------------------------------------------------
#43 lore raw

Re: [3/4] kevent: AIO, aio_sendfile() implementation.

In reply to Ulrich Drepper
Quoted 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_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.

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_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.

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
#44 lore raw

Re: [3/4] kevent: AIO, aio_sendfile() implementation.

In reply to Badari Pulavarty
Quoted 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 are

Quoted 6 lines

[ PATCH 1/3 ] Adding signal notification for event completion

[ PATCH 2/3 ] lio (listio) completion semantics

[ PATCH 3/3 ] cancel_fd support

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.

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

-----------------------------------------------------
#45 lore raw

Re: [1/4] kevent: core files.

In reply to Evgeniy Polyakov
Quoted 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;
#46 lore raw

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. Do

	if (file->f_fop != &kevent_user_fops)
		return -EINVAL;

Thanks, I will implement both.

Signature · 1 line
	Evgeniy Polyakov
#47 lore raw

Re: [1/4] kevent: core files.

In reply to Evgeniy Polyakov

kernel/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
maintainer
#48 lore raw
In reply to Evgeniy Polyakov

From: 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.

#49 lore raw
Quoted 12 lines · David Miller

From: 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.

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
maintainer
#50 lore raw

From: 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_tlb zero-copy sniffer (but I substitute mapped pages with physical skb->data pages), 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. :)

#51 lore raw
Quoted 7 lines · David Miller

From: 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).

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
#52 lore raw
Quoted 10 lines · Jens Axboe
Quoted 9 lines · David Miller

From: 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...

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
maintainer
#53 lore raw

From: 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.

#54 lore raw
Quoted 6 lines · David Miller

From: 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.

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
maintainer
#55 lore raw

From: 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.

#56 lore raw
Quoted 8 lines · David Miller

From: 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).

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
#57 lore raw
In reply to David Miller
Quoted 17 lines · David Miller

From: 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.

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_tlb zero-copy sniffer (but I substitute mapped pages with physical skb->data pages), and it was not very good.

Trying to be too clever with skb->data has 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
maintainer
#58 lore raw

From: 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 :))

#59 lore raw
Quoted 7 lines · David Miller

From: 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.

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