]> git.proxmox.com Git - qemu.git/blobdiff - block/raw-posix.c
qemu-img: There is more than one host device driver
[qemu.git] / block / raw-posix.c
index 5e65da00a792016313e443a311ecac28834aca66..706799fa39f757e5f7e1a105a33b8e2379eea02b 100644 (file)
 #include "qemu-common.h"
 #include "qemu-timer.h"
 #include "qemu-char.h"
+#include "qemu-log.h"
 #include "block_int.h"
 #include "module.h"
-#ifdef CONFIG_AIO
-#include "posix-aio-compat.h"
-#endif
+#include "block/raw-posix-aio.h"
 
 #ifdef CONFIG_COCOA
 #include <paths.h>
@@ -52,7 +51,7 @@
 #include <linux/cdrom.h>
 #include <linux/fd.h>
 #endif
-#ifdef __FreeBSD__
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
 #include <signal.h>
 #include <sys/disk.h>
 #include <sys/cdio.h>
 
 /* OS X does not have O_DSYNC */
 #ifndef O_DSYNC
+#ifdef O_SYNC
 #define O_DSYNC O_SYNC
+#elif defined(O_FSYNC)
+#define O_DSYNC O_FSYNC
+#endif
 #endif
 
 /* Approximate O_DIRECT with O_DSYNC if O_DIRECT isn't available */
@@ -110,30 +113,32 @@ typedef struct BDRVRawState {
     int64_t fd_error_time;
     int fd_got_error;
     int fd_media_changed;
+#endif
+#ifdef CONFIG_LINUX_AIO
+    int use_aio;
+    void *aio_ctx;
 #endif
     uint8_t* aligned_buf;
 } BDRVRawState;
 
-static int posix_aio_init(void);
-
 static int fd_open(BlockDriverState *bs);
+static int64_t raw_getlength(BlockDriverState *bs);
 
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 static int cdrom_reopen(BlockDriverState *bs);
 #endif
 
 static int raw_open_common(BlockDriverState *bs, const char *filename,
-        int flags)
+                           int bdrv_flags, int open_flags)
 {
     BDRVRawState *s = bs->opaque;
     int fd, ret;
 
-    posix_aio_init();
-
     s->lseek_err_cnt = 0;
 
-    s->open_flags |= O_BINARY;
-    if ((flags & BDRV_O_ACCESS) == O_RDWR) {
+    s->open_flags = open_flags | O_BINARY;
+    s->open_flags &= ~O_ACCMODE;
+    if ((bdrv_flags & BDRV_O_ACCESS) == BDRV_O_RDWR) {
         s->open_flags |= O_RDWR;
     } else {
         s->open_flags |= O_RDONLY;
@@ -142,9 +147,9 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
 
     /* Use O_DSYNC for write-through caching, no flags for write-back caching,
      * and O_DIRECT for no caching. */
-    if ((flags & BDRV_O_NOCACHE))
+    if ((bdrv_flags & BDRV_O_NOCACHE))
         s->open_flags |= O_DIRECT;
-    else if (!(flags & BDRV_O_CACHE_WB))
+    else if (!(bdrv_flags & BDRV_O_CACHE_WB))
         s->open_flags |= O_DSYNC;
 
     s->fd = -1;
@@ -157,26 +162,56 @@ static int raw_open_common(BlockDriverState *bs, const char *filename,
     }
     s->fd = fd;
     s->aligned_buf = NULL;
-    if ((flags & BDRV_O_NOCACHE)) {
+
+    if ((bdrv_flags & BDRV_O_NOCACHE)) {
         s->aligned_buf = qemu_blockalign(bs, ALIGNED_BUFFER_SIZE);
         if (s->aligned_buf == NULL) {
-            ret = -errno;
-            close(fd);
-            return ret;
+            goto out_close;
+        }
+    }
+
+#ifdef CONFIG_LINUX_AIO
+    if ((bdrv_flags & (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) ==
+                      (BDRV_O_NOCACHE|BDRV_O_NATIVE_AIO)) {
+
+        /* We're falling back to POSIX AIO in some cases */
+        paio_init();
+
+        s->aio_ctx = laio_init();
+        if (!s->aio_ctx) {
+            goto out_free_buf;
         }
+        s->use_aio = 1;
+    } else
+#endif
+    {
+        if (paio_init() < 0) {
+            goto out_free_buf;
+        }
+#ifdef CONFIG_LINUX_AIO
+        s->use_aio = 0;
+#endif
     }
+
     return 0;
+
+out_free_buf:
+    qemu_vfree(s->aligned_buf);
+out_close:
+    close(fd);
+    return -errno;
 }
 
 static int raw_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRawState *s = bs->opaque;
+    int open_flags = 0;
 
     s->type = FTYPE_FILE;
     if (flags & BDRV_O_CREAT)
-        s->open_flags |= O_CREAT | O_TRUNC;
+        open_flags = O_CREAT | O_TRUNC;
 
-    return raw_open_common(bs, filename, flags);
+    return raw_open_common(bs, filename, flags, open_flags);
 }
 
 /* XXX: use host sector size if necessary with:
@@ -229,6 +264,16 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset,
     if (ret == count)
         goto label__raw_read__success;
 
+    /* Allow reads beyond the end (needed for pwrite) */
+    if ((ret == 0) && bs->growable) {
+        int64_t size = raw_getlength(bs);
+        if (offset >= size) {
+            memset(buf, 0, count);
+            ret = count;
+            goto label__raw_read__success;
+        }
+    }
+
     DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64
                       "] read failed %d : %d = %s\n",
                       s->fd, bs->filename, offset, buf, count,
@@ -471,249 +516,77 @@ static int raw_write(BlockDriverState *bs, int64_t sector_num,
     return ret;
 }
 
-#ifdef CONFIG_AIO
-/***********************************************************/
-/* Unix AIO using POSIX AIO */
-
-typedef struct RawAIOCB {
-    BlockDriverAIOCB common;
-    struct qemu_paiocb aiocb;
-    struct RawAIOCB *next;
-    int ret;
-} RawAIOCB;
-
-typedef struct PosixAioState
-{
-    int rfd, wfd;
-    RawAIOCB *first_aio;
-} PosixAioState;
-
-static void posix_aio_read(void *opaque)
-{
-    PosixAioState *s = opaque;
-    RawAIOCB *acb, **pacb;
-    int ret;
-    ssize_t len;
-
-    /* read all bytes from signal pipe */
-    for (;;) {
-        char bytes[16];
-
-        len = read(s->rfd, bytes, sizeof(bytes));
-        if (len == -1 && errno == EINTR)
-            continue; /* try again */
-        if (len == sizeof(bytes))
-            continue; /* more to read */
-        break;
-    }
-
-    for(;;) {
-        pacb = &s->first_aio;
-        for(;;) {
-            acb = *pacb;
-            if (!acb)
-                goto the_end;
-            ret = qemu_paio_error(&acb->aiocb);
-            if (ret == ECANCELED) {
-                /* remove the request */
-                *pacb = acb->next;
-                qemu_aio_release(acb);
-            } else if (ret != EINPROGRESS) {
-                /* end of aio */
-                if (ret == 0) {
-                    ret = qemu_paio_return(&acb->aiocb);
-                    if (ret == acb->aiocb.aio_nbytes)
-                        ret = 0;
-                    else
-                        ret = -EINVAL;
-                } else {
-                    ret = -ret;
-                }
-                /* remove the request */
-                *pacb = acb->next;
-                /* call the callback */
-                acb->common.cb(acb->common.opaque, ret);
-                qemu_aio_release(acb);
-                break;
-            } else {
-                pacb = &acb->next;
-            }
-        }
-    }
- the_end: ;
-}
-
-static int posix_aio_flush(void *opaque)
-{
-    PosixAioState *s = opaque;
-    return !!s->first_aio;
-}
-
-static PosixAioState *posix_aio_state;
-
-static void aio_signal_handler(int signum)
-{
-    if (posix_aio_state) {
-        char byte = 0;
-
-        write(posix_aio_state->wfd, &byte, sizeof(byte));
-    }
-
-    qemu_service_io();
-}
-
-static int posix_aio_init(void)
+/*
+ * Check if all memory in this vector is sector aligned.
+ */
+static int qiov_is_aligned(QEMUIOVector *qiov)
 {
-    struct sigaction act;
-    PosixAioState *s;
-    int fds[2];
-    struct qemu_paioinit ai;
-  
-    if (posix_aio_state)
-        return 0;
-
-    s = qemu_malloc(sizeof(PosixAioState));
-
-    sigfillset(&act.sa_mask);
-    act.sa_flags = 0; /* do not restart syscalls to interrupt select() */
-    act.sa_handler = aio_signal_handler;
-    sigaction(SIGUSR2, &act, NULL);
+    int i;
 
-    s->first_aio = NULL;
-    if (pipe(fds) == -1) {
-        fprintf(stderr, "failed to create pipe\n");
-        return -errno;
-    }
-
-    s->rfd = fds[0];
-    s->wfd = fds[1];
-
-    fcntl(s->rfd, F_SETFL, O_NONBLOCK);
-    fcntl(s->wfd, F_SETFL, O_NONBLOCK);
-
-    qemu_aio_set_fd_handler(s->rfd, posix_aio_read, NULL, posix_aio_flush, s);
-
-    memset(&ai, 0, sizeof(ai));
-    ai.aio_threads = 64;
-    ai.aio_num = 64;
-    qemu_paio_init(&ai);
-
-    posix_aio_state = s;
-
-    return 0;
-}
-
-static void raw_aio_remove(RawAIOCB *acb)
-{
-    RawAIOCB **pacb;
-
-    /* remove the callback from the queue */
-    pacb = &posix_aio_state->first_aio;
-    for(;;) {
-        if (*pacb == NULL) {
-            fprintf(stderr, "raw_aio_remove: aio request not found!\n");
-            break;
-        } else if (*pacb == acb) {
-            *pacb = acb->next;
-            qemu_aio_release(acb);
-            break;
+    for (i = 0; i < qiov->niov; i++) {
+        if ((uintptr_t) qiov->iov[i].iov_base % 512) {
+            return 0;
         }
-        pacb = &(*pacb)->next;
-    }
-}
-
-static void raw_aio_cancel(BlockDriverAIOCB *blockacb)
-{
-    int ret;
-    RawAIOCB *acb = (RawAIOCB *)blockacb;
-
-    ret = qemu_paio_cancel(acb->aiocb.aio_fildes, &acb->aiocb);
-    if (ret == QEMU_PAIO_NOTCANCELED) {
-        /* fail safe: if the aio could not be canceled, we wait for
-           it */
-        while (qemu_paio_error(&acb->aiocb) == EINPROGRESS);
     }
 
-    raw_aio_remove(acb);
+    return 1;
 }
 
-static AIOPool raw_aio_pool = {
-    .aiocb_size         = sizeof(RawAIOCB),
-    .cancel             = raw_aio_cancel,
-};
-
-static RawAIOCB *raw_aio_setup(BlockDriverState *bs, int64_t sector_num,
-        QEMUIOVector *qiov, int nb_sectors,
-        BlockDriverCompletionFunc *cb, void *opaque)
+static BlockDriverAIOCB *raw_aio_submit(BlockDriverState *bs,
+        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
+        BlockDriverCompletionFunc *cb, void *opaque, int type)
 {
     BDRVRawState *s = bs->opaque;
-    RawAIOCB *acb;
 
     if (fd_open(bs) < 0)
         return NULL;
 
-    acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
-    if (!acb)
-        return NULL;
-    acb->aiocb.aio_fildes = s->fd;
-    acb->aiocb.ev_signo = SIGUSR2;
-    acb->aiocb.aio_iov = qiov->iov;
-    acb->aiocb.aio_niov = qiov->niov;
-    acb->aiocb.aio_nbytes = nb_sectors * 512;
-    acb->aiocb.aio_offset = sector_num * 512;
-    acb->aiocb.aio_flags = 0;
-
     /*
      * If O_DIRECT is used the buffer needs to be aligned on a sector
-     * boundary. Tell the low level code to ensure that in case it's
-     * not done yet.
+     * boundary.  Check if this is the case or telll the low-level
+     * driver that it needs to copy the buffer.
      */
-    if (s->aligned_buf)
-        acb->aiocb.aio_flags |= QEMU_AIO_SECTOR_ALIGNED;
+    if (s->aligned_buf) {
+        if (!qiov_is_aligned(qiov)) {
+            type |= QEMU_AIO_MISALIGNED;
+#ifdef CONFIG_LINUX_AIO
+        } else if (s->use_aio) {
+            return laio_submit(bs, s->aio_ctx, s->fd, sector_num, qiov,
+                               nb_sectors, cb, opaque, type);
+#endif
+        }
+    }
 
-    acb->next = posix_aio_state->first_aio;
-    posix_aio_state->first_aio = acb;
-    return acb;
+    return paio_submit(bs, s->fd, sector_num, qiov, nb_sectors,
+                       cb, opaque, type);
 }
 
 static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
-    RawAIOCB *acb;
-
-    acb = raw_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque);
-    if (!acb)
-        return NULL;
-    if (qemu_paio_read(&acb->aiocb) < 0) {
-        raw_aio_remove(acb);
-        return NULL;
-    }
-    return &acb->common;
+    return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
+                          cb, opaque, QEMU_AIO_READ);
 }
 
 static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs,
         int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
-    RawAIOCB *acb;
-
-    acb = raw_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque);
-    if (!acb)
-        return NULL;
-    if (qemu_paio_write(&acb->aiocb) < 0) {
-        raw_aio_remove(acb);
-        return NULL;
-    }
-    return &acb->common;
+    return raw_aio_submit(bs, sector_num, qiov, nb_sectors,
+                          cb, opaque, QEMU_AIO_WRITE);
 }
-#else /* CONFIG_AIO */
-static int posix_aio_init(void)
+
+static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs,
+        BlockDriverCompletionFunc *cb, void *opaque)
 {
-    return 0;
-}
-#endif /* CONFIG_AIO */
+    BDRVRawState *s = bs->opaque;
 
+    if (fd_open(bs) < 0)
+        return NULL;
+
+    return paio_submit(bs, s->fd, 0, NULL, 0, cb, opaque, QEMU_AIO_FLUSH);
+}
 
 static void raw_close(BlockDriverState *bs)
 {
@@ -761,9 +634,9 @@ static int64_t  raw_getlength(BlockDriverState *bs)
     BDRVRawState *s = bs->opaque;
     int fd = s->fd;
     int64_t size;
-#ifdef HOST_BSD
+#ifdef CONFIG_BSD
     struct stat sb;
-#ifdef __FreeBSD__
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
     int reopened = 0;
 #endif
 #endif
@@ -777,8 +650,8 @@ static int64_t  raw_getlength(BlockDriverState *bs)
     if (ret < 0)
         return ret;
 
-#ifdef HOST_BSD
-#ifdef __FreeBSD__
+#ifdef CONFIG_BSD
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
 again:
 #endif
     if (!fstat(fd, &sb) && (S_IFCHR & sb.st_mode)) {
@@ -799,7 +672,7 @@ again:
 #else
         size = lseek(fd, 0LL, SEEK_END);
 #endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
         switch(s->type) {
         case FTYPE_CD:
             /* XXX FreeBSD acd returns UINT_MAX sectors for an empty drive */
@@ -835,6 +708,7 @@ again:
 static int raw_create(const char *filename, QEMUOptionParameter *options)
 {
     int fd;
+    int result = 0;
     int64_t total_size = 0;
 
     /* Read out options */
@@ -847,17 +721,23 @@ static int raw_create(const char *filename, QEMUOptionParameter *options)
 
     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
               0644);
-    if (fd < 0)
-        return -EIO;
-    ftruncate(fd, total_size * 512);
-    close(fd);
-    return 0;
+    if (fd < 0) {
+        result = -errno;
+    } else {
+        if (ftruncate(fd, total_size * 512) != 0) {
+            result = -errno;
+        }
+        if (close(fd) != 0) {
+            result = -errno;
+        }
+    }
+    return result;
 }
 
 static void raw_flush(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
-    fsync(s->fd);
+    qemu_fdatasync(s->fd);
 }
 
 
@@ -881,10 +761,9 @@ static BlockDriver bdrv_raw = {
     .bdrv_create = raw_create,
     .bdrv_flush = raw_flush,
 
-#ifdef CONFIG_AIO
     .bdrv_aio_readv = raw_aio_readv,
     .bdrv_aio_writev = raw_aio_writev,
-#endif
+    .bdrv_aio_flush = raw_aio_flush,
 
     .bdrv_truncate = raw_truncate,
     .bdrv_getlength = raw_getlength,
@@ -1001,13 +880,13 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags)
 #endif
 
     s->type = FTYPE_FILE;
-#if defined(__linux__) && defined(CONFIG_AIO)
+#if defined(__linux__)
     if (strstart(filename, "/dev/sg", NULL)) {
         bs->sg = 1;
     }
 #endif
 
-    return raw_open_common(bs, filename, flags);
+    return raw_open_common(bs, filename, flags, 0);
 }
 
 #if defined(__linux__)
@@ -1060,47 +939,25 @@ static int fd_open(BlockDriverState *bs)
     return 0;
 }
 
-static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
+static int hdev_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
 {
     BDRVRawState *s = bs->opaque;
 
     return ioctl(s->fd, req, buf);
 }
 
-#ifdef CONFIG_AIO
-static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
+static BlockDriverAIOCB *hdev_aio_ioctl(BlockDriverState *bs,
         unsigned long int req, void *buf,
         BlockDriverCompletionFunc *cb, void *opaque)
 {
     BDRVRawState *s = bs->opaque;
-    RawAIOCB *acb;
 
     if (fd_open(bs) < 0)
         return NULL;
-
-    acb = qemu_aio_get(&raw_aio_pool, bs, cb, opaque);
-    if (!acb)
-        return NULL;
-    acb->aiocb.aio_fildes = s->fd;
-    acb->aiocb.ev_signo = SIGUSR2;
-    acb->aiocb.aio_offset = 0;
-    acb->aiocb.aio_flags = 0;
-
-    acb->next = posix_aio_state->first_aio;
-    posix_aio_state->first_aio = acb;
-
-    acb->aiocb.aio_ioctl_buf = buf;
-    acb->aiocb.aio_ioctl_cmd = req;
-    if (qemu_paio_ioctl(&acb->aiocb) < 0) {
-        raw_aio_remove(acb);
-        return NULL;
-    }
-
-    return &acb->common;
+    return paio_ioctl(bs, s->fd, req, buf, cb, opaque);
 }
-#endif
 
-#elif defined(__FreeBSD__)
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 static int fd_open(BlockDriverState *bs)
 {
     BDRVRawState *s = bs->opaque;
@@ -1110,11 +967,6 @@ static int fd_open(BlockDriverState *bs)
         return 0;
     return -EIO;
 }
-
-static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
-{
-    return -ENOTSUP;
-}
 #else /* !linux && !FreeBSD */
 
 static int fd_open(BlockDriverState *bs)
@@ -1122,17 +974,6 @@ static int fd_open(BlockDriverState *bs)
     return 0;
 }
 
-static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf)
-{
-    return -ENOTSUP;
-}
-
-static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs,
-        unsigned long int req, void *buf,
-        BlockDriverCompletionFunc *cb, void *opaque)
-{
-    return NULL;
-}
 #endif /* !linux && !FreeBSD */
 
 static int hdev_create(const char *filename, QEMUOptionParameter *options)
@@ -1166,27 +1007,28 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options)
 }
 
 static BlockDriver bdrv_host_device = {
-    .format_name       = "host_device",
-    .instance_size     = sizeof(BDRVRawState),
-    .bdrv_probe_device = hdev_probe_device,
-    .bdrv_open         = hdev_open,
-    .bdrv_close                = raw_close,
+    .format_name        = "host_device",
+    .instance_size      = sizeof(BDRVRawState),
+    .bdrv_probe_device  = hdev_probe_device,
+    .bdrv_open          = hdev_open,
+    .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
-    .bdrv_flush                = raw_flush,
+    .create_options     = raw_create_options,
+    .no_zero_init       = 1,
+    .bdrv_flush         = raw_flush,
 
-#ifdef CONFIG_AIO
     .bdrv_aio_readv    = raw_aio_readv,
     .bdrv_aio_writev   = raw_aio_writev,
-#endif
+    .bdrv_aio_flush    = raw_aio_flush,
 
     .bdrv_read          = raw_read,
     .bdrv_write         = raw_write,
     .bdrv_getlength    = raw_getlength,
 
     /* generic scsi device */
-    .bdrv_ioctl         = raw_ioctl,
-#ifdef CONFIG_AIO
-    .bdrv_aio_ioctl     = raw_aio_ioctl,
+#ifdef __linux__
+    .bdrv_ioctl         = hdev_ioctl,
+    .bdrv_aio_ioctl     = hdev_aio_ioctl,
 #endif
 };
 
@@ -1196,13 +1038,10 @@ static int floppy_open(BlockDriverState *bs, const char *filename, int flags)
     BDRVRawState *s = bs->opaque;
     int ret;
 
-    posix_aio_init();
-
     s->type = FTYPE_FD;
-    /* open will not fail even if no floppy is inserted */
-    s->open_flags |= O_NONBLOCK;
 
-    ret = raw_open_common(bs, filename, flags);
+    /* open will not fail even if no floppy is inserted, so add O_NONBLOCK */
+    ret = raw_open_common(bs, filename, flags, O_NONBLOCK);
     if (ret)
         return ret;
 
@@ -1271,12 +1110,13 @@ static BlockDriver bdrv_host_floppy = {
     .bdrv_open          = floppy_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
+    .create_options     = raw_create_options,
+    .no_zero_init       = 1,
     .bdrv_flush         = raw_flush,
 
-#ifdef CONFIG_AIO
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
-#endif
+    .bdrv_aio_flush    = raw_aio_flush,
 
     .bdrv_read          = raw_read,
     .bdrv_write         = raw_write,
@@ -1286,23 +1126,16 @@ static BlockDriver bdrv_host_floppy = {
     .bdrv_is_inserted   = floppy_is_inserted,
     .bdrv_media_changed = floppy_media_changed,
     .bdrv_eject         = floppy_eject,
-
-    /* generic scsi device */
-    .bdrv_ioctl         = raw_ioctl,
-#ifdef CONFIG_AIO
-    .bdrv_aio_ioctl     = raw_aio_ioctl,
-#endif
 };
 
 static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRawState *s = bs->opaque;
 
-    /* open will not fail even if no CD is inserted */
-    s->open_flags |= O_NONBLOCK;
     s->type = FTYPE_CD;
 
-    return raw_open_common(bs, filename, flags);
+    /* open will not fail even if no CD is inserted, so add O_NONBLOCK */
+    return raw_open_common(bs, filename, flags, O_NONBLOCK);
 }
 
 static int cdrom_probe_device(const char *filename)
@@ -1360,12 +1193,13 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_open          = cdrom_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
+    .create_options     = raw_create_options,
+    .no_zero_init       = 1,
     .bdrv_flush         = raw_flush,
 
-#ifdef CONFIG_AIO
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
-#endif
+    .bdrv_aio_flush    = raw_aio_flush,
 
     .bdrv_read          = raw_read,
     .bdrv_write         = raw_write,
@@ -1377,14 +1211,12 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_set_locked    = cdrom_set_locked,
 
     /* generic scsi device */
-    .bdrv_ioctl         = raw_ioctl,
-#ifdef CONFIG_AIO
-    .bdrv_aio_ioctl     = raw_aio_ioctl,
-#endif
+    .bdrv_ioctl         = hdev_ioctl,
+    .bdrv_aio_ioctl     = hdev_aio_ioctl,
 };
 #endif /* __linux__ */
 
-#ifdef __FreeBSD__
+#if defined (__FreeBSD__) || defined(__FreeBSD_kernel__)
 static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
 {
     BDRVRawState *s = bs->opaque;
@@ -1392,7 +1224,7 @@ static int cdrom_open(BlockDriverState *bs, const char *filename, int flags)
 
     s->type = FTYPE_CD;
 
-    ret = raw_open_common(bs, filename, flags);
+    ret = raw_open_common(bs, filename, flags, 0);
     if (ret)
         return ret;
 
@@ -1483,12 +1315,13 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_open          = cdrom_open,
     .bdrv_close         = raw_close,
     .bdrv_create        = hdev_create,
+    .create_options     = raw_create_options,
+    .no_zero_init       = 1,
     .bdrv_flush         = raw_flush,
 
-#ifdef CONFIG_AIO
     .bdrv_aio_readv     = raw_aio_readv,
     .bdrv_aio_writev    = raw_aio_writev,
-#endif
+    .bdrv_aio_flush    = raw_aio_flush,
 
     .bdrv_read          = raw_read,
     .bdrv_write         = raw_write,
@@ -1498,12 +1331,6 @@ static BlockDriver bdrv_host_cdrom = {
     .bdrv_is_inserted   = cdrom_is_inserted,
     .bdrv_eject         = cdrom_eject,
     .bdrv_set_locked    = cdrom_set_locked,
-
-    /* generic scsi device */
-    .bdrv_ioctl         = raw_ioctl,
-#ifdef CONFIG_AIO
-    .bdrv_aio_ioctl     = raw_aio_ioctl,
-#endif
 };
 #endif /* __FreeBSD__ */
 
@@ -1519,7 +1346,7 @@ static void bdrv_raw_init(void)
     bdrv_register(&bdrv_host_floppy);
     bdrv_register(&bdrv_host_cdrom);
 #endif
-#ifdef __FreeBSD__
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
     bdrv_register(&bdrv_host_cdrom);
 #endif
 }