[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH v2 5/6] VMDK: read/write compressed extent
From: |
Fam Zheng |
Subject: |
[Qemu-devel] [PATCH v2 5/6] VMDK: read/write compressed extent |
Date: |
Thu, 4 Aug 2011 11:09:20 +0800 |
Add support for reading/writing compressed extent.
Signed-off-by: Fam Zheng <address@hidden>
---
block/vmdk.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 101 insertions(+), 12 deletions(-)
diff --git a/block/vmdk.c b/block/vmdk.c
index df93ba5..da34b9d 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -774,10 +774,12 @@ static int get_cluster_offset(BlockDriverState *bs,
/* Avoid the L2 tables update for the images that have snapshots. */
*cluster_offset = bdrv_getlength(extent->file);
- bdrv_truncate(
- extent->file,
- *cluster_offset + (extent->cluster_sectors << 9)
- );
+ if (!extent->compressed) {
+ bdrv_truncate(
+ extent->file,
+ *cluster_offset + (extent->cluster_sectors << 9)
+ );
+ }
*cluster_offset >>= 9;
tmp = cpu_to_le32(*cluster_offset);
@@ -853,9 +855,28 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t
cluster_offset,
int nb_sectors, int64_t sector_num)
{
int ret;
+ VmdkGrainMarker *data = NULL;
+ uLongf buf_len;
const uint8_t *write_buf = buf;
int write_len = nb_sectors * 512;
+ if (extent->compressed) {
+ if (!extent->has_marker) {
+ ret = -EINVAL;
+ goto out;
+ }
+ buf_len = (extent->cluster_sectors << 9) * 2;
+ data = qemu_malloc(buf_len + sizeof(VmdkGrainMarker));
+ if (compress(data->data, &buf_len, buf, nb_sectors << 9) != Z_OK ||
+ buf_len == 0) {
+ ret = -EINVAL;
+ goto out;
+ }
+ data->lba = sector_num;
+ data->size = buf_len;
+ write_buf = (uint8_t *)data;
+ write_len = buf_len + sizeof(VmdkGrainMarker);
+ }
ret = bdrv_pwrite(extent->file,
cluster_offset + offset_in_cluster,
write_buf,
@@ -866,6 +887,7 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t
cluster_offset,
}
ret = 0;
out:
+ qemu_free(data);
return ret;
}
@@ -874,15 +896,65 @@ static int vmdk_read_extent(VmdkExtent *extent, int64_t
cluster_offset,
int nb_sectors)
{
int ret;
-
+ int cluster_bytes, buf_bytes;
+ uint8_t *cluster_buf, *compressed_data;
+ uint8_t *uncomp_buf;
+ uint32_t data_len;
+ VmdkGrainMarker *marker;
+ uLongf buf_len;
+
+
+ if (!extent->compressed) {
+ ret = bdrv_pread(extent->file,
+ cluster_offset + offset_in_cluster,
+ buf, nb_sectors * 512);
+ if (ret == nb_sectors * 512) {
+ return 0;
+ } else {
+ return -EIO;
+ }
+ }
+ cluster_bytes = extent->cluster_sectors * 512;
+ /* Read two clusters in case GrainMarker + compressed data > one cluster */
+ buf_bytes = cluster_bytes * 2;
+ cluster_buf = qemu_malloc(buf_bytes);
+ uncomp_buf = qemu_malloc(cluster_bytes);
ret = bdrv_pread(extent->file,
- cluster_offset + offset_in_cluster,
- buf, nb_sectors * 512);
- if (ret == nb_sectors * 512) {
- return 0;
- } else {
- return -EIO;
+ cluster_offset,
+ cluster_buf, buf_bytes);
+ if (ret < 0) {
+ goto out;
}
+ compressed_data = cluster_buf;
+ buf_len = cluster_bytes;
+ data_len = cluster_bytes;
+ if (extent->has_marker) {
+ marker = (VmdkGrainMarker *)cluster_buf;
+ compressed_data = marker->data;
+ data_len = le32_to_cpu(marker->size);
+ }
+ if (!data_len || data_len > buf_bytes) {
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = uncompress(uncomp_buf, &buf_len, compressed_data, data_len);
+ if (ret != Z_OK) {
+ ret = -EINVAL;
+ goto out;
+
+ }
+ if (offset_in_cluster < 0 ||
+ offset_in_cluster + nb_sectors * 512 > buf_len) {
+ ret = -EINVAL;
+ goto out;
+ }
+ memcpy(buf, uncomp_buf + offset_in_cluster, nb_sectors * 512);
+ ret = 0;
+
+ out:
+ qemu_free(uncomp_buf);
+ qemu_free(cluster_buf);
+ return ret;
}
static int vmdk_read(BlockDriverState *bs, int64_t sector_num,
@@ -962,8 +1034,25 @@ static int vmdk_write(BlockDriverState *bs, int64_t
sector_num,
bs,
extent,
&m_data,
- sector_num << 9, 1,
+ sector_num << 9, !extent->compressed,
&cluster_offset);
+ if (extent->compressed) {
+ if (ret == 0) {
+ /* Refuse write to allocated cluster for streamOptimized */
+ fprintf(stderr,
+ "VMDK: can't write to allocated cluster"
+ " for streamOptimized\n");
+ return -EIO;
+ } else {
+ /* allocate */
+ ret = get_cluster_offset(
+ bs,
+ extent,
+ &m_data,
+ sector_num << 9, 1,
+ &cluster_offset);
+ }
+ }
if (ret) {
return -EINVAL;
}