#include "qemu/osdep.h"
#include "qapi/error.h"
-#include "qemu-common.h"
#include "qcow2.h"
#include "qemu/range.h"
#include "qemu/bswap.h"
#include "qemu/cutils.h"
+#include "trace.h"
static int64_t alloc_clusters_noref(BlockDriverState *bs, uint64_t size,
uint64_t max);
/* Discard is optional, ignore the return value */
if (ret >= 0) {
- bdrv_pdiscard(bs->file, d->offset, d->bytes);
+ int r2 = bdrv_pdiscard(bs->file, d->offset, d->bytes);
+ if (r2 < 0) {
+ trace_qcow2_process_discards_failed_region(d->offset, d->bytes,
+ r2);
+ }
}
g_free(d);
goto resize_fail;
}
- ret = bdrv_truncate(bs->file, offset + s->cluster_size,
+ ret = bdrv_truncate(bs->file, offset + s->cluster_size, false,
PREALLOC_MODE_OFF, &local_err);
if (ret < 0) {
error_report_err(local_err);
"There are no references in the refcount table.");
return -EIO;
}
+
+int qcow2_detect_metadata_preallocation(BlockDriverState *bs)
+{
+ BDRVQcow2State *s = bs->opaque;
+ int64_t i, end_cluster, cluster_count = 0, threshold;
+ int64_t file_length, real_allocation, real_clusters;
+
+ qemu_co_mutex_assert_locked(&s->lock);
+
+ file_length = bdrv_getlength(bs->file->bs);
+ if (file_length < 0) {
+ return file_length;
+ }
+
+ real_allocation = bdrv_get_allocated_file_size(bs->file->bs);
+ if (real_allocation < 0) {
+ return real_allocation;
+ }
+
+ real_clusters = real_allocation / s->cluster_size;
+ threshold = MAX(real_clusters * 10 / 9, real_clusters + 2);
+
+ end_cluster = size_to_clusters(s, file_length);
+ for (i = 0; i < end_cluster && cluster_count < threshold; i++) {
+ uint64_t refcount;
+ int ret = qcow2_get_refcount(bs, i, &refcount);
+ if (ret < 0) {
+ return ret;
+ }
+ cluster_count += !!refcount;
+ }
+
+ return cluster_count >= threshold;
+}