lkml.org 
[lkml]   [2010]   [Mar]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH 1/2] AIO: Fix reference counting in io_cancel and aio_cancel_all
Date
io_cancel() and aio_cancel_all() have inconsistent reference counting 
(ki_users field of struct kiocb) which leads to unkillable processes upon
io_cancel() or io_destroy() syscalls. This patch fixes the undesired behavior.

Regards, Sergey Temerkhanov, Cifronic ZAO
diff -r b290b47c0880 fs/aio.c
--- a/fs/aio.c Tue Mar 16 13:51:13 2010 +0300
+++ b/fs/aio.c Tue Mar 16 14:11:36 2010 +0300
@@ -63,6 +63,8 @@
static void aio_kick_handler(struct work_struct *);
static void aio_queue_work(struct kioctx *);

+static void aio_cancel_all(struct kioctx *ctx);
+
/* aio_setup
* Creates the slab caches used by the aio routines, panic on
* failure as this is done early during the boot sequence.
@@ -315,33 +317,6 @@
return ctx;
}

-/* aio_cancel_all
- * Cancels all outstanding aio requests on an aio context. Used
- * when the processes owning a context have all exited to encourage
- * the rapid destruction of the kioctx.
- */
-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;
- while (!list_empty(&ctx->active_reqs)) {
- struct list_head *pos = ctx->active_reqs.next;
- struct kiocb *iocb = list_kiocb(pos);
- list_del_init(&iocb->ki_list);
- cancel = iocb->ki_cancel;
- kiocbSetCancelled(iocb);
- 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);
-}
-
static void wait_for_all_aios(struct kioctx *ctx)
{
struct task_struct *tsk = current;
@@ -1038,6 +1013,36 @@
return ret;
}

+/* aio_cancel_all
+ * Cancels all outstanding aio requests on an aio context. Used
+ * when the processes owning a context have all exited to encourage
+ * the rapid destruction of the kioctx.
+ */
+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;
+ while (!list_empty(&ctx->active_reqs)) {
+ struct list_head *pos = ctx->active_reqs.next;
+ struct kiocb *iocb = list_kiocb(pos);
+ list_del_init(&iocb->ki_list);
+ cancel = iocb->ki_cancel;
+ kiocbSetCancelled(iocb);
+ if (cancel) {
+ iocb->ki_users++;
+ spin_unlock_irq(&ctx->ctx_lock);
+ cancel(iocb, &res);
+ spin_lock_irq(&ctx->ctx_lock);
+ dprintk("aio_cancel_all: iocb->ki_users: %d\n", iocb->ki_users);
+ __aio_put_req(ctx, iocb);
+ }
+ __aio_put_req(ctx, iocb);
+ }
+ spin_unlock_irq(&ctx->ctx_lock);
+}
+
/* aio_read_evt
* Pull an event off of the ioctx's event ring. Returns the number of
* events fetched (0 or 1 ;-)
@@ -1787,9 +1792,11 @@
if (copy_to_user(result, &tmp, sizeof(tmp)))
ret = -EFAULT;
}
+ aio_put_req(kiocb);
} else
ret = -EINVAL;

+ aio_put_req(kiocb);
put_ioctx(ctx);

return ret;
\
 
 \ /
  Last update: 2010-03-16 12:25    [W:0.076 / U:0.528 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site