diff options
Diffstat (limited to 'fs/aio.c')
| -rw-r--r-- | fs/aio.c | 34 |
1 files changed, 28 insertions, 6 deletions
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/highmem.h> | 29 | #include <linux/highmem.h> |
| 30 | #include <linux/workqueue.h> | 30 | #include <linux/workqueue.h> |
| 31 | #include <linux/security.h> | 31 | #include <linux/security.h> |
| 32 | #include <linux/rcuref.h> | ||
| 32 | 33 | ||
| 33 | #include <asm/kmap_types.h> | 34 | #include <asm/kmap_types.h> |
| 34 | #include <asm/uaccess.h> | 35 | #include <asm/uaccess.h> |
| @@ -499,7 +500,7 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req) | |||
| 499 | /* Must be done under the lock to serialise against cancellation. | 500 | /* Must be done under the lock to serialise against cancellation. |
| 500 | * Call this aio_fput as it duplicates fput via the fput_work. | 501 | * Call this aio_fput as it duplicates fput via the fput_work. |
| 501 | */ | 502 | */ |
| 502 | if (unlikely(atomic_dec_and_test(&req->ki_filp->f_count))) { | 503 | if (unlikely(rcuref_dec_and_test(&req->ki_filp->f_count))) { |
| 503 | get_ioctx(ctx); | 504 | get_ioctx(ctx); |
| 504 | spin_lock(&fput_lock); | 505 | spin_lock(&fput_lock); |
| 505 | list_add(&req->ki_list, &fput_head); | 506 | list_add(&req->ki_list, &fput_head); |
| @@ -546,6 +547,24 @@ struct kioctx *lookup_ioctx(unsigned long ctx_id) | |||
| 546 | return ioctx; | 547 | return ioctx; |
| 547 | } | 548 | } |
| 548 | 549 | ||
| 550 | static int lock_kiocb_action(void *param) | ||
| 551 | { | ||
| 552 | schedule(); | ||
| 553 | return 0; | ||
| 554 | } | ||
| 555 | |||
| 556 | static inline void lock_kiocb(struct kiocb *iocb) | ||
| 557 | { | ||
| 558 | wait_on_bit_lock(&iocb->ki_flags, KIF_LOCKED, lock_kiocb_action, | ||
| 559 | TASK_UNINTERRUPTIBLE); | ||
| 560 | } | ||
| 561 | |||
| 562 | static inline void unlock_kiocb(struct kiocb *iocb) | ||
| 563 | { | ||
| 564 | kiocbClearLocked(iocb); | ||
| 565 | wake_up_bit(&iocb->ki_flags, KIF_LOCKED); | ||
| 566 | } | ||
| 567 | |||
| 549 | /* | 568 | /* |
| 550 | * use_mm | 569 | * use_mm |
| 551 | * Makes the calling kernel thread take on the specified | 570 | * Makes the calling kernel thread take on the specified |
| @@ -786,7 +805,9 @@ static int __aio_run_iocbs(struct kioctx *ctx) | |||
| 786 | * Hold an extra reference while retrying i/o. | 805 | * Hold an extra reference while retrying i/o. |
| 787 | */ | 806 | */ |
| 788 | iocb->ki_users++; /* grab extra reference */ | 807 | iocb->ki_users++; /* grab extra reference */ |
| 808 | lock_kiocb(iocb); | ||
| 789 | aio_run_iocb(iocb); | 809 | aio_run_iocb(iocb); |
| 810 | unlock_kiocb(iocb); | ||
| 790 | if (__aio_put_req(ctx, iocb)) /* drop extra ref */ | 811 | if (__aio_put_req(ctx, iocb)) /* drop extra ref */ |
| 791 | put_ioctx(ctx); | 812 | put_ioctx(ctx); |
| 792 | } | 813 | } |
| @@ -1527,10 +1548,9 @@ int fastcall io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, | |||
| 1527 | goto out_put_req; | 1548 | goto out_put_req; |
| 1528 | 1549 | ||
| 1529 | spin_lock_irq(&ctx->ctx_lock); | 1550 | spin_lock_irq(&ctx->ctx_lock); |
| 1530 | if (likely(list_empty(&ctx->run_list))) { | 1551 | aio_run_iocb(req); |
| 1531 | aio_run_iocb(req); | 1552 | unlock_kiocb(req); |
| 1532 | } else { | 1553 | if (!list_empty(&ctx->run_list)) { |
| 1533 | list_add_tail(&req->ki_run_list, &ctx->run_list); | ||
| 1534 | /* drain the run list */ | 1554 | /* drain the run list */ |
| 1535 | while (__aio_run_iocbs(ctx)) | 1555 | while (__aio_run_iocbs(ctx)) |
| 1536 | ; | 1556 | ; |
| @@ -1661,6 +1681,7 @@ asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, | |||
| 1661 | if (NULL != cancel) { | 1681 | if (NULL != cancel) { |
| 1662 | struct io_event tmp; | 1682 | struct io_event tmp; |
| 1663 | pr_debug("calling cancel\n"); | 1683 | pr_debug("calling cancel\n"); |
| 1684 | lock_kiocb(kiocb); | ||
| 1664 | memset(&tmp, 0, sizeof(tmp)); | 1685 | memset(&tmp, 0, sizeof(tmp)); |
| 1665 | tmp.obj = (u64)(unsigned long)kiocb->ki_obj.user; | 1686 | tmp.obj = (u64)(unsigned long)kiocb->ki_obj.user; |
| 1666 | tmp.data = kiocb->ki_user_data; | 1687 | tmp.data = kiocb->ki_user_data; |
| @@ -1672,8 +1693,9 @@ asmlinkage long sys_io_cancel(aio_context_t ctx_id, struct iocb __user *iocb, | |||
| 1672 | if (copy_to_user(result, &tmp, sizeof(tmp))) | 1693 | if (copy_to_user(result, &tmp, sizeof(tmp))) |
| 1673 | ret = -EFAULT; | 1694 | ret = -EFAULT; |
| 1674 | } | 1695 | } |
| 1696 | unlock_kiocb(kiocb); | ||
| 1675 | } else | 1697 | } else |
| 1676 | printk(KERN_DEBUG "iocb has no cancel operation\n"); | 1698 | ret = -EINVAL; |
| 1677 | 1699 | ||
| 1678 | put_ioctx(ctx); | 1700 | put_ioctx(ctx); |
| 1679 | 1701 | ||
