public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: "Sébastien Dugué" <sebastien.dugue@bull.net>
To: "linux-aio kvack.org" <linux-aio@kvack.org>,
	"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>
Subject: [PATCH 2/5] Add support for AIO completion notification
Date: Thu, 28 Jul 2005 17:46:32 +0200	[thread overview]
Message-ID: <1122565592.2019.81.camel@frecb000686> (raw)

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

             reply	other threads:[~2005-07-28 16:02 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-07-28 15:46 Sébastien Dugué [this message]
2005-08-09 21:00 ` [RFC] slight rework of [PATCH 2/5] Add support for AIO completion notification Benjamin LaHaise

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1122565592.2019.81.camel@frecb000686 \
    --to=sebastien.dugue@bull.net \
    --cc=linux-aio@kvack.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox