diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/loop/loop_file_fmt_qcow_main.c | 18 | ||||
-rw-r--r-- | drivers/block/loop/loop_file_fmt_qcow_main.h | 4 |
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 */ |