[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH v8 1/2] pflash: Require backend size to match de
From: |
Alex Bennée |
Subject: |
Re: [Qemu-devel] [PATCH v8 1/2] pflash: Require backend size to match device, improve errors |
Date: |
Thu, 21 Mar 2019 09:18:09 +0000 |
User-agent: |
mu4e 1.1.0; emacs 26.1 |
Markus Armbruster <address@hidden> writes:
> 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 <address@hidden>
> Signed-off-by: Markus Armbruster <address@hidden>
My this patch has morphed a bit... thanks for carrying it forward:
Reviewed-by: Alex Bennée <address@hidden>
> ---
> hw/block/block.c | 48 +++++++++++++++++++++++++++++++++++++++-
> hw/block/pflash_cfi01.c | 8 +++----
> hw/block/pflash_cfi02.c | 7 +++---
> include/hw/block/block.h | 7 +++++-
> 4 files changed, 59 insertions(+), 11 deletions(-)
>
> diff --git a/hw/block/block.c b/hw/block/block.c
> index cf0eb826f1..bf56c7612b 100644
> --- a/hw/block/block.c
> +++ b/hw/block/block.c
> @@ -13,7 +13,53 @@
> #include "hw/block/block.h"
> #include "qapi/error.h"
> #include "qapi/qapi-types-block.h"
> -#include "qemu/error-report.h"
> +
> +/*
> + * 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);
> + ret = blk_pread(blk, 0, buf, size);
> + if (ret < 0) {
> + error_setg_errno(errp, -ret, "can't read block backend");
> + return false;
> + }
> + return true;
> +}
>
> void blkconf_blocksizes(BlockConf *conf)
> {
> diff --git a/hw/block/pflash_cfi01.c b/hw/block/pflash_cfi01.c
> index 125f70b8e4..9937739a82 100644
> --- a/hw/block/pflash_cfi01.c
> +++ b/hw/block/pflash_cfi01.c
> @@ -38,6 +38,7 @@
>
> #include "qemu/osdep.h"
> #include "hw/hw.h"
> +#include "hw/block/block.h"
> #include "hw/block/flash.h"
> #include "sysemu/block-backend.h"
> #include "qapi/error.h"
> @@ -763,12 +764,9 @@ static void pflash_cfi01_realize(DeviceState *dev, Error
> **errp)
> }
>
> if (pfl->blk) {
> - /* read the initial flash content */
> - ret = blk_pread(pfl->blk, 0, pfl->storage, total_len);
> -
> - if (ret < 0) {
> + if (!blk_check_size_and_read_all(pfl->blk, pfl->storage, total_len,
> + errp)) {
> vmstate_unregister_ram(&pfl->mem, DEVICE(pfl));
> - error_setg(errp, "failed to read the initial flash content");
> return;
> }
> }
> diff --git a/hw/block/pflash_cfi02.c b/hw/block/pflash_cfi02.c
> index c9db430611..9b934305fa 100644
> --- a/hw/block/pflash_cfi02.c
> +++ b/hw/block/pflash_cfi02.c
> @@ -37,6 +37,7 @@
>
> #include "qemu/osdep.h"
> #include "hw/hw.h"
> +#include "hw/block/block.h"
> #include "hw/block/flash.h"
> #include "qapi/error.h"
> #include "qemu/timer.h"
> @@ -581,11 +582,9 @@ static void pflash_cfi02_realize(DeviceState *dev, Error
> **errp)
> }
>
> if (pfl->blk) {
> - /* read the initial flash content */
> - ret = blk_pread(pfl->blk, 0, pfl->storage, chip_len);
> - if (ret < 0) {
> + if (!blk_check_size_and_read_all(pfl->blk, pfl->storage, chip_len,
> + errp)) {
> vmstate_unregister_ram(&pfl->orig_mem, DEVICE(pfl));
> - error_setg(errp, "failed to read the initial flash content");
> return;
> }
> }
> diff --git a/include/hw/block/block.h b/include/hw/block/block.h
> index e9f9e2223f..d06f25aa0f 100644
> --- a/include/hw/block/block.h
> +++ b/include/hw/block/block.h
> @@ -11,7 +11,7 @@
> #ifndef HW_BLOCK_H
> #define HW_BLOCK_H
>
> -#include "qemu-common.h"
> +#include "exec/hwaddr.h"
> #include "qapi/qapi-types-block-core.h"
>
> /* Configuration */
> @@ -70,6 +70,11 @@ static inline unsigned int
> get_physical_block_exp(BlockConf *conf)
> DEFINE_PROP_BLOCKDEV_ON_ERROR("werror", _state, _conf.werror, \
> BLOCKDEV_ON_ERROR_AUTO)
>
> +/* Backend access helpers */
> +
> +bool blk_check_size_and_read_all(BlockBackend *blk, void *buf, hwaddr size,
> + Error **errp);
> +
> /* Configuration helpers */
>
> bool blkconf_geometry(BlockConf *conf, int *trans,
--
Alex Bennée