2 * Block driver for Parallels disk image format
4 * Copyright (c) 2007 Alex Beregszaszi
5 * Copyright (c) 2015 Denis V. Lunev <den@openvz.org>
7 * This code was originally based on comparing different disk images created
8 * by Parallels. Currently it is based on opened OpenVZ sources
10 * http://git.openvz.org/?p=ploop;a=summary
12 * Permission is hereby granted, free of charge, to any person obtaining a copy
13 * of this software and associated documentation files (the "Software"), to deal
14 * in the Software without restriction, including without limitation the rights
15 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16 * copies of the Software, and to permit persons to whom the Software is
17 * furnished to do so, subject to the following conditions:
19 * The above copyright notice and this permission notice shall be included in
20 * all copies or substantial portions of the Software.
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 #include "qemu-common.h"
31 #include "block/block_int.h"
32 #include "qemu/module.h"
34 /**************************************************************/
36 #define HEADER_MAGIC "WithoutFreeSpace"
37 #define HEADER_MAGIC2 "WithouFreSpacExt"
38 #define HEADER_VERSION 2
40 #define DEFAULT_CLUSTER_SIZE 1048576 /* 1 MiB */
43 // always little-endian
44 typedef struct ParallelsHeader
{
45 char magic
[16]; // "WithoutFreeSpace"
55 } QEMU_PACKED ParallelsHeader
;
57 typedef struct BDRVParallelsState
{
58 /** Locking is conservative, the lock protects
59 * - image file extending (truncate, fallocate)
60 * - any access to block allocation table
65 unsigned int bat_size
;
69 unsigned int off_multiplier
;
74 static int parallels_probe(const uint8_t *buf
, int buf_size
, const char *filename
)
76 const ParallelsHeader
*ph
= (const void *)buf
;
78 if (buf_size
< sizeof(ParallelsHeader
))
81 if ((!memcmp(ph
->magic
, HEADER_MAGIC
, 16) ||
82 !memcmp(ph
->magic
, HEADER_MAGIC2
, 16)) &&
83 (le32_to_cpu(ph
->version
) == HEADER_VERSION
))
89 static int parallels_open(BlockDriverState
*bs
, QDict
*options
, int flags
,
92 BDRVParallelsState
*s
= bs
->opaque
;
97 ret
= bdrv_pread(bs
->file
, 0, &ph
, sizeof(ph
));
102 bs
->total_sectors
= le64_to_cpu(ph
.nb_sectors
);
104 if (le32_to_cpu(ph
.version
) != HEADER_VERSION
) {
107 if (!memcmp(ph
.magic
, HEADER_MAGIC
, 16)) {
108 s
->off_multiplier
= 1;
109 bs
->total_sectors
= 0xffffffff & bs
->total_sectors
;
110 } else if (!memcmp(ph
.magic
, HEADER_MAGIC2
, 16)) {
111 s
->off_multiplier
= le32_to_cpu(ph
.tracks
);
116 s
->tracks
= le32_to_cpu(ph
.tracks
);
117 if (s
->tracks
== 0) {
118 error_setg(errp
, "Invalid image: Zero sectors per track");
122 if (s
->tracks
> INT32_MAX
/513) {
123 error_setg(errp
, "Invalid image: Too big cluster");
128 s
->bat_size
= le32_to_cpu(ph
.bat_entries
);
129 if (s
->bat_size
> INT_MAX
/ sizeof(uint32_t)) {
130 error_setg(errp
, "Catalog too large");
134 s
->bat_bitmap
= g_try_new(uint32_t, s
->bat_size
);
135 if (s
->bat_size
&& s
->bat_bitmap
== NULL
) {
140 ret
= bdrv_pread(bs
->file
, sizeof(ParallelsHeader
),
141 s
->bat_bitmap
, s
->bat_size
* sizeof(uint32_t));
146 for (i
= 0; i
< s
->bat_size
; i
++) {
147 le32_to_cpus(&s
->bat_bitmap
[i
]);
150 s
->has_truncate
= bdrv_has_zero_init(bs
->file
) &&
151 bdrv_truncate(bs
->file
, bdrv_getlength(bs
->file
)) == 0;
153 qemu_co_mutex_init(&s
->lock
);
157 error_setg(errp
, "Image not in Parallels format");
160 g_free(s
->bat_bitmap
);
164 static int64_t seek_to_sector(BDRVParallelsState
*s
, int64_t sector_num
)
166 uint32_t index
, offset
;
168 index
= sector_num
/ s
->tracks
;
169 offset
= sector_num
% s
->tracks
;
172 if ((index
>= s
->bat_size
) || (s
->bat_bitmap
[index
] == 0)) {
175 return (uint64_t)s
->bat_bitmap
[index
] * s
->off_multiplier
+ offset
;
178 static int cluster_remainder(BDRVParallelsState
*s
, int64_t sector_num
,
181 int ret
= s
->tracks
- sector_num
% s
->tracks
;
182 return MIN(nb_sectors
, ret
);
185 static int64_t allocate_cluster(BlockDriverState
*bs
, int64_t sector_num
)
187 BDRVParallelsState
*s
= bs
->opaque
;
188 uint32_t idx
, offset
, tmp
;
192 idx
= sector_num
/ s
->tracks
;
193 offset
= sector_num
% s
->tracks
;
195 if (idx
>= s
->bat_size
) {
198 if (s
->bat_bitmap
[idx
] != 0) {
199 return (uint64_t)s
->bat_bitmap
[idx
] * s
->off_multiplier
+ offset
;
202 pos
= bdrv_getlength(bs
->file
) >> BDRV_SECTOR_BITS
;
203 if (s
->has_truncate
) {
204 ret
= bdrv_truncate(bs
->file
, (pos
+ s
->tracks
) << BDRV_SECTOR_BITS
);
206 ret
= bdrv_write_zeroes(bs
->file
, pos
, s
->tracks
, 0);
212 s
->bat_bitmap
[idx
] = pos
/ s
->off_multiplier
;
214 tmp
= cpu_to_le32(s
->bat_bitmap
[idx
]);
216 ret
= bdrv_pwrite(bs
->file
,
217 sizeof(ParallelsHeader
) + idx
* sizeof(tmp
), &tmp
, sizeof(tmp
));
219 s
->bat_bitmap
[idx
] = 0;
222 return (uint64_t)s
->bat_bitmap
[idx
] * s
->off_multiplier
+ offset
;
225 static int64_t coroutine_fn
parallels_co_get_block_status(BlockDriverState
*bs
,
226 int64_t sector_num
, int nb_sectors
, int *pnum
)
228 BDRVParallelsState
*s
= bs
->opaque
;
231 qemu_co_mutex_lock(&s
->lock
);
232 offset
= seek_to_sector(s
, sector_num
);
233 qemu_co_mutex_unlock(&s
->lock
);
235 *pnum
= cluster_remainder(s
, sector_num
, nb_sectors
);
241 return (offset
<< BDRV_SECTOR_BITS
) |
242 BDRV_BLOCK_DATA
| BDRV_BLOCK_OFFSET_VALID
;
245 static coroutine_fn
int parallels_co_writev(BlockDriverState
*bs
,
246 int64_t sector_num
, int nb_sectors
, QEMUIOVector
*qiov
)
248 BDRVParallelsState
*s
= bs
->opaque
;
249 uint64_t bytes_done
= 0;
250 QEMUIOVector hd_qiov
;
253 qemu_iovec_init(&hd_qiov
, qiov
->niov
);
255 while (nb_sectors
> 0) {
259 qemu_co_mutex_lock(&s
->lock
);
260 position
= allocate_cluster(bs
, sector_num
);
261 qemu_co_mutex_unlock(&s
->lock
);
267 n
= cluster_remainder(s
, sector_num
, nb_sectors
);
268 nbytes
= n
<< BDRV_SECTOR_BITS
;
270 qemu_iovec_reset(&hd_qiov
);
271 qemu_iovec_concat(&hd_qiov
, qiov
, bytes_done
, nbytes
);
273 ret
= bdrv_co_writev(bs
->file
, position
, n
, &hd_qiov
);
280 bytes_done
+= nbytes
;
283 qemu_iovec_destroy(&hd_qiov
);
287 static coroutine_fn
int parallels_co_readv(BlockDriverState
*bs
,
288 int64_t sector_num
, int nb_sectors
, QEMUIOVector
*qiov
)
290 BDRVParallelsState
*s
= bs
->opaque
;
291 uint64_t bytes_done
= 0;
292 QEMUIOVector hd_qiov
;
295 qemu_iovec_init(&hd_qiov
, qiov
->niov
);
297 while (nb_sectors
> 0) {
301 qemu_co_mutex_lock(&s
->lock
);
302 position
= seek_to_sector(s
, sector_num
);
303 qemu_co_mutex_unlock(&s
->lock
);
305 n
= cluster_remainder(s
, sector_num
, nb_sectors
);
306 nbytes
= n
<< BDRV_SECTOR_BITS
;
309 qemu_iovec_memset(qiov
, bytes_done
, 0, nbytes
);
311 qemu_iovec_reset(&hd_qiov
);
312 qemu_iovec_concat(&hd_qiov
, qiov
, bytes_done
, nbytes
);
314 ret
= bdrv_co_readv(bs
->file
, position
, n
, &hd_qiov
);
322 bytes_done
+= nbytes
;
325 qemu_iovec_destroy(&hd_qiov
);
329 static int parallels_create(const char *filename
, QemuOpts
*opts
, Error
**errp
)
331 int64_t total_size
, cl_size
;
332 uint8_t tmp
[BDRV_SECTOR_SIZE
];
333 Error
*local_err
= NULL
;
334 BlockDriverState
*file
;
335 uint32_t bat_entries
, bat_sectors
;
336 ParallelsHeader header
;
339 total_size
= ROUND_UP(qemu_opt_get_size_del(opts
, BLOCK_OPT_SIZE
, 0),
341 cl_size
= ROUND_UP(qemu_opt_get_size_del(opts
, BLOCK_OPT_CLUSTER_SIZE
,
342 DEFAULT_CLUSTER_SIZE
), BDRV_SECTOR_SIZE
);
344 ret
= bdrv_create_file(filename
, opts
, &local_err
);
346 error_propagate(errp
, local_err
);
351 ret
= bdrv_open(&file
, filename
, NULL
, NULL
,
352 BDRV_O_RDWR
| BDRV_O_PROTOCOL
, NULL
, &local_err
);
354 error_propagate(errp
, local_err
);
357 ret
= bdrv_truncate(file
, 0);
362 bat_entries
= DIV_ROUND_UP(total_size
, cl_size
);
363 bat_sectors
= DIV_ROUND_UP(bat_entries
* sizeof(uint32_t) +
364 sizeof(ParallelsHeader
), cl_size
);
365 bat_sectors
= (bat_sectors
* cl_size
) >> BDRV_SECTOR_BITS
;
367 memset(&header
, 0, sizeof(header
));
368 memcpy(header
.magic
, HEADER_MAGIC2
, sizeof(header
.magic
));
369 header
.version
= cpu_to_le32(HEADER_VERSION
);
370 /* don't care much about geometry, it is not used on image level */
371 header
.heads
= cpu_to_le32(16);
372 header
.cylinders
= cpu_to_le32(total_size
/ BDRV_SECTOR_SIZE
/ 16 / 32);
373 header
.tracks
= cpu_to_le32(cl_size
>> BDRV_SECTOR_BITS
);
374 header
.bat_entries
= cpu_to_le32(bat_entries
);
375 header
.nb_sectors
= cpu_to_le64(DIV_ROUND_UP(total_size
, BDRV_SECTOR_SIZE
));
376 header
.data_off
= cpu_to_le32(bat_sectors
);
378 /* write all the data */
379 memset(tmp
, 0, sizeof(tmp
));
380 memcpy(tmp
, &header
, sizeof(header
));
382 ret
= bdrv_pwrite(file
, 0, tmp
, BDRV_SECTOR_SIZE
);
386 ret
= bdrv_write_zeroes(file
, 1, bat_sectors
- 1, 0);
397 error_setg_errno(errp
, -ret
, "Failed to create Parallels image");
401 static void parallels_close(BlockDriverState
*bs
)
403 BDRVParallelsState
*s
= bs
->opaque
;
404 g_free(s
->bat_bitmap
);
407 static QemuOptsList parallels_create_opts
= {
408 .name
= "parallels-create-opts",
409 .head
= QTAILQ_HEAD_INITIALIZER(parallels_create_opts
.head
),
412 .name
= BLOCK_OPT_SIZE
,
413 .type
= QEMU_OPT_SIZE
,
414 .help
= "Virtual disk size",
417 .name
= BLOCK_OPT_CLUSTER_SIZE
,
418 .type
= QEMU_OPT_SIZE
,
419 .help
= "Parallels image cluster size",
420 .def_value_str
= stringify(DEFAULT_CLUSTER_SIZE
),
422 { /* end of list */ }
426 static BlockDriver bdrv_parallels
= {
427 .format_name
= "parallels",
428 .instance_size
= sizeof(BDRVParallelsState
),
429 .bdrv_probe
= parallels_probe
,
430 .bdrv_open
= parallels_open
,
431 .bdrv_close
= parallels_close
,
432 .bdrv_co_get_block_status
= parallels_co_get_block_status
,
433 .bdrv_has_zero_init
= bdrv_has_zero_init_1
,
434 .bdrv_co_readv
= parallels_co_readv
,
435 .bdrv_co_writev
= parallels_co_writev
,
437 .bdrv_create
= parallels_create
,
438 .create_opts
= ¶llels_create_opts
,
441 static void bdrv_parallels_init(void)
443 bdrv_register(&bdrv_parallels
);
446 block_init(bdrv_parallels_init
);