Prep work for bio cancellation. At least initially, we don't want to implement a callback that has to chase down all the state (multiple bios/requests) associated with the iocb; a simple flag will suffice. Signed-off-by: Kent Overstreet <koverstreet@xxxxxxxxxx> --- drivers/usb/gadget/inode.c | 7 +---- fs/aio.c | 76 +++++++++++++++++++++------------------------- include/linux/aio.h | 5 +++ 3 files changed, 41 insertions(+), 47 deletions(-) diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c index fd1bf4a..e5e2210 100644 --- a/drivers/usb/gadget/inode.c +++ b/drivers/usb/gadget/inode.c @@ -528,19 +528,14 @@ static void ep_aio_cancel(struct kiocb *iocb) { struct kiocb_priv *priv = iocb->private; struct ep_data *epdata; - int value; local_irq_disable(); epdata = priv->epdata; // spin_lock(&epdata->dev->lock); if (likely(epdata && epdata->ep && priv->req)) - value = usb_ep_dequeue (epdata->ep, priv->req); - else - value = -EINVAL; + usb_ep_dequeue (epdata->ep, priv->req); // spin_unlock(&epdata->dev->lock); local_irq_enable(); - - return value; } static ssize_t ep_copy_to_user(struct kiocb_priv *priv) diff --git a/fs/aio.c b/fs/aio.c index 4b9bfb5..f5f27bd 100644 --- a/fs/aio.c +++ b/fs/aio.c @@ -242,48 +242,34 @@ static int aio_setup_ring(struct kioctx *ctx) void kiocb_set_cancel_fn(struct kiocb *req, kiocb_cancel_fn *cancel) { - struct kioctx *ctx = req->ki_ctx; - unsigned long flags; - - spin_lock_irqsave(&ctx->ctx_lock, flags); + kiocb_cancel_fn *p, *old = req->ki_cancel; - if (!req->ki_list.next) - list_add(&req->ki_list, &ctx->active_reqs); - - req->ki_cancel = cancel; + do { + if (old == KIOCB_CANCELLED) { + cancel(req); + return; + } - spin_unlock_irqrestore(&ctx->ctx_lock, flags); + p = old; + old = cmpxchg(&req->ki_cancel, old, cancel); + } while (old != p); } EXPORT_SYMBOL(kiocb_set_cancel_fn); -static int kiocb_cancel(struct kioctx *ctx, struct kiocb *kiocb) +static void kiocb_cancel(struct kioctx *ctx, struct kiocb *req) { - kiocb_cancel_fn *old, *cancel; - int ret = -EINVAL; - - /* - * Don't want to set kiocb->ki_cancel = KIOCB_CANCELLED unless it - * actually has a cancel function, hence the cmpxchg() - */ - - cancel = ACCESS_ONCE(kiocb->ki_cancel); - do { - if (!cancel || cancel == KIOCB_CANCELLED) - return ret; - - old = cancel; - cancel = cmpxchg(&kiocb->ki_cancel, old, KIOCB_CANCELLED); - } while (cancel != old); - - atomic_inc(&kiocb->ki_users); - spin_unlock_irq(&ctx->ctx_lock); + kiocb_cancel_fn *cancel; - ret = cancel(kiocb); + cancel = xchg(&req->ki_cancel, KIOCB_CANCELLED); + if (cancel && cancel != KIOCB_CANCELLED) { + atomic_inc(&req->ki_users); + spin_unlock_irq(&ctx->ctx_lock); - spin_lock_irq(&ctx->ctx_lock); - aio_put_req(kiocb); + cancel(req); - return ret; + spin_lock_irq(&ctx->ctx_lock); + aio_put_req(req); + } } static void free_ioctx_rcu(struct rcu_head *head) @@ -1126,6 +1112,10 @@ rw_common: req->ki_nbytes = ret; + spin_lock_irq(&req->ki_ctx->ctx_lock); + list_add(&req->ki_list, &req->ki_ctx->active_reqs); + spin_unlock_irq(&req->ki_ctx->ctx_lock); + /* XXX: move/kill - rw_verify_area()? */ /* This matches the pread()/pwrite() logic */ if (req->ki_pos < 0) { @@ -1141,6 +1131,10 @@ rw_common: if (!file->f_op->aio_fsync) return -EINVAL; + spin_lock_irq(&req->ki_ctx->ctx_lock); + list_add(&req->ki_list, &req->ki_ctx->active_reqs); + spin_unlock_irq(&req->ki_ctx->ctx_lock); + ret = file->f_op->aio_fsync(req, 1); break; @@ -1148,6 +1142,10 @@ rw_common: if (!file->f_op->aio_fsync) return -EINVAL; + spin_lock_irq(&req->ki_ctx->ctx_lock); + list_add(&req->ki_list, &req->ki_ctx->active_reqs); + spin_unlock_irq(&req->ki_ctx->ctx_lock); + ret = file->f_op->aio_fsync(req, 0); break; @@ -1363,14 +1361,8 @@ SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb, spin_lock_irq(&ctx->ctx_lock); kiocb = lookup_kiocb(ctx, iocb, key); - if (kiocb) - ret = kiocb_cancel(ctx, kiocb); - else - ret = -EINVAL; - - spin_unlock_irq(&ctx->ctx_lock); - - if (!ret) { + if (kiocb) { + kiocb_cancel(ctx, kiocb); /* * The result argument is no longer used - the io_event is * always delivered via the ring buffer. -EINPROGRESS indicates @@ -1379,6 +1371,8 @@ SYSCALL_DEFINE3(io_cancel, aio_context_t, ctx_id, struct iocb __user *, iocb, ret = -EINPROGRESS; } + spin_unlock_irq(&ctx->ctx_lock); + put_ioctx(ctx); return ret; diff --git a/include/linux/aio.h b/include/linux/aio.h index 7340f77..d9686f1 100644 --- a/include/linux/aio.h +++ b/include/linux/aio.h @@ -65,6 +65,11 @@ struct kiocb { struct eventfd_ctx *ki_eventfd; }; +static inline bool kiocb_cancelled(struct kiocb *kiocb) +{ + return kiocb->ki_cancel == KIOCB_CANCELLED; +} + static inline bool is_sync_kiocb(struct kiocb *kiocb) { return kiocb->ki_ctx == NULL; -- 1.7.12 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html