Commit 9018ccc4 authored by Christoph Hellwig's avatar Christoph Hellwig

aio: add a iocb refcount

This is needed to prevent races caused by the way the ->poll API works.
To avoid introducing overhead for other users of the iocbs we initialize
it to zero and only do refcount operations if it is non-zero in the
completion path.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Tested-by: default avatarAvi Kivity <avi@scylladb.com>
parent 7dda7128
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/export.h> #include <linux/export.h>
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/backing-dev.h> #include <linux/backing-dev.h>
#include <linux/refcount.h>
#include <linux/uio.h> #include <linux/uio.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
...@@ -178,6 +179,7 @@ struct aio_kiocb { ...@@ -178,6 +179,7 @@ struct aio_kiocb {
struct list_head ki_list; /* the aio core uses this struct list_head ki_list; /* the aio core uses this
* for cancellation */ * for cancellation */
refcount_t ki_refcnt;
/* /*
* If the aio_resfd field of the userspace iocb is not zero, * If the aio_resfd field of the userspace iocb is not zero,
...@@ -1015,6 +1017,7 @@ static inline struct aio_kiocb *aio_get_req(struct kioctx *ctx) ...@@ -1015,6 +1017,7 @@ static inline struct aio_kiocb *aio_get_req(struct kioctx *ctx)
percpu_ref_get(&ctx->reqs); percpu_ref_get(&ctx->reqs);
INIT_LIST_HEAD(&req->ki_list); INIT_LIST_HEAD(&req->ki_list);
refcount_set(&req->ki_refcnt, 0);
req->ki_ctx = ctx; req->ki_ctx = ctx;
return req; return req;
out_put: out_put:
...@@ -1049,6 +1052,15 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id) ...@@ -1049,6 +1052,15 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id)
return ret; return ret;
} }
static inline void iocb_put(struct aio_kiocb *iocb)
{
if (refcount_read(&iocb->ki_refcnt) == 0 ||
refcount_dec_and_test(&iocb->ki_refcnt)) {
percpu_ref_put(&iocb->ki_ctx->reqs);
kmem_cache_free(kiocb_cachep, iocb);
}
}
/* aio_complete /* aio_complete
* Called when the io request on the given iocb is complete. * Called when the io request on the given iocb is complete.
*/ */
...@@ -1118,8 +1130,6 @@ static void aio_complete(struct aio_kiocb *iocb, long res, long res2) ...@@ -1118,8 +1130,6 @@ static void aio_complete(struct aio_kiocb *iocb, long res, long res2)
eventfd_ctx_put(iocb->ki_eventfd); eventfd_ctx_put(iocb->ki_eventfd);
} }
kmem_cache_free(kiocb_cachep, iocb);
/* /*
* We have to order our ring_info tail store above and test * We have to order our ring_info tail store above and test
* of the wait list below outside the wait lock. This is * of the wait list below outside the wait lock. This is
...@@ -1130,8 +1140,7 @@ static void aio_complete(struct aio_kiocb *iocb, long res, long res2) ...@@ -1130,8 +1140,7 @@ static void aio_complete(struct aio_kiocb *iocb, long res, long res2)
if (waitqueue_active(&ctx->wait)) if (waitqueue_active(&ctx->wait))
wake_up(&ctx->wait); wake_up(&ctx->wait);
iocb_put(iocb);
percpu_ref_put(&ctx->reqs);
} }
/* aio_read_events_ring /* aio_read_events_ring
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment