diff -uprN -X dontdiff linux-2.6.8.1-liowait/fs/aio.c linux-2.6.8.1-cancelfd/fs/aio.c
--- linux-2.6.8.1-liowait/fs/aio.c	2004-11-05 18:09:42.000000000 +0100
+++ linux-2.6.8.1-cancelfd/fs/aio.c	2004-11-26 16:52:36.533992250 +0100
@@ -261,6 +261,28 @@ out_freectx:
 	return ctx;
 }
 
+static int __aio_cancel(struct kiocb *kiocb, struct io_event *result)
+{
+	int (*cancel)(struct kiocb *iocb, struct io_event *res);
+
+	if (kiocb == NULL)
+		return -EFAULT;
+
+	cancel = kiocb->ki_cancel;
+	if (NULL == cancel) {
+		printk(KERN_DEBUG "iocb has no cancel operation\n");
+		return -EFAULT;
+	}
+
+	kiocb->ki_users ++;
+
+	memset(result, 0, sizeof(*result));
+	result->obj = (u64)(unsigned long)kiocb->ki_obj.user;
+	result->data = kiocb->ki_user_data;
+
+	return cancel(kiocb, result);
+}
+
 /* aio_cancel_all
  *	Cancels all outstanding aio requests on an aio context.  Used 
  *	when the processes owning a context have all exited to encourage 
@@ -268,7 +290,6 @@ out_freectx:
  */
 static void aio_cancel_all(struct kioctx *ctx)
 {
-	int (*cancel)(struct kiocb *, struct io_event *);
 	struct io_event res;
 	spin_lock_irq(&ctx->ctx_lock);
 	ctx->dead = 1;
@@ -276,13 +297,9 @@ static void aio_cancel_all(struct kioctx
 		struct list_head *pos = ctx->active_reqs.next;
 		struct kiocb *iocb = list_kiocb(pos);
 		list_del_init(&iocb->ki_list);
-		cancel = iocb->ki_cancel;
-		if (cancel) {
-			iocb->ki_users++;
-			spin_unlock_irq(&ctx->ctx_lock);
-			cancel(iocb, &res);
-			spin_lock_irq(&ctx->ctx_lock);
-		}
+		spin_unlock_irq(&ctx->ctx_lock);
+		__aio_cancel(iocb, &res);
+		spin_lock_irq(&ctx->ctx_lock);
 	}
 	spin_unlock_irq(&ctx->ctx_lock);
 }
@@ -676,6 +693,48 @@ static void __aio_send_signal(pid_t 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);
+	tail = (tail + 1) % info->nr;
+
+	*ring_event = *event;
+
+	dprintk("aio_write_evt: %p[%lu]: %p %Lx %lx %lx\n",
+		ctx, tail, event->obj, event->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(ring_event, KM_IRQ0);
+	kunmap_atomic(ring, KM_IRQ1);
+
+	pr_debug("added to ring at [%lu]\n", tail);
+}
+
 static void wait_for_lio(struct kioctx *ctx, struct lio_event *lio)
 {
 	struct task_struct *tsk = current;
@@ -738,11 +797,8 @@ static inline void check_lio(struct kioc
 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
@@ -769,43 +825,16 @@ int fastcall aio_complete(struct kiocb *
 		return ret;
 	}
 
-	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.
-	 */
-	spin_lock_irqsave(&ctx->ctx_lock, flags);
-
-	ring = kmap_atomic(info->ring_pages[0], KM_IRQ1);
-
-	tail = info->tail;
-	event = aio_ring_event(info, tail, KM_IRQ0);
-	tail = (tail + 1) % info->nr;
+	/* 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;
-
-	dprintk("aio_complete: %p[%lu]: %p: %p %Lx %lx %lx\n",
-		ctx, tail, iocb, iocb->ki_obj.user, iocb->ki_user_data,
-		res, res2);
+	event.obj = (u64)(unsigned long)iocb->ki_obj.user;
+	event.data = iocb->ki_user_data;
+	event.res = res;
+	event.res2 = 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);
+	spin_lock_irqsave(&ctx->ctx_lock, flags);
 
-	pr_debug("added to ring %p at [%lu]\n", iocb, tail);
+	__aio_write_evt(ctx, &event);
 
 	if (iocb->ki_signo)
 		__aio_send_signal(iocb->ki_pid, iocb->ki_signo, iocb->ki_notify,
@@ -1462,6 +1491,66 @@ struct kiocb *lookup_kiocb(struct kioctx
 	return NULL;
 }
 
+static int aio_cancel_fd(aio_context_t ctx_id, int fildes)
+{
+	struct kioctx *ctx;
+	struct kiocb *kiocb;
+	int ret;
+	struct file *file;
+	struct list_head *pos;
+	int all_done;
+	int not_canceled;
+	struct io_event result_event;
+
+	/* cancel all I/O belonging to filedes */
+
+	file = fget(fildes);
+	if (unlikely(!file))
+		return -EBADF;
+
+	/* we must exit on EBADF before EINVAL */
+
+	ctx = lookup_ioctx(ctx_id);
+	if (unlikely(!ctx)) 
+		return -EINVAL;
+
+	/* get all operation for this file descriptor */
+
+	all_done = 1;
+	not_canceled = 0;
+	spin_lock_irq(&ctx->ctx_lock);
+
+	list_for_each(pos, &ctx->active_reqs) {
+
+		kiocb = list_kiocb(pos);
+
+		if (kiocb->ki_filp == file) {
+
+			all_done = 0;
+
+			spin_unlock_irq(&ctx->ctx_lock);
+			ret = __aio_cancel(kiocb, &result_event);
+			spin_lock_irq(&ctx->ctx_lock);
+			if (ret)
+				not_canceled++;
+			else
+				__aio_write_evt(kiocb->ki_ctx, &result_event);
+		}
+	}
+
+	spin_unlock_irq(&ctx->ctx_lock);
+
+	put_ioctx(ctx);
+
+	if (all_done)
+		return AIO_ALLDONE;
+
+	if (not_canceled)
+		return AIO_NOTCANCELED;
+
+	return AIO_CANCELED;
+}
+
 /* sys_io_cancel:
  *	Attempts to cancel an iocb previously passed to io_submit.  If
  *	the operation is successfully cancelled, the resulting event is
@@ -1475,9 +1564,9 @@ struct kiocb *lookup_kiocb(struct kioctx
 asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb,
 			      struct io_event __user *result)
 {
-	int (*cancel)(struct kiocb *iocb, struct io_event *res);
 	struct kioctx *ctx;
 	struct kiocb *kiocb;
+	struct io_event tmp;
 	u32 key;
 	int ret;
 
@@ -1485,36 +1574,39 @@ asmlinkage long sys_io_cancel(aio_contex
 	if (unlikely(ret))
 		return -EFAULT;
 
+	if ( (key == 0) &&  (result == NULL) ) {
+		/* cancel all IOCBs belonging to iocb->aio_fildes */
+
+		ret = aio_cancel_fd(ctx_id, iocb->aio_fildes);
+
+		return ret;
+	}
+
 	ctx = lookup_ioctx(ctx_id);
 	if (unlikely(!ctx))
 		return -EINVAL;
 
 	spin_lock_irq(&ctx->ctx_lock);
-	ret = -EAGAIN;
 	kiocb = lookup_kiocb(ctx, iocb, key);
-	if (kiocb && kiocb->ki_cancel) {
-		cancel = kiocb->ki_cancel;
-		kiocb->ki_users ++;
-	} else
-		cancel = NULL;
 	spin_unlock_irq(&ctx->ctx_lock);
+	if (kiocb == NULL) {
+		put_ioctx(ctx);
+		return -EINVAL;
+	}
 
-	if (NULL != cancel) {
-		struct io_event tmp;
-		pr_debug("calling cancel\n");
-		memset(&tmp, 0, sizeof(tmp));
-		tmp.obj = (u64)(unsigned long)kiocb->ki_obj.user;
-		tmp.data = kiocb->ki_user_data;
-		ret = cancel(kiocb, &tmp);
-		if (!ret) {
-			/* Cancellation succeeded -- copy the result
-			 * into the user's buffer.
-			 */
+	ret = __aio_cancel(kiocb, &tmp);
+	if (!ret) {
+		/* Cancellation succeeded -- copy the result
+		 * into the user's buffer.
+		 */
+		if (result == NULL) {
+			spin_lock_irq(&ctx->ctx_lock);
+			__aio_write_evt(kiocb->ki_ctx, &tmp);
+			spin_unlock_irq(&ctx->ctx_lock);
+		} else
 			if (copy_to_user(result, &tmp, sizeof(tmp)))
 				ret = -EFAULT;
-		}
-	} else
-		printk(KERN_DEBUG "iocb has no cancel operation\n");
+	}
 
 	put_ioctx(ctx);
 
diff -uprN -X dontdiff linux-2.6.8.1-liowait/include/linux/aio_abi.h linux-2.6.8.1-cancelfd/include/linux/aio_abi.h
--- linux-2.6.8.1-liowait/include/linux/aio_abi.h	2004-11-03 11:30:55.000000000 +0100
+++ linux-2.6.8.1-cancelfd/include/linux/aio_abi.h	2004-11-26 16:47:10.223449372 +0100
@@ -45,6 +45,12 @@ enum {
 	IOCB_CMD_CHECKPOINT = 8,
 };
 
+enum {
+	AIO_CANCELED = 0,
+	AIO_NOTCANCELED = 1,
+	AIO_ALLDONE = 2,
+};
+
 /* read() from /dev/aio returns these structures. */
 struct io_event {
 	__u64		data;		/* the data field from the iocb */

