Block patches for 2.3-rc0

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.22 (GNU/Linux)
 
 iQIcBAABAgAGBQJVBwDLAAoJEH8JsnLIjy/WPRwP/A8mF/yaGnSIs1zKYzikWiPg
 CPoIcWZnU27Uc2fa0jW7vFh7mnrQ1+fgzQx4MJ/zxuDGI63Nr7QnkDSQqNDsKlFb
 bQjH5NNFYlqLqsTNqMEc7bV1NnUUqC3932oqgzcAcVeh1DphNU//Mu87bmTE+NVi
 ZHtnnasEN8eBWPsiLyphCqirQWO2mPRHAwYjEE0SwHEX+HEoV0Bx8GUJMmZ8J+oA
 4FXl1R3iZiqFGE4ExNFa+XKy/kXChRkLT7GWlCgB8ngRQ42OdLIz3vV/KMwnzndA
 luz0yywCYBkfDohAYZ0wAWSDsGYgSAG33/XOatIatQfdLE/MMm9Ab9EN4WO9oeVs
 XnYJAZzd5i7hCL4fH76jPHo4seMq6F/4Ou9bCmevMzjZc9o6I6qaUyIFgSY7zZqf
 j08soL3KqlnxwvZNh+kAjrRhoJNzjTOvsz4e5h9Y8b9McG0ObRR1uxKCFIMyHSJB
 hJs0bgZiFye4pn9FDFOC6dU4ShVOgL2AeuREdVUJpIUq5kBIjk6djCGvIRJky1Rx
 WujcLml5vzqcfYIqzRFmh1wZ6JEnpqU70r6g7O6yUOEJA3qJC+vkue+bxiXW4KAX
 uFDz2zCDwsNmbMOwfClDs1D9DPoyikElVOwovq92erDTIHTcOqThcbUS+SmIV/ps
 bO68612w4UJZKyXbndDT
 =XCJ5
 -----END PGP SIGNATURE-----

Merge remote-tracking branch 'remotes/kevin/tags/for-upstream' into staging

Block patches for 2.3-rc0

# gpg: Signature made Mon Mar 16 16:11:55 2015 GMT using RSA key ID C88F2FD6
# gpg: Good signature from "Kevin Wolf <kwolf@redhat.com>"

* remotes/kevin/tags/for-upstream:
  block/vpc: remove disabled code from get_sector_offset
  block/vpc: rename footer->size -> footer->current_size
  block/vpc: make calculate_geometry spec conform
  vpc: Ignore geometry for large images
  block/vpc: optimize vpc_co_get_block_status
  block: Drop bdrv_find
  blockdev: Convert bdrv_find to blk_by_name
  migration: Convert bdrv_find to blk_by_name
  monitor: Convert bdrv_find to blk_by_name
  iotests: Test non-self-referential qcow2 refblocks
  iotests: Add tests for refcount table growth
  qcow2: Respect new_block in alloc_refcount_block()
  qemu-img: Avoid qerror_report_err() outside QMP handlers, again
  block: Fix block-set-write-threshold not to use funky error class
  block: Deprecate QCOW/QCOW2 encryption
  qemu-img: Fix convert, amend error messages for unknown options
  iotests: Update 051's reference output

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Peter Maydell 2015-03-16 19:19:03 +00:00
commit 3521f76706
20 changed files with 393 additions and 142 deletions

16
block.c
View File

@ -1065,6 +1065,13 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
goto free_and_fail; goto free_and_fail;
} }
if (bs->encrypted) {
error_report("Encrypted images are deprecated");
error_printf("Support for them will be removed in a future release.\n"
"You can use 'qemu-img convert' to convert your image"
" to an unencrypted one.\n");
}
ret = refresh_total_sectors(bs, bs->total_sectors); ret = refresh_total_sectors(bs, bs->total_sectors);
if (ret < 0) { if (ret < 0) {
error_setg_errno(errp, -ret, "Could not refresh total sector count"); error_setg_errno(errp, -ret, "Could not refresh total sector count");
@ -3814,15 +3821,6 @@ void bdrv_iterate_format(void (*it)(void *opaque, const char *name),
g_free(formats); g_free(formats);
} }
/* This function is to find block backend bs */
/* TODO convert callers to blk_by_name(), then remove */
BlockDriverState *bdrv_find(const char *name)
{
BlockBackend *blk = blk_by_name(name);
return blk ? blk_bs(blk) : NULL;
}
/* This function is to find a node in the bs graph */ /* This function is to find a node in the bs graph */
BlockDriverState *bdrv_find_node(const char *node_name) BlockDriverState *bdrv_find_node(const char *node_name)
{ {

View File

@ -466,8 +466,20 @@ static int alloc_refcount_block(BlockDriverState *bs,
*/ */
BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_GROW); BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_GROW);
/* Calculate the number of refcount blocks needed so far */ /* Calculate the number of refcount blocks needed so far; this will be the
uint64_t blocks_used = DIV_ROUND_UP(cluster_index, s->refcount_block_size); * basis for calculating the index of the first cluster used for the
* self-describing refcount structures which we are about to create.
*
* Because we reached this point, there cannot be any refcount entries for
* cluster_index or higher indices yet. However, because new_block has been
* allocated to describe that cluster (and it will assume this role later
* on), we cannot use that index; also, new_block may actually have a higher
* cluster index than cluster_index, so it needs to be taken into account
* here (and 1 needs to be added to its value because that cluster is used).
*/
uint64_t blocks_used = DIV_ROUND_UP(MAX(cluster_index + 1,
(new_block >> s->cluster_bits) + 1),
s->refcount_block_size);
if (blocks_used > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) { if (blocks_used > QCOW_MAX_REFTABLE_SIZE / sizeof(uint64_t)) {
return -EFBIG; return -EFBIG;

View File

@ -46,6 +46,7 @@ enum vhd_type {
#define VHD_TIMESTAMP_BASE 946684800 #define VHD_TIMESTAMP_BASE 946684800
#define VHD_MAX_SECTORS (65535LL * 255 * 255) #define VHD_MAX_SECTORS (65535LL * 255 * 255)
#define VHD_MAX_GEOMETRY (65535LL * 16 * 255)
// always big-endian // always big-endian
typedef struct vhd_footer { typedef struct vhd_footer {
@ -65,7 +66,7 @@ typedef struct vhd_footer {
char creator_os[4]; // "Wi2k" char creator_os[4]; // "Wi2k"
uint64_t orig_size; uint64_t orig_size;
uint64_t size; uint64_t current_size;
uint16_t cyls; uint16_t cyls;
uint8_t heads; uint8_t heads;
@ -215,13 +216,12 @@ static int vpc_open(BlockDriverState *bs, QDict *options, int flags,
bs->total_sectors = (int64_t) bs->total_sectors = (int64_t)
be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl; be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl;
/* images created with disk2vhd report a far higher virtual size /* Images that have exactly the maximum geometry are probably bigger and
* than expected with the cyls * heads * sectors_per_cyl formula. * would be truncated if we adhered to the geometry for them. Rely on
* use the footer->size instead if the image was created with * footer->current_size for them. */
* disk2vhd. if (bs->total_sectors == VHD_MAX_GEOMETRY) {
*/ bs->total_sectors = be64_to_cpu(footer->current_size) /
if (!strncmp(footer->creator_app, "d2v", 4)) { BDRV_SECTOR_SIZE;
bs->total_sectors = be64_to_cpu(footer->size) / BDRV_SECTOR_SIZE;
} }
/* Allow a maximum disk size of approximately 2 TB */ /* Allow a maximum disk size of approximately 2 TB */
@ -376,38 +376,6 @@ static inline int64_t get_sector_offset(BlockDriverState *bs,
bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size); bdrv_pwrite_sync(bs->file, bitmap_offset, bitmap, s->bitmap_size);
} }
// printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n",
// sector_num, pagetable_index, pageentry_index,
// bitmap_offset, block_offset);
// disabled by reason
#if 0
#ifdef CACHE
if (bitmap_offset != s->last_bitmap)
{
lseek(s->fd, bitmap_offset, SEEK_SET);
s->last_bitmap = bitmap_offset;
// Scary! Bitmap is stored as big endian 32bit entries,
// while we used to look it up byte by byte
read(s->fd, s->pageentry_u8, 512);
for (i = 0; i < 128; i++)
be32_to_cpus(&s->pageentry_u32[i]);
}
if ((s->pageentry_u8[pageentry_index / 8] >> (pageentry_index % 8)) & 1)
return -1;
#else
lseek(s->fd, bitmap_offset + (pageentry_index / 8), SEEK_SET);
read(s->fd, &bitmap_entry, 1);
if ((bitmap_entry >> (pageentry_index % 8)) & 1)
return -1; // not allocated
#endif
#endif
return block_offset; return block_offset;
} }
@ -602,7 +570,7 @@ static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
{ {
BDRVVPCState *s = bs->opaque; BDRVVPCState *s = bs->opaque;
VHDFooter *footer = (VHDFooter*) s->footer_buf; VHDFooter *footer = (VHDFooter*) s->footer_buf;
int64_t start, offset, next; int64_t start, offset;
bool allocated; bool allocated;
int n; int n;
@ -626,20 +594,18 @@ static int64_t coroutine_fn vpc_co_get_block_status(BlockDriverState *bs,
*pnum += n; *pnum += n;
sector_num += n; sector_num += n;
nb_sectors -= n; nb_sectors -= n;
next = start + (*pnum * BDRV_SECTOR_SIZE); /* *pnum can't be greater than one block for allocated
* sectors since there is always a bitmap in between. */
if (allocated) {
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
}
if (nb_sectors == 0) { if (nb_sectors == 0) {
break; break;
} }
offset = get_sector_offset(bs, sector_num, 0); offset = get_sector_offset(bs, sector_num, 0);
} while ((allocated && offset == next) || (!allocated && offset == -1)); } while (offset == -1);
if (allocated) { return 0;
return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start;
} else {
return 0;
}
} }
/* /*
@ -659,26 +625,20 @@ static int calculate_geometry(int64_t total_sectors, uint16_t* cyls,
{ {
uint32_t cyls_times_heads; uint32_t cyls_times_heads;
/* Allow a maximum disk size of approximately 2 TB */ total_sectors = MIN(total_sectors, VHD_MAX_GEOMETRY);
if (total_sectors > 65535LL * 255 * 255) {
return -EFBIG;
}
if (total_sectors > 65535 * 16 * 63) { if (total_sectors >= 65535LL * 16 * 63) {
*secs_per_cyl = 255; *secs_per_cyl = 255;
if (total_sectors > 65535 * 16 * 255) { *heads = 16;
*heads = 255;
} else {
*heads = 16;
}
cyls_times_heads = total_sectors / *secs_per_cyl; cyls_times_heads = total_sectors / *secs_per_cyl;
} else { } else {
*secs_per_cyl = 17; *secs_per_cyl = 17;
cyls_times_heads = total_sectors / *secs_per_cyl; cyls_times_heads = total_sectors / *secs_per_cyl;
*heads = (cyls_times_heads + 1023) / 1024; *heads = (cyls_times_heads + 1023) / 1024;
if (*heads < 4) if (*heads < 4) {
*heads = 4; *heads = 4;
}
if (cyls_times_heads >= (*heads * 1024) || *heads > 16) { if (cyls_times_heads >= (*heads * 1024) || *heads > 16) {
*secs_per_cyl = 31; *secs_per_cyl = 31;
@ -834,20 +794,28 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
* Calculate matching total_size and geometry. Increase the number of * Calculate matching total_size and geometry. Increase the number of
* sectors requested until we get enough (or fail). This ensures that * sectors requested until we get enough (or fail). This ensures that
* qemu-img convert doesn't truncate images, but rather rounds up. * qemu-img convert doesn't truncate images, but rather rounds up.
*
* If the image size can't be represented by a spec conform CHS geometry,
* we set the geometry to 65535 x 16 x 255 (CxHxS) sectors and use
* the image size from the VHD footer to calculate total_sectors.
*/ */
total_sectors = total_size / BDRV_SECTOR_SIZE; total_sectors = MIN(VHD_MAX_GEOMETRY, total_size / BDRV_SECTOR_SIZE);
for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) { for (i = 0; total_sectors > (int64_t)cyls * heads * secs_per_cyl; i++) {
if (calculate_geometry(total_sectors + i, &cyls, &heads, calculate_geometry(total_sectors + i, &cyls, &heads, &secs_per_cyl);
&secs_per_cyl)) }
{
if ((int64_t)cyls * heads * secs_per_cyl == VHD_MAX_GEOMETRY) {
total_sectors = total_size / BDRV_SECTOR_SIZE;
/* Allow a maximum disk size of approximately 2 TB */
if (total_sectors > VHD_MAX_SECTORS) {
ret = -EFBIG; ret = -EFBIG;
goto out; goto out;
} }
} else {
total_sectors = (int64_t)cyls * heads * secs_per_cyl;
total_size = total_sectors * BDRV_SECTOR_SIZE;
} }
total_sectors = (int64_t) cyls * heads * secs_per_cyl;
total_size = total_sectors * BDRV_SECTOR_SIZE;
/* Prepare the Hard Disk Footer */ /* Prepare the Hard Disk Footer */
memset(buf, 0, 1024); memset(buf, 0, 1024);
@ -869,7 +837,7 @@ static int vpc_create(const char *filename, QemuOpts *opts, Error **errp)
footer->major = cpu_to_be16(0x0005); footer->major = cpu_to_be16(0x0005);
footer->minor = cpu_to_be16(0x0003); footer->minor = cpu_to_be16(0x0003);
footer->orig_size = cpu_to_be64(total_size); footer->orig_size = cpu_to_be64(total_size);
footer->size = cpu_to_be64(total_size); footer->current_size = cpu_to_be64(total_size);
footer->cyls = cpu_to_be16(cyls); footer->cyls = cpu_to_be16(cyls);
footer->heads = heads; footer->heads = heads;
footer->secs_per_cyl = secs_per_cyl; footer->secs_per_cyl = secs_per_cyl;

View File

@ -112,7 +112,7 @@ void qmp_block_set_write_threshold(const char *node_name,
bs = bdrv_find_node(node_name); bs = bdrv_find_node(node_name);
if (!bs) { if (!bs) {
error_set(errp, QERR_DEVICE_NOT_FOUND, node_name); error_setg(errp, "Device '%s' not found", node_name);
return; return;
} }

View File

@ -1016,18 +1016,18 @@ fail:
void hmp_commit(Monitor *mon, const QDict *qdict) void hmp_commit(Monitor *mon, const QDict *qdict)
{ {
const char *device = qdict_get_str(qdict, "device"); const char *device = qdict_get_str(qdict, "device");
BlockDriverState *bs; BlockBackend *blk;
int ret; int ret;
if (!strcmp(device, "all")) { if (!strcmp(device, "all")) {
ret = bdrv_commit_all(); ret = bdrv_commit_all();
} else { } else {
bs = bdrv_find(device); blk = blk_by_name(device);
if (!bs) { if (!blk) {
monitor_printf(mon, "Device '%s' not found\n", device); monitor_printf(mon, "Device '%s' not found\n", device);
return; return;
} }
ret = bdrv_commit(bs); ret = bdrv_commit(blk_bs(blk));
} }
if (ret < 0) { if (ret < 0) {
monitor_printf(mon, "'commit' error for '%s': %s\n", device, monitor_printf(mon, "'commit' error for '%s': %s\n", device,
@ -1092,17 +1092,20 @@ SnapshotInfo *qmp_blockdev_snapshot_delete_internal_sync(const char *device,
const char *name, const char *name,
Error **errp) Error **errp)
{ {
BlockDriverState *bs = bdrv_find(device); BlockDriverState *bs;
BlockBackend *blk;
AioContext *aio_context; AioContext *aio_context;
QEMUSnapshotInfo sn; QEMUSnapshotInfo sn;
Error *local_err = NULL; Error *local_err = NULL;
SnapshotInfo *info = NULL; SnapshotInfo *info = NULL;
int ret; int ret;
if (!bs) { blk = blk_by_name(device);
if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return NULL; return NULL;
} }
bs = blk_bs(blk);
if (!has_id) { if (!has_id) {
id = NULL; id = NULL;
@ -1205,6 +1208,7 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
Error *local_err = NULL; Error *local_err = NULL;
const char *device; const char *device;
const char *name; const char *name;
BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
QEMUSnapshotInfo old_sn, *sn; QEMUSnapshotInfo old_sn, *sn;
bool ret; bool ret;
@ -1223,11 +1227,12 @@ static void internal_snapshot_prepare(BlkTransactionState *common,
name = internal->name; name = internal->name;
/* 2. check for validation */ /* 2. check for validation */
bs = bdrv_find(device); blk = blk_by_name(device);
if (!bs) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return; return;
} }
bs = blk_bs(blk);
/* AioContext is released in .clean() */ /* AioContext is released in .clean() */
state->aio_context = bdrv_get_aio_context(bs); state->aio_context = bdrv_get_aio_context(bs);
@ -1494,17 +1499,19 @@ static void drive_backup_prepare(BlkTransactionState *common, Error **errp)
{ {
DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common); DriveBackupState *state = DO_UPCAST(DriveBackupState, common, common);
BlockDriverState *bs; BlockDriverState *bs;
BlockBackend *blk;
DriveBackup *backup; DriveBackup *backup;
Error *local_err = NULL; Error *local_err = NULL;
assert(common->action->kind == TRANSACTION_ACTION_KIND_DRIVE_BACKUP); assert(common->action->kind == TRANSACTION_ACTION_KIND_DRIVE_BACKUP);
backup = common->action->drive_backup; backup = common->action->drive_backup;
bs = bdrv_find(backup->device); blk = blk_by_name(backup->device);
if (!bs) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device); error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device);
return; return;
} }
bs = blk_bs(blk);
/* AioContext is released in .clean() */ /* AioContext is released in .clean() */
state->aio_context = bdrv_get_aio_context(bs); state->aio_context = bdrv_get_aio_context(bs);
@ -1559,22 +1566,25 @@ static void blockdev_backup_prepare(BlkTransactionState *common, Error **errp)
BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common); BlockdevBackupState *state = DO_UPCAST(BlockdevBackupState, common, common);
BlockdevBackup *backup; BlockdevBackup *backup;
BlockDriverState *bs, *target; BlockDriverState *bs, *target;
BlockBackend *blk;
Error *local_err = NULL; Error *local_err = NULL;
assert(common->action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP); assert(common->action->kind == TRANSACTION_ACTION_KIND_BLOCKDEV_BACKUP);
backup = common->action->blockdev_backup; backup = common->action->blockdev_backup;
bs = bdrv_find(backup->device); blk = blk_by_name(backup->device);
if (!bs) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device); error_set(errp, QERR_DEVICE_NOT_FOUND, backup->device);
return; return;
} }
bs = blk_bs(blk);
target = bdrv_find(backup->target); blk = blk_by_name(backup->target);
if (!target) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, backup->target); error_set(errp, QERR_DEVICE_NOT_FOUND, backup->target);
return; return;
} }
target = blk_bs(blk);
/* AioContext is released in .clean() */ /* AioContext is released in .clean() */
state->aio_context = bdrv_get_aio_context(bs); state->aio_context = bdrv_get_aio_context(bs);
@ -1881,13 +1891,15 @@ void qmp_block_set_io_throttle(const char *device, int64_t bps, int64_t bps_rd,
{ {
ThrottleConfig cfg; ThrottleConfig cfg;
BlockDriverState *bs; BlockDriverState *bs;
BlockBackend *blk;
AioContext *aio_context; AioContext *aio_context;
bs = bdrv_find(device); blk = blk_by_name(device);
if (!bs) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return; return;
} }
bs = blk_bs(blk);
memset(&cfg, 0, sizeof(cfg)); memset(&cfg, 0, sizeof(cfg));
cfg.buckets[THROTTLE_BPS_TOTAL].avg = bps; cfg.buckets[THROTTLE_BPS_TOTAL].avg = bps;
@ -2091,6 +2103,7 @@ void qmp_block_stream(const char *device,
bool has_on_error, BlockdevOnError on_error, bool has_on_error, BlockdevOnError on_error,
Error **errp) Error **errp)
{ {
BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
BlockDriverState *base_bs = NULL; BlockDriverState *base_bs = NULL;
AioContext *aio_context; AioContext *aio_context;
@ -2101,11 +2114,12 @@ void qmp_block_stream(const char *device,
on_error = BLOCKDEV_ON_ERROR_REPORT; on_error = BLOCKDEV_ON_ERROR_REPORT;
} }
bs = bdrv_find(device); blk = blk_by_name(device);
if (!bs) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return; return;
} }
bs = blk_bs(blk);
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
@ -2155,6 +2169,7 @@ void qmp_block_commit(const char *device,
bool has_speed, int64_t speed, bool has_speed, int64_t speed,
Error **errp) Error **errp)
{ {
BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
BlockDriverState *base_bs, *top_bs; BlockDriverState *base_bs, *top_bs;
AioContext *aio_context; AioContext *aio_context;
@ -2173,11 +2188,12 @@ void qmp_block_commit(const char *device,
* live commit feature versions; for this to work, we must make sure to * live commit feature versions; for this to work, we must make sure to
* perform the device lookup before any generic errors that may occur in a * perform the device lookup before any generic errors that may occur in a
* scenario in which all optional arguments are omitted. */ * scenario in which all optional arguments are omitted. */
bs = bdrv_find(device); blk = blk_by_name(device);
if (!bs) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return; return;
} }
bs = blk_bs(blk);
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
@ -2258,6 +2274,7 @@ void qmp_drive_backup(const char *device, const char *target,
bool has_on_target_error, BlockdevOnError on_target_error, bool has_on_target_error, BlockdevOnError on_target_error,
Error **errp) Error **errp)
{ {
BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
BlockDriverState *target_bs; BlockDriverState *target_bs;
BlockDriverState *source = NULL; BlockDriverState *source = NULL;
@ -2281,11 +2298,12 @@ void qmp_drive_backup(const char *device, const char *target,
mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS; mode = NEW_IMAGE_MODE_ABSOLUTE_PATHS;
} }
bs = bdrv_find(device); blk = blk_by_name(device);
if (!bs) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return; return;
} }
bs = blk_bs(blk);
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
@ -2385,6 +2403,7 @@ void qmp_blockdev_backup(const char *device, const char *target,
BlockdevOnError on_target_error, BlockdevOnError on_target_error,
Error **errp) Error **errp)
{ {
BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
BlockDriverState *target_bs; BlockDriverState *target_bs;
Error *local_err = NULL; Error *local_err = NULL;
@ -2400,20 +2419,22 @@ void qmp_blockdev_backup(const char *device, const char *target,
on_target_error = BLOCKDEV_ON_ERROR_REPORT; on_target_error = BLOCKDEV_ON_ERROR_REPORT;
} }
bs = bdrv_find(device); blk = blk_by_name(device);
if (!bs) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return; return;
} }
bs = blk_bs(blk);
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
target_bs = bdrv_find(target); blk = blk_by_name(target);
if (!target_bs) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, target); error_set(errp, QERR_DEVICE_NOT_FOUND, target);
goto out; goto out;
} }
target_bs = blk_bs(blk);
bdrv_ref(target_bs); bdrv_ref(target_bs);
bdrv_set_aio_context(target_bs, aio_context); bdrv_set_aio_context(target_bs, aio_context);
@ -2442,6 +2463,7 @@ void qmp_drive_mirror(const char *device, const char *target,
bool has_on_target_error, BlockdevOnError on_target_error, bool has_on_target_error, BlockdevOnError on_target_error,
Error **errp) Error **errp)
{ {
BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
BlockDriverState *source, *target_bs; BlockDriverState *source, *target_bs;
AioContext *aio_context; AioContext *aio_context;
@ -2481,11 +2503,12 @@ void qmp_drive_mirror(const char *device, const char *target,
return; return;
} }
bs = bdrv_find(device); blk = blk_by_name(device);
if (!bs) { if (!blk) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return; return;
} }
bs = blk_bs(blk);
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);
@ -2623,12 +2646,14 @@ out:
static BlockJob *find_block_job(const char *device, AioContext **aio_context, static BlockJob *find_block_job(const char *device, AioContext **aio_context,
Error **errp) Error **errp)
{ {
BlockBackend *blk;
BlockDriverState *bs; BlockDriverState *bs;
bs = bdrv_find(device); blk = blk_by_name(device);
if (!bs) { if (!blk) {
goto notfound; goto notfound;
} }
bs = blk_bs(blk);
*aio_context = bdrv_get_aio_context(bs); *aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(*aio_context); aio_context_acquire(*aio_context);
@ -2733,6 +2758,7 @@ void qmp_change_backing_file(const char *device,
const char *backing_file, const char *backing_file,
Error **errp) Error **errp)
{ {
BlockBackend *blk;
BlockDriverState *bs = NULL; BlockDriverState *bs = NULL;
AioContext *aio_context; AioContext *aio_context;
BlockDriverState *image_bs = NULL; BlockDriverState *image_bs = NULL;
@ -2741,12 +2767,12 @@ void qmp_change_backing_file(const char *device,
int open_flags; int open_flags;
int ret; int ret;
/* find the top layer BDS of the chain */ blk = blk_by_name(device);
bs = bdrv_find(device); if (!blk) {
if (!bs) {
error_set(errp, QERR_DEVICE_NOT_FOUND, device); error_set(errp, QERR_DEVICE_NOT_FOUND, device);
return; return;
} }
bs = blk_bs(blk);
aio_context = bdrv_get_aio_context(bs); aio_context = bdrv_get_aio_context(bs);
aio_context_acquire(aio_context); aio_context_acquire(aio_context);

View File

@ -381,7 +381,6 @@ int bdrv_media_changed(BlockDriverState *bs);
void bdrv_lock_medium(BlockDriverState *bs, bool locked); void bdrv_lock_medium(BlockDriverState *bs, bool locked);
void bdrv_eject(BlockDriverState *bs, bool eject_flag); void bdrv_eject(BlockDriverState *bs, bool eject_flag);
const char *bdrv_get_format_name(BlockDriverState *bs); const char *bdrv_get_format_name(BlockDriverState *bs);
BlockDriverState *bdrv_find(const char *name);
BlockDriverState *bdrv_find_node(const char *node_name); BlockDriverState *bdrv_find_node(const char *node_name);
BlockDeviceInfoList *bdrv_named_nodes_list(void); BlockDeviceInfoList *bdrv_named_nodes_list(void);
BlockDriverState *bdrv_lookup_bs(const char *device, BlockDriverState *bdrv_lookup_bs(const char *device,

View File

@ -23,6 +23,7 @@
#include "migration/block.h" #include "migration/block.h"
#include "migration/migration.h" #include "migration/migration.h"
#include "sysemu/blockdev.h" #include "sysemu/blockdev.h"
#include "sysemu/block-backend.h"
#include <assert.h> #include <assert.h>
#define BLOCK_SIZE (1 << 20) #define BLOCK_SIZE (1 << 20)
@ -783,6 +784,7 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
char device_name[256]; char device_name[256];
int64_t addr; int64_t addr;
BlockDriverState *bs, *bs_prev = NULL; BlockDriverState *bs, *bs_prev = NULL;
BlockBackend *blk;
uint8_t *buf; uint8_t *buf;
int64_t total_sectors = 0; int64_t total_sectors = 0;
int nr_sectors; int nr_sectors;
@ -800,12 +802,13 @@ static int block_load(QEMUFile *f, void *opaque, int version_id)
qemu_get_buffer(f, (uint8_t *)device_name, len); qemu_get_buffer(f, (uint8_t *)device_name, len);
device_name[len] = '\0'; device_name[len] = '\0';
bs = bdrv_find(device_name); blk = blk_by_name(device_name);
if (!bs) { if (!blk) {
fprintf(stderr, "Error unknown block device %s\n", fprintf(stderr, "Error unknown block device %s\n",
device_name); device_name);
return -EINVAL; return -EINVAL;
} }
bs = blk_bs(blk);
if (bs != bs_prev) { if (bs != bs_prev) {
bs_prev = bs; bs_prev = bs;

View File

@ -73,6 +73,7 @@
#include "block/qapi.h" #include "block/qapi.h"
#include "qapi/qmp-event.h" #include "qapi/qmp-event.h"
#include "qapi-event.h" #include "qapi-event.h"
#include "sysemu/block-backend.h"
/* for hmp_info_irq/pic */ /* for hmp_info_irq/pic */
#if defined(TARGET_SPARC) #if defined(TARGET_SPARC)
@ -5414,15 +5415,15 @@ int monitor_read_block_device_key(Monitor *mon, const char *device,
BlockCompletionFunc *completion_cb, BlockCompletionFunc *completion_cb,
void *opaque) void *opaque)
{ {
BlockDriverState *bs; BlockBackend *blk;
bs = bdrv_find(device); blk = blk_by_name(device);
if (!bs) { if (!blk) {
monitor_printf(mon, "Device not found %s\n", device); monitor_printf(mon, "Device not found %s\n", device);
return -1; return -1;
} }
return monitor_read_bdrv_key_start(mon, bs, completion_cb, opaque); return monitor_read_bdrv_key_start(mon, blk_bs(blk), completion_cb, opaque);
} }
QemuOptsList qemu_mon_opts = { QemuOptsList qemu_mon_opts = {

View File

@ -1961,10 +1961,6 @@
# @write-threshold: configured threshold for the block device, bytes. # @write-threshold: configured threshold for the block device, bytes.
# Use 0 to disable the threshold. # Use 0 to disable the threshold.
# #
# Returns: Nothing on success
# If @node name is not found on the block device graph,
# DeviceNotFound
#
# Since: 2.3 # Since: 2.3
## ##
{ 'command': 'block-set-write-threshold', { 'command': 'block-set-write-threshold',

View File

@ -539,8 +539,8 @@ storage.
@item qcow2 @item qcow2
QEMU image format, the most versatile format. Use it to have smaller QEMU image format, the most versatile format. Use it to have smaller
images (useful if your filesystem does not supports holes, for example images (useful if your filesystem does not supports holes, for example
on Windows), optional AES encryption, zlib based compression and on Windows), zlib based compression and support of multiple VM
support of multiple VM snapshots. snapshots.
Supported options: Supported options:
@table @code @table @code
@ -574,9 +574,10 @@ original file must then be securely erased using a program like shred,
though even this is ineffective with many modern storage technologies. though even this is ineffective with many modern storage technologies.
@end itemize @end itemize
Use of qcow / qcow2 encryption is thus strongly discouraged. Users are Use of qcow / qcow2 encryption with QEMU is deprecated, and support for
recommended to use an alternative encryption technology such as the it will go away in a future release. Users are recommended to use an
Linux dm-crypt / LUKS system. alternative encryption technology such as the Linux dm-crypt / LUKS
system.
@item cluster_size @item cluster_size
Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster Changes the qcow2 cluster size (must be between 512 and 2M). Smaller cluster

View File

@ -274,8 +274,7 @@ static int print_block_option_help(const char *filename, const char *fmt)
if (filename) { if (filename) {
proto_drv = bdrv_find_protocol(filename, true, &local_err); proto_drv = bdrv_find_protocol(filename, true, &local_err);
if (!proto_drv) { if (!proto_drv) {
qerror_report_err(local_err); error_report_err(local_err);
error_free(local_err);
qemu_opts_free(create_opts); qemu_opts_free(create_opts);
return 1; return 1;
} }
@ -1526,8 +1525,7 @@ static int img_convert(int argc, char **argv)
proto_drv = bdrv_find_protocol(out_filename, true, &local_err); proto_drv = bdrv_find_protocol(out_filename, true, &local_err);
if (!proto_drv) { if (!proto_drv) {
qerror_report_err(local_err); error_report_err(local_err);
error_free(local_err);
ret = -1; ret = -1;
goto out; goto out;
} }
@ -1554,8 +1552,7 @@ static int img_convert(int argc, char **argv)
if (options) { if (options) {
qemu_opts_do_parse(opts, options, NULL, &local_err); qemu_opts_do_parse(opts, options, NULL, &local_err);
if (local_err) { if (local_err) {
error_report("Invalid options for file format '%s'", out_fmt); error_report_err(local_err);
error_free(local_err);
ret = -1; ret = -1;
goto out; goto out;
} }
@ -3001,8 +2998,7 @@ static int img_amend(int argc, char **argv)
if (options) { if (options) {
qemu_opts_do_parse(opts, options, NULL, &err); qemu_opts_do_parse(opts, options, NULL, &err);
if (err) { if (err) {
error_report("Invalid options for file format '%s'", fmt); error_report_err(err);
error_free(err);
ret = -1; ret = -1;
goto out; goto out;
} }

View File

@ -188,6 +188,12 @@ qemu-img create -f qcow2 -o encryption=off TEST_DIR/t.qcow2 64M
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=off cluster_size=65536 lazy_refcounts=off refcount_bits=16
qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M qemu-img create -f qcow2 -o encryption=on TEST_DIR/t.qcow2 64M
qemu-img: Encrypted images are deprecated
Support for them will be removed in a future release.
You can use 'qemu-img convert' to convert your image to an unencrypted one.
qemu-img: Encrypted images are deprecated
Support for them will be removed in a future release.
You can use 'qemu-img convert' to convert your image to an unencrypted one.
Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16 Formatting 'TEST_DIR/t.qcow2', fmt=qcow2 size=67108864 encryption=on cluster_size=65536 lazy_refcounts=off refcount_bits=16
== Check lazy_refcounts option (only with v3) == == Check lazy_refcounts option (only with v3) ==

View File

@ -128,13 +128,11 @@ QEMU_PROG: Initialization of device ide-hd failed: Device initialization failed.
Testing: -drive if=virtio Testing: -drive if=virtio
QEMU X.Y.Z monitor - type 'help' for more information QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty (qemu) QEMU_PROG: -drive if=virtio: Device needs media, but drive is empty
QEMU_PROG: -drive if=virtio: Device initialization failed.
QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized QEMU_PROG: -drive if=virtio: Device 'virtio-blk-pci' could not be initialized
Testing: -drive if=scsi Testing: -drive if=scsi
QEMU X.Y.Z monitor - type 'help' for more information QEMU X.Y.Z monitor - type 'help' for more information
(qemu) QEMU_PROG: -drive if=scsi: Device needs media, but drive is empty (qemu) QEMU_PROG: Initialization of device lsi53c895a failed: Device needs media, but drive is empty
QEMU_PROG: Initialization of device lsi53c895a failed: Device initialization failed.
Testing: -drive if=none,id=disk -device ide-cd,drive=disk Testing: -drive if=none,id=disk -device ide-cd,drive=disk
QEMU X.Y.Z monitor - type 'help' for more information QEMU X.Y.Z monitor - type 'help' for more information

View File

@ -288,7 +288,6 @@ qemu-img: Error while amending options: Invalid argument
Unknown compatibility level 0.42. Unknown compatibility level 0.42.
qemu-img: Error while amending options: Invalid argument qemu-img: Error while amending options: Invalid argument
qemu-img: Invalid parameter 'foo' qemu-img: Invalid parameter 'foo'
qemu-img: Invalid options for file format 'qcow2'
Changing the cluster size is not supported. Changing the cluster size is not supported.
qemu-img: Error while amending options: Operation not supported qemu-img: Error while amending options: Operation not supported
Changing the encryption flag is not supported. Changing the encryption flag is not supported.

View File

@ -44,10 +44,19 @@ QMP_VERSION
=== Encrypted image === === Encrypted image ===
qemu-img: Encrypted images are deprecated
Support for them will be removed in a future release.
You can use 'qemu-img convert' to convert your image to an unencrypted one.
qemu-img: Encrypted images are deprecated
Support for them will be removed in a future release.
You can use 'qemu-img convert' to convert your image to an unencrypted one.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
Testing: -S Testing: -S
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
Encrypted images are deprecated
Support for them will be removed in a future release.
You can use 'qemu-img convert' to convert your image to an unencrypted one.
{"error": {"class": "GenericError", "desc": "blockdev-add doesn't support encrypted devices"}} {"error": {"class": "GenericError", "desc": "blockdev-add doesn't support encrypted devices"}}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
@ -57,6 +66,9 @@ QMP_VERSION
Testing: Testing:
QMP_VERSION QMP_VERSION
{"return": {}} {"return": {}}
Encrypted images are deprecated
Support for them will be removed in a future release.
You can use 'qemu-img convert' to convert your image to an unencrypted one.
{"error": {"class": "GenericError", "desc": "Guest must be stopped for opening of encrypted image"}} {"error": {"class": "GenericError", "desc": "Guest must be stopped for opening of encrypted image"}}
{"return": {}} {"return": {}}
{"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"} {"timestamp": {"seconds": TIMESTAMP, "microseconds": TIMESTAMP}, "event": "SHUTDOWN"}
@ -66,6 +78,12 @@ QMP_VERSION
=== Missing driver === === Missing driver ===
qemu-img: Encrypted images are deprecated
Support for them will be removed in a future release.
You can use 'qemu-img convert' to convert your image to an unencrypted one.
qemu-img: Encrypted images are deprecated
Support for them will be removed in a future release.
You can use 'qemu-img convert' to convert your image to an unencrypted one.
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=134217728 encryption=on
Testing: -S Testing: -S
QMP_VERSION QMP_VERSION

95
tests/qemu-iotests/115 Executable file
View File

@ -0,0 +1,95 @@
#!/bin/bash
#
# Test case for non-self-referential qcow2 refcount blocks
#
# Copyright (C) 2014 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# creator
owner=mreitz@redhat.com
seq="$(basename $0)"
echo "QA output created by $seq"
here="$PWD"
tmp=/tmp/$$
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
# This test relies on refcounts being 64 bits wide (which does not work with
# compat=0.10)
_unsupported_imgopts 'refcount_bits=\([^6]\|.\([^4]\|$\)\)' 'compat=0.10'
echo
echo '=== Testing large refcount and L1 table ==='
echo
# Create an image with an L1 table and a refcount table that each span twice the
# number of clusters which can be described by a single refblock; therefore, at
# least two refblocks cannot count their own refcounts because all the clusters
# they describe are part of the L1 table or refcount table.
# One refblock can describe (with cluster_size=512 and refcount_bits=64)
# 512/8 = 64 clusters, therefore the L1 table should cover 128 clusters, which
# equals 128 * (512/8) = 8192 entries (actually, 8192 - 512/8 = 8129 would
# suffice, but it does not really matter). 8192 L2 tables can in turn describe
# 8192 * 512/8 = 524,288 clusters which cover a space of 256 MB.
# Since with refcount_bits=64 every refcount block entry is 64 bits wide (just
# like the L2 table entries), the same calculation applies to the refcount table
# as well; the difference is that while for the L1 table the guest disk size is
# concerned, for the refcount table it is the image length that has to be at
# least 256 MB. We can achieve that by using preallocation=metadata for an image
# which has a guest disk size of 256 MB.
IMGOPTS="$IMGOPTS,refcount_bits=64,cluster_size=512,preallocation=metadata" \
_make_test_img 256M
# We know for sure that the L1 and refcount tables do not overlap with any other
# structure because the metadata overlap checks would have caught that case.
# Because qemu refuses to open qcow2 files whose L1 table does not cover the
# whole guest disk size, it is definitely large enough. On the other hand, to
# test whether the refcount table is large enough, we simply have to verify that
# indeed all the clusters are allocated, which is done by qemu-img check.
# The final thing we need to test is whether the tables are actually covered by
# refcount blocks; since all clusters of the tables are referenced, we can use
# qemu-img check for that purpose, too.
$QEMU_IMG check "$TEST_IMG" | \
sed -e 's/^.* = \([0-9]\+\.[0-9]\+% allocated\).*\(clusters\)$/\1 \2/' \
-e '/^Image end offset/d'
# (Note that we cannot use _check_test_img because that function filters out the
# allocation status)
# success, all done
echo '*** done'
rm -f $seq.full
status=0

View File

@ -0,0 +1,8 @@
QA output created by 115
=== Testing large refcount and L1 table ===
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=268435456 preallocation='metadata'
No errors were found on the image.
100.00% allocated clusters
*** done

102
tests/qemu-iotests/121 Executable file
View File

@ -0,0 +1,102 @@
#!/bin/bash
#
# Test cases for qcow2 refcount table growth
#
# Copyright (C) 2015 Red Hat, Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# creator
owner=mreitz@redhat.com
seq="$(basename $0)"
echo "QA output created by $seq"
here="$PWD"
tmp=/tmp/$$
status=1 # failure is the default!
_cleanup()
{
_cleanup_test_img
}
trap "_cleanup; exit \$status" 0 1 2 3 15
# get standard environment, filters and checks
. ./common.rc
. ./common.filter
_supported_fmt qcow2
_supported_proto file
_supported_os Linux
echo
echo '=== New refcount structures may not conflict with existing structures ==='
echo
echo '--- Test 1 ---'
echo
# Preallocation speeds up the write operation, but preallocating everything will
# destroy the purpose of the write; so preallocate one KB less than what would
# cause a reftable growth...
IMGOPTS='preallocation=metadata,cluster_size=1k' _make_test_img 64512K
# ...and make the image the desired size afterwards.
$QEMU_IMG resize "$TEST_IMG" 65M
# The first write results in a growth of the refcount table during an allocation
# which has precisely the required size so that the new refcount block allocated
# in alloc_refcount_block() is right after cluster_index; this did lead to a
# different refcount block being written to disk (a zeroed cluster) than what is
# cached (a refblock with one entry having a refcount of 1), and the second
# write would then result in that cached cluster being marked dirty and then
# in it being written to disk.
# This should not happen, the new refcount structures may not conflict with
# new_block.
# (Note that for some reason, 'write 63M 1K' does not trigger the problem)
$QEMU_IO -c 'write 62M 1025K' -c 'write 64M 1M' "$TEST_IMG" | _filter_qemu_io
_check_test_img
echo
echo '--- Test 2 ---'
echo
IMGOPTS='preallocation=metadata,cluster_size=1k' _make_test_img 64513K
# This results in an L1 table growth which in turn results in some clusters at
# the start of the image becoming free
$QEMU_IMG resize "$TEST_IMG" 65M
# This write results in a refcount table growth; but the refblock allocated
# immediately before that (new_block) takes cluster index 4 (which is now free)
# and is thus not self-describing (in contrast to test 1, where new_block was
# self-describing). The refcount table growth algorithm then used to place the
# new refcount structures at cluster index 65536 (which is the same as the
# cluster_index parameter in this case), allocating a new refcount block for
# that cluster while new_block already existed, leaking new_block.
# Therefore, the new refcount structures may not be put at cluster_index
# (because new_block already describes that cluster, and the new structures try
# to be self-describing).
$QEMU_IO -c 'write 63M 130K' "$TEST_IMG" | _filter_qemu_io
_check_test_img
# success, all done
echo
echo '*** done'
rm -f $seq.full
status=0

View File

@ -0,0 +1,23 @@
QA output created by 121
=== New refcount structures may not conflict with existing structures ===
--- Test 1 ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=66060288 preallocation='metadata'
Image resized.
wrote 1049600/1049600 bytes at offset 65011712
1.001 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
wrote 1048576/1048576 bytes at offset 67108864
1 MiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
No errors were found on the image.
--- Test 2 ---
Formatting 'TEST_DIR/t.IMGFMT', fmt=IMGFMT size=66061312 preallocation='metadata'
Image resized.
wrote 133120/133120 bytes at offset 66060288
130 KiB, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
No errors were found on the image.
*** done

View File

@ -119,6 +119,8 @@
112 rw auto 112 rw auto
113 rw auto quick 113 rw auto quick
114 rw auto quick 114 rw auto quick
115 rw auto
116 rw auto quick 116 rw auto quick
121 rw auto
123 rw auto quick 123 rw auto quick
128 rw auto quick 128 rw auto quick