Skip to content

Commit

Permalink
Merge remote-tracking branch 'kwolf/for-anthony' into staging
Browse files Browse the repository at this point in the history
# By Max Reitz (10) and others
# Via Kevin Wolf
* kwolf/for-anthony: (30 commits)
  qcow2: Remove useless count_contiguous_clusters() parameter
  qcow2: COMPRESSED on count_contiguous_clusters
  qcow2: count_contiguous_clusters and compression
  qcow2: Free only newly allocated clusters on error
  qcow2: Always use error path in l2_allocate
  qcow2: Don't put invalid L2 table into cache
  qemu-iotests: Preallocated zero clusters in 061
  qcow2: Correct bitmap size in zero expansion
  qemu-iotests: Quote $TEST_IMG* and $TEST_DIR usage
  qemu-iotests: Add basic ability to use binary sample images
  qemu-iotests: fix qmp.py search path
  block: use DIV_ROUND_UP in bdrv_co_do_readv
  qcow2: Assert against currently impossible overflow
  block: qed - use QEMU_PACKED for on-disk structures
  block: qcow2 - used QEMU_PACKED for on-disk structures
  block: vpc - use QEMU_PACKED for on-disk structures
  block: vdi - use QEMU_PACKED for on-disk structures
  rbd: avoid qemu_rbd_snap_list() memory leaks
  qdict: Extract qdict_extract_subqdict
  block: Fix compiler warning (-Werror=uninitialized)
  ...

Message-id: 1380296370-14523-1-git-send-email-kwolf@redhat.com
  • Loading branch information
aliguori committed Sep 30, 2013
2 parents 3469a60 + 6165300 commit 4235d77
Show file tree
Hide file tree
Showing 75 changed files with 575 additions and 425 deletions.
39 changes: 12 additions & 27 deletions block.c
Expand Up @@ -792,7 +792,7 @@ static int bdrv_open_common(BlockDriverState *bs, BlockDriverState *file,
/* Open the image, either directly or using a protocol */
if (drv->bdrv_file_open) {
assert(file == NULL);
assert(drv->bdrv_parse_filename || filename != NULL);
assert(!drv->bdrv_needs_filename || filename != NULL);
ret = drv->bdrv_file_open(bs, options, open_flags, &local_err);
} else {
if (file == NULL) {
Expand Down Expand Up @@ -911,7 +911,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename,
goto fail;
}
qdict_del(options, "filename");
} else if (!drv->bdrv_parse_filename && !filename) {
} else if (drv->bdrv_needs_filename && !filename) {
error_setg(errp, "The '%s' block driver requires a file name",
drv->format_name);
ret = -EINVAL;
Expand Down Expand Up @@ -978,11 +978,12 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
} else if (bs->backing_file[0] == '\0' && qdict_size(options) == 0) {
QDECREF(options);
return 0;
} else {
bdrv_get_full_backing_filename(bs, backing_filename,
sizeof(backing_filename));
}

bs->backing_hd = bdrv_new("");
bdrv_get_full_backing_filename(bs, backing_filename,
sizeof(backing_filename));

if (bs->backing_format[0] != '\0') {
back_drv = bdrv_find_format(bs->backing_format);
Expand All @@ -994,6 +995,8 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
ret = bdrv_open(bs->backing_hd,
*backing_filename ? backing_filename : NULL, options,
back_flags, back_drv, &local_err);
pstrcpy(bs->backing_file, sizeof(bs->backing_file),
bs->backing_hd->file->filename);
if (ret < 0) {
bdrv_unref(bs->backing_hd);
bs->backing_hd = NULL;
Expand All @@ -1004,25 +1007,6 @@ int bdrv_open_backing_file(BlockDriverState *bs, QDict *options, Error **errp)
return 0;
}

static void extract_subqdict(QDict *src, QDict **dst, const char *start)
{
const QDictEntry *entry, *next;
const char *p;

*dst = qdict_new();
entry = qdict_first(src);

while (entry != NULL) {
next = qdict_next(src, entry);
if (strstart(entry->key, start, &p)) {
qobject_incref(entry->value);
qdict_put_obj(*dst, p, entry->value);
qdict_del(src, entry->key);
}
entry = next;
}
}

/*
* Opens a disk image (raw, qcow2, vmdk, ...)
*
Expand Down Expand Up @@ -1128,7 +1112,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
flags |= BDRV_O_ALLOW_RDWR;
}

extract_subqdict(options, &file_options, "file.");
qdict_extract_subqdict(options, &file_options, "file.");

ret = bdrv_file_open(&file, filename, file_options,
bdrv_open_flags(bs, flags | BDRV_O_UNMAP), &local_err);
Expand Down Expand Up @@ -1166,7 +1150,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, QDict *options,
if ((flags & BDRV_O_NO_BACKING) == 0) {
QDict *backing_options;

extract_subqdict(options, &backing_options, "backing.");
qdict_extract_subqdict(options, &backing_options, "backing.");
ret = bdrv_open_backing_file(bs, backing_options, &local_err);
if (ret < 0) {
goto close_and_fail;
Expand Down Expand Up @@ -2669,7 +2653,7 @@ static int coroutine_fn bdrv_co_do_readv(BlockDriverState *bs,
goto out;
}

total_sectors = (len + BDRV_SECTOR_SIZE - 1) >> BDRV_SECTOR_BITS;
total_sectors = DIV_ROUND_UP(len, BDRV_SECTOR_SIZE);
max_nb_sectors = MAX(0, total_sectors - sector_num);
if (max_nb_sectors > 0) {
ret = drv->bdrv_co_readv(bs, sector_num,
Expand Down Expand Up @@ -3159,13 +3143,14 @@ static int64_t coroutine_fn bdrv_co_get_block_status(BlockDriverState *bs,

ret = bs->drv->bdrv_co_get_block_status(bs, sector_num, nb_sectors, pnum);
if (ret < 0) {
*pnum = 0;
return ret;
}

if (!(ret & BDRV_BLOCK_DATA)) {
if (bdrv_has_zero_init(bs)) {
ret |= BDRV_BLOCK_ZERO;
} else {
} else if (bs->backing_hd) {
BlockDriverState *bs2 = bs->backing_hd;
int64_t length2 = bdrv_getlength(bs2);
if (length2 >= 0 && sector_num >= (length2 >> BDRV_SECTOR_BITS)) {
Expand Down
4 changes: 4 additions & 0 deletions block/gluster.c
Expand Up @@ -611,6 +611,7 @@ static BlockDriver bdrv_gluster = {
.format_name = "gluster",
.protocol_name = "gluster",
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
Expand All @@ -631,6 +632,7 @@ static BlockDriver bdrv_gluster_tcp = {
.format_name = "gluster",
.protocol_name = "gluster+tcp",
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
Expand All @@ -651,6 +653,7 @@ static BlockDriver bdrv_gluster_unix = {
.format_name = "gluster",
.protocol_name = "gluster+unix",
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
Expand All @@ -671,6 +674,7 @@ static BlockDriver bdrv_gluster_rdma = {
.format_name = "gluster",
.protocol_name = "gluster+rdma",
.instance_size = sizeof(BDRVGlusterState),
.bdrv_needs_filename = true,
.bdrv_file_open = qemu_gluster_open,
.bdrv_close = qemu_gluster_close,
.bdrv_create = qemu_gluster_create,
Expand Down
1 change: 1 addition & 0 deletions block/iscsi.c
Expand Up @@ -1520,6 +1520,7 @@ static BlockDriver bdrv_iscsi = {
.protocol_name = "iscsi",

.instance_size = sizeof(IscsiLun),
.bdrv_needs_filename = true,
.bdrv_file_open = iscsi_open,
.bdrv_close = iscsi_close,
.bdrv_create = iscsi_create,
Expand Down
87 changes: 56 additions & 31 deletions block/qcow2-cluster.c
Expand Up @@ -188,7 +188,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
{
BDRVQcowState *s = bs->opaque;
uint64_t old_l2_offset;
uint64_t *l2_table;
uint64_t *l2_table = NULL;
int64_t l2_offset;
int ret;

Expand All @@ -200,7 +200,8 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)

l2_offset = qcow2_alloc_clusters(bs, s->l2_size * sizeof(uint64_t));
if (l2_offset < 0) {
return l2_offset;
ret = l2_offset;
goto fail;
}

ret = qcow2_cache_flush(bs, s->refcount_block_cache);
Expand All @@ -213,7 +214,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
trace_qcow2_l2_allocate_get_empty(bs, l1_index);
ret = qcow2_cache_get_empty(bs, s->l2_table_cache, l2_offset, (void**) table);
if (ret < 0) {
return ret;
goto fail;
}

l2_table = *table;
Expand Down Expand Up @@ -265,7 +266,9 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)

fail:
trace_qcow2_l2_allocate_done(bs, l1_index, ret);
qcow2_cache_put(bs, s->l2_table_cache, (void**) table);
if (l2_table != NULL) {
qcow2_cache_put(bs, s->l2_table_cache, (void**) table);
}
s->l1_table[l1_index] = old_l2_offset;
return ret;
}
Expand All @@ -278,23 +281,26 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table)
* cluster which may require a different handling)
*/
static int count_contiguous_clusters(uint64_t nb_clusters, int cluster_size,
uint64_t *l2_table, uint64_t start, uint64_t stop_flags)
uint64_t *l2_table, uint64_t stop_flags)
{
int i;
uint64_t mask = stop_flags | L2E_OFFSET_MASK;
uint64_t offset = be64_to_cpu(l2_table[0]) & mask;
uint64_t mask = stop_flags | L2E_OFFSET_MASK | QCOW2_CLUSTER_COMPRESSED;
uint64_t first_entry = be64_to_cpu(l2_table[0]);
uint64_t offset = first_entry & mask;

if (!offset)
return 0;

for (i = start; i < start + nb_clusters; i++) {
assert(qcow2_get_cluster_type(first_entry) != QCOW2_CLUSTER_COMPRESSED);

for (i = 0; i < nb_clusters; i++) {
uint64_t l2_entry = be64_to_cpu(l2_table[i]) & mask;
if (offset + (uint64_t) i * cluster_size != l2_entry) {
break;
}
}

return (i - start);
return i;
}

static int count_contiguous_free_clusters(uint64_t nb_clusters, uint64_t *l2_table)
Expand Down Expand Up @@ -487,8 +493,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
return -EIO;
}
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0,
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
&l2_table[l2_index], QCOW_OFLAG_ZERO);
*cluster_offset = 0;
break;
case QCOW2_CLUSTER_UNALLOCATED:
Expand All @@ -499,8 +504,7 @@ int qcow2_get_cluster_offset(BlockDriverState *bs, uint64_t offset,
case QCOW2_CLUSTER_NORMAL:
/* how many allocated clusters ? */
c = count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0,
QCOW_OFLAG_COMPRESSED | QCOW_OFLAG_ZERO);
&l2_table[l2_index], QCOW_OFLAG_ZERO);
*cluster_offset &= L2E_OFFSET_MASK;
break;
default:
Expand Down Expand Up @@ -716,6 +720,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m)
}
qcow2_cache_entry_mark_dirty(s->l2_table_cache, l2_table);

assert(l2_index + m->nb_clusters <= s->l2_size);
for (i = 0; i < m->nb_clusters; i++) {
/* if two concurrent writes happen to the same unallocated cluster
* each write allocates separate cluster and writes data concurrently.
Expand Down Expand Up @@ -929,7 +934,7 @@ static int handle_copied(BlockDriverState *bs, uint64_t guest_offset,
/* We keep all QCOW_OFLAG_COPIED clusters */
keep_clusters =
count_contiguous_clusters(nb_clusters, s->cluster_size,
&l2_table[l2_index], 0,
&l2_table[l2_index],
QCOW_OFLAG_COPIED | QCOW_OFLAG_ZERO);
assert(keep_clusters <= nb_clusters);

Expand Down Expand Up @@ -1509,8 +1514,8 @@ int qcow2_zero_clusters(BlockDriverState *bs, uint64_t offset, int nb_sectors)
* i.e., the number of bits in expanded_clusters.
*/
static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
int l1_size, uint8_t *expanded_clusters,
uint64_t nb_clusters)
int l1_size, uint8_t **expanded_clusters,
uint64_t *nb_clusters)
{
BDRVQcowState *s = bs->opaque;
bool is_active_l1 = (l1_table == s->l1_table);
Expand Down Expand Up @@ -1550,11 +1555,12 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
uint64_t l2_entry = be64_to_cpu(l2_table[j]);
int64_t offset = l2_entry & L2E_OFFSET_MASK, cluster_index;
int cluster_type = qcow2_get_cluster_type(l2_entry);
bool preallocated = offset != 0;

if (cluster_type == QCOW2_CLUSTER_NORMAL) {
cluster_index = offset >> s->cluster_bits;
assert((cluster_index >= 0) && (cluster_index < nb_clusters));
if (expanded_clusters[cluster_index / 8] &
assert((cluster_index >= 0) && (cluster_index < *nb_clusters));
if ((*expanded_clusters)[cluster_index / 8] &
(1 << (cluster_index % 8))) {
/* Probably a shared L2 table; this cluster was a zero
* cluster which has been expanded, its refcount
Expand All @@ -1575,8 +1581,7 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
continue;
}

if (!offset) {
/* not preallocated */
if (!preallocated) {
if (!bs->backing_hd) {
/* not backed; therefore we can simply deallocate the
* cluster */
Expand All @@ -1595,25 +1600,46 @@ static int expand_zero_clusters_in_l1(BlockDriverState *bs, uint64_t *l1_table,
ret = qcow2_pre_write_overlap_check(bs, QCOW2_OL_DEFAULT,
offset, s->cluster_size);
if (ret < 0) {
qcow2_free_clusters(bs, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS);
if (!preallocated) {
qcow2_free_clusters(bs, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS);
}
goto fail;
}

ret = bdrv_write_zeroes(bs->file, offset / BDRV_SECTOR_SIZE,
s->cluster_sectors);
if (ret < 0) {
qcow2_free_clusters(bs, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS);
if (!preallocated) {
qcow2_free_clusters(bs, offset, s->cluster_size,
QCOW2_DISCARD_ALWAYS);
}
goto fail;
}

l2_table[j] = cpu_to_be64(offset | QCOW_OFLAG_COPIED);
l2_dirty = true;

cluster_index = offset >> s->cluster_bits;
assert((cluster_index >= 0) && (cluster_index < nb_clusters));
expanded_clusters[cluster_index / 8] |= 1 << (cluster_index % 8);

if (cluster_index >= *nb_clusters) {
uint64_t old_bitmap_size = (*nb_clusters + 7) / 8;
uint64_t new_bitmap_size;
/* The offset may lie beyond the old end of the underlying image
* file for growable files only */
assert(bs->file->growable);
*nb_clusters = size_to_clusters(s, bs->file->total_sectors *
BDRV_SECTOR_SIZE);
new_bitmap_size = (*nb_clusters + 7) / 8;
*expanded_clusters = g_realloc(*expanded_clusters,
new_bitmap_size);
/* clear the newly allocated space */
memset(&(*expanded_clusters)[old_bitmap_size], 0,
new_bitmap_size - old_bitmap_size);
}

assert((cluster_index >= 0) && (cluster_index < *nb_clusters));
(*expanded_clusters)[cluster_index / 8] |= 1 << (cluster_index % 8);
}

if (is_active_l1) {
Expand Down Expand Up @@ -1672,18 +1698,17 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs)
{
BDRVQcowState *s = bs->opaque;
uint64_t *l1_table = NULL;
int cluster_to_sector_bits = s->cluster_bits - BDRV_SECTOR_BITS;
uint64_t nb_clusters;
uint8_t *expanded_clusters;
int ret;
int i, j;

nb_clusters = (bs->total_sectors + (1 << cluster_to_sector_bits) - 1)
>> cluster_to_sector_bits;
nb_clusters = size_to_clusters(s, bs->file->total_sectors *
BDRV_SECTOR_SIZE);
expanded_clusters = g_malloc0((nb_clusters + 7) / 8);

ret = expand_zero_clusters_in_l1(bs, s->l1_table, s->l1_size,
expanded_clusters, nb_clusters);
&expanded_clusters, &nb_clusters);
if (ret < 0) {
goto fail;
}
Expand Down Expand Up @@ -1717,7 +1742,7 @@ int qcow2_expand_zero_clusters(BlockDriverState *bs)
}

ret = expand_zero_clusters_in_l1(bs, l1_table, s->snapshots[i].l1_size,
expanded_clusters, nb_clusters);
&expanded_clusters, &nb_clusters);
if (ret < 0) {
goto fail;
}
Expand Down
1 change: 0 additions & 1 deletion block/qcow2-refcount.c
Expand Up @@ -874,7 +874,6 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs,
nb_csectors = ((offset >> s->csize_shift) &
s->csize_mask) + 1;
if (addend != 0) {
int ret;
ret = update_refcount(bs,
(offset & s->cluster_offset_mask) & ~511,
nb_csectors * 512, addend,
Expand Down
2 changes: 1 addition & 1 deletion block/qcow2.c
Expand Up @@ -52,7 +52,7 @@
typedef struct {
uint32_t magic;
uint32_t len;
} QCowExtension;
} QEMU_PACKED QCowExtension;

#define QCOW2_EXT_MAGIC_END 0
#define QCOW2_EXT_MAGIC_BACKING_FORMAT 0xE2792ACA
Expand Down

0 comments on commit 4235d77

Please sign in to comment.