Newer
Older
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "block/trace.h"
#include "block/block_int.h"
#include "block/blockjob.h"
#include "module_block.h"
#include "qapi/qmp/qerror.h"
#include "sysemu/block-backend.h"
#include "sysemu/sysemu.h"
#include "qemu/coroutine.h"

Benoît Canet
committed
#include "block/qapi.h"
#include "qemu/cutils.h"
#include "qemu/id.h"
#ifdef _WIN32
#include <windows.h>
#endif
#define NOT_DONE 0x7fffffff /* used while emulated sync operation in progress */
static QTAILQ_HEAD(, BlockDriverState) graph_bdrv_states =
QTAILQ_HEAD_INITIALIZER(graph_bdrv_states);
static QTAILQ_HEAD(, BlockDriverState) all_bdrv_states =
QTAILQ_HEAD_INITIALIZER(all_bdrv_states);
static QLIST_HEAD(, BlockDriver) bdrv_drivers =
QLIST_HEAD_INITIALIZER(bdrv_drivers);
static BlockDriverState *bdrv_open_inherit(const char *filename,
const char *reference,
QDict *options, int flags,
BlockDriverState *parent,
const BdrvChildRole *child_role,
Error **errp);
/* If non-zero, use only whitelisted block drivers */
static int use_bdrv_whitelist;
#ifdef _WIN32
static int is_windows_drive_prefix(const char *filename)
{
return (((filename[0] >= 'a' && filename[0] <= 'z') ||
(filename[0] >= 'A' && filename[0] <= 'Z')) &&
filename[1] == ':');
}
int is_windows_drive(const char *filename)
{
if (is_windows_drive_prefix(filename) &&
filename[2] == '\0')
return 1;
if (strstart(filename, "\\\\.\\", NULL) ||
strstart(filename, "//./", NULL))
return 1;
return 0;
}
#endif
size_t bdrv_opt_mem_align(BlockDriverState *bs)
{
if (!bs || !bs->drv) {
/* page size or 4k (hdd sector size) should be on the safe side */
return MAX(4096, getpagesize());
}
return bs->bl.opt_mem_alignment;
}
size_t bdrv_min_mem_align(BlockDriverState *bs)
{
if (!bs || !bs->drv) {
/* page size or 4k (hdd sector size) should be on the safe side */
return MAX(4096, getpagesize());
}
return bs->bl.min_mem_alignment;
}
/* check if the path starts with "<protocol>:" */
int path_has_protocol(const char *path)
const char *p;
#ifdef _WIN32
if (is_windows_drive(path) ||
is_windows_drive_prefix(path)) {
return 0;
}
p = path + strcspn(path, ":/\\");
#else
p = path + strcspn(path, ":/");
return *p == ':';
#ifdef _WIN32
/* specific case for names like: "\\.\d:" */
if (is_windows_drive(path) || is_windows_drive_prefix(path)) {
}
return (*path == '/' || *path == '\\');
/* if filename is absolute, just copy it to dest. Otherwise, build a
path to it by considering it is relative to base_path. URL are
supported. */
void path_combine(char *dest, int dest_size,
const char *base_path,
const char *filename)
const char *p, *p1;
int len;
if (dest_size <= 0)
return;
if (path_is_absolute(filename)) {
pstrcpy(dest, dest_size, filename);
} else {
p = strchr(base_path, ':');
if (p)
p++;
else
p = base_path;
p1 = strrchr(base_path, '/');
#ifdef _WIN32
{
const char *p2;
p2 = strrchr(base_path, '\\');
if (!p1 || p2 > p1)
p1 = p2;
}
#endif
if (p1)
p1++;
else
p1 = base_path;
if (p1 > p)
p = p1;
len = p - base_path;
if (len > dest_size - 1)
len = dest_size - 1;
memcpy(dest, base_path, len);
dest[len] = '\0';
pstrcat(dest, dest_size, filename);
}
}
void bdrv_get_full_backing_filename_from_filename(const char *backed,
const char *backing,
char *dest, size_t sz,
Error **errp)
if (backing[0] == '\0' || path_has_protocol(backing) ||
path_is_absolute(backing))
{
} else if (backed[0] == '\0' || strstart(backed, "json:", NULL)) {
error_setg(errp, "Cannot use relative backing file names for '%s'",
backed);
} else {
path_combine(dest, sz, backed, backing);
}
}
void bdrv_get_full_backing_filename(BlockDriverState *bs, char *dest, size_t sz,
Error **errp)
char *backed = bs->exact_filename[0] ? bs->exact_filename : bs->filename;
bdrv_get_full_backing_filename_from_filename(backed, bs->backing_file,
dest, sz, errp);
void bdrv_register(BlockDriver *bdrv)
{
QLIST_INSERT_HEAD(&bdrv_drivers, bdrv, list);
BlockDriverState *bdrv_new(void)
{
BlockDriverState *bs;
int i;
bs = g_new0(BlockDriverState, 1);
for (i = 0; i < BLOCK_OP_TYPE_MAX; i++) {
QLIST_INIT(&bs->op_blockers[i]);
}
notifier_with_return_list_init(&bs->before_write_notifiers);
bs->aio_context = qemu_get_aio_context();
qemu_co_queue_init(&bs->flush_queue);
QTAILQ_INSERT_TAIL(&all_bdrv_states, bs, bs_list);
static BlockDriver *bdrv_do_find_format(const char *format_name)
QLIST_FOREACH(drv1, &bdrv_drivers, list) {
if (!strcmp(drv1->format_name, format_name)) {
BlockDriver *bdrv_find_format(const char *format_name)
{
BlockDriver *drv1;
int i;
drv1 = bdrv_do_find_format(format_name);
if (drv1) {
return drv1;
}
/* The driver isn't registered, maybe we need to load a module */
for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) {
if (!strcmp(block_driver_modules[i].format_name, format_name)) {
block_module_load_one(block_driver_modules[i].library_name);
break;
}
}
return bdrv_do_find_format(format_name);
}
static int bdrv_is_whitelisted(BlockDriver *drv, bool read_only)
static const char *whitelist_rw[] = {
CONFIG_BDRV_RW_WHITELIST
};
static const char *whitelist_ro[] = {
CONFIG_BDRV_RO_WHITELIST
if (!whitelist_rw[0] && !whitelist_ro[0]) {
return 1; /* no whitelist, anything goes */
for (p = whitelist_rw; *p; p++) {
if (!strcmp(drv->format_name, *p)) {
return 1;
}
}
if (read_only) {
for (p = whitelist_ro; *p; p++) {
if (!strcmp(drv->format_name, *p)) {
return 1;
}
}
}
bool bdrv_uses_whitelist(void)
{
return use_bdrv_whitelist;
}
typedef struct CreateCo {
BlockDriver *drv;
char *filename;
QemuOpts *opts;
} CreateCo;
static void coroutine_fn bdrv_create_co_entry(void *opaque)
{
Error *local_err = NULL;
int ret;
CreateCo *cco = opaque;
assert(cco->drv);
ret = cco->drv->bdrv_create(cco->filename, cco->opts, &local_err);
error_propagate(&cco->err, local_err);
int bdrv_create(BlockDriver *drv, const char* filename,
QemuOpts *opts, Error **errp)
int ret;
Coroutine *co;
CreateCo cco = {
.drv = drv,
.filename = g_strdup(filename),
.opts = opts,
error_setg(errp, "Driver '%s' does not support image creation", drv->format_name);
ret = -ENOTSUP;
goto out;
}
if (qemu_in_coroutine()) {
/* Fast-path if already in coroutine context */
bdrv_create_co_entry(&cco);
} else {
co = qemu_coroutine_create(bdrv_create_co_entry, &cco);
qemu_coroutine_enter(co);
aio_poll(qemu_get_aio_context(), true);
error_propagate(errp, cco.err);
} else {
error_setg_errno(errp, -ret, "Could not create image");
}
}
out:
g_free(cco.filename);
int bdrv_create_file(const char *filename, QemuOpts *opts, Error **errp)
{
BlockDriver *drv;
Error *local_err = NULL;
int ret;
drv = bdrv_find_protocol(filename, true, errp);
if (drv == NULL) {
return -ENOENT;
ret = bdrv_create(drv, filename, opts, &local_err);
error_propagate(errp, local_err);
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
/**
* Try to get @bs's logical and physical block size.
* On success, store them in @bsz struct and return 0.
* On failure return -errno.
* @bs must not be empty.
*/
int bdrv_probe_blocksizes(BlockDriverState *bs, BlockSizes *bsz)
{
BlockDriver *drv = bs->drv;
if (drv && drv->bdrv_probe_blocksizes) {
return drv->bdrv_probe_blocksizes(bs, bsz);
}
return -ENOTSUP;
}
/**
* Try to get @bs's geometry (cyls, heads, sectors).
* On success, store them in @geo struct and return 0.
* On failure return -errno.
* @bs must not be empty.
*/
int bdrv_probe_geometry(BlockDriverState *bs, HDGeometry *geo)
{
BlockDriver *drv = bs->drv;
if (drv && drv->bdrv_probe_geometry) {
return drv->bdrv_probe_geometry(bs, geo);
}
return -ENOTSUP;
}
/*
* Create a uniquely-named empty temporary file.
* Return 0 upon success, otherwise a negative errno value.
*/
int get_tmp_filename(char *filename, int size)
char temp_dir[MAX_PATH];
/* GetTempFileName requires that its output buffer (4th param)
have length MAX_PATH or greater. */
assert(size >= MAX_PATH);
return (GetTempPath(MAX_PATH, temp_dir)
&& GetTempFileName(temp_dir, "qem", 0, filename)
? 0 : -GetLastError());
const char *tmpdir;
if (!tmpdir) {
tmpdir = "/var/tmp";
}
if (snprintf(filename, size, "%s/vl.XXXXXX", tmpdir) >= size) {
return -EOVERFLOW;
}
if (fd < 0) {
return -errno;
}
if (close(fd) != 0) {
unlink(filename);
return -errno;
}
return 0;
/*
* 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;
QLIST_FOREACH(d, &bdrv_drivers, list) {
if (d->bdrv_probe_device) {
score = d->bdrv_probe_device(filename);
if (score > score_max) {
score_max = score;
drv = d;
}
}
}
return drv;
}
static BlockDriver *bdrv_do_find_protocol(const char *protocol)
{
BlockDriver *drv1;
QLIST_FOREACH(drv1, &bdrv_drivers, list) {
if (drv1->protocol_name && !strcmp(drv1->protocol_name, protocol)) {
return drv1;
}
}
return NULL;
}
BlockDriver *bdrv_find_protocol(const char *filename,
bool allow_protocol_prefix,
Error **errp)
/* TODO Drivers without bdrv_file_open must be specified explicitly */
/*
* XXX(hch): we really should not let host device detection
* override an explicit protocol specification, but moving this
* later breaks access to device names with colons in them.
* Thanks to the brain-dead persistent naming schemes on udev-
* based Linux systems those actually are quite common.
*/
drv1 = find_hdev_driver(filename);
if (drv1) {
return drv1;
}
if (!path_has_protocol(filename) || !allow_protocol_prefix) {
p = strchr(filename, ':');
assert(p != NULL);
len = p - filename;
if (len > sizeof(protocol) - 1)
len = sizeof(protocol) - 1;
memcpy(protocol, filename, len);
protocol[len] = '\0';
drv1 = bdrv_do_find_protocol(protocol);
if (drv1) {
return drv1;
}
for (i = 0; i < (int)ARRAY_SIZE(block_driver_modules); ++i) {
if (block_driver_modules[i].protocol_name &&
!strcmp(block_driver_modules[i].protocol_name, protocol)) {
block_module_load_one(block_driver_modules[i].library_name);
break;
drv1 = bdrv_do_find_protocol(protocol);
if (!drv1) {
error_setg(errp, "Unknown protocol '%s'", protocol);
}
return drv1;
/*
* Guess image format by probing its contents.
* This is not a good idea when your image is raw (CVE-2008-2004), but
* we do it anyway for backward compatibility.
*
* @buf contains the image's first @buf_size bytes.
* @buf_size is the buffer size in bytes (generally BLOCK_PROBE_BUF_SIZE,
* but can be smaller if the image file is smaller)
* @filename is its filename.
*
* For all block drivers, call the bdrv_probe() method to get its
* probing score.
* Return the first block driver with the highest probing score.
*/
BlockDriver *bdrv_probe_all(const uint8_t *buf, int buf_size,
const char *filename)
{
int score_max = 0, score;
BlockDriver *drv = NULL, *d;
QLIST_FOREACH(d, &bdrv_drivers, list) {
if (d->bdrv_probe) {
score = d->bdrv_probe(buf, buf_size, filename);
if (score > score_max) {
score_max = score;
drv = d;
}
}
}
return drv;
}
static int find_image_format(BlockBackend *file, const char *filename,
BlockDriver **pdrv, Error **errp)
BlockDriver *drv;
uint8_t buf[BLOCK_PROBE_BUF_SIZE];

Nicholas Bellinger
committed
/* Return the raw BlockDriver * to scsi-generic devices or empty drives */
if (blk_is_sg(file) || !blk_is_inserted(file) || blk_getlength(file) == 0) {

Nicholas Bellinger
committed
}

Nicholas Bellinger
committed
ret = blk_pread(file, 0, buf, sizeof(buf));
error_setg_errno(errp, -ret, "Could not read image for determining its "
"format");
*pdrv = NULL;
return ret;
drv = bdrv_probe_all(buf, ret, filename);
error_setg(errp, "Could not determine image format: No compatible "
"driver found");
ret = -ENOENT;
}
*pdrv = drv;
return ret;
/**
* Set the current 'total_sectors' value
* Return 0 on success, -errno on error.
*/
static int refresh_total_sectors(BlockDriverState *bs, int64_t hint)
{
BlockDriver *drv = bs->drv;
/* Do not attempt drv->bdrv_getlength() on scsi-generic devices */
return 0;
/* query actual device if possible, otherwise just trust the hint */
if (drv->bdrv_getlength) {
int64_t length = drv->bdrv_getlength(bs);
if (length < 0) {
return length;
}
hint = DIV_ROUND_UP(length, BDRV_SECTOR_SIZE);
}
bs->total_sectors = hint;
return 0;
}
/**
* Combines a QDict of new block driver @options with any missing options taken
* from @old_options, so that leaving out an option defaults to its old value.
*/
static void bdrv_join_options(BlockDriverState *bs, QDict *options,
QDict *old_options)
{
if (bs->drv && bs->drv->bdrv_join_options) {
bs->drv->bdrv_join_options(options, old_options);
} else {
qdict_join(options, old_options, false);
}
}
/**
* Set open flags for a given discard mode
*
* Return 0 on success, -1 if the discard mode was invalid.
*/
int bdrv_parse_discard_flags(const char *mode, int *flags)
{
*flags &= ~BDRV_O_UNMAP;
if (!strcmp(mode, "off") || !strcmp(mode, "ignore")) {
/* do nothing */
} else if (!strcmp(mode, "on") || !strcmp(mode, "unmap")) {
*flags |= BDRV_O_UNMAP;
} else {
return -1;
}
return 0;
}
/**
* Set open flags for a given cache mode
*
* Return 0 on success, -1 if the cache mode was invalid.
*/
int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough)
{
*flags &= ~BDRV_O_CACHE_MASK;
if (!strcmp(mode, "off") || !strcmp(mode, "none")) {
*writethrough = false;
*flags |= BDRV_O_NOCACHE;
} else if (!strcmp(mode, "directsync")) {
*flags |= BDRV_O_NOCACHE;
} else if (!strcmp(mode, "writeback")) {
} else if (!strcmp(mode, "unsafe")) {
*flags |= BDRV_O_NO_FLUSH;
} else if (!strcmp(mode, "writethrough")) {
} else {
return -1;
}
return 0;
}
static char *bdrv_child_get_parent_desc(BdrvChild *c)
{
BlockDriverState *parent = c->opaque;
return g_strdup(bdrv_get_device_or_node_name(parent));
}
static void bdrv_child_cb_drained_begin(BdrvChild *child)
{
BlockDriverState *bs = child->opaque;
bdrv_drained_begin(bs);
}
static void bdrv_child_cb_drained_end(BdrvChild *child)
{
BlockDriverState *bs = child->opaque;
bdrv_drained_end(bs);
}
* Returns the options and flags that a temporary snapshot should get, based on
* the originally requested flags (the originally requested image will have
* flags like a backing file)
static void bdrv_temp_snapshot_options(int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options)
*child_flags = (parent_flags & ~BDRV_O_SNAPSHOT) | BDRV_O_TEMPORARY;
/* For temporary files, unconditional cache=unsafe is fine */
qdict_set_default_str(child_options, BDRV_OPT_CACHE_DIRECT, "off");
qdict_set_default_str(child_options, BDRV_OPT_CACHE_NO_FLUSH, "on");
/* Copy the read-only option from the parent */
qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
/* aio=native doesn't work for cache.direct=off, so disable it for the
* temporary snapshot */
*child_flags &= ~BDRV_O_NATIVE_AIO;
* Returns the options and flags that bs->file should get if a protocol driver
* is expected, based on the given options and flags for the parent BDS
static void bdrv_inherited_options(int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options)
int flags = parent_flags;
/* Enable protocol handling, disable format probing for bs->file */
flags |= BDRV_O_PROTOCOL;
/* If the cache mode isn't explicitly set, inherit direct and no-flush from
* the parent. */
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
/* Inherit the read-only option from the parent if it's not set */
qdict_copy_default(child_options, parent_options, BDRV_OPT_READ_ONLY);
/* Our block drivers take care to send flushes and respect unmap policy,
* so we can default to enable both on lower layers regardless of the
* corresponding parent options. */
qdict_set_default_str(child_options, BDRV_OPT_DISCARD, "unmap");
/* Clear flags that only apply to the top layer */
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_COPY_ON_READ |
BDRV_O_NO_IO);
const BdrvChildRole child_file = {
.get_parent_desc = bdrv_child_get_parent_desc,
.inherit_options = bdrv_inherited_options,
.drained_begin = bdrv_child_cb_drained_begin,
.drained_end = bdrv_child_cb_drained_end,
* Returns the options and flags that bs->file should get if the use of formats
* (and not only protocols) is permitted for it, based on the given options and
* flags for the parent BDS
static void bdrv_inherited_fmt_options(int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options)
child_file.inherit_options(child_flags, child_options,
parent_flags, parent_options);
*child_flags &= ~(BDRV_O_PROTOCOL | BDRV_O_NO_IO);
}
const BdrvChildRole child_format = {
.get_parent_desc = bdrv_child_get_parent_desc,
.inherit_options = bdrv_inherited_fmt_options,
.drained_begin = bdrv_child_cb_drained_begin,
.drained_end = bdrv_child_cb_drained_end,
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
static void bdrv_backing_attach(BdrvChild *c)
{
BlockDriverState *parent = c->opaque;
BlockDriverState *backing_hd = c->bs;
assert(!parent->backing_blocker);
error_setg(&parent->backing_blocker,
"node is used as backing hd of '%s'",
bdrv_get_device_or_node_name(parent));
parent->open_flags &= ~BDRV_O_NO_BACKING;
pstrcpy(parent->backing_file, sizeof(parent->backing_file),
backing_hd->filename);
pstrcpy(parent->backing_format, sizeof(parent->backing_format),
backing_hd->drv ? backing_hd->drv->format_name : "");
bdrv_op_block_all(backing_hd, parent->backing_blocker);
/* Otherwise we won't be able to commit or stream */
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_COMMIT_TARGET,
parent->backing_blocker);
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_STREAM,
parent->backing_blocker);
/*
* We do backup in 3 ways:
* 1. drive backup
* The target bs is new opened, and the source is top BDS
* 2. blockdev backup
* Both the source and the target are top BDSes.
* 3. internal backup(used for block replication)
* Both the source and the target are backing file
*
* In case 1 and 2, neither the source nor the target is the backing file.
* In case 3, we will block the top BDS, so there is only one block job
* for the top BDS and its backing chain.
*/
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_SOURCE,
parent->backing_blocker);
bdrv_op_unblock(backing_hd, BLOCK_OP_TYPE_BACKUP_TARGET,
parent->backing_blocker);
}
static void bdrv_backing_detach(BdrvChild *c)
{
BlockDriverState *parent = c->opaque;
assert(parent->backing_blocker);
bdrv_op_unblock_all(c->bs, parent->backing_blocker);
error_free(parent->backing_blocker);
parent->backing_blocker = NULL;
}
* Returns the options and flags that bs->backing should get, based on the
* given options and flags for the parent BDS
static void bdrv_backing_options(int *child_flags, QDict *child_options,
int parent_flags, QDict *parent_options)
int flags = parent_flags;
/* The cache mode is inherited unmodified for backing files; except WCE,
* which is only applied on the top level (BlockBackend) */
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_DIRECT);
qdict_copy_default(child_options, parent_options, BDRV_OPT_CACHE_NO_FLUSH);
/* backing files always opened read-only */
qdict_set_default_str(child_options, BDRV_OPT_READ_ONLY, "on");
flags &= ~BDRV_O_COPY_ON_READ;
/* snapshot=on is handled on the top layer */
flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_TEMPORARY);
.get_parent_desc = bdrv_child_get_parent_desc,
.attach = bdrv_backing_attach,
.detach = bdrv_backing_detach,
.inherit_options = bdrv_backing_options,
.drained_begin = bdrv_child_cb_drained_begin,
.drained_end = bdrv_child_cb_drained_end,
static int bdrv_open_flags(BlockDriverState *bs, int flags)
{
/*
* Clear flags that are internal to the block layer before opening the
* image.
*/
open_flags &= ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING | BDRV_O_PROTOCOL);
/*
* Snapshots should be writable.
*/
if (flags & BDRV_O_TEMPORARY) {
open_flags |= BDRV_O_RDWR;
}
return open_flags;
}
static void update_flags_from_options(int *flags, QemuOpts *opts)
{
*flags &= ~BDRV_O_CACHE_MASK;
assert(qemu_opt_find(opts, BDRV_OPT_CACHE_NO_FLUSH));
if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_NO_FLUSH, false)) {
*flags |= BDRV_O_NO_FLUSH;
}
assert(qemu_opt_find(opts, BDRV_OPT_CACHE_DIRECT));
if (qemu_opt_get_bool(opts, BDRV_OPT_CACHE_DIRECT, false)) {
*flags |= BDRV_O_NOCACHE;
}
*flags &= ~BDRV_O_RDWR;
assert(qemu_opt_find(opts, BDRV_OPT_READ_ONLY));
if (!qemu_opt_get_bool(opts, BDRV_OPT_READ_ONLY, false)) {
*flags |= BDRV_O_RDWR;
}
}
static void update_options_from_flags(QDict *options, int flags)
{
if (!qdict_haskey(options, BDRV_OPT_CACHE_DIRECT)) {
qdict_put(options, BDRV_OPT_CACHE_DIRECT,
qbool_from_bool(flags & BDRV_O_NOCACHE));
}
if (!qdict_haskey(options, BDRV_OPT_CACHE_NO_FLUSH)) {
qdict_put(options, BDRV_OPT_CACHE_NO_FLUSH,
qbool_from_bool(flags & BDRV_O_NO_FLUSH));
}
if (!qdict_haskey(options, BDRV_OPT_READ_ONLY)) {
qdict_put(options, BDRV_OPT_READ_ONLY,
qbool_from_bool(!(flags & BDRV_O_RDWR)));
}
static void bdrv_assign_node_name(BlockDriverState *bs,
const char *node_name,
Error **errp)

Benoît Canet
committed
{

Benoît Canet
committed
if (!node_name) {
node_name = gen_node_name = id_generate(ID_BLOCK);
} else if (!id_wellformed(node_name)) {
/*
* Check for empty string or invalid characters, but not if it is
* generated (generated names use characters not available to the user)
*/

Benoît Canet
committed
}
/* takes care of avoiding namespaces collisions */
if (blk_by_name(node_name)) {
error_setg(errp, "node-name=%s is conflicting with a device id",
node_name);

Benoît Canet
committed
/* takes care of avoiding duplicates node names */
if (bdrv_find_node(node_name)) {
error_setg(errp, "Duplicate node name");

Benoît Canet
committed
}
/* copy node name into the bs and insert it into the graph list */
pstrcpy(bs->node_name, sizeof(bs->node_name), node_name);
QTAILQ_INSERT_TAIL(&graph_bdrv_states, bs, node_list);

Benoît Canet
committed
}
static int bdrv_open_driver(BlockDriverState *bs, BlockDriver *drv,
const char *node_name, QDict *options,
int open_flags, Error **errp)
{
Error *local_err = NULL;
int ret;
bdrv_assign_node_name(bs, node_name, &local_err);
if (local_err) {
error_propagate(errp, local_err);
return -EINVAL;