From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1M8V6F-0004oV-6L for qemu-devel@nongnu.org; Mon, 25 May 2009 03:59:59 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1M8V69-0004mV-7r for qemu-devel@nongnu.org; Mon, 25 May 2009 03:59:57 -0400 Received: from [199.232.76.173] (port=43358 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1M8V69-0004mR-3T for qemu-devel@nongnu.org; Mon, 25 May 2009 03:59:53 -0400 Received: from mx20.gnu.org ([199.232.41.8]:41454) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1M8V68-0005s9-1R for qemu-devel@nongnu.org; Mon, 25 May 2009 03:59:52 -0400 Received: from verein.lst.de ([213.95.11.210]) by mx20.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1M8V66-00053G-PC for qemu-devel@nongnu.org; Mon, 25 May 2009 03:59:51 -0400 Received: from verein.lst.de (localhost [127.0.0.1]) by verein.lst.de (8.12.3/8.12.3/Debian-7.1) with ESMTP id n4P7xnIF003060 (version=TLSv1/SSLv3 cipher=EDH-RSA-DES-CBC3-SHA bits=168 verify=NO) for ; Mon, 25 May 2009 09:59:49 +0200 Received: (from hch@localhost) by verein.lst.de (8.12.3/8.12.3/Debian-6.6) id n4P7xnjs003058 for qemu-devel@nongnu.org; Mon, 25 May 2009 09:59:49 +0200 Date: Mon, 25 May 2009 09:59:49 +0200 From: Christoph Hellwig Message-ID: <20090525075949.GC2936@lst.de> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Subject: [Qemu-devel] [PATCH 3/4] raw-posix: split hdev drivers List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org 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. I would love to move this into some OS-dependant file but I don't think we have a place where it fits nicely yet. Signed-off-by: Christoph Hellwig Index: qemu/block.c =================================================================== --- qemu.orig/block.c 2009-05-25 09:20:12.001840379 +0200 +++ qemu/block.c 2009-05-25 09:29:12.989848226 +0200 @@ -300,32 +300,55 @@ static BlockDriver *find_protocol(const return NULL; } -/* XXX: force raw format if block or character device ? It would - simplify the BSD case */ -static BlockDriver *find_image_format(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) { - int ret, score, score_max; - BlockDriver *drv1, *drv; - 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"); + 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 - { - struct stat st; - if (stat(filename, &st) >= 0 && + 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 bdrv_find_format("host_device"); } + + return NULL; +} #endif +static BlockDriver *find_image_format(const char *filename) +{ + int ret, score, score_max; + BlockDriver *drv1, *drv; + uint8_t buf[2048]; + BlockDriverState *bs; + drv = find_protocol(filename); /* no need to test disk image formats for vvfat */ if (drv && strcmp(drv->format_name, "vvfat") == 0) @@ -434,7 +457,10 @@ int bdrv_open2(BlockDriverState *bs, con 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; Index: qemu/block/raw-posix.c =================================================================== --- qemu.orig/block/raw-posix.c 2009-05-25 09:24:54.482814647 +0200 +++ qemu/block/raw-posix.c 2009-05-25 09:44:43.931816385 +0200 @@ -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) { @@ -803,7 +801,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; } @@ -951,7 +949,6 @@ kern_return_t GetBSDPath( io_iterator_t 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)) { @@ -981,46 +978,13 @@ static int hdev_open(BlockDriverState *b #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__) @@ -1073,105 +1037,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; @@ -1213,7 +1078,6 @@ static BlockDriverAIOCB *raw_aio_ioctl(B #endif #elif defined(__FreeBSD__) - static int fd_open(BlockDriverState *bs) { BDRVRawState *s = bs->opaque; @@ -1224,99 +1088,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; @@ -1328,26 +1099,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; @@ -1419,22 +1170,321 @@ static BlockDriver bdrv_host_device = { .bdrv_write = raw_write, .bdrv_getlength = raw_getlength, + /* generic scsi device */ + .bdrv_ioctl = raw_ioctl, +#ifdef CONFIG_AIO + .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, + .bdrv_aio_cancel = raw_aio_cancel, + .aiocb_size = sizeof(RawAIOCB), +#endif + + .bdrv_read = raw_read, + .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, + .bdrv_is_inserted = floppy_is_inserted, + .bdrv_media_changed = floppy_media_changed, + .bdrv_eject = floppy_eject, + /* 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 }; +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, + .bdrv_aio_cancel = raw_aio_cancel, + .aiocb_size = sizeof(RawAIOCB), +#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, + .bdrv_aio_cancel = raw_aio_cancel, + .aiocb_size = sizeof(RawAIOCB), +#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);