]> Git Repo - qemu.git/blobdiff - block-raw-posix.c
Fix build on non-Linux unices
[qemu.git] / block-raw-posix.c
index 7c42c108e7b7a882720c658cdf28843b2e82164d..8f0ceadea610af0f96d99fb041e4c3d7f1aeb678 100644 (file)
    reopen it to see if the disk has been changed */
 #define FD_OPEN_TIMEOUT 1000
 
+/* posix-aio doesn't allow multiple outstanding requests to a single file
+ * descriptor.  we implement a pool of dup()'d file descriptors to work
+ * around this */
+#define RAW_FD_POOL_SIZE       64
+
 typedef struct BDRVRawState {
     int fd;
     int type;
     unsigned int lseek_err_cnt;
+    int fd_pool[RAW_FD_POOL_SIZE];
 #if defined(__linux__)
     /* linux floppy specific */
     int fd_open_flags;
@@ -101,12 +107,17 @@ typedef struct BDRVRawState {
 #endif
 } BDRVRawState;
 
+static int posix_aio_init(void);
+
 static int fd_open(BlockDriverState *bs);
 
 static int raw_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRawState *s = bs->opaque;
     int fd, open_flags, ret;
+    int i;
+
+    posix_aio_init();
 
     s->lseek_err_cnt = 0;
 
@@ -134,6 +145,8 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags)
         return ret;
     }
     s->fd = fd;
+    for (i = 0; i < RAW_FD_POOL_SIZE; i++)
+        s->fd_pool[i] = -1;
 #if defined(O_DIRECT)
     s->aligned_buf = NULL;
     if (flags & BDRV_O_DIRECT) {
@@ -432,18 +445,53 @@ static int raw_pwrite(BlockDriverState *bs, int64_t offset,
 
 typedef struct RawAIOCB {
     BlockDriverAIOCB common;
+    int fd;
     struct aiocb aiocb;
     struct RawAIOCB *next;
     int ret;
 } RawAIOCB;
 
-static int aio_sig_fd = -1;
-static int aio_sig_num = SIGUSR2;
-static RawAIOCB *first_aio; /* AIO issued */
-static int aio_initialized = 0;
+typedef struct PosixAioState
+{
+    int fd;
+    RawAIOCB *first_aio;
+} PosixAioState;
+
+static int raw_fd_pool_get(BDRVRawState *s)
+{
+    int i;
+
+    for (i = 0; i < RAW_FD_POOL_SIZE; i++) {
+        /* already in use */
+        if (s->fd_pool[i] != -1)
+            continue;
+
+        /* try to dup file descriptor */
+        s->fd_pool[i] = dup(s->fd);
+        if (s->fd_pool[i] != -1)
+            return s->fd_pool[i];
+    }
+
+    /* we couldn't dup the file descriptor so just use the main one */
+    return s->fd;
+}
 
-static void qemu_aio_poll(void *opaque)
+static void raw_fd_pool_put(RawAIOCB *acb)
 {
+    BDRVRawState *s = acb->common.bs->opaque;
+    int i;
+
+    for (i = 0; i < RAW_FD_POOL_SIZE; i++) {
+        if (s->fd_pool[i] == acb->fd) {
+            close(s->fd_pool[i]);
+            s->fd_pool[i] = -1;
+        }
+    }
+}
+
+static void posix_aio_read(void *opaque)
+{
+    PosixAioState *s = opaque;
     RawAIOCB *acb, **pacb;
     int ret;
     size_t offset;
@@ -457,7 +505,7 @@ static void qemu_aio_poll(void *opaque)
     while (offset < 128) {
         ssize_t len;
 
-        len = read(aio_sig_fd, sig.buf + offset, 128 - offset);
+        len = read(s->fd, sig.buf + offset, 128 - offset);
         if (len == -1 && errno == EINTR)
             continue;
         if (len == -1 && errno == EAGAIN) {
@@ -472,7 +520,7 @@ static void qemu_aio_poll(void *opaque)
     }
 
     for(;;) {
-        pacb = &first_aio;
+        pacb = &s->first_aio;
         for(;;) {
             acb = *pacb;
             if (!acb)
@@ -481,6 +529,7 @@ static void qemu_aio_poll(void *opaque)
             if (ret == ECANCELED) {
                 /* remove the request */
                 *pacb = acb->next;
+                raw_fd_pool_put(acb);
                 qemu_aio_release(acb);
             } else if (ret != EINPROGRESS) {
                 /* end of aio */
@@ -497,6 +546,7 @@ static void qemu_aio_poll(void *opaque)
                 *pacb = acb->next;
                 /* call the callback */
                 acb->common.cb(acb->common.opaque, ret);
+                raw_fd_pool_put(acb);
                 qemu_aio_release(acb);
                 break;
             } else {
@@ -507,68 +557,54 @@ static void qemu_aio_poll(void *opaque)
  the_end: ;
 }
 
-void qemu_aio_init(void)
+static int posix_aio_flush(void *opaque)
+{
+    PosixAioState *s = opaque;
+    return !!s->first_aio;
+}
+
+static PosixAioState *posix_aio_state;
+
+static int posix_aio_init(void)
 {
     sigset_t mask;
+    PosixAioState *s;
+    struct aioinit ai;
+  
+    if (posix_aio_state)
+        return 0;
 
-    aio_initialized = 1;
+    s = qemu_malloc(sizeof(PosixAioState));
+    if (s == NULL)
+        return -ENOMEM;
 
     /* Make sure to block AIO signal */
     sigemptyset(&mask);
-    sigaddset(&mask, aio_sig_num);
+    sigaddset(&mask, SIGUSR2);
     sigprocmask(SIG_BLOCK, &mask, NULL);
     
-    aio_sig_fd = qemu_signalfd(&mask);
+    s->first_aio = NULL;
+    s->fd = qemu_signalfd(&mask);
 
-    fcntl(aio_sig_fd, F_SETFL, O_NONBLOCK);
+    fcntl(s->fd, F_SETFL, O_NONBLOCK);
 
-    qemu_set_fd_handler2(aio_sig_fd, NULL, qemu_aio_poll, NULL, NULL);
+    qemu_aio_set_fd_handler(s->fd, posix_aio_read, NULL, posix_aio_flush, s);
 
-#if defined(__GLIBC__) && defined(__linux__)
-    {
-        /* XXX: aio thread exit seems to hang on RedHat 9 and this init
-           seems to fix the problem. */
-        struct aioinit ai;
-        memset(&ai, 0, sizeof(ai));
-        ai.aio_threads = 1;
-        ai.aio_num = 1;
-        ai.aio_idle_time = 365 * 100000;
-        aio_init(&ai);
-    }
+    memset(&ai, 0, sizeof(ai));
+#if !defined(__linux__) || (defined(__GLIBC_PREREQ) && __GLIBC_PREREQ(2, 4))
+    ai.aio_threads = 5;
+    ai.aio_num = 1;
+#else
+    /* XXX: aio thread exit seems to hang on RedHat 9 and this init
+       seems to fix the problem. */
+    ai.aio_threads = 1;
+    ai.aio_num = 1;
+    ai.aio_idle_time = 365 * 100000;
 #endif
-}
-
-/* Wait for all IO requests to complete.  */
-void qemu_aio_flush(void)
-{
-    qemu_aio_poll(NULL);
-    while (first_aio) {
-        qemu_aio_wait();
-    }
-}
-
-void qemu_aio_wait(void)
-{
-    int ret;
-
-    if (qemu_bh_poll())
-        return;
-
-    if (!first_aio)
-        return;
+    aio_init(&ai);
+    posix_aio_state = s;
 
-    do {
-        fd_set rdfds;
-
-        FD_ZERO(&rdfds);
-        FD_SET(aio_sig_fd, &rdfds);
-
-        ret = select(aio_sig_fd + 1, &rdfds, NULL, NULL, NULL);
-        if (ret == -1 && errno == EINTR)
-            continue;
-    } while (ret == 0);
-
-    qemu_aio_poll(NULL);
+    return 0;
 }
 
 static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
@@ -584,8 +620,9 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
     acb = qemu_aio_get(bs, cb, opaque);
     if (!acb)
         return NULL;
-    acb->aiocb.aio_fildes = s->fd;
-    acb->aiocb.aio_sigevent.sigev_signo = aio_sig_num;
+    acb->fd = raw_fd_pool_get(s);
+    acb->aiocb.aio_fildes = acb->fd;
+    acb->aiocb.aio_sigevent.sigev_signo = SIGUSR2;
     acb->aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
     acb->aiocb.aio_buf = buf;
     if (nb_sectors < 0)
@@ -593,8 +630,8 @@ static RawAIOCB *raw_aio_setup(BlockDriverState *bs,
     else
         acb->aiocb.aio_nbytes = nb_sectors * 512;
     acb->aiocb.aio_offset = sector_num * 512;
-    acb->next = first_aio;
-    first_aio = acb;
+    acb->next = posix_aio_state->first_aio;
+    posix_aio_state->first_aio = acb;
     return acb;
 }
 
@@ -685,12 +722,13 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
     }
 
     /* remove the callback from the queue */
-    pacb = &first_aio;
+    pacb = &posix_aio_state->first_aio;
     for(;;) {
         if (*pacb == NULL) {
             break;
         } else if (*pacb == acb) {
             *pacb = acb->next;
+            raw_fd_pool_put(acb);
             qemu_aio_release(acb);
             break;
         }
@@ -698,23 +736,24 @@ static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
     }
 }
 
-# else /* CONFIG_AIO */
-
-void qemu_aio_init(void)
+#else /* CONFIG_AIO */
+static int posix_aio_init(void)
 {
 }
+#endif /* CONFIG_AIO */
 
-void qemu_aio_flush(void)
+static void raw_close_fd_pool(BDRVRawState *s)
 {
-}
+    int i;
 
-void qemu_aio_wait(void)
-{
-    qemu_bh_poll();
+    for (i = 0; i < RAW_FD_POOL_SIZE; i++) {
+        if (s->fd_pool[i] != -1) {
+            close(s->fd_pool[i]);
+            s->fd_pool[i] = -1;
+        }
+    }
 }
 
-#endif /* CONFIG_AIO */
-
 static void raw_close(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
@@ -726,6 +765,7 @@ static void raw_close(BlockDriverState *bs)
             qemu_free(s->aligned_buf);
 #endif
     }
+    raw_close_fd_pool(s);
 }
 
 static int raw_truncate(BlockDriverState *bs, int64_t offset)
@@ -916,7 +956,9 @@ kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex ma
 static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRawState *s = bs->opaque;
-    int fd, open_flags, ret;
+    int fd, open_flags, ret, i;
+
+    posix_aio_init();
 
 #ifdef CONFIG_COCOA
     if (strstart(filename, "/dev/cdrom", NULL)) {
@@ -979,6 +1021,8 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
         return ret;
     }
     s->fd = fd;
+    for (i = 0; i < RAW_FD_POOL_SIZE; i++)
+        s->fd_pool[i] = -1;
 #if defined(__linux__)
     /* close fd so that we can reopen it as needed */
     if (s->type == FTYPE_FD) {
@@ -991,7 +1035,6 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 }
 
 #if defined(__linux__)
-
 /* Note: we do not have a reliable method to detect if the floppy is
    present. The current method is to try to open the floppy at every
    I/O and to keep it opened during a few hundreds of ms. */
@@ -1007,6 +1050,7 @@ static int fd_open(BlockDriverState *bs)
         (qemu_get_clock(rt_clock) - s->fd_open_time) >= FD_OPEN_TIMEOUT) {
         close(s->fd);
         s->fd = -1;
+        raw_close_fd_pool(s);
 #ifdef DEBUG_FLOPPY
         printf("Floppy closed\n");
 #endif
@@ -1107,6 +1151,7 @@ static int raw_eject(BlockDriverState *bs, int eject_flag)
             if (s->fd >= 0) {
                 close(s->fd);
                 s->fd = -1;
+                raw_close_fd_pool(s);
             }
             fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK);
             if (fd >= 0) {
This page took 0.033475 seconds and 4 git commands to generate.