diff options
Diffstat (limited to 'fs/aio.c')
-rw-r--r-- | fs/aio.c | 52 |
1 files changed, 41 insertions, 11 deletions
@@ -239,15 +239,23 @@ static void __put_ioctx(struct kioctx *ctx) | |||
239 | call_rcu(&ctx->rcu_head, ctx_rcu_free); | 239 | call_rcu(&ctx->rcu_head, ctx_rcu_free); |
240 | } | 240 | } |
241 | 241 | ||
242 | #define get_ioctx(kioctx) do { \ | 242 | static inline void get_ioctx(struct kioctx *kioctx) |
243 | BUG_ON(atomic_read(&(kioctx)->users) <= 0); \ | 243 | { |
244 | atomic_inc(&(kioctx)->users); \ | 244 | BUG_ON(atomic_read(&kioctx->users) <= 0); |
245 | } while (0) | 245 | atomic_inc(&kioctx->users); |
246 | #define put_ioctx(kioctx) do { \ | 246 | } |
247 | BUG_ON(atomic_read(&(kioctx)->users) <= 0); \ | 247 | |
248 | if (unlikely(atomic_dec_and_test(&(kioctx)->users))) \ | 248 | static inline int try_get_ioctx(struct kioctx *kioctx) |
249 | __put_ioctx(kioctx); \ | 249 | { |
250 | } while (0) | 250 | return atomic_inc_not_zero(&kioctx->users); |
251 | } | ||
252 | |||
253 | static inline void put_ioctx(struct kioctx *kioctx) | ||
254 | { | ||
255 | BUG_ON(atomic_read(&kioctx->users) <= 0); | ||
256 | if (unlikely(atomic_dec_and_test(&kioctx->users))) | ||
257 | __put_ioctx(kioctx); | ||
258 | } | ||
251 | 259 | ||
252 | /* ioctx_alloc | 260 | /* ioctx_alloc |
253 | * Allocates and initializes an ioctx. Returns an ERR_PTR if it failed. | 261 | * Allocates and initializes an ioctx. Returns an ERR_PTR if it failed. |
@@ -601,8 +609,13 @@ static struct kioctx *lookup_ioctx(unsigned long ctx_id) | |||
601 | rcu_read_lock(); | 609 | rcu_read_lock(); |
602 | 610 | ||
603 | hlist_for_each_entry_rcu(ctx, n, &mm->ioctx_list, list) { | 611 | hlist_for_each_entry_rcu(ctx, n, &mm->ioctx_list, list) { |
604 | if (ctx->user_id == ctx_id && !ctx->dead) { | 612 | /* |
605 | get_ioctx(ctx); | 613 | * RCU protects us against accessing freed memory but |
614 | * we have to be careful not to get a reference when the | ||
615 | * reference count already dropped to 0 (ctx->dead test | ||
616 | * is unreliable because of races). | ||
617 | */ | ||
618 | if (ctx->user_id == ctx_id && !ctx->dead && try_get_ioctx(ctx)){ | ||
606 | ret = ctx; | 619 | ret = ctx; |
607 | break; | 620 | break; |
608 | } | 621 | } |
@@ -1629,6 +1642,23 @@ static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
1629 | goto out_put_req; | 1642 | goto out_put_req; |
1630 | 1643 | ||
1631 | spin_lock_irq(&ctx->ctx_lock); | 1644 | spin_lock_irq(&ctx->ctx_lock); |
1645 | /* | ||
1646 | * We could have raced with io_destroy() and are currently holding a | ||
1647 | * reference to ctx which should be destroyed. We cannot submit IO | ||
1648 | * since ctx gets freed as soon as io_submit() puts its reference. The | ||
1649 | * check here is reliable: io_destroy() sets ctx->dead before waiting | ||
1650 | * for outstanding IO and the barrier between these two is realized by | ||
1651 | * unlock of mm->ioctx_lock and lock of ctx->ctx_lock. Analogously we | ||
1652 | * increment ctx->reqs_active before checking for ctx->dead and the | ||
1653 | * barrier is realized by unlock and lock of ctx->ctx_lock. Thus if we | ||
1654 | * don't see ctx->dead set here, io_destroy() waits for our IO to | ||
1655 | * finish. | ||
1656 | */ | ||
1657 | if (ctx->dead) { | ||
1658 | spin_unlock_irq(&ctx->ctx_lock); | ||
1659 | ret = -EINVAL; | ||
1660 | goto out_put_req; | ||
1661 | } | ||
1632 | aio_run_iocb(req); | 1662 | aio_run_iocb(req); |
1633 | if (!list_empty(&ctx->run_list)) { | 1663 | if (!list_empty(&ctx->run_list)) { |
1634 | /* drain the run list */ | 1664 | /* drain the run list */ |