summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/block/loop/loop_file_fmt_qcow_main.c18
-rw-r--r--drivers/block/loop/loop_file_fmt_qcow_main.h4
2 files changed, 14 insertions, 8 deletions
diff --git a/drivers/block/loop/loop_file_fmt_qcow_main.c b/drivers/block/loop/loop_file_fmt_qcow_main.c
index dc2a7b0ee287..4a1fb5bf346d 100644
--- a/drivers/block/loop/loop_file_fmt_qcow_main.c
+++ b/drivers/block/loop/loop_file_fmt_qcow_main.c
@@ -148,13 +148,13 @@ static int __qcow_file_fmt_compression_init(struct loop_file_fmt *lo_fmt)
struct loop_file_fmt_qcow_data *qcow_data = lo_fmt->private_data;
int ret = 0;
- qcow_data->strm = kmalloc(sizeof(*qcow_data->strm), GFP_KERNEL);
+ qcow_data->strm = kzalloc(sizeof(*qcow_data->strm), GFP_KERNEL);
if (!qcow_data->strm) {
ret = -ENOMEM;
goto out;
}
- qcow_data->strm->workspace = vmalloc(zlib_inflate_workspacesize());
+ qcow_data->strm->workspace = vzalloc(zlib_inflate_workspacesize());
if (!qcow_data->strm->workspace) {
ret = -ENOMEM;
goto out_free_strm;
@@ -724,7 +724,8 @@ static int __qcow_file_fmt_read_compressed(struct loop_file_fmt *lo_fmt,
struct bio_vec *bvec,
u64 file_cluster_offset,
u64 offset,
- u64 bytes)
+ u64 bytes,
+ u64 bytes_done)
{
struct loop_file_fmt_qcow_data *qcow_data = lo_fmt->private_data;
struct loop_device *lo = loop_file_fmt_get_lo(lo_fmt);
@@ -732,15 +733,16 @@ static int __qcow_file_fmt_read_compressed(struct loop_file_fmt *lo_fmt,
u64 coffset;
u8 *in_buf, *out_buf;
ssize_t len;
- int offset_in_cluster = loop_file_fmt_qcow_offset_into_cluster(
- qcow_data, offset);
void *data;
unsigned long irq_flags;
+ int offset_in_cluster = loop_file_fmt_qcow_offset_into_cluster(
+ qcow_data, offset);
coffset = file_cluster_offset & qcow_data->cluster_offset_mask;
nb_csectors = ((file_cluster_offset >> qcow_data->csize_shift) &
qcow_data->csize_mask) + 1;
- csize = nb_csectors * 512 - (coffset & 511);
+ csize = nb_csectors * QCOW_COMPRESSED_SECTOR_SIZE -
+ (coffset & ~QCOW_COMPRESSED_SECTOR_MASK);
in_buf = vmalloc(csize);
if (!in_buf) {
@@ -766,7 +768,7 @@ static int __qcow_file_fmt_read_compressed(struct loop_file_fmt *lo_fmt,
}
ASSERT(bytes <= bvec->bv_len);
- data = bvec_kmap_irq(bvec, &irq_flags);
+ data = bvec_kmap_irq(bvec, &irq_flags) + bytes_done;
memcpy(data, out_buf + offset_in_cluster, bytes);
flush_dcache_page(bvec->bv_page);
bvec_kunmap_irq(data, &irq_flags);
@@ -824,7 +826,7 @@ static int __qcow_file_fmt_read_bvec(struct loop_file_fmt *lo_fmt,
case QCOW_CLUSTER_COMPRESSED:
ret = __qcow_file_fmt_read_compressed(lo_fmt, bvec,
- cluster_offset, *ppos, cur_bytes);
+ cluster_offset, *ppos, cur_bytes, bytes_done);
if (ret < 0) {
goto fail;
}
diff --git a/drivers/block/loop/loop_file_fmt_qcow_main.h b/drivers/block/loop/loop_file_fmt_qcow_main.h
index 8f2fa32cb422..9e4951fba079 100644
--- a/drivers/block/loop/loop_file_fmt_qcow_main.h
+++ b/drivers/block/loop/loop_file_fmt_qcow_main.h
@@ -83,6 +83,10 @@ do { \
#define QCOW_MIN_CLUSTER_BITS 9
#define QCOW_MAX_CLUSTER_BITS 21
+/* Defined in the qcow2 spec (compressed cluster descriptor) */
+#define QCOW_COMPRESSED_SECTOR_SIZE 512U
+#define QCOW_COMPRESSED_SECTOR_MASK (~(QCOW_COMPRESSED_SECTOR_SIZE - 1))
+
/* Must be at least 2 to cover COW */
#define QCOW_MIN_L2_CACHE_SIZE 2 /* cache entries */