[AIO] kiocb locking to serialise retry and cancel Implement a per-kiocb lock to serialise retry operations and cancel. This is done using wait_on_bit_lock() on the KIF_LOCKED bit of kiocb->ki_flags. Also, make the cancellation path lock the kiocb and subsequently release all references to it if the cancel was successful. Signed-off-by: Benjamin LaHaise diff -purN --exclude=description 30_aio_write/fs/aio.c 40_lock_kiocb/fs/aio.c --- 30_aio_write/fs/aio.c 2005-06-20 13:33:31.000000000 -0400 +++ 40_lock_kiocb/fs/aio.c 2005-06-20 17:16:08.000000000 -0400 @@ -545,6 +545,24 @@ struct kioctx *lookup_ioctx(unsigned lon return ioctx; } +static int lock_kiocb_action(void *param) +{ + schedule(); + return 0; +} + +static inline void lock_kiocb(struct kiocb *iocb) +{ + wait_on_bit_lock(&iocb->ki_flags, KIF_LOCKED, lock_kiocb_action, + TASK_UNINTERRUPTIBLE); +} + +static inline void unlock_kiocb(struct kiocb *iocb) +{ + kiocbClearLocked(iocb); + wake_up_bit(&iocb->ki_flags, KIF_LOCKED); +} + /* * use_mm * Makes the calling kernel thread take on the specified @@ -773,7 +791,9 @@ static int __aio_run_iocbs(struct kioctx * Hold an extra reference while retrying i/o. */ iocb->ki_users++; /* grab extra reference */ + lock_kiocb(iocb); aio_run_iocb(iocb); + unlock_kiocb(iocb); if (__aio_put_req(ctx, iocb)) /* drop extra ref */ put_ioctx(ctx); } @@ -1523,6 +1543,7 @@ int fastcall io_submit_one(struct kioctx ; } spin_unlock_irq(&ctx->ctx_lock); + unlock_kiocb(req); aio_put_req(req); /* drop extra ref to req */ return 0; @@ -1648,6 +1669,7 @@ asmlinkage long sys_io_cancel(aio_contex if (NULL != cancel) { struct io_event tmp; pr_debug("calling cancel\n"); + lock_kiocb(kiocb); memset(&tmp, 0, sizeof(tmp)); tmp.obj = (u64)(unsigned long)kiocb->ki_obj.user; tmp.data = kiocb->ki_user_data; @@ -1659,6 +1681,13 @@ asmlinkage long sys_io_cancel(aio_contex if (copy_to_user(result, &tmp, sizeof(tmp))) ret = -EFAULT; } + unlock_kiocb(kiocb); + /* If the cancellation was successful, we must discard the + * reference held for completion of the iocb. + */ + if (!ret) + aio_put_req(kiocb); + aio_put_req(kiocb); } else printk(KERN_DEBUG "iocb has no cancel operation\n");