2012-07-11 17:08:37 +04:00
|
|
|
/*
|
|
|
|
* Common code for block device models
|
|
|
|
*
|
|
|
|
* Copyright (C) 2012 Red Hat, Inc.
|
|
|
|
*
|
|
|
|
* This work is licensed under the terms of the GNU GPL, version 2 or
|
|
|
|
* later. See the COPYING file in the top-level directory.
|
|
|
|
*/
|
|
|
|
|
2016-01-18 21:01:42 +03:00
|
|
|
#include "qemu/osdep.h"
|
2022-12-21 16:35:49 +03:00
|
|
|
#include "block/block_int-common.h"
|
2012-12-17 21:20:04 +04:00
|
|
|
#include "sysemu/blockdev.h"
|
2014-10-07 15:59:18 +04:00
|
|
|
#include "sysemu/block-backend.h"
|
2013-02-05 20:06:20 +04:00
|
|
|
#include "hw/block/block.h"
|
include/qemu/osdep.h: Don't include qapi/error.h
Commit 57cb38b included qapi/error.h into qemu/osdep.h to get the
Error typedef. Since then, we've moved to include qemu/osdep.h
everywhere. Its file comment explains: "To avoid getting into
possible circular include dependencies, this file should not include
any other QEMU headers, with the exceptions of config-host.h,
compiler.h, os-posix.h and os-win32.h, all of which are doing a
similar job to this file and are under similar constraints."
qapi/error.h doesn't do a similar job, and it doesn't adhere to
similar constraints: it includes qapi-types.h. That's in excess of
100KiB of crap most .c files don't actually need.
Add the typedef to qemu/typedefs.h, and include that instead of
qapi/error.h. Include qapi/error.h in .c files that need it and don't
get it now. Include qapi-types.h in qom/object.h for uint16List.
Update scripts/clean-includes accordingly. Update it further to match
reality: replace config.h by config-target.h, add sysemu/os-posix.h,
sysemu/os-win32.h. Update the list of includes in the qemu/osdep.h
comment quoted above similarly.
This reduces the number of objects depending on qapi/error.h from "all
of them" to less than a third. Unfortunately, the number depending on
qapi-types.h shrinks only a little. More work is needed for that one.
Signed-off-by: Markus Armbruster <armbru@redhat.com>
[Fix compilation without the spice devel packages. - Paolo]
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
2016-03-14 11:01:28 +03:00
|
|
|
#include "qapi/error.h"
|
2018-02-11 12:36:01 +03:00
|
|
|
#include "qapi/qapi-types-block.h"
|
pflash: Require backend size to match device, improve errors
We reject undersized backends with a rather enigmatic "failed to read
the initial flash content" error. For instance:
$ qemu-system-ppc64 -S -display none -M sam460ex -drive if=pflash,format=raw,file=eins.img
qemu-system-ppc64: Initialization of device cfi.pflash02 failed: failed to read the initial flash content
We happily accept oversized images, ignoring their tail. Throwing
away parts of firmware that way is pretty much certain to end in an
even more enigmatic failure to boot.
Require the backend's size to match the device's size exactly. Report
mismatch like this:
qemu-system-ppc64: Initialization of device cfi.pflash01 failed: device requires 1048576 bytes, block backend provides 512 bytes
Improve the error for actual read failures to "can't read block
backend".
To avoid duplicating even more code between the two pflash device
models, do all that in new helper blk_check_size_and_read_all().
The error reporting can still be confusing. For instance:
qemu-system-ppc64 -S -display none -M taihu -drive if=pflash,format=raw,file=eins.img -drive if=pflash,unit=1,format=raw,file=zwei.img
qemu-system-ppc64: Initialization of device cfi.pflash02 failed: device requires 2097152 bytes, block backend provides 512 bytes
Leaves the user guessing which of the two -drive is wrong. Mention
the issue in a TODO comment.
Suggested-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20190319163551.32499-2-armbru@redhat.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
2019-03-19 19:35:50 +03:00
|
|
|
|
2022-12-20 11:42:46 +03:00
|
|
|
/*
|
|
|
|
* Read the non-zeroes parts of @blk into @buf
|
|
|
|
* Reading all of the @blk is expensive if the zeroes parts of @blk
|
|
|
|
* is large enough. Therefore check the block status and only write
|
|
|
|
* the non-zeroes block into @buf.
|
|
|
|
*
|
|
|
|
* Return 0 on success, non-zero on error.
|
|
|
|
*/
|
|
|
|
static int blk_pread_nonzeroes(BlockBackend *blk, hwaddr size, void *buf)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int64_t bytes, offset = 0;
|
|
|
|
BlockDriverState *bs = blk_bs(blk);
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
bytes = MIN(size - offset, BDRV_REQUEST_MAX_SECTORS);
|
|
|
|
if (bytes <= 0) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ret = bdrv_block_status(bs, offset, bytes, &bytes, NULL, NULL);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
if (!(ret & BDRV_BLOCK_ZERO)) {
|
2023-03-07 18:53:18 +03:00
|
|
|
ret = blk_pread(blk, offset, bytes, (uint8_t *) buf + offset, 0);
|
2022-12-20 11:42:46 +03:00
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
offset += bytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
pflash: Require backend size to match device, improve errors
We reject undersized backends with a rather enigmatic "failed to read
the initial flash content" error. For instance:
$ qemu-system-ppc64 -S -display none -M sam460ex -drive if=pflash,format=raw,file=eins.img
qemu-system-ppc64: Initialization of device cfi.pflash02 failed: failed to read the initial flash content
We happily accept oversized images, ignoring their tail. Throwing
away parts of firmware that way is pretty much certain to end in an
even more enigmatic failure to boot.
Require the backend's size to match the device's size exactly. Report
mismatch like this:
qemu-system-ppc64: Initialization of device cfi.pflash01 failed: device requires 1048576 bytes, block backend provides 512 bytes
Improve the error for actual read failures to "can't read block
backend".
To avoid duplicating even more code between the two pflash device
models, do all that in new helper blk_check_size_and_read_all().
The error reporting can still be confusing. For instance:
qemu-system-ppc64 -S -display none -M taihu -drive if=pflash,format=raw,file=eins.img -drive if=pflash,unit=1,format=raw,file=zwei.img
qemu-system-ppc64: Initialization of device cfi.pflash02 failed: device requires 2097152 bytes, block backend provides 512 bytes
Leaves the user guessing which of the two -drive is wrong. Mention
the issue in a TODO comment.
Suggested-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20190319163551.32499-2-armbru@redhat.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
2019-03-19 19:35:50 +03:00
|
|
|
/*
|
|
|
|
* Read the entire contents of @blk into @buf.
|
|
|
|
* @blk's contents must be @size bytes, and @size must be at most
|
|
|
|
* BDRV_REQUEST_MAX_BYTES.
|
|
|
|
* On success, return true.
|
|
|
|
* On failure, store an error through @errp and return false.
|
|
|
|
* Note that the error messages do not identify the block backend.
|
|
|
|
* TODO Since callers don't either, this can result in confusing
|
|
|
|
* errors.
|
|
|
|
* This function not intended for actual block devices, which read on
|
|
|
|
* demand. It's for things like memory devices that (ab)use a block
|
|
|
|
* backend to provide persistence.
|
|
|
|
*/
|
|
|
|
bool blk_check_size_and_read_all(BlockBackend *blk, void *buf, hwaddr size,
|
|
|
|
Error **errp)
|
|
|
|
{
|
|
|
|
int64_t blk_len;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
blk_len = blk_getlength(blk);
|
|
|
|
if (blk_len < 0) {
|
|
|
|
error_setg_errno(errp, -blk_len,
|
|
|
|
"can't get size of block backend");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (blk_len != size) {
|
|
|
|
error_setg(errp, "device requires %" HWADDR_PRIu " bytes, "
|
|
|
|
"block backend provides %" PRIu64 " bytes",
|
|
|
|
size, blk_len);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We could loop for @size > BDRV_REQUEST_MAX_BYTES, but if we
|
|
|
|
* ever get to the point we want to read *gigabytes* here, we
|
|
|
|
* should probably rework the device to be more like an actual
|
|
|
|
* block device and read only on demand.
|
|
|
|
*/
|
|
|
|
assert(size <= BDRV_REQUEST_MAX_BYTES);
|
2022-12-20 11:42:46 +03:00
|
|
|
ret = blk_pread_nonzeroes(blk, size, buf);
|
pflash: Require backend size to match device, improve errors
We reject undersized backends with a rather enigmatic "failed to read
the initial flash content" error. For instance:
$ qemu-system-ppc64 -S -display none -M sam460ex -drive if=pflash,format=raw,file=eins.img
qemu-system-ppc64: Initialization of device cfi.pflash02 failed: failed to read the initial flash content
We happily accept oversized images, ignoring their tail. Throwing
away parts of firmware that way is pretty much certain to end in an
even more enigmatic failure to boot.
Require the backend's size to match the device's size exactly. Report
mismatch like this:
qemu-system-ppc64: Initialization of device cfi.pflash01 failed: device requires 1048576 bytes, block backend provides 512 bytes
Improve the error for actual read failures to "can't read block
backend".
To avoid duplicating even more code between the two pflash device
models, do all that in new helper blk_check_size_and_read_all().
The error reporting can still be confusing. For instance:
qemu-system-ppc64 -S -display none -M taihu -drive if=pflash,format=raw,file=eins.img -drive if=pflash,unit=1,format=raw,file=zwei.img
qemu-system-ppc64: Initialization of device cfi.pflash02 failed: device requires 2097152 bytes, block backend provides 512 bytes
Leaves the user guessing which of the two -drive is wrong. Mention
the issue in a TODO comment.
Suggested-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Message-Id: <20190319163551.32499-2-armbru@redhat.com>
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
2019-03-19 19:35:50 +03:00
|
|
|
if (ret < 0) {
|
|
|
|
error_setg_errno(errp, -ret, "can't read block backend");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2012-07-11 17:08:37 +04:00
|
|
|
|
2020-05-29 01:55:10 +03:00
|
|
|
bool blkconf_blocksizes(BlockConf *conf, Error **errp)
|
2015-02-16 14:47:58 +03:00
|
|
|
{
|
|
|
|
BlockBackend *blk = conf->blk;
|
|
|
|
BlockSizes blocksizes;
|
2021-07-05 16:04:57 +03:00
|
|
|
BlockDriverState *bs;
|
|
|
|
bool use_blocksizes;
|
|
|
|
bool use_bs;
|
|
|
|
|
|
|
|
switch (conf->backend_defaults) {
|
|
|
|
case ON_OFF_AUTO_AUTO:
|
|
|
|
use_blocksizes = !blk_probe_blocksizes(blk, &blocksizes);
|
|
|
|
use_bs = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ON_OFF_AUTO_ON:
|
|
|
|
use_blocksizes = !blk_probe_blocksizes(blk, &blocksizes);
|
|
|
|
bs = blk_bs(blk);
|
|
|
|
use_bs = bs;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ON_OFF_AUTO_OFF:
|
|
|
|
use_blocksizes = false;
|
|
|
|
use_bs = false;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
2015-02-16 14:47:58 +03:00
|
|
|
|
|
|
|
/* fill in detected values if they are not defined via qemu command line */
|
|
|
|
if (!conf->physical_block_size) {
|
2021-07-05 16:04:57 +03:00
|
|
|
if (use_blocksizes) {
|
2015-02-16 14:47:58 +03:00
|
|
|
conf->physical_block_size = blocksizes.phys;
|
|
|
|
} else {
|
|
|
|
conf->physical_block_size = BDRV_SECTOR_SIZE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!conf->logical_block_size) {
|
2021-07-05 16:04:57 +03:00
|
|
|
if (use_blocksizes) {
|
2015-02-16 14:47:58 +03:00
|
|
|
conf->logical_block_size = blocksizes.log;
|
|
|
|
} else {
|
|
|
|
conf->logical_block_size = BDRV_SECTOR_SIZE;
|
|
|
|
}
|
|
|
|
}
|
2021-07-05 16:04:57 +03:00
|
|
|
if (use_bs) {
|
|
|
|
if (!conf->opt_io_size) {
|
|
|
|
conf->opt_io_size = bs->bl.opt_transfer;
|
|
|
|
}
|
|
|
|
if (conf->discard_granularity == -1) {
|
|
|
|
if (bs->bl.pdiscard_alignment) {
|
|
|
|
conf->discard_granularity = bs->bl.pdiscard_alignment;
|
|
|
|
} else if (bs->bl.request_alignment != 1) {
|
|
|
|
conf->discard_granularity = bs->bl.request_alignment;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-05-29 01:55:10 +03:00
|
|
|
|
|
|
|
if (conf->logical_block_size > conf->physical_block_size) {
|
|
|
|
error_setg(errp,
|
|
|
|
"logical_block_size > physical_block_size not supported");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!QEMU_IS_ALIGNED(conf->min_io_size, conf->logical_block_size)) {
|
|
|
|
error_setg(errp,
|
|
|
|
"min_io_size must be a multiple of logical_block_size");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-29 01:55:14 +03:00
|
|
|
/*
|
|
|
|
* all devices which support min_io_size (scsi and virtio-blk) expose it to
|
|
|
|
* the guest as a uint16_t in units of logical blocks
|
|
|
|
*/
|
|
|
|
if (conf->min_io_size / conf->logical_block_size > UINT16_MAX) {
|
|
|
|
error_setg(errp, "min_io_size must not exceed %u logical blocks",
|
|
|
|
UINT16_MAX);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-05-29 01:55:10 +03:00
|
|
|
if (!QEMU_IS_ALIGNED(conf->opt_io_size, conf->logical_block_size)) {
|
|
|
|
error_setg(errp,
|
|
|
|
"opt_io_size must be a multiple of logical_block_size");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (conf->discard_granularity != -1 &&
|
|
|
|
!QEMU_IS_ALIGNED(conf->discard_granularity,
|
|
|
|
conf->logical_block_size)) {
|
|
|
|
error_setg(errp, "discard_granularity must be "
|
|
|
|
"a multiple of logical_block_size");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2015-02-16 14:47:58 +03:00
|
|
|
}
|
|
|
|
|
2017-11-22 06:08:44 +03:00
|
|
|
bool blkconf_apply_backend_options(BlockConf *conf, bool readonly,
|
2017-01-24 15:43:31 +03:00
|
|
|
bool resizable, Error **errp)
|
2016-06-23 16:12:35 +03:00
|
|
|
{
|
|
|
|
BlockBackend *blk = conf->blk;
|
2016-06-29 18:41:35 +03:00
|
|
|
BlockdevOnError rerror, werror;
|
2017-01-24 15:43:31 +03:00
|
|
|
uint64_t perm, shared_perm;
|
2016-06-23 16:12:35 +03:00
|
|
|
bool wce;
|
2017-01-24 15:43:31 +03:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
perm = BLK_PERM_CONSISTENT_READ;
|
|
|
|
if (!readonly) {
|
|
|
|
perm |= BLK_PERM_WRITE;
|
|
|
|
}
|
|
|
|
|
block: drop BLK_PERM_GRAPH_MOD
First, this permission never protected a node from being changed, as
generic child-replacing functions don't check it.
Second, it's a strange thing: it presents a permission of parent node
to change its child. But generally, children are replaced by different
mechanisms, like jobs or qmp commands, not by nodes.
Graph-mod permission is hard to understand. All other permissions
describe operations which done by parent node on its child: read,
write, resize. Graph modification operations are something completely
different.
The only place where BLK_PERM_GRAPH_MOD is used as "perm" (not shared
perm) is mirror_start_job, for s->target. Still modern code should use
bdrv_freeze_backing_chain() to protect from graph modification, if we
don't do it somewhere it may be considered as a bug. So, it's a bit
risky to drop GRAPH_MOD, and analyzing of possible loss of protection
is hard. But one day we should do it, let's do it now.
One more bit of information is that locking the corresponding byte in
file-posix doesn't make sense at all.
Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
Message-Id: <20210902093754.2352-1-vsementsov@virtuozzo.com>
Signed-off-by: Kevin Wolf <kwolf@redhat.com>
2021-09-02 12:37:54 +03:00
|
|
|
shared_perm = BLK_PERM_CONSISTENT_READ | BLK_PERM_WRITE_UNCHANGED;
|
2017-01-24 15:43:31 +03:00
|
|
|
if (resizable) {
|
|
|
|
shared_perm |= BLK_PERM_RESIZE;
|
|
|
|
}
|
2017-01-24 15:58:00 +03:00
|
|
|
if (conf->share_rw) {
|
|
|
|
shared_perm |= BLK_PERM_WRITE;
|
|
|
|
}
|
2017-01-24 15:43:31 +03:00
|
|
|
|
|
|
|
ret = blk_set_perm(blk, perm, shared_perm, errp);
|
|
|
|
if (ret < 0) {
|
2017-11-22 06:08:44 +03:00
|
|
|
return false;
|
2017-01-24 15:43:31 +03:00
|
|
|
}
|
2016-06-23 16:12:35 +03:00
|
|
|
|
|
|
|
switch (conf->wce) {
|
|
|
|
case ON_OFF_AUTO_ON: wce = true; break;
|
|
|
|
case ON_OFF_AUTO_OFF: wce = false; break;
|
|
|
|
case ON_OFF_AUTO_AUTO: wce = blk_enable_write_cache(blk); break;
|
|
|
|
default:
|
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
2016-06-29 18:41:35 +03:00
|
|
|
rerror = conf->rerror;
|
|
|
|
if (rerror == BLOCKDEV_ON_ERROR_AUTO) {
|
|
|
|
rerror = blk_get_on_error(blk, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
werror = conf->werror;
|
|
|
|
if (werror == BLOCKDEV_ON_ERROR_AUTO) {
|
|
|
|
werror = blk_get_on_error(blk, false);
|
|
|
|
}
|
|
|
|
|
2016-06-23 16:12:35 +03:00
|
|
|
blk_set_enable_write_cache(blk, wce);
|
2016-06-29 18:41:35 +03:00
|
|
|
blk_set_on_error(blk, rerror, werror);
|
2017-11-22 06:08:44 +03:00
|
|
|
|
2022-08-24 12:50:44 +03:00
|
|
|
block_acct_setup(blk_get_stats(blk), conf->account_invalid,
|
|
|
|
conf->account_failed);
|
2017-11-22 06:08:44 +03:00
|
|
|
return true;
|
2016-06-23 16:12:35 +03:00
|
|
|
}
|
|
|
|
|
2017-11-22 06:08:44 +03:00
|
|
|
bool blkconf_geometry(BlockConf *conf, int *ptrans,
|
2014-08-12 06:12:54 +04:00
|
|
|
unsigned cyls_max, unsigned heads_max, unsigned secs_max,
|
|
|
|
Error **errp)
|
2012-07-11 17:08:39 +04:00
|
|
|
{
|
|
|
|
if (!conf->cyls && !conf->heads && !conf->secs) {
|
2014-10-07 15:59:18 +04:00
|
|
|
hd_geometry_guess(conf->blk,
|
2012-07-11 17:08:39 +04:00
|
|
|
&conf->cyls, &conf->heads, &conf->secs,
|
|
|
|
ptrans);
|
|
|
|
} else if (ptrans && *ptrans == BIOS_ATA_TRANSLATION_AUTO) {
|
|
|
|
*ptrans = hd_bios_chs_auto_trans(conf->cyls, conf->heads, conf->secs);
|
|
|
|
}
|
|
|
|
if (conf->cyls || conf->heads || conf->secs) {
|
|
|
|
if (conf->cyls < 1 || conf->cyls > cyls_max) {
|
2014-08-12 06:12:54 +04:00
|
|
|
error_setg(errp, "cyls must be between 1 and %u", cyls_max);
|
2017-11-22 06:08:44 +03:00
|
|
|
return false;
|
2012-07-11 17:08:39 +04:00
|
|
|
}
|
|
|
|
if (conf->heads < 1 || conf->heads > heads_max) {
|
2014-08-12 06:12:54 +04:00
|
|
|
error_setg(errp, "heads must be between 1 and %u", heads_max);
|
2017-11-22 06:08:44 +03:00
|
|
|
return false;
|
2012-07-11 17:08:39 +04:00
|
|
|
}
|
|
|
|
if (conf->secs < 1 || conf->secs > secs_max) {
|
2014-08-12 06:12:54 +04:00
|
|
|
error_setg(errp, "secs must be between 1 and %u", secs_max);
|
2017-11-22 06:08:44 +03:00
|
|
|
return false;
|
2012-07-11 17:08:39 +04:00
|
|
|
}
|
|
|
|
}
|
2017-11-22 06:08:44 +03:00
|
|
|
return true;
|
2012-07-11 17:08:39 +04:00
|
|
|
}
|