提交 7e30e6a6 编写于 作者: J Jeff Cody 提交者: Stefan Hajnoczi

block: vhdx - improve error message, and .bdrv_check implementation

If there is a dirty log file to be replayed in a VHDX image, it is
replayed in .vhdx_open().  However, if the file is opened read-only,
then a somewhat cryptic error message results.

This adds a more helpful error message for the user.  If an image file
contains a log to be replayed, and is opened read-only, the user is
instructed to run 'qemu-img check -r all' on the image file.

Running qemu-img check -r all will cause the image file to be opened
r/w, which will replay the log file.  If a log file replay is detected,
this is flagged, and bdrv_check will increase the corruptions_fixed
count for the image.

[Fixed typo in error message that was pointed out by Eric Blake
<eblake@redhat.com>.
--Stefan]
Signed-off-by: NJeff Cody <jcody@redhat.com>
Signed-off-by: NStefan Hajnoczi <stefanha@redhat.com>
上级 219c2521
...@@ -706,7 +706,8 @@ exit: ...@@ -706,7 +706,8 @@ exit:
* *
* If read-only, we must replay the log in RAM (or refuse to open * If read-only, we must replay the log in RAM (or refuse to open
* a dirty VHDX file read-only) */ * a dirty VHDX file read-only) */
int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed) int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
Error **errp)
{ {
int ret = 0; int ret = 0;
VHDXHeader *hdr; VHDXHeader *hdr;
...@@ -761,6 +762,16 @@ int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed) ...@@ -761,6 +762,16 @@ int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed)
} }
if (logs.valid) { if (logs.valid) {
if (bs->read_only) {
ret = -EPERM;
error_setg_errno(errp, EPERM,
"VHDX image file '%s' opened read-only, but "
"contains a log that needs to be replayed. To "
"replay the log, execute:\n qemu-img check -r "
"all '%s'",
bs->filename, bs->filename);
goto exit;
}
/* now flush the log */ /* now flush the log */
ret = vhdx_log_flush(bs, s, &logs); ret = vhdx_log_flush(bs, s, &logs);
if (ret < 0) { if (ret < 0) {
......
...@@ -878,7 +878,6 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, ...@@ -878,7 +878,6 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
int ret = 0; int ret = 0;
uint32_t i; uint32_t i;
uint64_t signature; uint64_t signature;
bool log_flushed = false;
s->bat = NULL; s->bat = NULL;
...@@ -907,7 +906,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags, ...@@ -907,7 +906,7 @@ static int vhdx_open(BlockDriverState *bs, QDict *options, int flags,
goto fail; goto fail;
} }
ret = vhdx_parse_log(bs, s, &log_flushed); ret = vhdx_parse_log(bs, s, &s->log_replayed_on_open, errp);
if (ret < 0) { if (ret < 0) {
goto fail; goto fail;
} }
...@@ -1854,6 +1853,24 @@ exit: ...@@ -1854,6 +1853,24 @@ exit:
return ret; return ret;
} }
/* If opened r/w, the VHDX driver will automatically replay the log,
* if one is present, inside the vhdx_open() call.
*
* If qemu-img check -r all is called, the image is automatically opened
* r/w and any log has already been replayed, so there is nothing (currently)
* for us to do here
*/
static int vhdx_check(BlockDriverState *bs, BdrvCheckResult *result,
BdrvCheckMode fix)
{
BDRVVHDXState *s = bs->opaque;
if (s->log_replayed_on_open) {
result->corruptions_fixed++;
}
return 0;
}
static QEMUOptionParameter vhdx_create_options[] = { static QEMUOptionParameter vhdx_create_options[] = {
{ {
.name = BLOCK_OPT_SIZE, .name = BLOCK_OPT_SIZE,
...@@ -1898,6 +1915,7 @@ static BlockDriver bdrv_vhdx = { ...@@ -1898,6 +1915,7 @@ static BlockDriver bdrv_vhdx = {
.bdrv_co_writev = vhdx_co_writev, .bdrv_co_writev = vhdx_co_writev,
.bdrv_create = vhdx_create, .bdrv_create = vhdx_create,
.bdrv_get_info = vhdx_get_info, .bdrv_get_info = vhdx_get_info,
.bdrv_check = vhdx_check,
.create_options = vhdx_create_options, .create_options = vhdx_create_options,
}; };
......
...@@ -394,6 +394,8 @@ typedef struct BDRVVHDXState { ...@@ -394,6 +394,8 @@ typedef struct BDRVVHDXState {
Error *migration_blocker; Error *migration_blocker;
bool log_replayed_on_open;
QLIST_HEAD(VHDXRegionHead, VHDXRegionEntry) regions; QLIST_HEAD(VHDXRegionHead, VHDXRegionEntry) regions;
} BDRVVHDXState; } BDRVVHDXState;
...@@ -408,7 +410,8 @@ uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size, ...@@ -408,7 +410,8 @@ uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset); bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset);
int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed); int vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
Error **errp);
int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s, int vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
void *data, uint32_t length, uint64_t offset); void *data, uint32_t length, uint64_t offset);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册