diff options
author | Anthony Liguori <aliguori@us.ibm.com> | 2009-06-15 12:52:49 -0500 |
---|---|---|
committer | Anthony Liguori <aliguori@us.ibm.com> | 2009-06-15 12:53:56 -0500 |
commit | e510e05b5d68386a0518e69eaf364a34bdb6283c (patch) | |
tree | 52220869147546a06d2735a9e8abc87769b1acb3 | |
parent | f5de141b34f3ca1c5aef58403cfd16cf10715bff (diff) | |
parent | 63ec93db2178c8caaecd546e640f2fa2296c0a5a (diff) |
Merge commit 'block/master' into staging
* commit 'block/master':
raw-posix: cleanup ioctl methods
block: add bdrv_probe_device method
raw-posix: split hdev drivers
raw-posix: add a raw_open_common helper
raw-posix: always store open flags
fix qemu_aio_flush
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
-rw-r--r-- | aio.c | 8 | ||||
-rw-r--r-- | block.c | 48 | ||||
-rw-r--r-- | block/raw-posix.c | 662 | ||||
-rw-r--r-- | block/raw-win32.c | 10 | ||||
-rw-r--r-- | block_int.h | 5 | ||||
-rw-r--r-- | qemu-aio.h | 7 |
6 files changed, 408 insertions, 332 deletions
@@ -103,11 +103,15 @@ void qemu_aio_flush(void) do { ret = 0; + /* + * If there are pending emulated aio start them now so flush + * will be able to return 1. + */ + qemu_aio_wait(); + LIST_FOREACH(node, &aio_handlers, node) { ret |= node->io_flush(node->opaque); } - - qemu_aio_wait(); } while (ret > 0); } @@ -209,7 +209,7 @@ static int is_windows_drive_prefix(const char *filename) filename[1] == ':'); } -static int is_windows_drive(const char *filename) +int is_windows_drive(const char *filename) { if (is_windows_drive_prefix(filename) && filename[2] == '\0') @@ -249,8 +249,28 @@ static BlockDriver *find_protocol(const char *filename) return NULL; } -/* XXX: force raw format if block or character device ? It would - simplify the BSD case */ +/* + * Detect host devices. By convention, /dev/cdrom[N] is always + * recognized as a host CDROM. + */ +static BlockDriver *find_hdev_driver(const char *filename) +{ + int score_max = 0, score; + BlockDriver *drv = NULL, *d; + + for (d = first_drv; d; d = d->next) { + if (d->bdrv_probe_device) { + score = d->bdrv_probe_device(filename); + if (score > score_max) { + score_max = score; + drv = d; + } + } + } + + return drv; +} + static BlockDriver *find_image_format(const char *filename) { int ret, score, score_max; @@ -258,23 +278,6 @@ static BlockDriver *find_image_format(const char *filename) uint8_t buf[2048]; BlockDriverState *bs; - /* detect host devices. By convention, /dev/cdrom[N] is always - recognized as a host CDROM */ - if (strstart(filename, "/dev/cdrom", NULL)) - return bdrv_find_format("host_device"); -#ifdef _WIN32 - if (is_windows_drive(filename)) - return bdrv_find_format("host_device"); -#else - { - struct stat st; - if (stat(filename, &st) >= 0 && - (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) { - return bdrv_find_format("host_device"); - } - } -#endif - drv = find_protocol(filename); /* no need to test disk image formats for vvfat */ if (drv && strcmp(drv->format_name, "vvfat") == 0) @@ -394,7 +397,10 @@ int bdrv_open2(BlockDriverState *bs, const char *filename, int flags, if (flags & BDRV_O_FILE) { drv = find_protocol(filename); } else if (!drv) { - drv = find_image_format(filename); + drv = find_hdev_driver(filename); + if (!drv) { + drv = find_image_format(filename); + } } if (!drv) { ret = -ENOENT; diff --git a/block/raw-posix.c b/block/raw-posix.c index 4798d626c3..50323485f9 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -103,17 +103,14 @@ typedef struct BDRVRawState { int fd; int type; unsigned int lseek_err_cnt; + int open_flags; #if defined(__linux__) /* linux floppy specific */ - int fd_open_flags; int64_t fd_open_time; int64_t fd_error_time; int fd_got_error; int fd_media_changed; #endif -#if defined(__FreeBSD__) - int cd_open_flags; -#endif uint8_t* aligned_buf; } BDRVRawState; @@ -122,40 +119,36 @@ static int posix_aio_init(void); static int fd_open(BlockDriverState *bs); #if defined(__FreeBSD__) -static int cd_open(BlockDriverState *bs); +static int cdrom_reopen(BlockDriverState *bs); #endif -static int raw_is_inserted(BlockDriverState *bs); - -static int raw_open(BlockDriverState *bs, const char *filename, int flags) +static int raw_open_common(BlockDriverState *bs, const char *filename, + int flags) { BDRVRawState *s = bs->opaque; - int fd, open_flags, ret; + int fd, ret; posix_aio_init(); s->lseek_err_cnt = 0; - open_flags = O_BINARY; + s->open_flags |= O_BINARY; if ((flags & BDRV_O_ACCESS) == O_RDWR) { - open_flags |= O_RDWR; + s->open_flags |= O_RDWR; } else { - open_flags |= O_RDONLY; + s->open_flags |= O_RDONLY; bs->read_only = 1; } - if (flags & BDRV_O_CREAT) - open_flags |= O_CREAT | O_TRUNC; /* Use O_DSYNC for write-through caching, no flags for write-back caching, * and O_DIRECT for no caching. */ if ((flags & BDRV_O_NOCACHE)) - open_flags |= O_DIRECT; + s->open_flags |= O_DIRECT; else if (!(flags & BDRV_O_CACHE_WB)) - open_flags |= O_DSYNC; + s->open_flags |= O_DSYNC; - s->type = FTYPE_FILE; - - fd = open(filename, open_flags, 0644); + s->fd = -1; + fd = open(filename, s->open_flags, 0644); if (fd < 0) { ret = -errno; if (ret == -EROFS) @@ -175,6 +168,17 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) return 0; } +static int raw_open(BlockDriverState *bs, const char *filename, int flags) +{ + BDRVRawState *s = bs->opaque; + + s->type = FTYPE_FILE; + if (flags & BDRV_O_CREAT) + s->open_flags |= O_CREAT | O_TRUNC; + + return raw_open_common(bs, filename, flags); +} + /* XXX: use host sector size if necessary with: #ifdef DIOCGSECTORSIZE { @@ -802,7 +806,7 @@ again: if (size == 2048LL * (unsigned)-1) size = 0; /* XXX no disc? maybe we need to reopen... */ - if (size <= 0 && !reopened && cd_open(bs) >= 0) { + if (size <= 0 && !reopened && cdrom_reopen(bs) >= 0) { reopened = 1; goto again; } @@ -949,12 +953,25 @@ kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex ma #endif +static int hdev_probe_device(const char *filename) +{ + struct stat st; + + /* allow a dedicated CD-ROM driver to match with a higher priority */ + if (strstart(filename, "/dev/cdrom", NULL)) + return 50; + + if (stat(filename, &st) >= 0 && + (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) { + return 100; + } + + return 0; +} + static int hdev_open(BlockDriverState *bs, const char *filename, int flags) { BDRVRawState *s = bs->opaque; - int fd, open_flags, ret; - - posix_aio_init(); #ifdef CONFIG_COCOA if (strstart(filename, "/dev/cdrom", NULL)) { @@ -982,67 +999,15 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) IOObjectRelease( mediaIterator ); } #endif - open_flags = O_BINARY; - if ((flags & BDRV_O_ACCESS) == O_RDWR) { - open_flags |= O_RDWR; - } else { - open_flags |= O_RDONLY; - bs->read_only = 1; - } - /* Use O_DSYNC for write-through caching, no flags for write-back caching, - * and O_DIRECT for no caching. */ - if ((flags & BDRV_O_NOCACHE)) - open_flags |= O_DIRECT; - else if (!(flags & BDRV_O_CACHE_WB)) - open_flags |= O_DSYNC; s->type = FTYPE_FILE; -#if defined(__linux__) - if (strstart(filename, "/dev/cd", NULL)) { - /* open will not fail even if no CD is inserted */ - open_flags |= O_NONBLOCK; - s->type = FTYPE_CD; - } else if (strstart(filename, "/dev/fd", NULL)) { - s->type = FTYPE_FD; - s->fd_open_flags = open_flags; - /* open will not fail even if no floppy is inserted */ - open_flags |= O_NONBLOCK; -#ifdef CONFIG_AIO - } else if (strstart(filename, "/dev/sg", NULL)) { +#if defined(__linux__) && defined(CONFIG_AIO) + if (strstart(filename, "/dev/sg", NULL)) { bs->sg = 1; -#endif - } -#endif -#if defined(__FreeBSD__) - if (strstart(filename, "/dev/cd", NULL) || - strstart(filename, "/dev/acd", NULL)) { - s->type = FTYPE_CD; - s->cd_open_flags = open_flags; } #endif - s->fd = -1; - fd = open(filename, open_flags, 0644); - if (fd < 0) { - ret = -errno; - if (ret == -EROFS) - ret = -EACCES; - return ret; - } - s->fd = fd; -#if defined(__FreeBSD__) - /* make sure the door isnt locked at this time */ - if (s->type == FTYPE_CD) - ioctl (s->fd, CDIOCALLOW); -#endif -#if defined(__linux__) - /* close fd so that we can reopen it as needed */ - if (s->type == FTYPE_FD) { - close(s->fd); - s->fd = -1; - s->fd_media_changed = 1; - } -#endif - return 0; + + return raw_open_common(bs, filename, flags); } #if defined(__linux__) @@ -1073,7 +1038,7 @@ static int fd_open(BlockDriverState *bs) #endif return -EIO; } - s->fd = open(bs->filename, s->fd_open_flags); + s->fd = open(bs->filename, s->open_flags & ~O_NONBLOCK); if (s->fd < 0) { s->fd_error_time = qemu_get_clock(rt_clock); s->fd_got_error = 1; @@ -1095,106 +1060,7 @@ static int fd_open(BlockDriverState *bs) return 0; } -static int raw_is_inserted(BlockDriverState *bs) -{ - BDRVRawState *s = bs->opaque; - int ret; - - switch(s->type) { - case FTYPE_CD: - ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT); - if (ret == CDS_DISC_OK) - return 1; - else - return 0; - break; - case FTYPE_FD: - ret = fd_open(bs); - return (ret >= 0); - default: - return 1; - } -} - -/* currently only used by fdc.c, but a CD version would be good too */ -static int raw_media_changed(BlockDriverState *bs) -{ - BDRVRawState *s = bs->opaque; - - switch(s->type) { - case FTYPE_FD: - { - int ret; - /* XXX: we do not have a true media changed indication. It - does not work if the floppy is changed without trying - to read it */ - fd_open(bs); - ret = s->fd_media_changed; - s->fd_media_changed = 0; -#ifdef DEBUG_FLOPPY - printf("Floppy changed=%d\n", ret); -#endif - return ret; - } - default: - return -ENOTSUP; - } -} - -static int raw_eject(BlockDriverState *bs, int eject_flag) -{ - BDRVRawState *s = bs->opaque; - - switch(s->type) { - case FTYPE_CD: - if (eject_flag) { - if (ioctl (s->fd, CDROMEJECT, NULL) < 0) - perror("CDROMEJECT"); - } else { - if (ioctl (s->fd, CDROMCLOSETRAY, NULL) < 0) - perror("CDROMEJECT"); - } - break; - case FTYPE_FD: - { - int fd; - if (s->fd >= 0) { - close(s->fd); - s->fd = -1; - } - fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK); - if (fd >= 0) { - if (ioctl(fd, FDEJECT, 0) < 0) - perror("FDEJECT"); - close(fd); - } - } - break; - default: - return -ENOTSUP; - } - return 0; -} - -static int raw_set_locked(BlockDriverState *bs, int locked) -{ - BDRVRawState *s = bs->opaque; - - switch(s->type) { - case FTYPE_CD: - if (ioctl (s->fd, CDROM_LOCKDOOR, locked) < 0) { - /* Note: an error can happen if the distribution automatically - mounts the CD-ROM */ - // perror("CDROM_LOCKDOOR"); - } - break; - default: - return -ENOTSUP; - } - 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; @@ -1202,7 +1068,7 @@ static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *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) { @@ -1235,7 +1101,6 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs, #endif #elif defined(__FreeBSD__) - static int fd_open(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -1245,207 +1110,392 @@ static int fd_open(BlockDriverState *bs) return 0; return -EIO; } +#else /* !linux && !FreeBSD */ -static int cd_open(BlockDriverState *bs) +static int fd_open(BlockDriverState *bs) +{ + return 0; +} + +#endif /* !linux && !FreeBSD */ + +static int hdev_create(const char *filename, QEMUOptionParameter *options) { -#if defined(__FreeBSD__) - BDRVRawState *s = bs->opaque; int fd; + int ret = 0; + struct stat stat_buf; + int64_t total_size = 0; - switch(s->type) { - case FTYPE_CD: - /* XXX force reread of possibly changed/newly loaded disc, - * FreeBSD seems to not notice sometimes... */ - if (s->fd >= 0) - close (s->fd); - fd = open(bs->filename, s->cd_open_flags, 0644); - if (fd < 0) { - s->fd = -1; - return -EIO; + /* Read out options */ + while (options && options->name) { + if (!strcmp(options->name, "size")) { + total_size = options->value.n / 512; } - s->fd = fd; - /* make sure the door isnt locked at this time */ - ioctl (s->fd, CDIOCALLOW); + options++; } + + fd = open(filename, O_WRONLY | O_BINARY); + if (fd < 0) + return -EIO; + + if (fstat(fd, &stat_buf) < 0) + ret = -EIO; + else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode)) + ret = -EIO; + else if (lseek(fd, 0, SEEK_END) < total_size * 512) + ret = -ENOSPC; + + close(fd); + return ret; +} + +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, + .bdrv_create = hdev_create, + .bdrv_flush = raw_flush, + +#ifdef CONFIG_AIO + .bdrv_aio_readv = raw_aio_readv, + .bdrv_aio_writev = raw_aio_writev, #endif + + .bdrv_read = raw_read, + .bdrv_write = raw_write, + .bdrv_getlength = raw_getlength, + + /* generic scsi device */ +#ifdef __linux__ + .bdrv_ioctl = hdev_ioctl, +#ifdef CONFIG_AIO + .bdrv_aio_ioctl = hdev_aio_ioctl, +#endif +#endif +}; + +#ifdef __linux__ +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); + if (ret) + return ret; + + /* close fd so that we can reopen it as needed */ + close(s->fd); + s->fd = -1; + s->fd_media_changed = 1; + return 0; } -static int raw_is_inserted(BlockDriverState *bs) +static int floppy_probe_device(const char *filename) { - BDRVRawState *s = bs->opaque; + if (strstart(filename, "/dev/fd", NULL)) + return 100; + return 0; +} - switch(s->type) { - case FTYPE_CD: - return (raw_getlength(bs) > 0); - case FTYPE_FD: - /* XXX handle this */ - /* FALLTHRU */ - default: - return 1; - } + +static int floppy_is_inserted(BlockDriverState *bs) +{ + return fd_open(bs) >= 0; } -static int raw_media_changed(BlockDriverState *bs) +static int floppy_media_changed(BlockDriverState *bs) { - return -ENOTSUP; + BDRVRawState *s = bs->opaque; + int ret; + + /* + * XXX: we do not have a true media changed indication. + * It does not work if the floppy is changed without trying to read it. + */ + fd_open(bs); + ret = s->fd_media_changed; + s->fd_media_changed = 0; +#ifdef DEBUG_FLOPPY + printf("Floppy changed=%d\n", ret); +#endif + return ret; } -static int raw_eject(BlockDriverState *bs, int eject_flag) +static int floppy_eject(BlockDriverState *bs, int eject_flag) { BDRVRawState *s = bs->opaque; + int fd; - switch(s->type) { - case FTYPE_CD: - if (s->fd < 0) - return -ENOTSUP; - (void) ioctl (s->fd, CDIOCALLOW); - if (eject_flag) { - if (ioctl (s->fd, CDIOCEJECT) < 0) - perror("CDIOCEJECT"); - } else { - if (ioctl (s->fd, CDIOCCLOSE) < 0) - perror("CDIOCCLOSE"); - } - if (cd_open(bs) < 0) - return -ENOTSUP; - break; - case FTYPE_FD: - /* XXX handle this */ - /* FALLTHRU */ - default: - return -ENOTSUP; + if (s->fd >= 0) { + close(s->fd); + s->fd = -1; + } + fd = open(bs->filename, s->open_flags | O_NONBLOCK); + if (fd >= 0) { + if (ioctl(fd, FDEJECT, 0) < 0) + perror("FDEJECT"); + close(fd); } + return 0; } -static int raw_set_locked(BlockDriverState *bs, int locked) +static BlockDriver bdrv_host_floppy = { + .format_name = "host_floppy", + .instance_size = sizeof(BDRVRawState), + .bdrv_probe_device = floppy_probe_device, + .bdrv_open = floppy_open, + .bdrv_close = raw_close, + .bdrv_create = hdev_create, + .bdrv_flush = raw_flush, + +#ifdef CONFIG_AIO + .bdrv_aio_readv = raw_aio_readv, + .bdrv_aio_writev = raw_aio_writev, +#endif + + .bdrv_read = raw_read, + .bdrv_write = raw_write, + .bdrv_getlength = raw_getlength, + + /* removable device support */ + .bdrv_is_inserted = floppy_is_inserted, + .bdrv_media_changed = floppy_media_changed, + .bdrv_eject = floppy_eject, +}; + +static int cdrom_open(BlockDriverState *bs, const char *filename, int flags) { BDRVRawState *s = bs->opaque; - switch(s->type) { - case FTYPE_CD: - if (s->fd < 0) - return -ENOTSUP; - if (ioctl (s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) { - /* Note: an error can happen if the distribution automatically - mounts the CD-ROM */ - // perror("CDROM_LOCKDOOR"); - } - break; - default: - return -ENOTSUP; - } - return 0; + /* 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); } -static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) +static int cdrom_probe_device(const char *filename) { - return -ENOTSUP; + if (strstart(filename, "/dev/cd", NULL)) + return 100; + return 0; } -#else /* !linux && !FreeBSD */ -static int fd_open(BlockDriverState *bs) +static int cdrom_is_inserted(BlockDriverState *bs) { + BDRVRawState *s = bs->opaque; + int ret; + + ret = ioctl(s->fd, CDROM_DRIVE_STATUS, CDSL_CURRENT); + if (ret == CDS_DISC_OK) + return 1; return 0; } -static int raw_is_inserted(BlockDriverState *bs) +static int cdrom_eject(BlockDriverState *bs, int eject_flag) { - return 1; + BDRVRawState *s = bs->opaque; + + if (eject_flag) { + if (ioctl(s->fd, CDROMEJECT, NULL) < 0) + perror("CDROMEJECT"); + } else { + if (ioctl(s->fd, CDROMCLOSETRAY, NULL) < 0) + perror("CDROMEJECT"); + } + + return 0; } -static int raw_media_changed(BlockDriverState *bs) +static int cdrom_set_locked(BlockDriverState *bs, int locked) { - return -ENOTSUP; + BDRVRawState *s = bs->opaque; + + if (ioctl(s->fd, CDROM_LOCKDOOR, locked) < 0) { + /* + * Note: an error can happen if the distribution automatically + * mounts the CD-ROM + */ + /* perror("CDROM_LOCKDOOR"); */ + } + + return 0; } -static int raw_eject(BlockDriverState *bs, int eject_flag) +static BlockDriver bdrv_host_cdrom = { + .format_name = "host_cdrom", + .instance_size = sizeof(BDRVRawState), + .bdrv_probe_device = cdrom_probe_device, + .bdrv_open = cdrom_open, + .bdrv_close = raw_close, + .bdrv_create = hdev_create, + .bdrv_flush = raw_flush, + +#ifdef CONFIG_AIO + .bdrv_aio_readv = raw_aio_readv, + .bdrv_aio_writev = raw_aio_writev, +#endif + + .bdrv_read = raw_read, + .bdrv_write = raw_write, + .bdrv_getlength = raw_getlength, + + /* removable device support */ + .bdrv_is_inserted = cdrom_is_inserted, + .bdrv_eject = cdrom_eject, + .bdrv_set_locked = cdrom_set_locked, + + /* generic scsi device */ + .bdrv_ioctl = hdev_ioctl, +#ifdef CONFIG_AIO + .bdrv_aio_ioctl = hdev_aio_ioctl, +#endif +}; +#endif /* __linux__ */ + +#ifdef __FreeBSD__ +static int cdrom_open(BlockDriverState *bs, const char *filename, int flags) { - return -ENOTSUP; + BDRVRawState *s = bs->opaque; + int ret; + + s->type = FTYPE_CD; + + ret = raw_open_common(bs, filename, flags); + if (ret) + return ret; + + /* make sure the door isnt locked at this time */ + ioctl(s->fd, CDIOCALLOW); + return 0; } -static int raw_set_locked(BlockDriverState *bs, int locked) +static int cdrom_probe_device(const char *filename) { - return -ENOTSUP; + if (strstart(filename, "/dev/cd", NULL) || + strstart(filename, "/dev/acd", NULL)) + return 100; + return 0; } -static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) +static int cdrom_reopen(BlockDriverState *bs) { - return -ENOTSUP; + BDRVRawState *s = bs->opaque; + int fd; + + /* + * Force reread of possibly changed/newly loaded disc, + * FreeBSD seems to not notice sometimes... + */ + if (s->fd >= 0) + close(s->fd); + fd = open(bs->filename, s->open_flags, 0644); + if (fd < 0) { + s->fd = -1; + return -EIO; + } + s->fd = fd; + + /* make sure the door isnt locked at this time */ + ioctl(s->fd, CDIOCALLOW); + return 0; } -static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs, - unsigned long int req, void *buf, - BlockDriverCompletionFunc *cb, void *opaque) +static int cdrom_is_inserted(BlockDriverState *bs) { - return NULL; + return raw_getlength(bs) > 0; } -#endif /* !linux && !FreeBSD */ -static int hdev_create(const char *filename, QEMUOptionParameter *options) +static int cdrom_eject(BlockDriverState *bs, int eject_flag) { - int fd; - int ret = 0; - struct stat stat_buf; - int64_t total_size = 0; + BDRVRawState *s = bs->opaque; - /* Read out options */ - while (options && options->name) { - if (!strcmp(options->name, "size")) { - total_size = options->value.n / 512; - } - options++; + if (s->fd < 0) + return -ENOTSUP; + + (void) ioctl(s->fd, CDIOCALLOW); + + if (eject_flag) { + if (ioctl(s->fd, CDIOCEJECT) < 0) + perror("CDIOCEJECT"); + } else { + if (ioctl(s->fd, CDIOCCLOSE) < 0) + perror("CDIOCCLOSE"); } - fd = open(filename, O_WRONLY | O_BINARY); - if (fd < 0) - return -EIO; + if (cdrom_reopen(bs) < 0) + return -ENOTSUP; + return 0; +} - if (fstat(fd, &stat_buf) < 0) - ret = -EIO; - else if (!S_ISBLK(stat_buf.st_mode) && !S_ISCHR(stat_buf.st_mode)) - ret = -EIO; - else if (lseek(fd, 0, SEEK_END) < total_size * 512) - ret = -ENOSPC; +static int cdrom_set_locked(BlockDriverState *bs, int locked) +{ + BDRVRawState *s = bs->opaque; - close(fd); - return ret; + if (s->fd < 0) + return -ENOTSUP; + if (ioctl(s->fd, (locked ? CDIOCPREVENT : CDIOCALLOW)) < 0) { + /* + * Note: an error can happen if the distribution automatically + * mounts the CD-ROM + */ + /* perror("CDROM_LOCKDOOR"); */ + } + + return 0; } -static BlockDriver bdrv_host_device = { - .format_name = "host_device", - .instance_size = sizeof(BDRVRawState), - .bdrv_open = hdev_open, - .bdrv_close = raw_close, +static BlockDriver bdrv_host_cdrom = { + .format_name = "host_cdrom", + .instance_size = sizeof(BDRVRawState), + .bdrv_probe_device = cdrom_probe_device, + .bdrv_open = cdrom_open, + .bdrv_close = raw_close, .bdrv_create = hdev_create, - .bdrv_flush = raw_flush, + .bdrv_flush = raw_flush, #ifdef CONFIG_AIO - .bdrv_aio_readv = raw_aio_readv, - .bdrv_aio_writev = raw_aio_writev, + .bdrv_aio_readv = raw_aio_readv, + .bdrv_aio_writev = raw_aio_writev, #endif .bdrv_read = raw_read, .bdrv_write = raw_write, - .bdrv_getlength = raw_getlength, + .bdrv_getlength = raw_getlength, /* removable device support */ - .bdrv_is_inserted = raw_is_inserted, - .bdrv_media_changed = raw_media_changed, - .bdrv_eject = raw_eject, - .bdrv_set_locked = raw_set_locked, - /* generic scsi device */ - .bdrv_ioctl = raw_ioctl, -#ifdef CONFIG_AIO - .bdrv_aio_ioctl = raw_aio_ioctl, -#endif + .bdrv_is_inserted = cdrom_is_inserted, + .bdrv_eject = cdrom_eject, + .bdrv_set_locked = cdrom_set_locked, }; +#endif /* __FreeBSD__ */ static void bdrv_raw_init(void) { + /* + * Register all the drivers. Note that order is important, the driver + * registered last will get probed first. + */ bdrv_register(&bdrv_raw); bdrv_register(&bdrv_host_device); +#ifdef __linux__ + bdrv_register(&bdrv_host_floppy); + bdrv_register(&bdrv_host_cdrom); +#endif +#ifdef __FreeBSD__ + bdrv_register(&bdrv_host_cdrom); +#endif } block_init(bdrv_raw_init); diff --git a/block/raw-win32.c b/block/raw-win32.c index 1e95153d56..72acad58f9 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -306,6 +306,15 @@ static int find_device_type(BlockDriverState *bs, const char *filename) } } +static int hdev_probe_device(const char *filename) +{ + if (strstart(filename, "/dev/cdrom", NULL)) + return 100; + if (is_windows_drive(filename)) + return 100; + return 0; +} + static int hdev_open(BlockDriverState *bs, const char *filename, int flags) { BDRVRawState *s = bs->opaque; @@ -391,6 +400,7 @@ static int raw_set_locked(BlockDriverState *bs, int locked) 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, .bdrv_flush = raw_flush, diff --git a/block_int.h b/block_int.h index 8d0da7cfd7..830b7e9c9d 100644 --- a/block_int.h +++ b/block_int.h @@ -48,6 +48,7 @@ struct BlockDriver { const char *format_name; int instance_size; int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); + int (*bdrv_probe_device)(const char *filename); int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags); int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); @@ -177,4 +178,8 @@ void *qemu_blockalign(BlockDriverState *bs, size_t size); extern BlockDriverState *bdrv_first; +#ifdef _WIN32 +int is_windows_drive(const char *filename); +#endif + #endif /* BLOCK_INT_H */ diff --git a/qemu-aio.h b/qemu-aio.h index 79678293ef..f262344af3 100644 --- a/qemu-aio.h +++ b/qemu-aio.h @@ -24,9 +24,10 @@ typedef int (AioFlushHandler)(void *opaque); * outstanding AIO operations have been completed or cancelled. */ void qemu_aio_flush(void); -/* Wait for a single AIO completion to occur. This function will until a - * single AIO opeartion has completed. It is intended to be used as a looping - * primative when simulating synchronous IO based on asynchronous IO. */ +/* Wait for a single AIO completion to occur. This function will wait + * until a single AIO event has completed and it will ensure something + * has moved before returning. This can issue new pending aio as + * result of executing I/O completion or bh callbacks. */ void qemu_aio_wait(void); /* Register a file descriptor and associated callbacks. Behaves very similarly |