public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 2/5] Add support for AIO completion notification
@ 2005-07-28 15:46 Sébastien Dugué
  2005-08-09 21:00 ` [RFC] slight rework of " Benjamin LaHaise
  0 siblings, 1 reply; 2+ messages in thread
From: Sébastien Dugué @ 2005-07-28 15:46 UTC (permalink / raw)
  To: linux-aio kvack.org, linux-kernel@vger.kernel.org

[-- Attachment #1: Type: text/plain, Size: 1 bytes --]



[-- Attachment #2: aioevent --]
[-- Type: application/octet-stream, Size: 10584 bytes --]

aioevent:

 This patch adds POSIX AIO completion notification event by adding an aio_sigevent
field to the aiocb.

 The sigevent structure is filled in by the user application as part of the
AIO request preparation. Upon request completion, the kernel notifies the
application using those sigevent parameters.



 Makefile                |    2
 fs/aio.c                |  264 ++++++++++++++++++++++++++++++++++++++++--------
 include/linux/aio.h     |   10 +
 include/linux/aio_abi.h |    2
 4 files changed, 236 insertions(+), 42 deletions(-)

Signed-off-by: Sébastien Dugué <sebastien.dugue@bull.net>

Index: linux-2.6.12/fs/aio.c
===================================================================
--- linux-2.6.12.orig/fs/aio.c	2005-06-23 14:19:26.000000000 +0200
+++ linux-2.6.12/fs/aio.c	2005-06-23 14:19:28.000000000 +0200
@@ -406,6 +406,10 @@
 	req->ki_cancel = NULL;
 	req->ki_retry = NULL;
 	req->ki_dtor = NULL;
+	req->ki_pid = 0;
+	req->ki_signo = 0;
+	req->ki_notify = 0;
+	req->ki_value = 0;
 	req->private = NULL;
 	INIT_LIST_HEAD(&req->ki_run_list);
 
@@ -906,6 +910,92 @@
 }
 EXPORT_SYMBOL(kick_iocb);
 
+static void __aio_send_signal(pid_t pid, int signo, int notify, void *obj)
+{
+	struct siginfo info;
+	struct task_struct *p;
+
+	memset(&info, 0, sizeof(struct siginfo));
+
+	info.si_signo = signo;
+	info.si_errno = 0;
+	info.si_code = SI_ASYNCIO;
+	info.si_pid = 0;
+	info.si_uid = 0;
+	info.si_ptr = obj;
+
+	read_lock(&tasklist_lock);
+	p = find_task_by_pid(pid);
+
+	if (p->sighand) {
+		unsigned long flags;
+		int ret = -1;
+
+		spin_lock_irqsave(&p->sighand->siglock, flags);
+
+		switch(notify) {
+
+		case IO_NOTIFY_SIGNAL:
+			ret = __group_send_sig_info(signo, &info, p);
+			break;
+		case IO_NOTIFY_THREAD_ID:
+			//ret = specific_send_sig_info(signo, &info, p);
+			ret = __group_send_sig_info(signo, &info, p);
+			break;
+		}
+
+		spin_unlock_irqrestore(&p->sighand->siglock, flags);
+
+		if (ret)
+			printk(KERN_DEBUG "__aio_send_signal: failed to send signal %d to %d\n",
+			       signo, pid);
+	}
+	read_unlock(&tasklist_lock);
+}
+
+static void __aio_write_evt(struct kioctx *ctx, struct io_event *event)
+{
+	struct aio_ring_info	*info;
+	struct aio_ring *ring;
+	struct io_event *ring_event;
+	unsigned long   tail;
+
+	info = &ctx->ring_info;
+
+	/* add a completion event to the ring buffer.
+	 * must be done holding ctx->ctx_lock to prevent
+	 * other code from messing with the tail
+	 * pointer since we might be called from irq
+	 * context.
+	 */
+
+	ring = kmap_atomic(info->ring_pages[0], KM_IRQ1);
+
+	tail = info->tail;
+	ring_event = aio_ring_event(info, tail, KM_IRQ0);
+	if (++tail >= info->nr)
+		tail = 0;
+
+	*ring_event = *event;
+
+	dprintk("aio_write_evt: %p[%lu]: %Lx %Lx %Lx %Lx\n",
+		ctx, tail, event->obj, event->data, event->res, event->res2);
+
+	/* after flagging the request as done, we
+	 * must never even look at it again
+	 */
+
+	smp_wmb();	/* make event visible before updating tail */
+
+	info->tail = tail;
+	ring->tail = tail;
+
+	put_aio_ring_event(ring_event, KM_IRQ0);
+	kunmap_atomic(ring, KM_IRQ1);
+
+	pr_debug("added to ring at [%lu]\n", tail);
+}
+
 /* aio_complete
  *	Called when the io request on the given iocb is complete.
  *	Returns true if this is the last user of the request.  The 
@@ -914,11 +1004,8 @@
 int fastcall aio_complete(struct kiocb *iocb, long res, long res2)
 {
 	struct kioctx	*ctx = iocb->ki_ctx;
-	struct aio_ring_info	*info;
-	struct aio_ring	*ring;
-	struct io_event	*event;
+	struct io_event event;
 	unsigned long	flags;
-	unsigned long	tail;
 	int		ret;
 
 	/* Special case handling for sync iocbs: events go directly
@@ -945,14 +1032,13 @@
 		return ret;
 	}
 
-	info = &ctx->ring_info;
+	/* insert event in the event ring */
+
+	event.obj = (u64)(unsigned long)iocb->ki_obj.user;
+	event.data = iocb->ki_user_data;
+	event.res = res;
+	event.res2 = res2;
 
-	/* add a completion event to the ring buffer.
-	 * must be done holding ctx->ctx_lock to prevent
-	 * other code from messing with the tail
-	 * pointer since we might be called from irq
-	 * context.
-	 */
 	spin_lock_irqsave(&ctx->ctx_lock, flags);
 
 	if (iocb->ki_run_list.prev && !list_empty(&iocb->ki_run_list))
@@ -965,34 +1051,11 @@
 	if (kiocbIsCancelled(iocb))
 		goto put_rq;
 
-	ring = kmap_atomic(info->ring_pages[0], KM_IRQ1);
-
-	tail = info->tail;
-	event = aio_ring_event(info, tail, KM_IRQ0);
-	if (++tail >= info->nr)
-		tail = 0;
+	__aio_write_evt(ctx, &event);
 
-	event->obj = (u64)(unsigned long)iocb->ki_obj.user;
-	event->data = iocb->ki_user_data;
-	event->res = res;
-	event->res2 = res2;
-
-	dprintk("aio_complete: %p[%lu]: %p: %p %Lx %lx %lx\n",
-		ctx, tail, iocb, iocb->ki_obj.user, iocb->ki_user_data,
-		res, res2);
-
-	/* after flagging the request as done, we
-	 * must never even look at it again
-	 */
-	smp_wmb();	/* make event visible before updating tail */
-
-	info->tail = tail;
-	ring->tail = tail;
-
-	put_aio_ring_event(event, KM_IRQ0);
-	kunmap_atomic(ring, KM_IRQ1);
-
-	pr_debug("added to ring %p at [%lu]\n", iocb, tail);
+	if (iocb->ki_signo)
+		__aio_send_signal(iocb->ki_pid, iocb->ki_signo, iocb->ki_notify,
+				  (void*)(unsigned long)iocb->ki_value);
 
 	pr_debug("%ld retries: %d of %d\n", iocb->ki_retried,
 		iocb->ki_nbytes - iocb->ki_left, iocb->ki_nbytes);
@@ -1470,10 +1533,14 @@
 	struct kiocb *req;
 	struct file *file;
 	ssize_t ret;
+	int notify = 0;
+	struct sigevent __user *user_event = NULL;
+	int aio_pid = 0;
+	int aio_signo = 0;
+	int aio_value = 0;
 
 	/* enforce forwards compatibility on users */
-	if (unlikely(iocb->aio_reserved1 || iocb->aio_reserved2 ||
-		     iocb->aio_reserved3)) {
+	if (unlikely(iocb->aio_reserved1)) {
 		pr_debug("EINVAL: io_submit: reserve field set\n");
 		return -EINVAL;
 	}
@@ -1488,6 +1555,74 @@
 		return -EINVAL;
 	}
 
+	
+	/* Get sigevent */
+	if (unlikely(__get_user(user_event, (struct sigevent __user **)&user_iocb->aio_sigevent))) {
+		return -EFAULT;
+	}
+
+	if (user_event != NULL) {
+
+		/*
+		 * We avoid copying the whole sigevent bunch and only get the
+		 * needed fields.
+		 */
+		if (unlikely(__get_user(aio_pid,
+					&user_event->sigev_notify_thread_id))) {
+			return -EFAULT;
+		}
+
+		if (unlikely(__get_user(aio_signo,
+					&user_event->sigev_signo))) {
+			return -EFAULT;
+		}
+
+		if (unlikely(__get_user(aio_value,
+					&user_event->sigev_value.sival_int))) {
+			return -EFAULT;
+		}
+	}
+
+	if (aio_signo) {
+
+		if ( (iocb->aio_lio_opcode != IOCB_CMD_PREAD) &&
+		     (iocb->aio_lio_opcode != IOCB_CMD_PWRITE) )
+			return -EINVAL;
+
+		if (aio_pid == 0) {
+			/* notify itself */
+
+			aio_pid = current->pid;
+			notify = IO_NOTIFY_SIGNAL;
+		} else {
+		        pid_t group_id;
+			task_t *ptask;
+			/* notify given thread */
+
+			/* caller thread and target thread must be in same
+			 * thread group
+			 */
+
+			read_lock(&tasklist_lock);
+
+			ptask = find_task_by_pid(aio_pid);
+
+			if (unlikely (ptask == NULL)) {
+				read_unlock(&tasklist_lock);
+				return -EFAULT;
+			}
+
+			group_id = ptask->tgid;
+
+			read_unlock(&tasklist_lock);
+
+			if (group_id != current->tgid)
+				return -EINVAL;
+
+			notify = IO_NOTIFY_THREAD_ID;
+		}
+	}
+
 	file = fget(iocb->aio_fildes);
 	if (unlikely(!file))
 		return -EBADF;
@@ -1509,6 +1644,13 @@
 	req->ki_user_data = iocb->aio_data;
 	req->ki_pos = iocb->aio_offset;
 
+	if (aio_signo) {
+		req->ki_pid = aio_pid;
+		req->ki_signo = aio_signo;
+		req->ki_notify = notify;
+		req->ki_value = aio_value;
+	}
+
 	req->ki_buf = (char __user *)(unsigned long)iocb->aio_buf;
 	req->ki_left = req->ki_nbytes = iocb->aio_nbytes;
 	req->ki_opcode = iocb->aio_lio_opcode;
@@ -1578,6 +1720,10 @@
 	for (i=0; i<nr; i++) {
 		struct iocb __user *user_iocb;
 		struct iocb tmp;
+		struct sigevent __user *user_event = NULL;
+		int aio_pid = 0;
+		int aio_signo = 0;
+		
 
 		if (unlikely(__get_user(user_iocb, iocbpp + i))) {
 			ret = -EFAULT;
@@ -1589,6 +1735,44 @@
 			break;
 		}
 
+		/* Check user_iocb access */
+		if (unlikely(!access_ok(VERIFY_READ, user_iocb, sizeof(struct iocb)))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		/* Get sigevent */
+		if (unlikely(__get_user(user_event, (struct sigevent __user **)&user_iocb->aio_sigevent))) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if (user_event != NULL) {
+
+			/* Check user_event access */
+			if (unlikely(!access_ok(VERIFY_READ, user_event,
+						sizeof(struct sigevent)))) {
+				ret = -EFAULT;
+				break;
+			}
+
+			/*
+			 * We avoid copying the whole sigevent bunch and only get the
+			 * needed fields.
+			 */
+			if (unlikely(__get_user(aio_pid,
+						&user_event->sigev_notify_thread_id))) {
+				ret = -EFAULT;
+				break;
+			}
+
+			if (unlikely(__get_user(aio_signo,
+						&user_event->sigev_signo))) {
+				ret = -EFAULT;
+				break;
+			}
+		}
+
 		ret = io_submit_one(ctx, user_iocb, &tmp);
 		if (ret)
 			break;
Index: linux-2.6.12/include/linux/aio_abi.h
===================================================================
--- linux-2.6.12.orig/include/linux/aio_abi.h	2005-06-23 14:19:20.000000000 +0200
+++ linux-2.6.12/include/linux/aio_abi.h	2005-06-23 14:19:28.000000000 +0200
@@ -81,7 +81,7 @@
 	__s64	aio_offset;
 
 	/* extra parameters */
-	__u64	aio_reserved2;	/* TODO: use this for a (struct sigevent *) */
+	__u64	aio_sigevent;	/* TODO: use this for a (struct sigevent *) */
 	__u64	aio_reserved3;
 }; /* 64 bytes */
 
Index: linux-2.6.12/include/linux/aio.h
===================================================================
--- linux-2.6.12.orig/include/linux/aio.h	2005-06-23 14:19:26.000000000 +0200
+++ linux-2.6.12/include/linux/aio.h	2005-06-23 14:19:28.000000000 +0200
@@ -7,6 +7,11 @@
 
 #include <asm/atomic.h>
 
+enum {
+	IO_NOTIFY_SIGNAL = 0,		/* send signal to a processe */
+	IO_NOTIFY_THREAD_ID = 1,	/* send signal to a specific thread */
+};
+
 #define AIO_MAXSEGS		4
 #define AIO_KIOGRP_NR_ATOMIC	8
 
@@ -73,6 +78,11 @@
 	long			ki_retried; 	/* just for testing */
 	long			ki_kicked; 	/* just for testing */
 	long			ki_queued; 	/* just for testing */
+	/* to notify a process on I/O event */
+	__s32			ki_pid;
+	__u16			ki_signo;
+	__u16			ki_notify;
+	__u64			ki_value;
 
 	void			*private;
 };
Index: linux-2.6.12/Makefile
===================================================================
--- linux-2.6.12.orig/Makefile	2005-06-23 14:19:26.000000000 +0200
+++ linux-2.6.12/Makefile	2005-06-23 14:19:28.000000000 +0200
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 12
-EXTRAVERSION = .PAIO-aiomaxevents
+EXTRAVERSION = .PAIO-aioevent
 NAME=Woozy Numbat
 
 # *DOCUMENTATION*

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2005-08-09 20:57 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-07-28 15:46 [PATCH 2/5] Add support for AIO completion notification Sébastien Dugué
2005-08-09 21:00 ` [RFC] slight rework of " Benjamin LaHaise

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox