]> git.proxmox.com Git - qemu.git/blobdiff - linux-aio.c
Merge remote-tracking branch 'riku/linux-user-for-upstream' into staging
[qemu.git] / linux-aio.c
index f53a08cb0c3e91af7d5bfa5193ae9a5a2387a0c6..fa0fbf34aaaddd57eba83b3d3a56436552175e3b 100644 (file)
@@ -9,7 +9,6 @@
  */
 #include "qemu-common.h"
 #include "qemu-aio.h"
-#include "block_int.h"
 #include "block/raw-posix-aio.h"
 
 #include <sys/eventfd.h>
@@ -31,6 +30,9 @@ struct qemu_laiocb {
     struct iocb iocb;
     ssize_t ret;
     size_t nbytes;
+    QEMUIOVector *qiov;
+    bool is_read;
+    QLIST_ENTRY(qemu_laiocb) node;
 };
 
 struct qemu_laio_state {
@@ -44,6 +46,36 @@ static inline ssize_t io_event_ret(struct io_event *ev)
     return (ssize_t)(((uint64_t)ev->res2 << 32) | ev->res);
 }
 
+/*
+ * Completes an AIO request (calls the callback and frees the ACB).
+ */
+static void qemu_laio_process_completion(struct qemu_laio_state *s,
+    struct qemu_laiocb *laiocb)
+{
+    int ret;
+
+    s->count--;
+
+    ret = laiocb->ret;
+    if (ret != -ECANCELED) {
+        if (ret == laiocb->nbytes) {
+            ret = 0;
+        } else if (ret >= 0) {
+            /* Short reads mean EOF, pad with zeros. */
+            if (laiocb->is_read) {
+                qemu_iovec_memset_skip(laiocb->qiov, 0,
+                    laiocb->qiov->size - ret, ret);
+            } else {
+                ret = -EINVAL;
+            }
+        }
+
+        laiocb->common.cb(laiocb->common.opaque, ret);
+    }
+
+    qemu_aio_release(laiocb);
+}
+
 static void qemu_laio_completion_cb(void *opaque)
 {
     struct qemu_laio_state *s = opaque;
@@ -57,7 +89,7 @@ static void qemu_laio_completion_cb(void *opaque)
 
         do {
             ret = read(s->efd, &val, sizeof(val));
-        } while (ret == 1 && errno == EINTR);
+        } while (ret == -1 && errno == EINTR);
 
         if (ret == -1 && errno == EAGAIN)
             break;
@@ -74,19 +106,8 @@ static void qemu_laio_completion_cb(void *opaque)
             struct qemu_laiocb *laiocb =
                     container_of(iocb, struct qemu_laiocb, iocb);
 
-            s->count--;
-
-            ret = laiocb->ret = io_event_ret(&events[i]);
-            if (ret != -ECANCELED) {
-                if (ret == laiocb->nbytes)
-                    ret = 0;
-                else if (ret >= 0)
-                    ret = -EINVAL;
-
-                laiocb->common.cb(laiocb->common.opaque, ret);
-            }
-
-            qemu_aio_release(laiocb);
+            laiocb->ret = io_event_ret(&events[i]);
+            qemu_laio_process_completion(s, laiocb);
         }
     }
 }
@@ -144,11 +165,11 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
     off_t offset = sector_num * 512;
 
     laiocb = qemu_aio_get(&laio_pool, bs, cb, opaque);
-    if (!laiocb)
-        return NULL;
     laiocb->nbytes = nb_sectors * 512;
     laiocb->ctx = s;
     laiocb->ret = -EINPROGRESS;
+    laiocb->is_read = (type == QEMU_AIO_READ);
+    laiocb->qiov = qiov;
 
     iocbs = &laiocb->iocb;
 
@@ -159,6 +180,7 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
     case QEMU_AIO_READ:
         io_prep_preadv(iocbs, fd, qiov->iov, qiov->niov, offset);
        break;
+    /* Currently Linux kernel does not support other operations */
     default:
         fprintf(stderr, "%s: invalid AIO request type 0x%x.\n",
                         __func__, type);
@@ -171,10 +193,10 @@ BlockDriverAIOCB *laio_submit(BlockDriverState *bs, void *aio_ctx, int fd,
         goto out_dec_count;
     return &laiocb->common;
 
-out_free_aiocb:
-    qemu_aio_release(laiocb);
 out_dec_count:
     s->count--;
+out_free_aiocb:
+    qemu_aio_release(laiocb);
     return NULL;
 }
 
@@ -182,7 +204,7 @@ void *laio_init(void)
 {
     struct qemu_laio_state *s;
 
-    s = qemu_mallocz(sizeof(*s));
+    s = g_malloc0(sizeof(*s));
     s->efd = eventfd(0, 0);
     if (s->efd == -1)
         goto out_free_state;
@@ -191,14 +213,14 @@ void *laio_init(void)
     if (io_setup(MAX_EVENTS, &s->ctx) != 0)
         goto out_close_efd;
 
-    qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb,
-                            NULL, qemu_laio_flush_cb, s);
+    qemu_aio_set_fd_handler(s->efd, qemu_laio_completion_cb, NULL,
+        qemu_laio_flush_cb, s);
 
     return s;
 
 out_close_efd:
     close(s->efd);
 out_free_state:
-    qemu_free(s);
+    g_free(s);
     return NULL;
 }