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 | ||