diff mbox

[v3,09/10] sheepdog: cancel aio requests if possible

Message ID 1374741125-31859-10-git-send-email-morita.kazutaka@lab.ntt.co.jp
State New
Headers show

Commit Message

MORITA Kazutaka July 25, 2013, 8:32 a.m. UTC
This patch tries to cancel aio requests in pending queue and failed
queue.  When the sheepdog driver cannot cancel the requests, it waits
for them to be completed.

Signed-off-by: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp>
---
 block/sheepdog.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 59 insertions(+), 11 deletions(-)

Comments

Liu Yuan July 25, 2013, 9:04 a.m. UTC | #1
On Thu, Jul 25, 2013 at 05:32:04PM +0900, MORITA Kazutaka wrote:
> This patch tries to cancel aio requests in pending queue and failed
> queue.  When the sheepdog driver cannot cancel the requests, it waits
> for them to be completed.
> 
> Signed-off-by: MORITA Kazutaka <morita.kazutaka@lab.ntt.co.jp>
> ---
>  block/sheepdog.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++---------
>  1 file changed, 59 insertions(+), 11 deletions(-)
> 
> diff --git a/block/sheepdog.c b/block/sheepdog.c
> index 9f3fa89..7bf882a 100644
> --- a/block/sheepdog.c
> +++ b/block/sheepdog.c
> @@ -294,7 +294,8 @@ struct SheepdogAIOCB {
>      Coroutine *coroutine;
>      void (*aio_done_func)(SheepdogAIOCB *);
>  
> -    bool canceled;
> +    bool cancelable;
> +    bool *finished;
>      int nr_pending;
>  };
>  
> @@ -411,6 +412,7 @@ static inline void free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req)
>  {
>      SheepdogAIOCB *acb = aio_req->aiocb;
>  
> +    acb->cancelable = false;
>      QLIST_REMOVE(aio_req, aio_siblings);
>      g_free(aio_req);
>  
> @@ -419,23 +421,68 @@ static inline void free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req)
>  
>  static void coroutine_fn sd_finish_aiocb(SheepdogAIOCB *acb)
>  {
> -    if (!acb->canceled) {
> -        qemu_coroutine_enter(acb->coroutine, NULL);
> +    qemu_coroutine_enter(acb->coroutine, NULL);
> +    if (acb->finished) {
> +        *acb->finished = true;
>      }
>      qemu_aio_release(acb);
>  }
>  
> +/*
> + * Check whether the specified acb can be canceled
> + *
> + * We can cancel aio when any request belonging to the acb is:
> + *  - Not processed by the sheepdog server.
> + *  - Not linked to the inflight queue.
> + */
> +static bool sd_acb_cancelable(const SheepdogAIOCB *acb)
> +{
> +    BDRVSheepdogState *s = acb->common.bs->opaque;
> +    AIOReq *aioreq;
> +
> +    if (!acb->cancelable) {
> +        return false;
> +    }
> +
> +    QLIST_FOREACH(aioreq, &s->inflight_aio_head, aio_siblings) {
> +        if (aioreq->aiocb == acb) {
> +            return false;
> +        }
> +    }
> +
> +    return false;

return true; ?

> +}

Thanks
Yuan
MORITA Kazutaka July 25, 2013, 12:54 p.m. UTC | #2
At Thu, 25 Jul 2013 17:04:53 +0800,
Liu Yuan wrote:
> 
> >  
> > +/*
> > + * Check whether the specified acb can be canceled
> > + *
> > + * We can cancel aio when any request belonging to the acb is:
> > + *  - Not processed by the sheepdog server.
> > + *  - Not linked to the inflight queue.
> > + */
> > +static bool sd_acb_cancelable(const SheepdogAIOCB *acb)
> > +{
> > +    BDRVSheepdogState *s = acb->common.bs->opaque;
> > +    AIOReq *aioreq;
> > +
> > +    if (!acb->cancelable) {
> > +        return false;
> > +    }
> > +
> > +    QLIST_FOREACH(aioreq, &s->inflight_aio_head, aio_siblings) {
> > +        if (aioreq->aiocb == acb) {
> > +            return false;
> > +        }
> > +    }
> > +
> > +    return false;
> 
> return true; ?

Oops, thanks for the catch!

Thanks,

Kazutaka
diff mbox

Patch

diff --git a/block/sheepdog.c b/block/sheepdog.c
index 9f3fa89..7bf882a 100644
--- a/block/sheepdog.c
+++ b/block/sheepdog.c
@@ -294,7 +294,8 @@  struct SheepdogAIOCB {
     Coroutine *coroutine;
     void (*aio_done_func)(SheepdogAIOCB *);
 
-    bool canceled;
+    bool cancelable;
+    bool *finished;
     int nr_pending;
 };
 
@@ -411,6 +412,7 @@  static inline void free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req)
 {
     SheepdogAIOCB *acb = aio_req->aiocb;
 
+    acb->cancelable = false;
     QLIST_REMOVE(aio_req, aio_siblings);
     g_free(aio_req);
 
@@ -419,23 +421,68 @@  static inline void free_aio_req(BDRVSheepdogState *s, AIOReq *aio_req)
 
 static void coroutine_fn sd_finish_aiocb(SheepdogAIOCB *acb)
 {
-    if (!acb->canceled) {
-        qemu_coroutine_enter(acb->coroutine, NULL);
+    qemu_coroutine_enter(acb->coroutine, NULL);
+    if (acb->finished) {
+        *acb->finished = true;
     }
     qemu_aio_release(acb);
 }
 
+/*
+ * Check whether the specified acb can be canceled
+ *
+ * We can cancel aio when any request belonging to the acb is:
+ *  - Not processed by the sheepdog server.
+ *  - Not linked to the inflight queue.
+ */
+static bool sd_acb_cancelable(const SheepdogAIOCB *acb)
+{
+    BDRVSheepdogState *s = acb->common.bs->opaque;
+    AIOReq *aioreq;
+
+    if (!acb->cancelable) {
+        return false;
+    }
+
+    QLIST_FOREACH(aioreq, &s->inflight_aio_head, aio_siblings) {
+        if (aioreq->aiocb == acb) {
+            return false;
+        }
+    }
+
+    return false;
+}
+
 static void sd_aio_cancel(BlockDriverAIOCB *blockacb)
 {
     SheepdogAIOCB *acb = (SheepdogAIOCB *)blockacb;
+    BDRVSheepdogState *s = acb->common.bs->opaque;
+    AIOReq *aioreq, *next;
+    bool finished = false;
+
+    acb->finished = &finished;
+    while (!finished) {
+        if (sd_acb_cancelable(acb)) {
+            /* Remove outstanding requests from pending and failed queues.  */
+            QLIST_FOREACH_SAFE(aioreq, &s->pending_aio_head, aio_siblings,
+                               next) {
+                if (aioreq->aiocb == acb) {
+                    free_aio_req(s, aioreq);
+                }
+            }
+            QLIST_FOREACH_SAFE(aioreq, &s->failed_aio_head, aio_siblings,
+                               next) {
+                if (aioreq->aiocb == acb) {
+                    free_aio_req(s, aioreq);
+                }
+            }
 
-    /*
-     * Sheepdog cannot cancel the requests which are already sent to
-     * the servers, so we just complete the request with -EIO here.
-     */
-    acb->ret = -EIO;
-    qemu_coroutine_enter(acb->coroutine, NULL);
-    acb->canceled = true;
+            assert(acb->nr_pending == 0);
+            sd_finish_aiocb(acb);
+            return;
+        }
+        qemu_aio_wait();
+    }
 }
 
 static const AIOCBInfo sd_aiocb_info = {
@@ -456,7 +503,8 @@  static SheepdogAIOCB *sd_aio_setup(BlockDriverState *bs, QEMUIOVector *qiov,
     acb->nb_sectors = nb_sectors;
 
     acb->aio_done_func = NULL;
-    acb->canceled = false;
+    acb->cancelable = true;
+    acb->finished = NULL;
     acb->coroutine = qemu_coroutine_self();
     acb->ret = 0;
     acb->nr_pending = 0;