|
|
@@ -1016,6 +1016,9 @@ static bool get_reqs_available(struct kioctx *ctx)
|
|
|
/* aio_get_req
|
|
|
* Allocate a slot for an aio request.
|
|
|
* Returns NULL if no requests are free.
|
|
|
+ *
|
|
|
+ * The refcount is initialized to 2 - one for the async op completion,
|
|
|
+ * one for the synchronous code that does this.
|
|
|
*/
|
|
|
static inline struct aio_kiocb *aio_get_req(struct kioctx *ctx)
|
|
|
{
|
|
|
@@ -1028,7 +1031,7 @@ static inline struct aio_kiocb *aio_get_req(struct kioctx *ctx)
|
|
|
percpu_ref_get(&ctx->reqs);
|
|
|
req->ki_ctx = ctx;
|
|
|
INIT_LIST_HEAD(&req->ki_list);
|
|
|
- refcount_set(&req->ki_refcnt, 0);
|
|
|
+ refcount_set(&req->ki_refcnt, 2);
|
|
|
req->ki_eventfd = NULL;
|
|
|
return req;
|
|
|
}
|
|
|
@@ -1061,15 +1064,18 @@ out:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static inline void iocb_destroy(struct aio_kiocb *iocb)
|
|
|
+{
|
|
|
+ if (iocb->ki_filp)
|
|
|
+ fput(iocb->ki_filp);
|
|
|
+ percpu_ref_put(&iocb->ki_ctx->reqs);
|
|
|
+ kmem_cache_free(kiocb_cachep, iocb);
|
|
|
+}
|
|
|
+
|
|
|
static inline void iocb_put(struct aio_kiocb *iocb)
|
|
|
{
|
|
|
- if (refcount_read(&iocb->ki_refcnt) == 0 ||
|
|
|
- refcount_dec_and_test(&iocb->ki_refcnt)) {
|
|
|
- if (iocb->ki_filp)
|
|
|
- fput(iocb->ki_filp);
|
|
|
- percpu_ref_put(&iocb->ki_ctx->reqs);
|
|
|
- kmem_cache_free(kiocb_cachep, iocb);
|
|
|
- }
|
|
|
+ if (refcount_dec_and_test(&iocb->ki_refcnt))
|
|
|
+ iocb_destroy(iocb);
|
|
|
}
|
|
|
|
|
|
static void aio_fill_event(struct io_event *ev, struct aio_kiocb *iocb,
|
|
|
@@ -1743,9 +1749,6 @@ static ssize_t aio_poll(struct aio_kiocb *aiocb, const struct iocb *iocb)
|
|
|
INIT_LIST_HEAD(&req->wait.entry);
|
|
|
init_waitqueue_func_entry(&req->wait, aio_poll_wake);
|
|
|
|
|
|
- /* one for removal from waitqueue, one for this function */
|
|
|
- refcount_set(&aiocb->ki_refcnt, 2);
|
|
|
-
|
|
|
mask = vfs_poll(req->file, &apt.pt) & req->events;
|
|
|
if (unlikely(!req->head)) {
|
|
|
/* we did not manage to set up a waitqueue, done */
|
|
|
@@ -1776,7 +1779,6 @@ out:
|
|
|
|
|
|
if (mask)
|
|
|
aio_poll_complete(aiocb, mask);
|
|
|
- iocb_put(aiocb);
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
@@ -1867,18 +1869,21 @@ static int __io_submit_one(struct kioctx *ctx, const struct iocb *iocb,
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
+ /* Done with the synchronous reference */
|
|
|
+ iocb_put(req);
|
|
|
+
|
|
|
/*
|
|
|
* If ret is 0, we'd either done aio_complete() ourselves or have
|
|
|
* arranged for that to be done asynchronously. Anything non-zero
|
|
|
* means that we need to destroy req ourselves.
|
|
|
*/
|
|
|
- if (ret)
|
|
|
- goto out_put_req;
|
|
|
- return 0;
|
|
|
+ if (!ret)
|
|
|
+ return 0;
|
|
|
+
|
|
|
out_put_req:
|
|
|
if (req->ki_eventfd)
|
|
|
eventfd_ctx_put(req->ki_eventfd);
|
|
|
- iocb_put(req);
|
|
|
+ iocb_destroy(req);
|
|
|
out_put_reqs_available:
|
|
|
put_reqs_available(ctx, 1);
|
|
|
return ret;
|