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 <hch@lst.de>
This commit is contained in:
Christoph Hellwig 2009-06-15 13:55:19 +02:00 committed by Christoph Hellwig
parent 90babde0ca
commit f3a5d3f8a1
2 changed files with 351 additions and 281 deletions

66
block.c
View File

@ -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;

View File

@ -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);