[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [PATCH 5/6] VMDK: read/write compressed extent
From: |
Fam Zheng |
Subject: |
[Qemu-devel] [PATCH 5/6] VMDK: read/write compressed extent |
Date: |
Wed, 27 Jul 2011 17:27:45 +0800 |
Add support for reading/writing compressed extent.
Signed-off-by: Fam Zheng <address@hidden>
---
block/vmdk.c | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 103 insertions(+), 12 deletions(-)
diff --git a/block/vmdk.c b/block/vmdk.c
index 5f1638e..4799aa5 100644
--- a/block/vmdk.c
+++ b/block/vmdk.c
@@ -771,10 +771,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);
@@ -850,9 +852,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_mallocz(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,
@@ -863,6 +884,9 @@ static int vmdk_write_extent(VmdkExtent *extent, int64_t
cluster_offset,
}
ret = 0;
out:
+ if (data) {
+ qemu_free(data);
+ }
return ret;
}
@@ -871,15 +895,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_mallocz(buf_bytes);
+ uncomp_buf = qemu_mallocz(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 = 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,
@@ -959,8 +1033,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;
}
- [Qemu-devel] [PATCH 0/6] Add various VMDK subformats support, Fam Zheng, 2011/07/27
- [Qemu-devel] [PATCH 1/6] VMDK: enable twoGbMaxExtentFlat, Fam Zheng, 2011/07/27
- [Qemu-devel] [PATCH 2/6] VMDK: add twoGbMaxExtentSparse support, Fam Zheng, 2011/07/27
- [Qemu-devel] [PATCH 3/6] VMDK: separate vmdk_read_extent/vmdk_write_extent, Fam Zheng, 2011/07/27
- [Qemu-devel] [PATCH 4/6] VMDK: Opening compressed extent., Fam Zheng, 2011/07/27
- [Qemu-devel] [PATCH 5/6] VMDK: read/write compressed extent,
Fam Zheng <=
- [Qemu-devel] [PATCH 6/6] VMDK: creating streamOptimized subformat, Fam Zheng, 2011/07/27