bool has_discard:1;
bool has_write_zeroes:1;
bool discard_zeroes:1;
+#ifdef CONFIG_FIEMAP
+ bool skip_fiemap;
+#endif
} BDRVRawState;
typedef struct BDRVRawReopenState {
}
}
+static void raw_detach_aio_context(BlockDriverState *bs)
+{
+#ifdef CONFIG_LINUX_AIO
+ BDRVRawState *s = bs->opaque;
+
+ if (s->use_aio) {
+ laio_detach_aio_context(s->aio_ctx, bdrv_get_aio_context(bs));
+ }
+#endif
+}
+
+static void raw_attach_aio_context(BlockDriverState *bs,
+ AioContext *new_context)
+{
+#ifdef CONFIG_LINUX_AIO
+ BDRVRawState *s = bs->opaque;
+
+ if (s->use_aio) {
+ laio_attach_aio_context(s->aio_ctx, new_context);
+ }
+#endif
+}
+
#ifdef CONFIG_LINUX_AIO
static int raw_set_aio(void **aio_ctx, int *use_aio, int bdrv_flags)
{
}
#endif
+static void raw_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ /* The filename does not have to be prefixed by the protocol name, since
+ * "file" is the default protocol; therefore, the return value of this
+ * function call can be ignored. */
+ strstart(filename, "file:", &filename);
+
+ qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+
static QemuOptsList raw_runtime_opts = {
.name = "raw",
.head = QTAILQ_HEAD_INITIALIZER(raw_runtime_opts.head),
BDRVRawState *s = bs->opaque;
QemuOpts *opts;
Error *local_err = NULL;
- const char *filename;
+ const char *filename = NULL;
int fd, ret;
struct stat st;
}
#endif
+ raw_attach_aio_context(bs, bdrv_get_aio_context(bs));
+
ret = 0;
fail:
+ if (filename && (bdrv_flags & BDRV_O_TEMPORARY)) {
+ unlink(filename);
+ }
qemu_opts_del(opts);
return ret;
}
static void raw_close(BlockDriverState *bs)
{
BDRVRawState *s = bs->opaque;
+
+ raw_detach_aio_context(bs);
+
+#ifdef CONFIG_LINUX_AIO
+ if (s->use_aio) {
+ laio_cleanup(s->aio_ctx);
+ }
+#endif
if (s->fd >= 0) {
qemu_close(s->fd);
s->fd = -1;
if (size == 0)
#endif
#if defined(__APPLE__) && defined(__MACH__)
- size = LONG_LONG_MAX;
+ size = LLONG_MAX;
#else
size = lseek(fd, 0LL, SEEK_END);
#endif
int result = 0;
int64_t total_size = 0;
+ strstart(filename, "file:", &filename);
+
/* Read out options */
while (options && options->name) {
if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
return result;
}
-/*
- * Returns true iff the specified sector is present in the disk image. Drivers
- * not implementing the functionality are assumed to not support backing files,
- * hence all their sectors are reported as allocated.
- *
- * If 'sector_num' is beyond the end of the disk image the return value is 0
- * and 'pnum' is set to 0.
- *
- * 'pnum' is set to the number of sectors (including and immediately following
- * the specified sector) that are known to be in the same
- * allocated/unallocated state.
- *
- * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
- * beyond the end of the disk image it will be clamped.
- */
-static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
- int64_t sector_num,
- int nb_sectors, int *pnum)
+static int64_t try_fiemap(BlockDriverState *bs, off_t start, off_t *data,
+ off_t *hole, int nb_sectors, int *pnum)
{
- off_t start, data, hole;
- int64_t ret;
-
- ret = fd_open(bs);
- if (ret < 0) {
- return ret;
- }
-
- start = sector_num * BDRV_SECTOR_SIZE;
- ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
-
#ifdef CONFIG_FIEMAP
-
BDRVRawState *s = bs->opaque;
+ int64_t ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
struct {
struct fiemap fm;
struct fiemap_extent fe;
} f;
+ if (s->skip_fiemap) {
+ return -ENOTSUP;
+ }
+
f.fm.fm_start = start;
f.fm.fm_length = (int64_t)nb_sectors * BDRV_SECTOR_SIZE;
f.fm.fm_flags = 0;
f.fm.fm_extent_count = 1;
f.fm.fm_reserved = 0;
if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) {
- /* Assume everything is allocated. */
- *pnum = nb_sectors;
- return ret;
+ s->skip_fiemap = true;
+ return -errno;
}
if (f.fm.fm_mapped_extents == 0) {
* f.fm.fm_start + f.fm.fm_length must be clamped to the file size!
*/
off_t length = lseek(s->fd, 0, SEEK_END);
- hole = f.fm.fm_start;
- data = MIN(f.fm.fm_start + f.fm.fm_length, length);
+ *hole = f.fm.fm_start;
+ *data = MIN(f.fm.fm_start + f.fm.fm_length, length);
} else {
- data = f.fe.fe_logical;
- hole = f.fe.fe_logical + f.fe.fe_length;
+ *data = f.fe.fe_logical;
+ *hole = f.fe.fe_logical + f.fe.fe_length;
if (f.fe.fe_flags & FIEMAP_EXTENT_UNWRITTEN) {
ret |= BDRV_BLOCK_ZERO;
}
}
-#elif defined SEEK_HOLE && defined SEEK_DATA
+ return ret;
+#else
+ return -ENOTSUP;
+#endif
+}
+static int64_t try_seek_hole(BlockDriverState *bs, off_t start, off_t *data,
+ off_t *hole, int *pnum)
+{
+#if defined SEEK_HOLE && defined SEEK_DATA
BDRVRawState *s = bs->opaque;
- hole = lseek(s->fd, start, SEEK_HOLE);
- if (hole == -1) {
+ *hole = lseek(s->fd, start, SEEK_HOLE);
+ if (*hole == -1) {
/* -ENXIO indicates that sector_num was past the end of the file.
* There is a virtual hole there. */
assert(errno != -ENXIO);
- /* Most likely EINVAL. Assume everything is allocated. */
- *pnum = nb_sectors;
- return ret;
+ return -errno;
}
- if (hole > start) {
- data = start;
+ if (*hole > start) {
+ *data = start;
} else {
/* On a hole. We need another syscall to find its end. */
- data = lseek(s->fd, start, SEEK_DATA);
- if (data == -1) {
- data = lseek(s->fd, 0, SEEK_END);
+ *data = lseek(s->fd, start, SEEK_DATA);
+ if (*data == -1) {
+ *data = lseek(s->fd, 0, SEEK_END);
}
}
+
+ return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
#else
- data = 0;
- hole = start + nb_sectors * BDRV_SECTOR_SIZE;
+ return -ENOTSUP;
#endif
+}
+
+/*
+ * Returns true iff the specified sector is present in the disk image. Drivers
+ * not implementing the functionality are assumed to not support backing files,
+ * hence all their sectors are reported as allocated.
+ *
+ * If 'sector_num' is beyond the end of the disk image the return value is 0
+ * and 'pnum' is set to 0.
+ *
+ * 'pnum' is set to the number of sectors (including and immediately following
+ * the specified sector) that are known to be in the same
+ * allocated/unallocated state.
+ *
+ * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes
+ * beyond the end of the disk image it will be clamped.
+ */
+static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs,
+ int64_t sector_num,
+ int nb_sectors, int *pnum)
+{
+ off_t start, data = 0, hole = 0;
+ int64_t ret;
+
+ ret = fd_open(bs);
+ if (ret < 0) {
+ return ret;
+ }
+
+ start = sector_num * BDRV_SECTOR_SIZE;
+
+ ret = try_fiemap(bs, start, &data, &hole, nb_sectors, pnum);
+ if (ret < 0) {
+ ret = try_seek_hole(bs, start, &data, &hole, pnum);
+ if (ret < 0) {
+ /* Assume everything is allocated. */
+ data = 0;
+ hole = start + nb_sectors * BDRV_SECTOR_SIZE;
+ ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
+ }
+ }
if (data <= start) {
/* On a data extent, compute sectors to the end of the extent. */
.instance_size = sizeof(BDRVRawState),
.bdrv_needs_filename = true,
.bdrv_probe = NULL, /* no probe for protocols */
+ .bdrv_parse_filename = raw_parse_filename,
.bdrv_file_open = raw_open,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_reopen_commit = raw_reopen_commit,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
+ .bdrv_detach_aio_context = raw_detach_aio_context,
+ .bdrv_attach_aio_context = raw_attach_aio_context,
+
.create_options = raw_create_options,
};
return 0;
}
+static void hdev_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ /* The prefix is optional, just as for "file". */
+ strstart(filename, "host_device:", &filename);
+
+ qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+
static int hdev_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
int ret = 0;
struct stat stat_buf;
int64_t total_size = 0;
+ bool has_prefix;
+
+ /* This function is used by all three protocol block drivers and therefore
+ * any of these three prefixes may be given.
+ * The return value has to be stored somewhere, otherwise this is an error
+ * due to -Werror=unused-value. */
+ has_prefix =
+ strstart(filename, "host_device:", &filename) ||
+ strstart(filename, "host_cdrom:" , &filename) ||
+ strstart(filename, "host_floppy:", &filename);
+
+ (void)has_prefix;
/* Read out options */
while (options && options->name) {
.instance_size = sizeof(BDRVRawState),
.bdrv_needs_filename = true,
.bdrv_probe_device = hdev_probe_device,
+ .bdrv_parse_filename = hdev_parse_filename,
.bdrv_file_open = hdev_open,
.bdrv_close = raw_close,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
+ .bdrv_detach_aio_context = raw_detach_aio_context,
+ .bdrv_attach_aio_context = raw_attach_aio_context,
+
/* generic scsi device */
#ifdef __linux__
.bdrv_ioctl = hdev_ioctl,
};
#ifdef __linux__
+static void floppy_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ /* The prefix is optional, just as for "file". */
+ strstart(filename, "host_floppy:", &filename);
+
+ qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+
static int floppy_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
.instance_size = sizeof(BDRVRawState),
.bdrv_needs_filename = true,
.bdrv_probe_device = floppy_probe_device,
+ .bdrv_parse_filename = floppy_parse_filename,
.bdrv_file_open = floppy_open,
.bdrv_close = raw_close,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
+ .bdrv_detach_aio_context = raw_detach_aio_context,
+ .bdrv_attach_aio_context = raw_attach_aio_context,
+
/* removable device support */
.bdrv_is_inserted = floppy_is_inserted,
.bdrv_media_changed = floppy_media_changed,
.bdrv_eject = floppy_eject,
};
+#endif
+
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+static void cdrom_parse_filename(const char *filename, QDict *options,
+ Error **errp)
+{
+ /* The prefix is optional, just as for "file". */
+ strstart(filename, "host_cdrom:", &filename);
+ qdict_put_obj(options, "filename", QOBJECT(qstring_from_str(filename)));
+}
+#endif
+
+#ifdef __linux__
static int cdrom_open(BlockDriverState *bs, QDict *options, int flags,
Error **errp)
{
.instance_size = sizeof(BDRVRawState),
.bdrv_needs_filename = true,
.bdrv_probe_device = cdrom_probe_device,
+ .bdrv_parse_filename = cdrom_parse_filename,
.bdrv_file_open = cdrom_open,
.bdrv_close = raw_close,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
+ .bdrv_detach_aio_context = raw_detach_aio_context,
+ .bdrv_attach_aio_context = raw_attach_aio_context,
+
/* removable device support */
.bdrv_is_inserted = cdrom_is_inserted,
.bdrv_eject = cdrom_eject,
.instance_size = sizeof(BDRVRawState),
.bdrv_needs_filename = true,
.bdrv_probe_device = cdrom_probe_device,
+ .bdrv_parse_filename = cdrom_parse_filename,
.bdrv_file_open = cdrom_open,
.bdrv_close = raw_close,
.bdrv_reopen_prepare = raw_reopen_prepare,
.bdrv_get_allocated_file_size
= raw_get_allocated_file_size,
+ .bdrv_detach_aio_context = raw_detach_aio_context,
+ .bdrv_attach_aio_context = raw_attach_aio_context,
+
/* removable device support */
.bdrv_is_inserted = cdrom_is_inserted,
.bdrv_eject = cdrom_eject,
};
#endif /* __FreeBSD__ */
-#ifdef CONFIG_LINUX_AIO
-/**
- * Return the file descriptor for Linux AIO
- *
- * This function is a layering violation and should be removed when it becomes
- * possible to call the block layer outside the global mutex. It allows the
- * caller to hijack the file descriptor so I/O can be performed outside the
- * block layer.
- */
-int raw_get_aio_fd(BlockDriverState *bs)
-{
- BDRVRawState *s;
-
- if (!bs->drv) {
- return -ENOMEDIUM;
- }
-
- if (bs->drv == bdrv_find_format("raw")) {
- bs = bs->file;
- }
-
- /* raw-posix has several protocols so just check for raw_aio_readv */
- if (bs->drv->bdrv_aio_readv != raw_aio_readv) {
- return -ENOTSUP;
- }
-
- s = bs->opaque;
- if (!s->use_aio) {
- return -ENOTSUP;
- }
- return s->fd;
-}
-#endif /* CONFIG_LINUX_AIO */
-
static void bdrv_file_init(void)
{
/*