From 986c28d655dc9196c9c426c667c1764bd3d6d5bd Mon Sep 17 00:00:00 2001 From: Andrea Arcangeli Date: Mon, 15 Jun 2009 13:52:27 +0200 Subject: [PATCH 1/6] fix qemu_aio_flush qemu_aio_wait by invoking the bh or one of the aio completion callbacks, could end up submitting new pending aio, breaking the invariant that qemu_aio_flush returns only when no pending aio is outstanding (possibly a problem for migration as such). Signed-off-by: Andrea Arcangeli Signed-off-by: Christoph Hellwig Acked-by: Kevin Wolf --- aio.c | 8 ++++++-- qemu-aio.h | 7 ++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/aio.c b/aio.c index 11fbb6c0c5..dc9b85d167 100644 --- a/aio.c +++ b/aio.c @@ -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); } 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 From 0e1d8f4c549e51fd19793a154862979fdc199477 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Jun 2009 13:53:26 +0200 Subject: [PATCH 2/6] raw-posix: always store open flags Both the Linux floppy and the FreeBSD CDROM host device need to store the open flags so that they can re-open the device later. Store the open flags unconditionally to remove the ifdef mess and simply the calling conventions for the later patches in the series. Signed-off-by: Christoph Hellwig --- block/raw-posix.c | 47 +++++++++++++++++++++-------------------------- 1 file changed, 21 insertions(+), 26 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index 4798d626c3..6e8dfbdb38 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -103,16 +103,13 @@ 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; @@ -130,32 +127,32 @@ static int raw_is_inserted(BlockDriverState *bs); static int raw_open(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; + s->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); + fd = open(filename, s->open_flags, 0644); if (fd < 0) { ret = -errno; if (ret == -EROFS) @@ -952,7 +949,7 @@ 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, ret; posix_aio_init(); @@ -982,31 +979,30 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) IOObjectRelease( mediaIterator ); } #endif - 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; } /* 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; #if defined(__linux__) if (strstart(filename, "/dev/cd", NULL)) { /* open will not fail even if no CD is inserted */ - open_flags |= O_NONBLOCK; + s->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; + s->open_flags |= O_NONBLOCK; #ifdef CONFIG_AIO } else if (strstart(filename, "/dev/sg", NULL)) { bs->sg = 1; @@ -1017,11 +1013,10 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) 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); + fd = open(filename, s->open_flags, 0644); if (fd < 0) { ret = -errno; if (ret == -EROFS) @@ -1073,7 +1068,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; @@ -1162,7 +1157,7 @@ static int raw_eject(BlockDriverState *bs, int eject_flag) close(s->fd); s->fd = -1; } - fd = open(bs->filename, s->fd_open_flags | O_NONBLOCK); + fd = open(bs->filename, s->open_flags | O_NONBLOCK); if (fd >= 0) { if (ioctl(fd, FDEJECT, 0) < 0) perror("FDEJECT"); @@ -1258,7 +1253,7 @@ static int cd_open(BlockDriverState *bs) * FreeBSD seems to not notice sometimes... */ if (s->fd >= 0) close (s->fd); - fd = open(bs->filename, s->cd_open_flags, 0644); + fd = open(bs->filename, s->open_flags, 0644); if (fd < 0) { s->fd = -1; return -EIO; From 90babde0cad8a485e5f74a2113c0425c08395a47 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Jun 2009 13:53:38 +0200 Subject: [PATCH 3/6] raw-posix: add a raw_open_common helper raw_open and hdev_open contain the same basic logic. Add a new raw_open_common helper containing the guts of the open routine and call it from raw_open and hdev_open. We use the new open_flags field in BDRVRawState to allow passing additional open flags to raw_open_common from both. Signed-off-by: Christoph Hellwig --- block/raw-posix.c | 48 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 29 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index 6e8dfbdb38..ae2f70f01d 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -124,7 +124,8 @@ static int cd_open(BlockDriverState *bs); 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, ret; @@ -140,8 +141,6 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) s->open_flags |= O_RDONLY; bs->read_only = 1; } - if (flags & BDRV_O_CREAT) - s->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. */ @@ -150,8 +149,7 @@ static int raw_open(BlockDriverState *bs, const char *filename, int flags) else if (!(flags & BDRV_O_CACHE_WB)) s->open_flags |= O_DSYNC; - s->type = FTYPE_FILE; - + s->fd = -1; fd = open(filename, s->open_flags, 0644); if (fd < 0) { ret = -errno; @@ -172,6 +170,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 { @@ -949,9 +958,7 @@ 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, ret; - - posix_aio_init(); + int ret; #ifdef CONFIG_COCOA if (strstart(filename, "/dev/cdrom", NULL)) { @@ -979,19 +986,6 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) IOObjectRelease( mediaIterator ); } #endif - s->open_flags |= O_BINARY; - if ((flags & BDRV_O_ACCESS) == O_RDWR) { - s->open_flags |= O_RDWR; - } else { - s->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)) - s->open_flags |= O_DIRECT; - else if (!(flags & BDRV_O_CACHE_WB)) - s->open_flags |= O_DSYNC; s->type = FTYPE_FILE; #if defined(__linux__) @@ -1015,15 +1009,11 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) s->type = FTYPE_CD; } #endif - s->fd = -1; - fd = open(filename, s->open_flags, 0644); - if (fd < 0) { - ret = -errno; - if (ret == -EROFS) - ret = -EACCES; + + ret = raw_open_common(bs, filename, flags); + if (ret) return ret; - } - s->fd = fd; + #if defined(__FreeBSD__) /* make sure the door isnt locked at this time */ if (s->type == FTYPE_CD) From f3a5d3f8a1a992376e3dd128ceee917cd1281da7 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Jun 2009 13:55:19 +0200 Subject: [PATCH 4/6] raw-posix: split hdev drivers Instead of declaring one BlockDriver for all host devices declared one for each type: a generic one for normal disk devices, a Linux floppy driver and a CDROM driver for Linux and FreeBSD. This gets rid of a lot of messy ifdefs and switching based on the type in the various removal device methods. block.c grows a new method to find the correct host device driver based on OS-sepcific criteria, which will later into the actual drivers in a later patch in this series. Signed-off-by: Christoph Hellwig --- block.c | 66 ++++-- block/raw-posix.c | 566 +++++++++++++++++++++++++--------------------- 2 files changed, 351 insertions(+), 281 deletions(-) diff --git a/block.c b/block.c index e6b91c60ac..2e2059333c 100644 --- a/block.c +++ b/block.c @@ -249,8 +249,48 @@ 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. + */ +#ifdef _WIN32 +static BlockDriver *find_hdev_driver(const char *filename) +{ + if (strstart(filename, "/dev/cdrom", NULL)) + return bdrv_find_format("host_device"); + if (is_windows_drive(filename)) + return bdrv_find_format("host_device"); + return NULL; +} +#else +static BlockDriver *find_hdev_driver(const char *filename) +{ + struct stat st; + +#ifdef __linux__ + if (strstart(filename, "/dev/fd", NULL)) + return bdrv_find_format("host_floppy"); + if (strstart(filename, "/dev/cd", NULL)) + return bdrv_find_format("host_cdrom"); +#elif defined(__FreeBSD__) + if (strstart(filename, "/dev/cd", NULL) || + strstart(filename, "/dev/acd", NULL)) { + return bdrv_find_format("host_cdrom"); + } +#else + if (strstart(filename, "/dev/cdrom", NULL)) + return bdrv_find_format("host_device"); +#endif + + if (stat(filename, &st) >= 0 && + (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) { + return bdrv_find_format("host_device"); + } + + return NULL; +} +#endif + static BlockDriver *find_image_format(const char *filename) { int ret, score, score_max; @@ -258,23 +298,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 +417,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 ae2f70f01d..d7f9b4843e 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -119,11 +119,9 @@ 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_common(BlockDriverState *bs, const char *filename, int flags) { @@ -808,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; } @@ -958,7 +956,6 @@ 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 ret; #ifdef CONFIG_COCOA if (strstart(filename, "/dev/cdrom", NULL)) { @@ -988,46 +985,13 @@ static int hdev_open(BlockDriverState *bs, const char *filename, int flags) #endif s->type = FTYPE_FILE; -#if defined(__linux__) - if (strstart(filename, "/dev/cd", NULL)) { - /* open will not fail even if no CD is inserted */ - s->open_flags |= O_NONBLOCK; - s->type = FTYPE_CD; - } else if (strstart(filename, "/dev/fd", NULL)) { - s->type = FTYPE_FD; - /* open will not fail even if no floppy is inserted */ - s->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; } #endif - ret = raw_open_common(bs, filename, flags); - if (ret) - return ret; - -#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__) @@ -1080,105 +1044,6 @@ 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->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) { BDRVRawState *s = bs->opaque; @@ -1220,7 +1085,6 @@ static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs, #endif #elif defined(__FreeBSD__) - static int fd_open(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -1231,99 +1095,6 @@ static int fd_open(BlockDriverState *bs) return -EIO; } -static int cd_open(BlockDriverState *bs) -{ -#if defined(__FreeBSD__) - BDRVRawState *s = bs->opaque; - int fd; - - 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->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); - } -#endif - return 0; -} - -static int raw_is_inserted(BlockDriverState *bs) -{ - BDRVRawState *s = bs->opaque; - - switch(s->type) { - case FTYPE_CD: - return (raw_getlength(bs) > 0); - case FTYPE_FD: - /* XXX handle this */ - /* FALLTHRU */ - default: - return 1; - } -} - -static int raw_media_changed(BlockDriverState *bs) -{ - return -ENOTSUP; -} - -static int raw_eject(BlockDriverState *bs, int eject_flag) -{ - BDRVRawState *s = bs->opaque; - - 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; - } - return 0; -} - -static int raw_set_locked(BlockDriverState *bs, int locked) -{ - 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; -} - static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) { return -ENOTSUP; @@ -1335,26 +1106,6 @@ static int fd_open(BlockDriverState *bs) return 0; } -static int raw_is_inserted(BlockDriverState *bs) -{ - return 1; -} - -static int raw_media_changed(BlockDriverState *bs) -{ - return -ENOTSUP; -} - -static int raw_eject(BlockDriverState *bs, int eject_flag) -{ - return -ENOTSUP; -} - -static int raw_set_locked(BlockDriverState *bs, int locked) -{ - return -ENOTSUP; -} - static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) { return -ENOTSUP; @@ -1415,22 +1166,315 @@ static BlockDriver bdrv_host_device = { .bdrv_write = raw_write, .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, + .bdrv_ioctl = raw_ioctl, #ifdef CONFIG_AIO - .bdrv_aio_ioctl = raw_aio_ioctl, + .bdrv_aio_ioctl = raw_aio_ioctl, #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 floppy_is_inserted(BlockDriverState *bs) +{ + return fd_open(bs) >= 0; +} + +static int floppy_media_changed(BlockDriverState *bs) +{ + 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 floppy_eject(BlockDriverState *bs, int eject_flag) +{ + BDRVRawState *s = bs->opaque; + int fd; + + 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 BlockDriver bdrv_host_floppy = { + .format_name = "host_floppy", + .instance_size = sizeof(BDRVRawState), + .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, + + /* 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); +} + +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 cdrom_eject(BlockDriverState *bs, int eject_flag) +{ + 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 cdrom_set_locked(BlockDriverState *bs, int locked) +{ + 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 BlockDriver bdrv_host_cdrom = { + .format_name = "host_cdrom", + .instance_size = sizeof(BDRVRawState), + .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 = raw_ioctl, +#ifdef CONFIG_AIO + .bdrv_aio_ioctl = raw_aio_ioctl, +#endif +}; +#endif /* __linux__ */ + +#ifdef __FreeBSD__ +static int cdrom_open(BlockDriverState *bs, const char *filename, int flags) +{ + 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 cdrom_reopen(BlockDriverState *bs) +{ + 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 int cdrom_is_inserted(BlockDriverState *bs) +{ + return raw_getlength(bs) > 0; +} + +static int cdrom_eject(BlockDriverState *bs, int eject_flag) +{ + BDRVRawState *s = bs->opaque; + + 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 (cdrom_reopen(bs) < 0) + return -ENOTSUP; + return 0; +} + +static int cdrom_set_locked(BlockDriverState *bs, int locked) +{ + BDRVRawState *s = bs->opaque; + + 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_cdrom = { + .format_name = "host_cdrom", + .instance_size = sizeof(BDRVRawState), + .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 = raw_ioctl, +#ifdef CONFIG_AIO + .bdrv_aio_ioctl = raw_aio_ioctl, +#endif +}; +#endif /* __FreeBSD__ */ + static void bdrv_raw_init(void) { 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); From 508c7cb3fa666f0c4723946869f318ec7751ecbd Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Jun 2009 14:04:22 +0200 Subject: [PATCH 5/6] block: add bdrv_probe_device method Add a bdrv_probe_device method to all BlockDriver instances implementing host devices to move matching of host device types into the actual drivers. For now we keep exacly the old matching behaviour based on the devices names, although we really should have better detetion methods based on device information in the future. Signed-off-by: Christoph Hellwig --- block.c | 44 ++++++++++++-------------------------------- block/raw-posix.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ block/raw-win32.c | 10 ++++++++++ block_int.h | 5 +++++ 4 files changed, 74 insertions(+), 32 deletions(-) diff --git a/block.c b/block.c index 2e2059333c..c7e0dcbc5c 100644 --- a/block.c +++ b/block.c @@ -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') @@ -253,43 +253,23 @@ static BlockDriver *find_protocol(const char *filename) * Detect host devices. By convention, /dev/cdrom[N] is always * recognized as a host CDROM. */ -#ifdef _WIN32 static BlockDriver *find_hdev_driver(const char *filename) { - if (strstart(filename, "/dev/cdrom", NULL)) - return bdrv_find_format("host_device"); - if (is_windows_drive(filename)) - return bdrv_find_format("host_device"); - return NULL; -} -#else -static BlockDriver *find_hdev_driver(const char *filename) -{ - struct stat st; + int score_max = 0, score; + BlockDriver *drv = NULL, *d; -#ifdef __linux__ - if (strstart(filename, "/dev/fd", NULL)) - return bdrv_find_format("host_floppy"); - if (strstart(filename, "/dev/cd", NULL)) - return bdrv_find_format("host_cdrom"); -#elif defined(__FreeBSD__) - if (strstart(filename, "/dev/cd", NULL) || - strstart(filename, "/dev/acd", NULL)) { - return bdrv_find_format("host_cdrom"); - } -#else - if (strstart(filename, "/dev/cdrom", NULL)) - return bdrv_find_format("host_device"); -#endif - - if (stat(filename, &st) >= 0 && - (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))) { - return bdrv_find_format("host_device"); + 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 NULL; + return drv; } -#endif static BlockDriver *find_image_format(const char *filename) { diff --git a/block/raw-posix.c b/block/raw-posix.c index d7f9b4843e..5e65da00a7 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -953,6 +953,22 @@ 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; @@ -1152,6 +1168,7 @@ 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, .bdrv_create = hdev_create, @@ -1197,6 +1214,14 @@ static int floppy_open(BlockDriverState *bs, const char *filename, int flags) return 0; } +static int floppy_probe_device(const char *filename) +{ + if (strstart(filename, "/dev/fd", NULL)) + return 100; + return 0; +} + + static int floppy_is_inserted(BlockDriverState *bs) { return fd_open(bs) >= 0; @@ -1242,6 +1267,7 @@ static int floppy_eject(BlockDriverState *bs, int eject_flag) 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, @@ -1279,6 +1305,13 @@ static int cdrom_open(BlockDriverState *bs, const char *filename, int flags) return raw_open_common(bs, filename, flags); } +static int cdrom_probe_device(const char *filename) +{ + if (strstart(filename, "/dev/cd", NULL)) + return 100; + return 0; +} + static int cdrom_is_inserted(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -1323,6 +1356,7 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked) 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, @@ -1367,6 +1401,14 @@ static int cdrom_open(BlockDriverState *bs, const char *filename, int flags) return 0; } +static int cdrom_probe_device(const char *filename) +{ + if (strstart(filename, "/dev/cd", NULL) || + strstart(filename, "/dev/acd", NULL)) + return 100; + return 0; +} + static int cdrom_reopen(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -1437,6 +1479,7 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked) 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, @@ -1466,6 +1509,10 @@ static BlockDriver bdrv_host_cdrom = { 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__ 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 */ From 63ec93db2178c8caaecd546e640f2fa2296c0a5a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Mon, 15 Jun 2009 14:04:34 +0200 Subject: [PATCH 6/6] raw-posix: cleanup ioctl methods Rename raw_ioctl and raw_aio_ioctl to hdev_ioctl and hdev_aio_ioctl as they are only used for the host device. Also only add them to the method table for the cases where we need them (generic hdev if linux and linux CDROM) instead of declaring stubs and always add them. Signed-off-by: Christoph Hellwig --- block/raw-posix.c | 42 ++++++++---------------------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/block/raw-posix.c b/block/raw-posix.c index 5e65da00a7..50323485f9 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -1060,7 +1060,7 @@ 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; @@ -1068,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) { @@ -1110,11 +1110,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 +1117,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) @@ -1184,9 +1168,11 @@ static BlockDriver bdrv_host_device = { .bdrv_getlength = raw_getlength, /* generic scsi device */ - .bdrv_ioctl = raw_ioctl, +#ifdef __linux__ + .bdrv_ioctl = hdev_ioctl, #ifdef CONFIG_AIO - .bdrv_aio_ioctl = raw_aio_ioctl, + .bdrv_aio_ioctl = hdev_aio_ioctl, +#endif #endif }; @@ -1286,12 +1272,6 @@ 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) @@ -1377,9 +1357,9 @@ static BlockDriver bdrv_host_cdrom = { .bdrv_set_locked = cdrom_set_locked, /* generic scsi device */ - .bdrv_ioctl = raw_ioctl, + .bdrv_ioctl = hdev_ioctl, #ifdef CONFIG_AIO - .bdrv_aio_ioctl = raw_aio_ioctl, + .bdrv_aio_ioctl = hdev_aio_ioctl, #endif }; #endif /* __linux__ */ @@ -1498,12 +1478,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__ */