From: Bakul Shah <bakul+qemu@bitblocks.com>
To: qemu-devel@nongnu.org
Subject: [Qemu-devel] patch to avoid space allocation for zero blocks in the qcow format
Date: Mon, 24 Apr 2006 15:12:06 -0700 [thread overview]
Message-ID: <20060424221206.9BFF42946A@mail.bitblocks.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 720 bytes --]
The below patch avoids allocating space in the qcow image
format when a block of zeroes is being written. No attempt
is made to free up space if a previously written block of
nonzero data is being overwritten with zeroes. This patch
makes a big difference in space use for cases where the s/w
wants to clear large swaths of a disk (such as Plan 9 with
fossil+venti). It has a negligible effect on performance for
writing nonzero data and significat performance improvement
for zero data as the much bigger overhead of allocating and
writing is avoided. As an added benefit you can simulate
extremely large disks and create huge files of zeroes to
test whether your guest OS can handle 2^63 byte size disk.
-- bakul
[-- Attachment #2: Type: text/plain, Size: 3954 bytes --]
--- cvs/block-qcow.c Fri Apr 21 12:46:44 2006
+++ my/block-qcow.c Sun Apr 23 17:37:54 2006
@@ -256,12 +256,18 @@
* 'compressed_size'. 'compressed_size' must be > 0 and <
* cluster_size
*
+ * 'z' is
+ *
+ * 1 if data to be written is all zeroes.
+ * set it to 0 if the cluster was previously allocated
+ * else leave it as 1 and don't allocate
+ *
* return 0 if not allocated.
*/
static uint64_t get_cluster_offset(BlockDriverState *bs,
uint64_t offset, int allocate,
int compressed_size,
- int n_start, int n_end)
+ int n_start, int n_end, int* z)
{
BDRVQcowState *s = bs->opaque;
int min_index, i, j, l1_index, l2_index;
@@ -273,7 +279,7 @@
l2_offset = s->l1_table[l1_index];
new_l2_table = 0;
if (!l2_offset) {
- if (!allocate)
+ if (!allocate || *z)
return 0;
/* allocate a new l2 entry */
l2_offset = lseek(s->fd, 0, SEEK_END);
@@ -296,10 +302,13 @@
}
}
l2_table = s->l2_cache + (i << s->l2_bits);
+ if (z) *z = 0;
goto found;
}
}
/* not found: load a new entry in the least used one */
+ if (z && *z) /* no allocation if we are writing a zero buf */
+ return 0;
min_index = 0;
min_count = 0xffffffff;
for(i = 0; i < L2_CACHE_SIZE; i++) {
@@ -393,7 +402,7 @@
int index_in_cluster, n;
uint64_t cluster_offset;
- cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
+ cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0, 0);
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
@@ -459,7 +468,7 @@
uint64_t cluster_offset;
while (nb_sectors > 0) {
- cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0);
+ cluster_offset = get_cluster_offset(bs, sector_num << 9, 0, 0, 0, 0, 0);
index_in_cluster = sector_num & (s->cluster_sectors - 1);
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
@@ -487,11 +496,13 @@
return 0;
}
+static uint8_t zerobuf[0x10000] = {0}; // XXX depends on cluster_sectors
+
static int qcow_write(BlockDriverState *bs, int64_t sector_num,
const uint8_t *buf, int nb_sectors)
{
BDRVQcowState *s = bs->opaque;
- int ret, index_in_cluster, n;
+ int ret, index_in_cluster, n, z;
uint64_t cluster_offset;
while (nb_sectors > 0) {
@@ -499,9 +510,11 @@
n = s->cluster_sectors - index_in_cluster;
if (n > nb_sectors)
n = nb_sectors;
+ z = !buf[0] && !buf[n*512-1] && memcmp(buf, zerobuf, n*512) == 0;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1, 0,
index_in_cluster,
- index_in_cluster + n);
+ index_in_cluster + n, &z);
+ if (!z) {
if (!cluster_offset)
return -1;
lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
@@ -514,6 +527,7 @@
}
if (ret != n * 512)
return -1;
+ }
nb_sectors -= n;
sector_num += n;
buf += n * 512;
@@ -679,8 +693,9 @@
/* could not compress: write normal cluster */
qcow_write(bs, sector_num, buf, s->cluster_sectors);
} else {
+ int z = 0;
cluster_offset = get_cluster_offset(bs, sector_num << 9, 2,
- out_len, 0, 0);
+ out_len, 0, 0, &z);
cluster_offset &= s->cluster_offset_mask;
lseek(s->fd, cluster_offset, SEEK_SET);
if (write(s->fd, out_buf, out_len) != out_len) {
next reply other threads:[~2006-04-24 22:12 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-04-24 22:12 Bakul Shah [this message]
2006-04-24 23:43 ` [Qemu-devel] Re: patch to avoid space allocation for zero blocks in the qcow format Ben Pfaff
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20060424221206.9BFF42946A@mail.bitblocks.com \
--to=bakul+qemu@bitblocks.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).