diff -urN linux-2.6.24/Makefile linux-2.6.24-in-090827/Makefile
--- linux-2.6.24/Makefile	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/Makefile	2009-08-28 12:52:06.000000000 +0900
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 24
-EXTRAVERSION =
+EXTRAVERSION = -ezio-090827
 NAME = Arr Matey! A Hairy Bilge Rat!
 
 # *DOCUMENTATION*
diff -urN linux-2.6.24/arch/x86/kernel/syscall_table_32.S linux-2.6.24-in-090827/arch/x86/kernel/syscall_table_32.S
--- linux-2.6.24/arch/x86/kernel/syscall_table_32.S	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/arch/x86/kernel/syscall_table_32.S	2008-09-19 15:54:04.000000000 +0900
@@ -324,3 +324,10 @@
 	.long sys_timerfd
 	.long sys_eventfd
 	.long sys_fallocate
+	.long sys_cp_create_port	/* 325 */
+	.long sys_cp_add_file_to_port	/* 326 */
+	.long sys_cp_del_file_from_port	/* 327 */
+	.long sys_cp_destroy_port		/* 328 */
+	.long sys_cp_get_completion_status		/* 329 */
+	.long sys_cp_post_completion_status		/* 330 */
+	.long sys_aio_post_io_completion		/* 331 */
diff -urN linux-2.6.24/fs/Makefile linux-2.6.24-in-090827/fs/Makefile
--- linux-2.6.24/fs/Makefile	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/fs/Makefile	2008-07-22 14:58:03.000000000 +0900
@@ -11,7 +11,7 @@
 		attr.o bad_inode.o file.o filesystems.o namespace.o aio.o \
 		seq_file.o xattr.o libfs.o fs-writeback.o \
 		pnode.o drop_caches.o splice.o sync.o utimes.o \
-		stack.o
+		stack.o iocp.o
 
 ifeq ($(CONFIG_BLOCK),y)
 obj-y +=	buffer.o bio.o block_dev.o direct-io.o mpage.o ioprio.o
diff -urN linux-2.6.24/fs/aio.c linux-2.6.24-in-090827/fs/aio.c
--- linux-2.6.24/fs/aio.c	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/fs/aio.c	2009-08-27 15:10:20.000000000 +0900
@@ -32,16 +32,36 @@
 #include <linux/security.h>
 #include <linux/eventfd.h>
 
+#if defined(CONFIG_NAIO)
+#include <linux/tcp.h>
+#include <linux/pagevec.h>
+#include <linux/writeback.h>
+#include <net/sock.h>
+#include <linux/splice.h>
+#include <linux/net.h>
+#endif
+
 #include <asm/kmap_types.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 
+#include <linux/iocp.h>
+
+#if defined(CONFIG_NAIO_DEBUG)
+#undef DEBUG
+#define DEBUG 2
+#endif
+
 #if DEBUG > 1
 #define dprintk		printk
 #else
 #define dprintk(x...)	do { ; } while (0)
 #endif
 
+#if defined(CONFIG_NAIO)
+#define MAX_SOCK_ADDR 128
+#endif
+
 /*------ sysctl variables----*/
 static DEFINE_SPINLOCK(aio_nr_lock);
 unsigned long aio_nr;		/* current system wide number of aio requests */
@@ -759,7 +779,9 @@
 {
 	struct kiocb *iocb;
 	struct list_head run_list;
+	int ret;
 
+	dprintk("\n");
 	assert_spin_locked(&ctx->ctx_lock);
 
 	list_replace_init(&ctx->run_list, &run_list);
@@ -771,7 +793,10 @@
 		 * Hold an extra reference while retrying i/o.
 		 */
 		iocb->ki_users++;       /* grab extra reference */
-		aio_run_iocb(iocb);
+		ret = aio_run_iocb(iocb);
+		dprintk("[%s:%d] aio_run_iocb_ret = %d\n", __FUNCTION__, __LINE__, ret);
+		if (ret < 0)
+			dprintk("[%s:%d] aio_run_iocb_FAIL\n", __FUNCTION__, __LINE__);
 		__aio_put_req(ctx, iocb);
  	}
 	if (!list_empty(&ctx->run_list))
@@ -787,10 +812,12 @@
 	 * away, otherwise, use a longer delay
 	 */
 	smp_mb();
-	if (waitqueue_active(&ctx->wait))
+/*	if (waitqueue_active(&ctx->wait))
 		timeout = 1;
 	else
 		timeout = HZ/10;
+*/
+	timeout = 0;
 	queue_delayed_work(aio_wq, &ctx->wq, timeout);
 }
 
@@ -907,6 +934,104 @@
 }
 EXPORT_SYMBOL(kick_iocb);
 
+#if defined(CONFIG_NAIO)
+static int aio_move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int len)
+{
+	if (len > klen)
+		len = klen;
+	if (len < 0 || len > MAX_SOCK_ADDR)
+		return -EINVAL;
+	if (len) {
+		if (copy_to_user(uaddr, kaddr, len))
+			return -EFAULT;
+	}
+	return 0;
+}
+
+static void aio_accept_map_fd(struct io_event *ent)
+{
+	int err;
+	struct socket *newsock = NULL;
+	char address[MAX_SOCK_ADDR];
+	int addrlen;
+	struct iocb __user *user_iocb;
+	struct iocb iocb;
+
+	dprintk("[%s] Enter.\n", __FUNCTION__);
+
+	/* ent->res2 : newsock */
+	if (!ent->res2) { /* not ACCEPT or accept failed */
+		dprintk("[%s] is not ACCEPT or accept failed\n", __FUNCTION__);
+		return; /* do nothing, just return */
+	}
+	/* ent->res : return value of aio_paccept() */
+	if (ent->res < 0) {
+		dprintk("[%s] accept failed, event->res = %ld\n", __FUNCTION__, (long)ent->res);
+		return ;
+	}
+
+	newsock = (struct socket *)(long)ent->res2;
+	dprintk("[%s] %d newsock=%p\n", __FUNCTION__, __LINE__, newsock);
+
+	user_iocb = (struct iocb __user *)(unsigned long)ent->obj;
+	dprintk("[%s] %d user_iocb=%p\n", __FUNCTION__, __LINE__, user_iocb);
+
+	if (unlikely(copy_from_user(&iocb, user_iocb, sizeof(iocb)))) {
+		dprintk("[%s] %d in if()\n", __FUNCTION__, __LINE__);
+		err = -EFAULT;	
+		goto do_err;
+	}
+	dprintk("[%s] %d after copy_from_user(), iocb=%p\n", __FUNCTION__, __LINE__, &iocb);
+
+	if (!iocb.aio_buf) {
+		return;
+	}
+	
+	dprintk("[%s] %d iocb.aio_buf=%p\n", __FUNCTION__, __LINE__, (struct socket *)(unsigned long)iocb.aio_buf);
+
+	if (newsock->ops->getname(newsock, (struct sockaddr*)address, &addrlen, 2) < 0) {
+		dprintk("[%s] getname failed!\n", __FUNCTION__);
+		err = -ECONNABORTED;
+		goto do_err;
+	}
+
+	dprintk("[%s] %d iocb->aio_nbytes=%d\n", __FUNCTION__, __LINE__,
+						(int)iocb.aio_nbytes);
+	err = aio_move_addr_to_user(address, addrlen,
+				(struct sockaddr __user *)(unsigned long)iocb.aio_buf,
+				(int)iocb.aio_nbytes);
+	if (err < 0) {
+		dprintk("[%s] move_addr_to_user failed!! err = %d\n", __FUNCTION__, err);
+		goto do_err;
+	}
+	else {
+		dprintk("[%s] move_addr_to_user success!!\n", __FUNCTION__);
+	}
+	/* actual length of the address returned.
+	 * The value of ent->res and ent->res2 will be exchanged
+	 * in aio_accept_map_fd()
+	*/
+	ent->res2 = (long)addrlen;
+	dprintk("[%s] addrlen = %ld\n", __FUNCTION__, (long)ent->res2);
+
+	if ((err = sock_map_fd(newsock)) < 0) {
+		dprintk("[%s] sock_map_fd failed.. err = %d\n", __FUNCTION__, err);
+		goto do_err;
+	}
+
+	dprintk("[%s] newsock = %p, fd = %d, addrlen = %ld\n",
+		__FUNCTION__, newsock, err, (long)ent->res2);
+
+	ent->res = err;			// socket fd
+	return;
+
+do_err:
+	ent->res = err;
+	sock_release(newsock);
+	return;
+}
+#endif  /* if defined(CONFIG_NAIO) */
+
 /* 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 
@@ -921,6 +1046,7 @@
 	unsigned long	flags;
 	unsigned long	tail;
 	int		ret;
+	struct file		*filp = iocb->ki_filp;
 
 	/*
 	 * Special case handling for sync iocbs:
@@ -965,6 +1091,19 @@
 	if (kiocbIsCancelled(iocb))
 		goto put_rq;
 
+	/*
+	 * for IOCP, check if socket is linked to iocp port 
+	 */
+	if (filp->ioc_ctx != NULL) {
+		spin_unlock_irqrestore(&ctx->ctx_lock, flags);
+
+		dprintk("calling post_io_completion, iocb=%p, res=%ld\n", iocb, res);
+		post_io_completion(filp, res, iocb->ki_obj.user);
+
+		spin_lock_irqsave(&ctx->ctx_lock, flags);
+		goto put_rq;
+	}
+
 	ring = kmap_atomic(info->ring_pages[0], KM_IRQ1);
 
 	tail = info->tail;
@@ -977,6 +1116,16 @@
 	event->res = res;
 	event->res2 = res2;
 
+
+#if defined(CONFIG_NAIO)
+	if (iocb->ki_opcode == IOCB_CMD_ACCEPT && res >= 0) {
+		// store address of newsock to event->res2
+		event->res2 = (s64)(unsigned long)iocb->private;
+		dprintk("[%s] iocb->ki_buf=%p, event->res2=%p\n", __FUNCTION__, iocb->ki_buf, 
+						(struct socket *)(long)event->res2);
+	}
+#endif
+
 	dprintk("aio_complete: %p[%lu]: %p: %p %Lx %lx %lx\n",
 		ctx, tail, iocb, iocb->ki_obj.user, iocb->ki_user_data,
 		res, res2);
@@ -1041,8 +1190,15 @@
 
 out:
 	kunmap_atomic(ring, KM_USER0);
+#if defined(CONFIG_NAIO_DEBUG)
+#if 0
+	dprintk("leaving aio_read_evt: %d  h%lu t%lu\n", ret,
+		 (unsigned long)ring->head, (unsigned long)ring->tail);
+#endif
+#else
 	dprintk("leaving aio_read_evt: %d  h%lu t%lu\n", ret,
 		 (unsigned long)ring->head, (unsigned long)ring->tail);
+#endif
 	return ret;
 }
 
@@ -1105,10 +1261,15 @@
 retry:
 	ret = 0;
 	while (likely(i < nr)) {
+		dprintk("[%s] %d\n", __FUNCTION__, __LINE__);
 		ret = aio_read_evt(ctx, &ent);
 		if (unlikely(ret <= 0))
 			break;
 
+#if defined(CONFIG_NAIO)
+		aio_accept_map_fd(&ent);
+#endif
+
 		dprintk("read event: %Lx %Lx %Lx %Lx\n",
 			ent.data, ent.obj, ent.res, ent.res2);
 
@@ -1153,9 +1314,14 @@
 		add_wait_queue_exclusive(&ctx->wait, &wait);
 		do {
 			set_task_state(tsk, TASK_INTERRUPTIBLE);
+			dprintk("[%s] %d\n", __FUNCTION__, __LINE__);
 			ret = aio_read_evt(ctx, &ent);
-			if (ret)
+			if (ret) {
+#if defined(CONFIG_NAIO)
+				aio_accept_map_fd(&ent);
+#endif
 				break;
+			}
 			if (min_nr <= i)
 				break;
 			ret = 0;
@@ -1311,7 +1477,304 @@
 	BUG_ON(ret > 0 && iocb->ki_left == 0);
 }
 
+#ifdef CONFIG_NAIO
+static int aio_rw_cancel(struct kiocb *iocb, struct io_event *evt)
+{
+	struct kioctx *ctx = iocb->ki_ctx;
+	struct socket *sock = iocb->ki_filp->private_data;
+
+	dprintk("[%s]\n", __FUNCTION__);
+
+	spin_lock_irq(&sock->sk->sk_sleep->lock);
+	if(!list_empty(&iocb->ki_wait.task_list)) {
+		list_del_init(&iocb->ki_wait.task_list);
+		spin_unlock_irq(&sock->sk->sk_sleep->lock);
+
+		spin_lock_irq(&ctx->ctx_lock);
+		aio_run_iocb(iocb);
+		spin_unlock_irq(&ctx->ctx_lock);
+	}
+	else {
+		spin_unlock_irq(&sock->sk->sk_sleep->lock);
+		dprintk("[%s]not_on_wait_q\n", __FUNCTION__);
+	}
+
+	aio_put_req(iocb);
+	return 0;
+}
+
+/* Default cancel method for aio_read */
+static inline int aio_pread_cancel(struct kiocb *iocb, struct io_event *evt)
+{
+	return aio_rw_cancel(iocb, evt);
+}
+
+/* Default cancel method for aio_write */
+static inline int aio_pwrite_cancel(struct kiocb *iocb, struct io_event *evt)
+{
+	return aio_rw_cancel(iocb, evt);
+}
+
+static inline void sock_aio_dtor(struct kiocb *iocb)
+{
+	kfree(iocb->private);
+}
+static ssize_t aio_precv(struct kiocb *iocb, const struct iovec *iov, 
+				unsigned long nr_segs, loff_t pos)
+{
+	struct sock_iocb *siocb;
+	struct socket *sock;
+	int flags, err, i;
+	size_t size = 0;
+
+	if (iocb->ki_pos)
+		return -ESPIPE;
+
+	if (iocb->ki_left == 0)
+		return 0;
+
+	dprintk("[%s] %d\n", __FUNCTION__, __LINE__);
+	if (!iocb->private) {
+		dprintk("[%s] %d iocb->private = NULL\n", __FUNCTION__, __LINE__);
+		if (!(siocb = kmalloc(sizeof(struct sock_iocb), GFP_KERNEL)))
+			return -ENOMEM;
+    
+		iocb->ki_dtor = sock_aio_dtor;
+		iocb->private = siocb;
+	} else {
+		dprintk("[%s] %d iocb->private != NULL\n", __FUNCTION__, __LINE__);
+		siocb = kiocb_to_siocb(iocb);
+	}
+
+	for (i = 0; i < nr_segs; i++)
+		size += iov[i].iov_len;
+
+	dprintk("[%s] %d size=%d, nr_segs=%lu\n", __FUNCTION__, __LINE__, size, nr_segs);
+
+	siocb->kiocb = iocb;
+	siocb->async_msg.msg_name = NULL;
+	siocb->async_msg.msg_namelen = 0;
+	siocb->async_msg.msg_control = NULL;
+	siocb->async_msg.msg_controllen = 0;
+
+	siocb->async_msg.msg_iov = (struct iovec *)iov;
+	siocb->async_msg.msg_iovlen = nr_segs;
+//	siocb->async_iov.iov_base = iocb->ki_buf;
+//	siocb->async_iov.iov_len = iocb->ki_left;
+	flags = MSG_DONTWAIT;
+    
+	sock = iocb->ki_filp->private_data;
+	siocb->sock = sock;
+	siocb->scm = NULL;
+	siocb->msg = &siocb->async_msg;
+//	siocb->size = iocb->ki_left;
+	siocb->size = size;
+	siocb->flags = flags;
+
+	err = security_socket_recvmsg(sock, &siocb->async_msg, size, flags);
+	if (err)
+		return err;
+
+	dprintk("[%s] %d\n", __FUNCTION__, __LINE__);
+	return sock->ops->recvmsg(iocb, sock, &siocb->async_msg, size, flags);
+}
+
+static ssize_t aio_pread_sock(struct kiocb *iocb)
+{
+	struct socket *sock;
+	unsigned long flags;
+	int retried = 0;
+	ssize_t ret = 0;
+
+	sock = iocb->ki_filp->private_data;
+
+	dprintk("[%s]%p left=%d,buf=%p\n", __FUNCTION__, iocb, iocb->ki_left, iocb->ki_buf);
+
+aio_read_retry:
+	ret = aio_precv(iocb, &iocb->ki_iovec[iocb->ki_cur_seg],
+			iocb->ki_nr_segs - iocb->ki_cur_seg,
+			iocb->ki_pos);
+    /*
+	* Can't just depend on iocb->ki_left to determine
+	*           * whether we are done. This may have been a short read.
+	*/
+	/*
+	* For sockets we return once we have some data; though for
+	* regular files we retry till we complete the entire read or
+	* find that we can't read any more data (e.g short reads).
+	*/
+	if (ret > 0) {
+		aio_advance_iovec(iocb, ret);
+	}
+	dprintk("[%s] ret=%d\n", __FUNCTION__, ret);
+
+/*	if (iocb->ki_filp->f_flags & O_NONBLOCK)
+		goto out;
+*/
+	/* This means we must have transferred all that we could 
+	No need to retry anymore */
+	if (!ret || !iocb->ki_left)
+		ret = iocb->ki_nbytes - iocb->ki_left;
+
+	if ((ret == -EAGAIN) || (ret == -EWOULDBLOCK)) {
+		spin_lock_irqsave(&sock->sk->sk_sleep->lock, flags);
+		if (atomic_read(&sock->sk->sk_rmem_alloc) > 0) {
+			dprintk("[%s]%p rmem=%d, read_after_spin_lock\n", __FUNCTION__, iocb, atomic_read(&sock->sk->sk_rmem_alloc));
+
+			if (++retried > 1) {
+				dprintk("[%s]%p rmem=%d, retried>1\n", __FUNCTION__, iocb,
+					atomic_read(&sock->sk->sk_rmem_alloc));
+
+				(&iocb->ki_wait)->flags &= ~WQ_FLAG_EXCLUSIVE;
+				__add_wait_queue(sock->sk->sk_sleep, &iocb->ki_wait);
+				spin_unlock_irqrestore(&sock->sk->sk_sleep->lock, flags);
+				ret = -EIOCBRETRY;
+				goto out;
+			}
+			spin_unlock_irqrestore(&sock->sk->sk_sleep->lock, flags);
+			dprintk("[%s]%p rmem=%d, goto_aio_read_retry\n", __FUNCTION__, iocb,
+				atomic_read(&sock->sk->sk_rmem_alloc));
+			goto aio_read_retry;
+		} else {
+			(&iocb->ki_wait)->flags &= ~WQ_FLAG_EXCLUSIVE;
+			__add_wait_queue(sock->sk->sk_sleep, &iocb->ki_wait);
+			spin_unlock_irqrestore(&sock->sk->sk_sleep->lock, flags);
+			ret = -EIOCBRETRY;
+		}
+	}
+
+out:
+	dprintk("[%s] returing %d\n", __FUNCTION__, ret);
+	return ret;
+}
+
+static ssize_t aio_psend(struct kiocb *iocb, const struct iovec *iov, 
+				unsigned long nr_segs, loff_t pos)
+{
+	struct sock_iocb *siocb;
+	struct socket *sock;
+	int err, i;
+	size_t size = 0;
+
+	if (iocb->ki_pos)
+		return -ESPIPE;
+
+	if (!iocb->private) {
+		if (!(siocb = kmalloc(sizeof(struct sock_iocb), GFP_KERNEL)))
+			return -ENOMEM;
+
+		iocb->ki_dtor = sock_aio_dtor;
+		iocb->private = siocb;
+	} else
+		siocb = kiocb_to_siocb(iocb);
+
+	for (i = 0; i < nr_segs; i++)
+		size += iov[i].iov_len;
+
+	siocb->kiocb = iocb;
+	siocb->async_msg.msg_name = NULL;
+	siocb->async_msg.msg_namelen = 0;
+	siocb->async_msg.msg_control = NULL;
+	siocb->async_msg.msg_controllen = 0;
+
+	siocb->async_msg.msg_iov = (struct iovec *)iov;
+	siocb->async_msg.msg_iovlen = nr_segs;
+	siocb->async_msg.msg_flags = MSG_DONTWAIT;
+
+	sock = iocb->ki_filp->private_data;
+	if (sock->type == SOCK_SEQPACKET)
+		siocb->async_msg.msg_flags |= MSG_EOR;
+//	siocb->async_iov.iov_base = iocb->ki_buf;
+//	siocb->async_iov.iov_len = iocb->ki_left;
+
+	siocb->sock = sock;
+	siocb->scm = NULL;
+	siocb->msg = &siocb->async_msg;
+	siocb->size = size;
+
+	if ((err = security_socket_sendmsg(sock, siocb->msg, size)))
+		return err;
+
+	return sock->ops->sendmsg(iocb, sock, &siocb->async_msg, size);
+}
+
+static ssize_t aio_pwrite_sock(struct kiocb *iocb)
+{
+	struct socket *sock;
+	unsigned long flags;
+	int retried = 0;
+	ssize_t ret = 0;
+
+	sock = iocb->ki_filp->private_data;
+
+	dprintk("[%s]%p left=%d,buf=%p\n", __FUNCTION__, iocb, iocb->ki_left, iocb->ki_buf);
+
+aio_write_retry:
+	ret = aio_psend(iocb, &iocb->ki_iovec[iocb->ki_cur_seg],
+		iocb->ki_nr_segs - iocb->ki_cur_seg,
+		iocb->ki_pos);
+	dprintk("[%s]%p ret = %d\n", __FUNCTION__, iocb, ret);
+
+	if (ret > 0) {
+		aio_advance_iovec(iocb, ret);
+	}
+
+/*	if (iocb->ki_filp->f_flags & O_NONBLOCK)
+		goto out;
+*/
+	if (!ret || !iocb->ki_left)
+		ret = iocb->ki_nbytes - iocb->ki_left;
+
+	if ((ret == -EAGAIN) || (ret == -EWOULDBLOCK)) {
+		spin_lock_irqsave(&sock->sk->sk_sleep->lock, flags);
+		if (sock->sk->sk_sndbuf > sock->sk->sk_wmem_queued) {
+			dprintk("[%s]%p sndbuf=%d,wmem_q=%d, write_after_spin_lock\n",
+				__FUNCTION__, iocb, sock->sk->sk_sndbuf,
+				sock->sk->sk_wmem_queued);
+
+			if (++retried > 1) {
+				dprintk("[%s]%p sndbuf=%d,wmem_q=%d, retried>1\n",
+					__FUNCTION__, iocb, sock->sk->sk_sndbuf,
+					sock->sk->sk_wmem_queued);
+
+				(&iocb->ki_wait)->flags &= ~WQ_FLAG_EXCLUSIVE;
+				__add_wait_queue(sock->sk->sk_sleep, &iocb->ki_wait);
+				spin_unlock_irqrestore(&sock->sk->sk_sleep->lock, flags);
+				ret = -EIOCBRETRY;
+				goto out;
+			}
+			spin_unlock_irqrestore(&sock->sk->sk_sleep->lock, flags);
+			dprintk("[%s]%p sndbuf=%d,wmem_q=%d, goto_aio_write_retry\n",
+				__FUNCTION__, iocb, sock->sk->sk_sndbuf,
+				sock->sk->sk_wmem_queued);
+			goto aio_write_retry;
+		} else {
+			(&iocb->ki_wait)->flags &= ~WQ_FLAG_EXCLUSIVE;
+			__add_wait_queue(sock->sk->sk_sleep, &iocb->ki_wait);
+			spin_unlock_irqrestore(&sock->sk->sk_sleep->lock, flags);
+			ret = -EIOCBRETRY;
+		}
+	}
+
+out:
+	dprintk("[%s]%p returing %d\n", __FUNCTION__, iocb, ret);
+	return ret;
+}
+
+static ssize_t aio_rw_sock_retry(struct kiocb *iocb)
+{
+	if ((iocb->ki_opcode == IOCB_CMD_PREADV) ||
+		(iocb->ki_opcode == IOCB_CMD_PREAD)) {
+		return aio_pread_sock(iocb);
+	} else {
+		return aio_pwrite_sock(iocb);
+	}
+}
+
+static ssize_t aio_rw_file_retry(struct kiocb *iocb)
+#else
 static ssize_t aio_rw_vect_retry(struct kiocb *iocb)
+#endif
 {
 	struct file *file = iocb->ki_filp;
 	struct address_space *mapping = file->f_mapping;
@@ -1351,6 +1814,19 @@
 	return ret;
 }
 
+#if defined(CONFIG_NAIO)
+static ssize_t aio_rw_vect_retry(struct kiocb *iocb)
+{
+	struct inode *inode = iocb->ki_filp->f_mapping->host;
+
+	if (S_ISSOCK(inode->i_mode))
+		return aio_rw_sock_retry(iocb);	/* for Network AIO, ejlim */
+
+	else
+		return aio_rw_file_retry(iocb);
+}
+#endif
+
 static ssize_t aio_fdsync(struct kiocb *iocb)
 {
 	struct file *file = iocb->ki_filp;
@@ -1371,6 +1847,369 @@
 	return ret;
 }
 
+#if defined(CONFIG_NAIO)
+static ssize_t aio_psendfile_cancel(struct kiocb *iocb, struct io_event *evt)
+{
+	struct kioctx *ctx = iocb->ki_ctx;
+	struct file *out_file;
+	struct socket *sock;
+
+	dprintk("[aio_psendfile_cancel] entered\n");
+
+	sock = SOCKET_I(((struct file *)iocb->private)->f_dentry->d_inode);
+
+	spin_lock_irq(&sock->sk->sk_sleep->lock);
+	if(!list_empty(&iocb->ki_wait.task_list)) {
+		list_del_init(&iocb->ki_wait.task_list);
+		spin_unlock_irq(&sock->sk->sk_sleep->lock);
+
+		spin_lock_irq(&ctx->ctx_lock);
+		aio_run_iocb(iocb);
+		spin_unlock_irq(&ctx->ctx_lock);
+	} else {
+		spin_unlock_irq(&sock->sk->sk_sleep->lock);
+		dprintk("[%s]not_on_wait_q\n", __FUNCTION__);
+	}
+
+	if (iocb->private != NULL) {
+		out_file = (struct file *)iocb->private;
+		fput(out_file);
+		iocb->private = NULL;
+	}
+
+	aio_put_req(iocb);
+	dprintk("[aio_psendfile_cancel] returning\n");
+
+	return 0;
+}
+
+/*
+ * Attempt to initiate a splice from pipe to file.
+*/
+static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
+				loff_t *ppos, size_t len, unsigned int flags)
+{
+	int ret;
+
+	if (unlikely(!out->f_op || !out->f_op->splice_write))
+		return -EINVAL;
+
+	if (unlikely(!(out->f_mode & FMODE_WRITE)))
+		return -EBADF;
+
+	ret = rw_verify_area(WRITE, out, ppos, len);
+	if (unlikely(ret < 0))
+		return ret;
+
+	ret = security_file_permission(out, MAY_WRITE);
+	if (unlikely(ret < 0))
+		return ret;
+
+	return out->f_op->splice_write(pipe, out, ppos, len, flags);
+}
+
+/*
+ * Attempt to initiate a splice from a file to a pipe.
+*/
+static long do_splice_to(struct file *in, loff_t *ppos,
+			struct pipe_inode_info *pipe, size_t len,
+			unsigned int flags)
+{
+	int ret;
+
+	if (unlikely(!in->f_op || !in->f_op->splice_read))
+		return -EINVAL;
+
+	if (unlikely(!(in->f_mode & FMODE_READ)))
+		return -EBADF;
+
+	ret = rw_verify_area(READ, in, ppos, len);
+	if (unlikely(ret < 0))
+		return ret;
+
+	ret = security_file_permission(in, MAY_READ);
+	if (unlikely(ret < 0))
+		return ret;
+
+	return in->f_op->splice_read(in, ppos, pipe, len, flags);
+}
+
+static int aio_direct_splice_actor(struct pipe_inode_info *pipe,
+					struct splice_desc *sd)
+{
+	struct file *file = sd->u.file;
+
+	return do_splice_from(pipe, file, &sd->pos, sd->total_len, sd->flags);
+}
+
+ssize_t aio_splice_direct_to_actor(struct kiocb *iocb, struct splice_desc *sd)
+{
+	struct file *in = iocb->ki_filp;
+	struct pipe_inode_info *pipe;
+	long ret, bytes;
+	umode_t i_mode;
+	size_t len;
+	int i, flags;
+
+	/*
+	* We require the input being a regular file, as we don't want to
+	* randomly drop data for eg socket -> socket splicing. Use the
+	* piped splicing for that!
+	*/
+	i_mode = in->f_path.dentry->d_inode->i_mode;
+	if (unlikely(!S_ISREG(i_mode) && !S_ISBLK(i_mode)))
+		return -EINVAL;
+
+	/*
+	* neither in nor out is a pipe, setup an internal pipe attached to
+	* 'out' and transfer the wanted data from 'in' to 'out' through that
+	*/
+	pipe = current->splice_pipe;
+	if (unlikely(!pipe)) {
+		pipe = alloc_pipe_info(NULL);
+		if (!pipe)
+			return -ENOMEM;
+
+		/*
+		* We don't have an immediate reader, but we'll read the stuff
+		* out of the pipe right after the splice_to_pipe(). So set
+		* PIPE_READERS appropriately.
+		*/
+		pipe->readers = 1;
+
+		current->splice_pipe = pipe;
+    }
+
+	/*
+	* Do the splice.
+	*/
+	ret = 0;
+	bytes = 0;
+	len = sd->total_len;
+	flags = sd->flags;
+
+	/*
+	* Don't block on output, we have to drain the direct pipe.
+	*/
+	sd->flags &= ~SPLICE_F_NONBLOCK;
+
+	while (len) {
+		size_t read_len;
+		loff_t pos = sd->pos;
+
+		ret = do_splice_to(in, &pos, pipe, len, flags);
+		if (unlikely(ret <= 0))
+			goto out_release;
+
+		read_len = ret;
+		sd->total_len = read_len;
+
+		/*
+		* NOTE: nonblocking mode only applies to the input. We
+		* must not do the output in nonblocking mode as then we
+		* could get stuck data in the internal pipe:
+		*/
+		ret = aio_direct_splice_actor(pipe, sd);
+		if (unlikely(ret <= 0))
+			goto out_release;
+
+		bytes += ret;
+		len -= ret;
+		sd->pos = pos;
+
+		if (ret < read_len)
+			goto out_release;
+	}
+
+	pipe->nrbufs = pipe->curbuf = 0;
+	return bytes;
+
+out_release:
+	/*
+	* If we did an incomplete transfer we must release
+	* the pipe buffers in question:
+	*/
+	for (i = 0; i < PIPE_BUFFERS; i++) {
+		struct pipe_buffer *buf = pipe->bufs + i;
+
+		if (buf->ops) {
+			buf->ops->release(pipe, buf);
+			buf->ops = NULL;
+		}
+	}
+	pipe->nrbufs = pipe->curbuf = 0;
+
+	/*
+	* If we transferred some data, return the number of bytes:
+	*/
+	if (bytes > 0)
+		return bytes;
+
+	return ret;
+}
+
+static long aio_do_splice_direct(struct kiocb *iocb, struct file *in, 
+			loff_t pos, struct file *out, size_t len, unsigned int flags)
+{
+	struct splice_desc sd = {
+		.len		= len,
+		.total_len	= len,
+		.flags		= flags,
+		.pos		= pos,
+		.u.file		= out,
+	};
+	long ret;
+	int oldflags;
+
+	oldflags = out->f_flags;
+	out->f_flags |= O_NONBLOCK;
+	ret = aio_splice_direct_to_actor(iocb, &sd);
+	out->f_flags = oldflags;
+	
+	return ret;
+}
+
+static ssize_t aio_psendfile(struct kiocb *iocb)
+{
+	struct file *in_file, *out_file;
+	struct inode *in_inode, *out_inode;
+	struct socket *sock;
+	ssize_t ret;
+	int fl;
+
+	in_file = iocb->ki_filp;
+	out_file = (struct file *) iocb->private;
+	in_inode = in_file->f_dentry->d_inode;
+	out_inode = out_file->f_dentry->d_inode;
+	if (S_ISSOCK(out_inode->i_mode))
+		sock = SOCKET_I(out_inode);
+	else
+		sock = SOCKET_I(in_inode);
+
+	dprintk("[aio_psendfile] pos = %Ld, nbytes=%d\n", iocb->ki_pos, iocb->ki_left);
+
+	fl = 0;
+
+	// changed aio_generic_file_sendfile() in kernel 2.6.16 
+	ret = aio_do_splice_direct(iocb, in_file, iocb->ki_pos, out_file, iocb->ki_left, fl);
+
+	dprintk("[aio_psendfile] ret = %d\n", ret);
+	if (ret >= 0) {
+		iocb->ki_left -= ret;
+		iocb->ki_pos += ret;
+		ret = -EIOCBRETRY;
+		dprintk("[aio_psendfile] ki_left = %d\n", iocb->ki_left);
+		if (iocb->ki_left)
+			add_wait_queue(sock->sk->sk_sleep, &iocb->ki_wait);
+	}
+
+	if (!iocb->ki_left) {
+		ret = iocb->ki_nbytes - iocb->ki_left;
+		fput(out_file);
+	}
+	dprintk("[aio_psendfile] ret = %d, ki_pos = %Ld, ki_left = %d\n\n",
+			ret, iocb->ki_pos, iocb->ki_left);
+
+	return ret;
+}
+
+static ssize_t aio_paccept(struct kiocb *iocb)
+{
+	struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
+	struct socket *sock, *newsock;
+	int err = -ENOTSOCK;
+
+	sock = SOCKET_I(inode);
+	if (!sock)
+		goto end_1;
+
+	if (iocb->private == NULL) {
+		dprintk("[%s], iocb->private == NULL\n", __FUNCTION__);
+		err = -EMFILE;
+		if (!(newsock = sock_alloc()))
+			goto end_1;
+
+		newsock->type = sock->type;
+		newsock->ops = sock->ops;
+
+		if ((err=security_socket_accept(sock, newsock)))
+			goto do_err;
+
+		__module_get(newsock->ops->owner);
+
+		iocb->private = (void *)newsock;
+	}
+	else {
+		newsock = (struct socket *)iocb->private;
+		dprintk("[%s], iocb->private != NULL, newsock=%p\n", __FUNCTION__, newsock);
+	}
+
+	if ((err = sock->ops->aio_accept(iocb, sock, newsock, sock->file->f_flags)) < 0) {
+		dprintk("[%s] err = %d\n", __FUNCTION__, err);
+		if (err==-EIOCBRETRY) {
+			goto end_1;
+		}
+		else {
+			goto do_err;
+		}
+	}
+
+	security_socket_post_accept(sock, newsock);
+
+end_1:
+	return (ssize_t)err;
+do_err:
+	sock_release(newsock);
+	goto end_1;
+}
+
+static ssize_t aio_paccept_cancel(struct kiocb *iocb, struct io_event *evt)
+{
+	struct kioctx *ctx = iocb->ki_ctx;
+	struct inode *inode = iocb->ki_filp->f_dentry->d_inode;
+	struct socket *sock, *newsock;
+	int err = -ENOTSOCK;
+
+	dprintk("[aio_paccept_cancel] entered\n");
+
+	if (!(sock=SOCKET_I(inode)))
+		goto end_3;
+
+	spin_lock_irq(&sock->sk->sk_sleep->lock);
+	if(!list_empty(&iocb->ki_wait.task_list)) {
+		list_del_init(&iocb->ki_wait.task_list);
+		spin_unlock_irq(&sock->sk->sk_sleep->lock);
+
+		spin_lock_irq(&ctx->ctx_lock);
+		aio_run_iocb(iocb);
+		spin_unlock_irq(&ctx->ctx_lock);
+	} 
+	else {
+		spin_unlock_irq(&sock->sk->sk_sleep->lock);
+		dprintk("[%s]not_on_wait_q\n", __FUNCTION__);
+	}
+
+	err = -EAGAIN;
+	if (iocb->private) {
+		newsock = (struct socket *)iocb->private;
+		sock_release(newsock);
+		iocb->private = NULL;
+	}
+
+end_3:
+	evt->obj = (u64)(unsigned long)iocb->ki_obj.user;
+	evt->data = iocb->ki_user_data;
+	evt->res = err;
+	evt->res2 = 0;
+
+	aio_put_req(iocb);
+	dprintk("[aio_paccept_cancel] returning\n");
+
+	return 0;
+}
+
+#endif	/* if defined(CONFIG_NAIO) */
+
 static ssize_t aio_setup_vectored_rw(int type, struct kiocb *kiocb)
 {
 	ssize_t ret;
@@ -1428,8 +2267,13 @@
 		if (ret)
 			break;
 		ret = -EINVAL;
-		if (file->f_op->aio_read)
+		if (file->f_op->aio_read) {
 			kiocb->ki_retry = aio_rw_vect_retry;
+#if defined(CONFIG_NAIO)
+			if (S_ISSOCK(kiocb->ki_filp->f_mapping->host->i_mode))
+				kiocb->ki_cancel = aio_pread_cancel;
+#endif
+		}
 		break;
 	case IOCB_CMD_PWRITE:
 		ret = -EBADF;
@@ -1446,8 +2290,13 @@
 		if (ret)
 			break;
 		ret = -EINVAL;
-		if (file->f_op->aio_write)
+		if (file->f_op->aio_write) {
 			kiocb->ki_retry = aio_rw_vect_retry;
+#if defined(CONFIG_NAIO)
+			if (S_ISSOCK(kiocb->ki_filp->f_mapping->host->i_mode))
+				kiocb->ki_cancel = aio_pwrite_cancel;
+#endif
+		}
 		break;
 	case IOCB_CMD_PREADV:
 		ret = -EBADF;
@@ -1460,8 +2309,13 @@
 		if (ret)
 			break;
 		ret = -EINVAL;
-		if (file->f_op->aio_read)
+		if (file->f_op->aio_read) {
 			kiocb->ki_retry = aio_rw_vect_retry;
+#if defined(CONFIG_NAIO)
+			if (S_ISSOCK(kiocb->ki_filp->f_mapping->host->i_mode))
+				kiocb->ki_cancel = aio_pread_cancel;
+#endif
+		}
 		break;
 	case IOCB_CMD_PWRITEV:
 		ret = -EBADF;
@@ -1474,8 +2328,13 @@
 		if (ret)
 			break;
 		ret = -EINVAL;
-		if (file->f_op->aio_write)
+		if (file->f_op->aio_write) {
 			kiocb->ki_retry = aio_rw_vect_retry;
+#if defined(CONFIG_NAIO)
+			if (S_ISSOCK(kiocb->ki_filp->f_mapping->host->i_mode))
+				kiocb->ki_cancel = aio_pwrite_cancel;
+#endif
+		}
 		break;
 	case IOCB_CMD_FDSYNC:
 		ret = -EINVAL;
@@ -1487,6 +2346,75 @@
 		if (file->f_op->aio_fsync)
 			kiocb->ki_retry = aio_fsync;
 		break;
+#if defined(CONFIG_NAIO)
+	case IOCB_CMD_SENDFILE:
+	{
+		struct file *in_file, *out_file;
+		struct inode *in_inode, *out_inode;
+		size_t count;
+
+		in_file = kiocb->ki_filp;
+
+		if (!(in_file->f_mode & FMODE_READ))
+			break;
+
+		ret = -EINVAL;
+		if (!(in_inode = in_file->f_path.dentry->d_inode))
+			break;
+		if (!in_file->f_op)
+			break;
+
+		count = kiocb->ki_nbytes;
+		ret = rw_verify_area(READ, in_file, &kiocb->ki_pos, count);
+		if (ret!=count) {
+			ret = -EFAULT;
+			break;
+		}
+
+		if ((ret = security_file_permission (in_file, MAY_READ)))
+			break;
+
+		ret = -EBADF;
+		if (!(out_file = fget( (unsigned int) kiocb->ki_buf)))
+			break;
+
+		if (!(out_file->f_mode & FMODE_WRITE))
+			goto end_3;
+
+		ret = -EINVAL;      /* FIXME: ejlim */
+		if (!out_file->f_op)
+			goto end_3; 
+
+		if (!((in_file->f_op->splice_read && out_file->f_op->sendpage) ||
+			(in_file->f_op->sendpage && out_file->f_op->splice_read)))
+			goto end_3;
+
+		out_inode = out_file->f_path.dentry->d_inode;
+		ret = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
+		if (ret!=count) {
+			ret = -EFAULT;
+			goto end_3;
+		}
+
+		if ((ret= security_file_permission (out_file, MAY_WRITE)))
+			goto end_3;
+
+		kiocb->private = (void *)out_file;
+
+		kiocb->ki_retry = aio_psendfile;
+		kiocb->ki_cancel = aio_psendfile_cancel;
+		break;
+
+end_3:
+		fput(out_file);
+	}
+		break;
+	case IOCB_CMD_ACCEPT:
+		ret = -EINVAL;
+		kiocb->ki_retry = aio_paccept;
+		kiocb->ki_cancel = aio_paccept_cancel;
+		break;
+#endif	/* #if defined(CONFIG_NAIO) */
 	default:
 		dprintk("EINVAL: io_submit: no operation provided\n");
 		ret = -EINVAL;
@@ -1537,6 +2465,22 @@
 	}
 
 	/* prevent overflows */
+#if defined(CONFIG_NAIO)
+	if (unlikely((iocb->aio_buf != (unsigned long)iocb->aio_buf) ||
+			(iocb->aio_nbytes != (size_t)iocb->aio_nbytes))) {
+		dprintk("EINVAL: io_submit: overflow check\n");
+		return -EINVAL;
+	}
+	if (iocb->aio_lio_opcode != IOCB_CMD_ACCEPT) {
+		if ((ssize_t)iocb->aio_nbytes < 0) {
+			dprintk("EINVAL: io_submit: overflow check, aio_nbytes < 0\n");
+			return -EINVAL;
+		}
+	} else if ((int *)(unsigned long)iocb->aio_nbytes < 0) {
+		dprintk("EINVAL: io_submit: overflow check, pointer < 0\n");
+		return -EINVAL;
+	}
+#else
 	if (unlikely(
 	    (iocb->aio_buf != (unsigned long)iocb->aio_buf) ||
 	    (iocb->aio_nbytes != (size_t)iocb->aio_nbytes) ||
@@ -1545,6 +2489,7 @@
 		pr_debug("EINVAL: io_submit: overflow check\n");
 		return -EINVAL;
 	}
+#endif
 
 	file = fget(iocb->aio_fildes);
 	if (unlikely(!file))
@@ -1658,6 +2603,11 @@
 		}
 
 		ret = io_submit_one(ctx, user_iocb, &tmp);
+#if defined(CONFIG_NAIO_DEBUG)
+		if (ret < 0) {
+			dprintk("FAIL : %ld\n", ret);
+		}
+#endif
 		if (ret)
 			break;
 	}
diff -urN linux-2.6.24/fs/file_table.c linux-2.6.24-in-090827/fs/file_table.c
--- linux-2.6.24/fs/file_table.c	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/fs/file_table.c	2009-08-27 15:52:17.000000000 +0900
@@ -23,6 +23,8 @@
 
 #include <asm/atomic.h>
 
+#include <linux/iocp.h>
+
 /* sysctl tunables... */
 struct files_stat_struct files_stat = {
 	.max_files = NR_FILE
@@ -236,6 +238,14 @@
 	file_kill(file);
 	file->f_path.dentry = NULL;
 	file->f_path.mnt = NULL;
+	if (file->ioc_ctx != NULL) {
+		if (file->ioc_ctx->iocp_ptr != NULL) {
+			atomic_dec(&file->ioc_ctx->iocp_ptr->files);
+		}
+		kfree(file->ioc_ctx);
+		file->ioc_ctx = NULL;
+		printk("[%s] ioc_ctx set NULL\n", __FUNCTION__);
+	}
 	file_free(file);
 	dput(dentry);
 	mntput(mnt);
diff -urN linux-2.6.24/fs/iocp.c linux-2.6.24-in-090827/fs/iocp.c
--- linux-2.6.24/fs/iocp.c	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.24-in-090827/fs/iocp.c	2009-08-27 15:12:30.000000000 +0900
@@ -0,0 +1,989 @@
+/*
+ * Linux IOCP (Input Output Completion Port) implementation
+ * Written by EunJi Lim <ejlim@etri.re.kr>
+ *
+ * Copyright 2008 ETRI. All Rights Researved.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/time.h>
+#include <linux/iocp.h>
+#include <linux/syscalls.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <asm/uaccess.h>
+#include <linux/file.h>
+
+
+#define DEBUG 0
+
+#if defined(CONFIG_IOCP_DEBUG)
+#undef DEBUG
+#define DEBUG 1
+#endif
+
+#if DEBUG > 0
+#define dprintk(...)				\
+	do {							\
+		printk("DEBUG[%s:%d] ", __FUNCTION__, __LINE__);   \
+		printk(__VA_ARGS__);                               \
+	} while(0)
+#else
+#define dprintk(x...)   do { ; } while (0)
+#endif
+
+static int init_compl_queue(struct completion_queue *queue);
+static struct cp_event *del_packet_queue_head(struct completion_queue_head *cqh);
+static struct task_struct *del_thread_list (struct list_head *list_ptr);
+
+
+
+static struct kmem_cache	*compl_packet_cachep;
+static struct kmem_cache	*ioc_ctx_cachep;
+
+/* iocp_setup
+ * Creates the slab caches used by the linux iocp routines
+ */
+static int __init iocp_setup(void)
+{
+	compl_packet_cachep = KMEM_CACHE(completion_packet, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
+	ioc_ctx_cachep = KMEM_CACHE(io_completion_ctx, SLAB_HWCACHE_ALIGN|SLAB_PANIC);
+
+	return 0;
+}
+
+/* setup completion queue */
+static int cp_setup_compl_queue_head(struct kiocp *iocp, unsigned nr_threads)
+{
+	struct completion_queue_head *cqh;
+	int i;
+
+	cqh = kmalloc(sizeof(struct completion_queue_head), GFP_KERNEL);
+	if (!cqh)
+		return -ENOMEM;
+	
+	atomic_set(&cqh->active_threads, 0);
+	cqh->max_threads = nr_threads;
+	atomic_set(&cqh->nr_packets, 0);
+	atomic_set(&cqh->add_index, -1);
+	atomic_set(&cqh->del_index, -1);
+	for (i = 0 ; i < NR_QUEUE; i++) {
+		init_compl_queue(&cqh->queue[i]);
+	}
+
+	rwlock_init(&cqh->add_rwlock);
+	spin_lock_init(&cqh->active_lock);
+	iocp->compl_queue_head = cqh;
+
+	dprintk("iocp: allocated compl_queue %p, max_threads %d\n", cqh, cqh->max_threads);
+
+	return 0;
+}
+
+static int init_compl_queue(struct completion_queue *queue) 
+{
+	rwlock_init(&queue->rwlock);
+	INIT_LIST_HEAD(&queue->list);
+
+	return 0;
+}
+
+/* setup thread list */
+static int cp_setup_tl(struct kiocp *iocp)
+{
+	struct thread_list_head *tlh;
+
+	tlh = kmalloc(sizeof(struct thread_list_head), GFP_KERNEL);
+	if (!tlh)
+		return -ENOMEM;
+	
+	atomic_set(&tlh->nr_threads, 0);
+	spin_lock_init(&tlh->lock);
+	INIT_LIST_HEAD(&tlh->list);
+
+	iocp->tl_head = tlh;
+	dprintk("iocp: allocated tl_head %p\n", tlh);
+
+	return 0;
+}
+
+
+static struct kiocp *iocp_alloc(unsigned nr_threads)
+{
+	struct mm_struct *mm;
+	struct kiocp *iocp;
+
+	/* FIX ME, check nr_threads */
+
+
+
+
+	iocp = kmalloc(sizeof(struct kiocp), GFP_KERNEL);
+	if (!iocp)
+		return ERR_PTR(-ENOMEM);
+
+	dprintk("\n");
+	
+	mm = iocp->mm = current->mm;
+	atomic_inc(&mm->mm_count);
+		
+	
+
+	iocp->user_id = (u64)(unsigned long)iocp;
+	iocp->dead = 0;
+
+	dprintk("\n");
+	atomic_set(&iocp->users, 1);
+	atomic_set(&iocp->files, 0);
+	spin_lock_init(&iocp->iocp_lock);
+
+	dprintk("\n");
+	if (cp_setup_compl_queue_head(iocp, nr_threads) < 0)
+		goto out_freeiocp;
+	if (cp_setup_tl(iocp) < 0)
+		goto out_freeiocp;
+
+	dprintk("\n");
+
+	/* now link into global list.  kludge.  FIXME */
+	write_lock(&mm->iocp_list_lock);
+	iocp->next = mm->iocp_list;
+	mm->iocp_list = iocp;
+	write_unlock(&mm->iocp_list_lock);
+
+
+	dprintk("iocp: allocated iocp %p[%ld]\n", iocp, iocp->user_id);
+
+	return iocp;
+	
+
+out_freeiocp:
+	//mmdrop(mm);
+	kfree(iocp);
+	iocp = ERR_PTR(-ENOMEM);
+
+	dprintk("iocp: error allocating kiocp %p\n", iocp);
+	return iocp;
+}
+
+static void cp_free_compl_queue(struct kiocp *iocp)
+{
+	struct completion_queue_head *cqh = iocp->compl_queue_head;
+	struct cp_event *evt;
+	
+	while ((evt = del_packet_queue_head(cqh)) != NULL) {
+		kfree(evt);
+	}
+
+	kfree(cqh);
+	dprintk("compl_queue free succ\n");
+}
+
+static void cp_free_tl(struct kiocp *iocp)
+{
+	struct thread_list_head *tlh = iocp->tl_head;
+	struct task_struct *tsk;
+	struct list_head *head;
+
+	spin_lock_irq(&tlh->lock);	
+	head = &tlh->list;
+	while ((&tlh->list)->next != head) {
+		tsk = del_thread_list((&tlh->list)->next);
+		if (tsk) {
+			// FIXME
+			// wakeup thread 
+			// and let it to get out of the get() function
+		}
+	}
+	spin_unlock_irq(&tlh->lock);	
+
+	kfree(tlh);
+	dprintk("thread list free succ\n");
+}
+
+void fastcall __put_iocp(struct kiocp *iocp)
+{
+	dprintk("\n");
+	mmdrop(iocp->mm);
+	iocp->mm = NULL;
+
+	cp_free_compl_queue(iocp);
+	cp_free_tl(iocp);
+
+	kfree(iocp);
+	dprintk("iocp free succ\n");
+}
+
+asmlinkage long sys_cp_create_port(unsigned nr_threads, io_port_t __user *uport)
+{
+	struct kiocp *iocp = NULL;
+	unsigned long port;
+	unsigned num_threads = nr_threads;
+	long ret;
+
+	dprintk("\n");
+
+	ret = get_user(port, uport);
+	if (unlikely(ret))
+		goto out;
+
+	dprintk("\n");
+	ret = -EINVAL;
+	if (unlikely(nr_threads == 0)) {
+		num_threads = num_online_cpus();
+	}
+
+	dprintk("num_threads=%d\n", num_threads);
+	iocp = iocp_alloc(num_threads);
+	dprintk("\n");
+	ret = PTR_ERR(iocp);
+	if (!IS_ERR(iocp)) {
+		ret = put_user(iocp->user_id, uport);
+		if (!ret)
+			return 0;
+
+//		get_iocp(iocp);
+//		iocp_destroy(iocp);
+	}
+
+	dprintk("iocp->users = %d\n", atomic_read(&iocp->users));
+
+out:
+	return ret;
+}
+
+/* Lookup an iocp id. iocp_list is lockless for reads.
+ */
+struct kiocp *lookup_iocp(unsigned long port_id)
+{
+	struct kiocp *iocp;
+	struct mm_struct *mm;
+
+	dprintk("\n");
+	mm = current->mm;
+	read_lock(&mm->iocp_list_lock);
+	for (iocp = mm->iocp_list; iocp; iocp = iocp->next)
+		if (likely(iocp->user_id == port_id && !iocp->dead)) {
+			get_iocp(iocp);
+			break;
+		}
+	read_unlock(&mm->iocp_list_lock);
+
+	dprintk("iocp = %p\n", iocp);
+	return iocp;
+}
+
+
+asmlinkage long sys_cp_destroy_port(io_port_t port_id)
+{
+	struct kiocp *iocp;
+	struct mm_struct *mm = current->mm;
+	struct kiocp **tmp;
+	int was_dead;
+
+	iocp = lookup_iocp(port_id);
+	if (unlikely(iocp == NULL)) {
+		dprintk("iocp == NULL\n");
+		return -EINVAL;
+	}
+
+	if (atomic_read(&iocp->files)) {
+		printk("added file exist\n");
+		return -EINVAL;
+	}
+
+	write_lock(&mm->iocp_list_lock);
+	was_dead = iocp->dead;
+	iocp->dead = 1;
+	for (tmp = &mm->iocp_list; *tmp && *tmp != iocp;
+		tmp = &(*tmp)->next);
+	if (*tmp)
+		*tmp = iocp->next;
+	write_unlock(&mm->iocp_list_lock);
+
+	dprintk("iocp to be released (%p)\n", iocp);
+	dprintk("iocp->users = %d\n", atomic_read(&iocp->users));
+
+	if (likely(!was_dead))
+		put_iocp(iocp);
+
+	put_iocp(iocp);		/* once for the lookup */
+
+	dprintk("iocp destroy succ\n");
+
+	return 0;
+}
+
+asmlinkage long sys_cp_add_file_to_port(io_port_t port_id, unsigned int fd, void __user *compl_key)
+{
+	struct kiocp *iocp;
+	struct file *file;
+	int ret = 0;
+	int fput_needed;
+	struct io_completion_ctx *ioc_ctx;
+
+	iocp = lookup_iocp(port_id);
+	if (unlikely(!iocp)) {
+		pr_debug("EINVAL: cp_add_file_to_port: invalid iocp id\n");
+		return -EINVAL;
+	}
+	dprintk("lookup_iocp succ, iocp = %p\n", iocp);
+
+	file = fget_light(fd, &fput_needed);
+	if (!file) {
+		printk("fget returned NULL\n");
+		ret = -EBADF;
+		goto out;
+	}
+	dprintk("fget_light succ, file = %p\n", file);
+
+	ioc_ctx = kmem_cache_alloc(ioc_ctx_cachep, GFP_KERNEL);
+	if (unlikely(!ioc_ctx)) {
+		ret = -ENOMEM;
+		goto out_fput;
+	}
+	dprintk("ioc_ctx alloc succ, ioc_ctx = %p\n", ioc_ctx);
+
+	ioc_ctx->iocp_ptr = iocp;
+	ioc_ctx->completion_key = compl_key;
+	file->ioc_ctx = ioc_ctx;
+
+	atomic_inc(&iocp->files);
+
+	dprintk("all succ, file->ioc_ctx->iocp_ptr = %p\n", file->ioc_ctx->iocp_ptr);
+out_fput:
+	fput_light(file, fput_needed);
+out:
+	put_iocp(iocp);	
+
+	return ret;
+}
+
+asmlinkage long sys_cp_del_file_from_port(io_port_t port_id, unsigned int fd)
+{
+	struct kiocp *iocp;
+	struct file *file;
+	int ret = 0;
+	int fput_needed;
+	struct io_completion_ctx *ioc_ctx;
+
+	iocp = lookup_iocp(port_id);
+	if (unlikely(!iocp)) {
+		pr_debug("EINVAL: cp_add_file_to_port: invalid iocp id\n");
+		return -EINVAL;
+	}
+	dprintk("lookup_iocp succ, iocp = %p\n", iocp);
+
+	file = fget_light(fd, &fput_needed);
+	if (!file) {
+		dprintk("fget returned NULL\n");
+		ret = -EBADF;
+		goto out;
+	}
+	dprintk("fget_light succ, file = %p\n", file);
+
+	if (file->ioc_ctx == NULL) {
+		dprintk("ioc_ctx == NULL\n");
+		goto out_fput;
+	}
+
+	ioc_ctx = file->ioc_ctx;
+	kfree(ioc_ctx);
+	file->ioc_ctx = NULL;
+
+	atomic_dec(&iocp->files);
+
+	dprintk("all succ\n");
+	
+out_fput:
+	fput_light(file, fput_needed);
+out:
+	put_iocp(iocp);	
+
+	return ret;
+}
+
+static struct completion_packet *init_packet(struct cp_event *event)
+{
+	struct completion_packet *pkt;
+
+	pkt = kmem_cache_alloc(compl_packet_cachep, GFP_KERNEL);
+	if (unlikely(!pkt)) {
+		return NULL;
+	}
+	INIT_LIST_HEAD(&pkt->list);
+	pkt->event = event;
+
+	return pkt;
+}
+
+static void add_packet(struct completion_queue *queue, struct completion_packet *pkt)
+{
+	dprintk("\n");
+	list_add_tail(&pkt->list, &queue->list);
+	dprintk("\n");
+}
+
+static int add_packet_queue(struct completion_queue *queue, struct cp_event *event)
+{
+	struct completion_packet *pkt;
+	int ret = 0;
+	
+	// alloc packet
+	pkt = init_packet(event);
+	if (pkt == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	dprintk("pkt init succ, pkt=%p, pkt->event=%p\n", pkt, pkt->event);
+
+	write_lock(&queue->rwlock);
+	// add packet to completion queue
+		//list_add_tail(&pkt->list, &cqh->list);
+	dprintk("befor add_packet()\n");
+	add_packet(queue, pkt);
+	write_unlock(&queue->rwlock);
+
+out:
+	return ret;
+}
+
+int add_packet_queue_head(struct completion_queue_head *cqh, struct cp_event *event)
+{
+	int add_index, q_index, ret, nr = 0;
+	struct completion_queue *queue;
+
+	write_lock(&cqh->add_rwlock);	
+	add_index = atomic_inc_return(&cqh->add_index);
+	q_index = add_index % NR_QUEUE;
+	dprintk("add_index=%d, q_index=%d\n", add_index, q_index);
+	queue = &(cqh->queue[q_index]);
+	ret = add_packet_queue(queue, event);
+	if (!ret) {
+		nr = atomic_inc_return(&cqh->nr_packets);
+	}
+	else {
+		atomic_dec(&cqh->add_index);
+	}
+	write_unlock(&cqh->add_rwlock);	
+
+	if (!ret)
+		dprintk("nr_packets=%d\n", nr);
+
+	return ret;
+}
+
+static struct completion_packet *del_packet(struct completion_queue *queue)
+{
+	struct completion_packet *pkt;
+
+	if (unlikely(queue->list.next == &queue->list))
+		return NULL;
+	pkt = list_entry(queue->list.next, struct completion_packet, list);
+	list_del(&pkt->list);
+
+	return pkt;
+}
+
+static struct cp_event *del_packet_queue(struct completion_queue *queue)
+{
+	struct completion_packet *pkt;
+	struct cp_event *event = NULL;
+	
+	write_lock(&queue->rwlock);
+	pkt = del_packet(queue);
+	write_unlock(&queue->rwlock);
+	if (unlikely(pkt == NULL))
+		return NULL;
+	event = pkt->event;
+	kmem_cache_free(compl_packet_cachep, pkt);
+
+	return event;
+}
+
+struct cp_event *del_packet_queue_head(struct completion_queue_head *cqh)
+{
+	int yes;
+	int	del_index, q_index;
+	struct completion_queue *queue;
+	struct cp_event *event = NULL;
+	int temp;
+
+	yes = atomic_add_unless(&cqh->nr_packets, -1, 0);
+	/* yes == 1, if nr_packet is not 0,
+	 * yes == 0, if nr_packet is 0
+	 */
+	dprintk("yes = %d\n", yes);
+	if (yes) {
+		del_index = atomic_inc_return(&cqh->del_index);
+		q_index = del_index % NR_QUEUE;
+		dprintk("del_index = %d, q_index = %d\n", del_index, q_index);
+
+		queue = &(cqh->queue[q_index]);
+		event = del_packet_queue(queue);
+		/* check event */
+		if (event == NULL) {
+			dprintk("event is NULL\n");
+			temp = atomic_dec_return(&cqh->del_index);
+			dprintk("del_index = %d\n", temp);
+			temp = atomic_inc_return(&cqh->nr_packets);
+			dprintk("nr_packets = %d\n", temp);
+		}
+	}
+
+	return event;
+}
+
+/*
+ * return 1 if queue is empty
+ * return 0 if queue is not empty
+ */
+static int is_empty_compl_queue(struct completion_queue_head *cqh)
+{
+	if(atomic_read(&cqh->nr_packets) == 0)
+		return 1;
+	else
+		return 0;
+}
+
+// modified 08.11.13
+int get_nr_packets(struct kiocp *iocp)
+{
+	struct completion_queue_head *cqh = iocp->compl_queue_head;
+
+	return atomic_read(&cqh->nr_packets);
+}
+
+void fastcall inc_active_threads(struct completion_queue_head *cqh)
+{
+	int nr;
+
+	spin_lock_irq(&cqh->active_lock);
+	nr = atomic_inc_return(&cqh->active_threads);
+	spin_unlock_irq(&cqh->active_lock);
+	dprintk("%d active_threads : %d\n", current->pid, nr);
+}
+
+static void	lock_inc_active_threads(struct completion_queue_head *cqh)
+{
+	int nr;
+	assert_spin_locked(&cqh->active_lock);
+
+	nr = atomic_inc_return(&cqh->active_threads);
+	dprintk("%d active_threads : %d\n", current->pid, nr);
+}
+
+void fastcall dec_active_threads(struct completion_queue_head *cqh)
+{
+	int nr;
+
+	spin_lock_irq(&cqh->active_lock);
+	nr = atomic_dec_return(&cqh->active_threads);
+	spin_unlock_irq(&cqh->active_lock);
+	dprintk("%d active_threads : %d\n", current->pid, nr);
+}
+
+static void	lock_dec_active_threads(struct completion_queue_head *cqh)
+{
+	int nr;
+	assert_spin_locked(&cqh->active_lock);
+
+	nr = atomic_dec_return(&cqh->active_threads);
+	dprintk("%d active_threads : %d\n", current->pid, nr);
+}
+
+static int check_queue(struct completion_queue_head *cqh)
+{
+	int ret = 0;
+
+	spin_lock_irq(&cqh->active_lock);
+	if (atomic_read(&cqh->active_threads) < cqh->max_threads) {
+		ret = 1;
+	}
+	spin_unlock_irq(&cqh->active_lock);
+	
+	return ret;
+}
+
+
+/* return 1 : if thread can get a packet from the completion queue
+ * return 0 : if thread can not get a packet from the queue
+ */
+static int lock_check_queue(struct completion_queue_head *cqh)
+{
+	assert_spin_locked(&cqh->active_lock);
+
+	if (atomic_read(&cqh->active_threads) < cqh->max_threads) 
+		return 1;
+
+	return 0;
+}
+
+
+
+
+
+
+
+static void add_thread_list(struct thread_list_head *tl_head, struct thread_list *tl)
+{
+	list_add(&tl->list, &tl_head->list);
+}
+
+static int add_wait_thread (struct thread_list_head *tl_head, struct task_struct *tsk)
+{
+	struct thread_list *tl;
+	int nr;
+	
+	tl = kmalloc(sizeof(struct thread_list), GFP_KERNEL);
+	if (!tl)
+		return -ENOMEM;
+
+	INIT_LIST_HEAD(&tl->list);
+	tl->tsk = tsk;
+
+	/* Insert a new entry after the head.
+	 * to be LIFO 
+	 */
+	spin_lock_irq(&tl_head->lock);
+	//list_add(&tl->list, &tl_head->list);
+	add_thread_list(tl_head, tl);
+	atomic_inc(&tl_head->nr_threads);
+	nr = atomic_read(&tl_head->nr_threads);
+	spin_unlock_irq(&tl_head->lock);
+	dprintk("num of waiting thread : %d\n", nr);
+
+	return 0;
+}
+
+/*
+ * delete the first thread from the list
+ * LIFO
+ */
+static struct task_struct *del_thread_list (struct list_head *list_ptr)
+{
+	struct thread_list *tl;
+	struct task_struct *tsk;
+
+	if (list_ptr == NULL)
+		return NULL;
+
+	tl = list_entry(list_ptr, struct thread_list, list);
+	list_del(list_ptr);
+	tsk = tl->tsk;
+	kfree(tl);
+
+	return tsk;
+}
+
+static struct task_struct *del_wait_thread (struct thread_list_head *tl_head)
+{
+	struct task_struct *tsk;
+	int nr;
+
+	spin_lock_irq(&tl_head->lock);
+	if (atomic_read(&tl_head->nr_threads) == 0) {
+		spin_unlock_irq(&tl_head->lock);
+		dprintk("no waiting thread !\n");
+		return NULL;
+	}
+	tsk = del_thread_list((&tl_head->list)->next);
+	if (tsk != NULL) {
+		atomic_dec(&tl_head->nr_threads);
+		dprintk("thread_id=%d\n", tsk->pid);
+	}
+	nr = atomic_read(&tl_head->nr_threads);
+	spin_unlock_irq(&tl_head->lock);
+	dprintk("num of waiting thread : %d\n", nr);
+
+	return tsk;
+}
+
+static void search_del_wait_thread(struct thread_list_head *tl_head, struct task_struct *tsk)
+{
+	struct list_head *pos, *n;
+	struct thread_list *tl;
+
+	spin_lock_irq(&tl_head->lock);
+	list_for_each_safe(pos, n, &tl_head->list) {
+		tl = hlist_entry(pos, struct thread_list, list);
+		if (tl->tsk == tsk) {
+			list_del(pos);
+			kfree(tl);
+			atomic_dec(&tl_head->nr_threads);
+			dprintk("num of waiting thread : %d\n", atomic_read(&tl_head->nr_threads));
+			dprintk("delete succ (%p) thread_id=%d\n", tsk, tsk->pid);
+		}
+	}
+	spin_unlock_irq(&tl_head->lock);
+}
+
+static int remove_io_compl(struct kiocp *iocp, struct cp_event __user *event, struct timespec __user *timeout)
+{
+	int ret = 0;
+	struct completion_queue_head *cqh = iocp->compl_queue_head;
+	struct cp_event *ent;
+	unsigned long jiffies = 0;
+	struct timespec ts;
+	int retried = 0;
+	int was_dead;
+
+	dprintk("\n");
+	if (timeout) {
+		if (unlikely(copy_from_user(&ts, timeout, sizeof(ts)))) {
+			printk("iocp: invalid timeout, returing EFAULT.\n");
+			return -EFAULT;
+		}
+		jiffies = timespec_to_jiffies(&ts);
+	}
+
+retry:
+	was_dead = iocp->dead;
+
+//	write_lock(&cqh->lock);
+	if (current->iocp != NULL) {
+		dprintk("current->iocp != NULL\n");
+		current->iocp = NULL;
+		/* decrease active_threads */
+		dec_active_threads(cqh);
+		put_iocp(iocp);
+	}
+	if (was_dead) {
+		printk("iocp dead, returing -EINVAL\n");
+		return -EINVAL;
+	}
+
+	spin_lock_irq(&cqh->active_lock);
+	if (lock_check_queue(cqh)) {
+		/* active threads < max threads */
+		dprintk("lock_check_queue returned SUCC\n");
+		ent = del_packet_queue_head(cqh);
+		if (ent != NULL) {
+			dprintk("ent = %p\n", ent);
+			/* increase active_threads */
+			lock_inc_active_threads(cqh);
+			/* assign completion queue ptr to thread task_struct */
+			current->iocp = iocp;
+			get_iocp(iocp);
+
+			spin_unlock_irq(&cqh->active_lock);
+
+			/* copy io result to io_event structure */
+			if (unlikely(copy_to_user(event, ent, sizeof(struct cp_event)))) {
+				printk("iocp: lost an event due to EFAULT.\n");
+				return -EFAULT;
+			}
+			kfree(ent);
+
+			return 1;
+		}
+	/*	if (unlikely(ent == NULL)) {
+			printk("EINVAL: invalid completion packet\n");
+			spin_unlock_irq(&cqh->active_lock);
+			return -EINVAL;
+		} */
+	}
+	/* add thread to thread list
+	 * and sleep
+	 */
+	dprintk("lock_check_queue returned FAIL\n");
+
+	if (jiffies || !timeout) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		ret = add_wait_thread(iocp->tl_head, current);	
+		spin_unlock_irq(&cqh->active_lock);
+		if (!timeout) {
+			dprintk("calling schedule()\n");
+			schedule();
+		}
+		else {
+			dprintk("calling schedule_timeout(%lu)\n", jiffies);
+			jiffies = schedule_timeout(jiffies);
+		}
+		set_current_state(TASK_RUNNING);
+		if (signal_pending(current)) {
+			dprintk("signal_pending returning EINTR\n");
+			dprintk("delete current thread(%p) from waiting list\n", current);
+			search_del_wait_thread(iocp->tl_head, current);
+			ret = -EINTR;
+			goto out;
+		}
+
+		retried = 1;
+		goto retry;
+	}
+	else {
+		spin_unlock_irq(&cqh->active_lock);
+		ret = 0;
+	}
+
+out:
+	return ret;
+}
+
+asmlinkage long sys_cp_get_completion_status(io_port_t port_id, struct cp_event __user *event, struct timespec __user *timeout)
+{
+	int ret = 0;
+	struct kiocp *iocp;
+
+	iocp = lookup_iocp(port_id);
+	if (unlikely(iocp == NULL)) {
+		dprintk("iocp == NULL\n");
+		return -EINVAL;
+	}
+	dprintk("iocp = %p\n", iocp);
+	
+	if (iocp->compl_queue_head == NULL) {
+		ret = -EFAULT;
+		printk("compl_queue_head == NULL, returning -EFAULT\n");
+		goto out;
+	}
+
+	ret = remove_io_compl(iocp, event, timeout);
+
+
+out:
+	put_iocp(iocp);	
+
+	return ret;
+}
+
+void fastcall try_activate_thread(struct kiocp *iocp)
+{
+	struct completion_queue_head *cqh = iocp->compl_queue_head;
+	struct thread_list_head *tl_head = iocp->tl_head;
+	struct task_struct *tsk;
+
+	if (check_queue(cqh)) {
+		/* wakeup a waiting thread */
+		tsk = del_wait_thread(tl_head);	
+		if (tsk != NULL)
+			wake_up_process(tsk);	
+	}
+}
+
+
+static int add_compl_packet_activate(struct kiocp *iocp, struct cp_event *event)
+{
+	int ret;
+	struct completion_queue_head *cqh;
+	
+	if (!iocp->compl_queue_head)
+		return -EFAULT;
+
+	cqh = iocp->compl_queue_head;
+
+	dprintk("cqh : %p\n", cqh);
+	ret = add_packet_queue_head(cqh, event);
+	if (ret)	/* fail */
+		return ret;
+	
+	try_activate_thread(iocp);
+
+	return ret;
+}
+
+asmlinkage long sys_cp_post_completion_status(io_port_t port_id, struct cp_event __user *event)
+{
+	int ret = 0;
+	struct kiocp *iocp;
+	struct cp_event *kern_event;
+
+	iocp = lookup_iocp(port_id);
+	if (unlikely(iocp == NULL)) {
+		dprintk("iocp == NULL\n");
+		return -EINVAL;
+	}
+	if (!iocp->compl_queue_head) {
+		ret = -EFAULT;
+		goto out;
+	}
+
+	// alloc event, copy from user
+	kern_event = kmalloc(sizeof(struct cp_event), GFP_KERNEL);	
+	if (kern_event == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	dprintk("event alloc succ, kern_event = %p\n", kern_event);
+	if (unlikely(copy_from_user(kern_event, event, sizeof(struct cp_event)))) {
+		ret = -EFAULT;
+		goto out_freeevent;
+	}
+	dprintk("kern_event : result=%ld, compl_key=%p, iocb=%p\n", 
+		(long)(s64)kern_event->result, (void *)(unsigned long)kern_event->completion_key, 
+		(void *)(unsigned long)kern_event->user);
+
+	ret = add_compl_packet_activate(iocp, kern_event);
+	if (!ret)
+		goto out;
+
+out_freeevent:
+	kfree(kern_event);
+out:
+	put_iocp(iocp);	
+	return ret;
+}
+
+long post_io_completion(struct file *filp, long result, struct iocb __user *iocb)
+{
+	int ret = 0;
+	struct cp_event *event;
+	struct kiocp *iocp;
+
+	if (filp->ioc_ctx == NULL) {
+		printk("file->ioc_ctx == NULL\n");
+		ret = -EFAULT;
+		goto out;
+	}
+
+	// alloc event
+	event = kmalloc(sizeof(struct cp_event), GFP_KERNEL);	
+	if (event == NULL) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	event->result = (s64)result;
+	event->completion_key = (u64)(unsigned long)filp->ioc_ctx->completion_key;
+	event->user = (u64)(unsigned long)iocb;
+
+	iocp = filp->ioc_ctx->iocp_ptr;
+	dprintk("iocp : %p\n", iocp);
+
+	ret = add_compl_packet_activate(iocp, event);
+	if (ret) {		// if fail, free event
+		kfree(event);
+	}
+
+out:
+	return ret;
+}
+
+asmlinkage long sys_aio_post_io_completion(unsigned int fd, long result, struct iocb __user *iocb)
+{
+	struct file *file;
+	int fput_needed;
+	int ret = 0;
+
+	file = fget_light(fd, &fput_needed);
+	if (!file) {
+		printk("fget returned NULL\n");
+		ret = -EBADF;
+		goto out;
+	}
+	dprintk("fget_light succ, file = %p\n", file);
+
+	ret = post_io_completion(file, result, iocb);
+	if (ret)
+		goto out_fput;
+
+out_fput:
+	fput_light(file, fput_needed);
+out:
+	return ret;
+}
+
+
+__initcall(iocp_setup);
diff -urN linux-2.6.24/fs/open.c linux-2.6.24-in-090827/fs/open.c
--- linux-2.6.24/fs/open.c	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/fs/open.c	2008-08-08 17:06:32.000000000 +0900
@@ -757,6 +757,7 @@
 	f->f_pos = 0;
 	f->f_op = fops_get(inode->i_fop);
 	file_move(f, &inode->i_sb->s_files);
+	f->ioc_ctx = NULL;
 
 	error = security_dentry_open(f);
 	if (error)
diff -urN linux-2.6.24/include/asm-x86/unistd_32.h linux-2.6.24-in-090827/include/asm-x86/unistd_32.h
--- linux-2.6.24/include/asm-x86/unistd_32.h	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/include/asm-x86/unistd_32.h	2008-09-19 15:53:22.000000000 +0900
@@ -330,10 +330,17 @@
 #define __NR_timerfd		322
 #define __NR_eventfd		323
 #define __NR_fallocate		324
+#define __NR_cp_create_port		325
+#define __NR_cp_add_file_to_port		326
+#define __NR_cp_del_file_from_port		327
+#define __NR_cp_destroy_port			328
+#define __NR_cp_get_completion_status	329
+#define __NR_cp_post_completion_status	330
+#define __NR_aio_post_io_completion		331
 
 #ifdef __KERNEL__
 
-#define NR_syscalls 325
+#define NR_syscalls 332
 
 #define __ARCH_WANT_IPC_PARSE_VERSION
 #define __ARCH_WANT_OLD_READDIR
diff -urN linux-2.6.24/include/linux/aio_abi.h linux-2.6.24-in-090827/include/linux/aio_abi.h
--- linux-2.6.24/include/linux/aio_abi.h	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/include/linux/aio_abi.h	2008-11-14 11:24:03.000000000 +0900
@@ -43,6 +43,10 @@
 	IOCB_CMD_NOOP = 6,
 	IOCB_CMD_PREADV = 7,
 	IOCB_CMD_PWRITEV = 8,
+#if defined(CONFIG_NAIO)
+	IOCB_CMD_SENDFILE = 9,
+	IOCB_CMD_ACCEPT = 10,
+#endif
 };
 
 /*
diff -urN linux-2.6.24/include/linux/fs.h linux-2.6.24-in-090827/include/linux/fs.h
--- linux-2.6.24/include/linux/fs.h	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/include/linux/fs.h	2008-08-08 15:52:21.000000000 +0900
@@ -808,6 +808,7 @@
 	spinlock_t		f_ep_lock;
 #endif /* #ifdef CONFIG_EPOLL */
 	struct address_space	*f_mapping;
+	struct io_completion_ctx *ioc_ctx;
 };
 extern spinlock_t files_lock;
 #define file_list_lock() spin_lock(&files_lock);
diff -urN linux-2.6.24/include/linux/iocp.h linux-2.6.24-in-090827/include/linux/iocp.h
--- linux-2.6.24/include/linux/iocp.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.24-in-090827/include/linux/iocp.h	2008-11-14 13:42:55.000000000 +0900
@@ -0,0 +1,94 @@
+#ifndef _LINUX_IOCP_H
+#define _LINUX_IOCP_H
+
+#include <linux/list.h>
+#include <linux/iocp_abi.h>
+
+#define NR_QUEUE 4
+
+struct kiocp {
+	unsigned long	user_id;
+	atomic_t		users;
+	atomic_t		files;
+	struct mm_struct	*mm;
+	spinlock_t		iocp_lock;
+	struct completion_queue_head	*compl_queue_head;
+	struct thread_list_head	*tl_head;
+	struct kiocp	*next;
+	int		dead;
+};
+
+struct completion_queue {
+	rwlock_t		rwlock;
+	struct list_head	list;
+};
+
+struct completion_queue_head {
+	atomic_t		active_threads;
+	unsigned		max_threads;
+	atomic_t		nr_packets;
+	atomic_t		add_index;
+	atomic_t		del_index;
+	struct completion_queue queue[NR_QUEUE];
+	rwlock_t		add_rwlock;
+	spinlock_t		active_lock;
+//	rwlock_t		lock;
+//	struct list_head		list;
+};
+
+struct completion_packet {
+	struct list_head	list;
+	struct cp_event *event;
+/*	long	result;
+	void __user 	*completion_key;
+	void __user 	*user;		// iocb
+*/
+};
+
+struct thread_list_head {
+	atomic_t	nr_threads;
+	spinlock_t	lock;
+	struct list_head	list;
+};
+
+struct thread_list {
+	struct list_head	list;
+	struct task_struct	*tsk;
+};
+
+struct io_completion_ctx {
+	struct kiocp *iocp_ptr;
+	void __user		*completion_key;
+};
+
+
+/*
+struct cp_event {
+	long result;
+	void __user		*completion_key;
+	void __user		*user;
+};
+*/
+
+
+#define get_iocp(kiocp) do {                      \
+	BUG_ON(atomic_read(&(kiocp)->users) <= 0);         \
+	atomic_inc(&(kiocp)->users);                   \
+} while (0)
+#define put_iocp(kiocp) do {                      \
+	BUG_ON(atomic_read(&(kiocp)->users) <= 0);         \
+	if (unlikely(atomic_dec_and_test(&(kiocp)->users)))        \
+		__put_iocp(kiocp);                    \
+} while (0)
+
+
+extern void FASTCALL(inc_active_threads(struct completion_queue_head *cqh));
+extern void FASTCALL(dec_active_threads(struct completion_queue_head *cqh));
+extern void FASTCALL(try_activate_thread(struct kiocp *iocp));
+extern void FASTCALL(__put_iocp(struct kiocp *iocp));
+struct iocb;
+struct file;
+extern long FASTCALL(post_io_completion(struct file *filp, long result, struct iocb __user *iocb));
+
+
+#endif	/* _LINUX_IOCP_H */
diff -urN linux-2.6.24/include/linux/iocp_abi.h linux-2.6.24-in-090827/include/linux/iocp_abi.h
--- linux-2.6.24/include/linux/iocp_abi.h	1970-01-01 09:00:00.000000000 +0900
+++ linux-2.6.24-in-090827/include/linux/iocp_abi.h	2008-08-22 10:21:54.000000000 +0900
@@ -0,0 +1,30 @@
+/* include/linux/iocp_abi.h
+ *
+ * Copyright 2008 ETRI.
+ *
+ * Written by EunJi Lim <ejlim@etri.re.kr>
+ *
+ */
+#ifndef _LINUX_IOCP_ABI_H
+#define _LINUX_IOCP_ABI_H
+
+#include <asm/byteorder.h>
+
+typedef unsigned long	io_port_t;
+
+struct cp_event {
+	__s64	result;
+	__u64	completion_key;
+	__u64	user;			// iocb
+};
+
+#if defined(__LITTLE_ENDIAN)
+#define PADDED(x,y)	x, y
+#elif defined(__BIG_ENDIAN)
+#define PADDED(x,y)	y, x
+#else
+#error edit for your odd byteorder.
+#endif
+
+#endif /* _LINUX_IOCP_ABI_H */
+
diff -urN linux-2.6.24/include/linux/mm_types.h linux-2.6.24-in-090827/include/linux/mm_types.h
--- linux-2.6.24/include/linux/mm_types.h	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/include/linux/mm_types.h	2008-08-08 10:50:36.000000000 +0900
@@ -219,6 +219,8 @@
 	/* aio bits */
 	rwlock_t		ioctx_list_lock;
 	struct kioctx		*ioctx_list;
+	rwlock_t		iocp_list_lock;
+	struct kiocp		*iocp_list;
 };
 
 #endif /* _LINUX_MM_TYPES_H */
diff -urN linux-2.6.24/include/linux/net.h linux-2.6.24-in-090827/include/linux/net.h
--- linux-2.6.24/include/linux/net.h	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/include/linux/net.h	2008-11-14 11:24:03.000000000 +0900
@@ -144,6 +144,10 @@
 				      struct socket *sock2);
 	int		(*accept)    (struct socket *sock,
 				      struct socket *newsock, int flags);
+#if defined(CONFIG_NAIO)
+	int		(*aio_accept) (struct kiocb *iocb, struct socket *sock,
+				      struct socket *newsock, int flags);
+#endif
 	int		(*getname)   (struct socket *sock,
 				      struct sockaddr *addr,
 				      int *sockaddr_len, int peer);
@@ -192,6 +196,7 @@
 				      struct socket **res);
 extern int	     sock_create_lite(int family, int type, int proto,
 				      struct socket **res); 
+extern struct socket *sock_alloc(void);
 extern void	     sock_release(struct socket *sock);
 extern int   	     sock_sendmsg(struct socket *sock, struct msghdr *msg,
 				  size_t len);
diff -urN linux-2.6.24/include/linux/sched.h linux-2.6.24-in-090827/include/linux/sched.h
--- linux-2.6.24/include/linux/sched.h	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/include/linux/sched.h	2008-08-28 14:57:27.000000000 +0900
@@ -1178,6 +1178,7 @@
 	int make_it_fail;
 #endif
 	struct prop_local_single dirties;
+	struct kiocp *iocp;
 };
 
 /*
diff -urN linux-2.6.24/include/linux/syscalls.h linux-2.6.24-in-090827/include/linux/syscalls.h
--- linux-2.6.24/include/linux/syscalls.h	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/include/linux/syscalls.h	2008-09-19 15:54:19.000000000 +0900
@@ -65,6 +65,7 @@
 #include <asm/signal.h>
 #include <linux/quota.h>
 #include <linux/key.h>
+#include <linux/iocp_abi.h>
 
 asmlinkage long sys_time(time_t __user *tloc);
 asmlinkage long sys_stime(time_t __user *tptr);
@@ -611,6 +612,13 @@
 			    const struct itimerspec __user *utmr);
 asmlinkage long sys_eventfd(unsigned int count);
 asmlinkage long sys_fallocate(int fd, int mode, loff_t offset, loff_t len);
+asmlinkage long sys_cp_create_port(unsigned nr_threads, io_port_t __user *uport);
+asmlinkage long sys_cp_add_file_to_port(io_port_t port_id, unsigned int fd, void __user *compl_key);
+asmlinkage long sys_cp_del_file_from_port(io_port_t port_id, unsigned int fd);
+asmlinkage long sys_cp_destroy_port(io_port_t port_id);
+asmlinkage long sys_cp_get_completion_status(io_port_t port_id, struct cp_event __user *event, struct timespec __user *timeout);
+asmlinkage long sys_cp_post_completion_status(io_port_t port_id, struct cp_event __user *event);
+asmlinkage long sys_aio_post_io_completion(unsigned int fd, long result, struct iocb __user *iocb);
 
 int kernel_execve(const char *filename, char *const argv[], char *const envp[]);
 
diff -urN linux-2.6.24/include/net/inet_connection_sock.h linux-2.6.24-in-090827/include/net/inet_connection_sock.h
--- linux-2.6.24/include/net/inet_connection_sock.h	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/include/net/inet_connection_sock.h	2008-11-14 11:24:03.000000000 +0900
@@ -236,6 +236,8 @@
 }
 
 extern struct sock *inet_csk_accept(struct sock *sk, int flags, int *err);
+extern struct sock *inet_csk_aio_accept(struct kiocb *iocb, struct sock *sk, 
+							int flags, int *p_err);
 
 extern struct request_sock *inet_csk_search_req(const struct sock *sk,
 						struct request_sock ***prevp,
diff -urN linux-2.6.24/include/net/sock.h linux-2.6.24-in-090827/include/net/sock.h
--- linux-2.6.24/include/net/sock.h	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/include/net/sock.h	2008-11-14 11:24:04.000000000 +0900
@@ -521,7 +521,10 @@
 	int			(*disconnect)(struct sock *sk, int flags);
 
 	struct sock *		(*accept) (struct sock *sk, int flags, int *err);
-
+#if defined(CONFIG_NAIO)
+	struct sock *		(*aio_accept) (struct kiocb *iocb, struct sock*sk,
+					int flags, int *p_err);
+#endif
 	int			(*ioctl)(struct sock *sk, int cmd,
 					 unsigned long arg);
 	int			(*init)(struct sock *sk);
diff -urN linux-2.6.24/kernel/fork.c linux-2.6.24-in-090827/kernel/fork.c
--- linux-2.6.24/kernel/fork.c	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/kernel/fork.c	2008-08-28 15:00:14.000000000 +0900
@@ -202,6 +202,7 @@
 	tsk->btrace_seq = 0;
 #endif
 	tsk->splice_pipe = NULL;
+	tsk->iocp = NULL;
 	return tsk;
 }
 
@@ -354,6 +355,8 @@
 	spin_lock_init(&mm->page_table_lock);
 	rwlock_init(&mm->ioctx_list_lock);
 	mm->ioctx_list = NULL;
+	rwlock_init(&mm->iocp_list_lock);
+	mm->iocp_list = NULL;
 	mm->free_area_cache = TASK_UNMAPPED_BASE;
 	mm->cached_hole_size = ~0UL;
 
diff -urN linux-2.6.24/kernel/sched.c linux-2.6.24-in-090827/kernel/sched.c
--- linux-2.6.24/kernel/sched.c	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/kernel/sched.c	2008-11-11 01:51:38.000000000 +0900
@@ -63,6 +63,7 @@
 #include <linux/reciprocal_div.h>
 #include <linux/unistd.h>
 #include <linux/pagemap.h>
+#include <linux/iocp.h>
 
 #include <asm/tlb.h>
 #include <asm/irq_regs.h>
@@ -3623,6 +3624,16 @@
 	struct rq *rq;
 	int cpu;
 
+	/* for iocp , written by ejlim */
+	if (unlikely(current->iocp != NULL)) {
+		dec_active_threads(current->iocp->compl_queue_head);
+		try_activate_thread(current->iocp);
+		if (current->state == TASK_DEAD) {
+			put_iocp(current->iocp);
+			current->iocp = NULL;
+		}
+	}
+	/********************************************/
 need_resched:
 	preempt_disable();
 	cpu = smp_processor_id();
@@ -3679,6 +3690,11 @@
 	preempt_enable_no_resched();
 	if (unlikely(test_thread_flag(TIF_NEED_RESCHED)))
 		goto need_resched;
+
+	/* for iocp , written by ejlim */
+	if (unlikely(current->iocp != NULL))
+		inc_active_threads(current->iocp->compl_queue_head);
+	/********************************************/
 }
 EXPORT_SYMBOL(schedule);
 
diff -urN linux-2.6.24/net/Kconfig linux-2.6.24-in-090827/net/Kconfig
--- linux-2.6.24/net/Kconfig	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/net/Kconfig	2009-08-27 15:30:53.000000000 +0900
@@ -40,6 +40,26 @@
 source "net/xfrm/Kconfig"
 source "net/iucv/Kconfig"
 
+config NAIO
+	bool 'Network Asynchronous I/O'
+	default y
+	---help---
+		Network Asyncrhonous I/O for TCP/IP socket
+   
+config NAIO_DEBUG
+	bool 'Network Asynchronous I/O debugging'
+	depends on NAIO
+	---help---
+		You can say Y here if you want to get additional messages useful in
+		debugging the Network Asynchronous I/O code.
+
+config IOCP_DEBUG
+	bool 'Input Output Completion Port debugging'
+	default n
+	---help---
+		You can say Y here if you want to get additional messages useful in
+		debugging the IOCP code.
+
 config INET
 	bool "TCP/IP networking"
 	---help---
diff -urN linux-2.6.24/net/ipv4/af_inet.c linux-2.6.24-in-090827/net/ipv4/af_inet.c
--- linux-2.6.24/net/ipv4/af_inet.c	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/net/ipv4/af_inet.c	2008-11-14 11:24:04.000000000 +0900
@@ -652,6 +652,37 @@
 	return err;
 }
 
+#if defined(CONFIG_NAIO)
+int inet_aio_accept(struct kiocb *iocb, struct socket *sock, 
+			struct socket *newsock, int flags)
+{
+	struct sock *sk1 = sock->sk;
+	int err = -EINVAL;
+	struct sock *sk2 = sk1->sk_prot->aio_accept(iocb, sk1, flags, &err);
+
+	if (!sk2)
+		goto do_err;
+
+	lock_sock(sk2);
+
+	BUG_TRAP((1 << sk2->sk_state) &
+		 (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_CLOSE));
+
+	sock_graft(sk2, newsock);
+
+	newsock->state = SS_CONNECTED;
+	err = 0;
+	release_sock(sk2);
+do_err:
+	return err;
+}
+
+static int sock_no_aio_accept(struct kiocb *iocb, struct socket *sock,
+				struct socket *newsock, int flags)
+{
+	return -EOPNOTSUPP;
+}
+#endif /* #if defined(CONFIG_NAIO) */
 
 /*
  *	This does both peername and sockname.
@@ -827,6 +858,9 @@
 	.connect	   = inet_stream_connect,
 	.socketpair	   = sock_no_socketpair,
 	.accept		   = inet_accept,
+#if defined(CONFIG_NAIO)
+	.aio_accept	   = inet_aio_accept,
+#endif
 	.getname	   = inet_getname,
 	.poll		   = tcp_poll,
 	.ioctl		   = inet_ioctl,
@@ -852,6 +886,9 @@
 	.connect	   = inet_dgram_connect,
 	.socketpair	   = sock_no_socketpair,
 	.accept		   = sock_no_accept,
+#if defined(CONFIG_NAIO)
+	.aio_accept	   = sock_no_aio_accept,
+#endif
 	.getname	   = inet_getname,
 	.poll		   = udp_poll,
 	.ioctl		   = inet_ioctl,
@@ -881,6 +918,9 @@
 	.connect	   = inet_dgram_connect,
 	.socketpair	   = sock_no_socketpair,
 	.accept		   = sock_no_accept,
+#if defined(CONFIG_NAIO)
+	.aio_accept	   = sock_no_aio_accept,
+#endif
 	.getname	   = inet_getname,
 	.poll		   = datagram_poll,
 	.ioctl		   = inet_ioctl,
diff -urN linux-2.6.24/net/ipv4/inet_connection_sock.c linux-2.6.24-in-090827/net/ipv4/inet_connection_sock.c
--- linux-2.6.24/net/ipv4/inet_connection_sock.c	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/net/ipv4/inet_connection_sock.c	2008-11-14 11:24:04.000000000 +0900
@@ -265,6 +265,43 @@
 
 EXPORT_SYMBOL(inet_csk_accept);
 
+#if defined(CONFIG_NAIO)
+struct sock *inet_csk_aio_accept(struct kiocb *iocb, struct sock *sk, 
+				int flags, int *p_err)
+{
+	struct inet_connection_sock *icsk = inet_csk(sk);
+	struct sock *newsk;
+	int error;
+
+	*p_err = 0;
+	lock_sock(sk);
+
+	/* We need to make sure that this socket is listening,
+	 * and that it has something pending.
+	 */
+	error = -EINVAL;
+	if (sk->sk_state != TCP_LISTEN)
+		goto out_err;
+
+	/* Find already established connection */
+	error = -EIOCBRETRY;
+	if (reqsk_queue_empty(&icsk->icsk_accept_queue)) {
+		add_wait_queue(sk->sk_sleep, &iocb->ki_wait);
+		goto out_err;
+	}
+
+	newsk = reqsk_queue_get_child(&icsk->icsk_accept_queue, sk);
+	BUG_TRAP(newsk->sk_state != TCP_SYN_RECV);
+out:
+	release_sock(sk);
+	return newsk;
+out_err:
+	newsk = NULL;
+	*p_err = error;
+	goto out;
+}
+#endif  /* #if defined(CONFIG_NAIO) */
+
 /*
  * Using different timers for retransmit, delayed acks and probes
  * We may wish use just one timer maintaining a list of expire jiffies
diff -urN linux-2.6.24/net/ipv4/tcp_ipv4.c linux-2.6.24-in-090827/net/ipv4/tcp_ipv4.c
--- linux-2.6.24/net/ipv4/tcp_ipv4.c	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/net/ipv4/tcp_ipv4.c	2008-11-14 11:24:04.000000000 +0900
@@ -2426,6 +2426,9 @@
 	.connect		= tcp_v4_connect,
 	.disconnect		= tcp_disconnect,
 	.accept			= inet_csk_accept,
+#if defined(CONFIG_NAIO)
+	.aio_accept		= inet_csk_aio_accept,
+#endif
 	.ioctl			= tcp_ioctl,
 	.init			= tcp_v4_init_sock,
 	.destroy		= tcp_v4_destroy_sock,
diff -urN linux-2.6.24/net/socket.c linux-2.6.24-in-090827/net/socket.c
--- linux-2.6.24/net/socket.c	2008-01-25 07:58:37.000000000 +0900
+++ linux-2.6.24-in-090827/net/socket.c	2008-11-14 11:24:04.000000000 +0900
@@ -472,7 +472,7 @@
  *	NULL is returned.
  */
 
-static struct socket *sock_alloc(void)
+struct socket *sock_alloc(void)
 {
 	struct inode *inode;
 	struct socket *sock;
@@ -492,6 +492,8 @@
 	return sock;
 }
 
+EXPORT_SYMBOL_GPL(sock_alloc);
+
 /*
  *	In theory you can't get an open on this inode, but /proc provides
  *	a back door. Remember to keep it shut otherwise you'll let the
