block/parallels: rename catalog_ names to bat_
[qemu/kevin.git] / block / parallels.c
blob16fbdf4442c7b955d2b15bdf58c5f3ccf861e6da
1 /*
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
9 * available at
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
28 * THE SOFTWARE.
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"
46 uint32_t version;
47 uint32_t heads;
48 uint32_t cylinders;
49 uint32_t tracks;
50 uint32_t bat_entries;
51 uint64_t nb_sectors;
52 uint32_t inuse;
53 uint32_t data_off;
54 char padding[12];
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
62 CoMutex lock;
64 uint32_t *bat_bitmap;
65 unsigned int bat_size;
67 unsigned int tracks;
69 unsigned int off_multiplier;
71 bool has_truncate;
72 } BDRVParallelsState;
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))
79 return 0;
81 if ((!memcmp(ph->magic, HEADER_MAGIC, 16) ||
82 !memcmp(ph->magic, HEADER_MAGIC2, 16)) &&
83 (le32_to_cpu(ph->version) == HEADER_VERSION))
84 return 100;
86 return 0;
89 static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
90 Error **errp)
92 BDRVParallelsState *s = bs->opaque;
93 int i;
94 ParallelsHeader ph;
95 int ret;
97 ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
98 if (ret < 0) {
99 goto fail;
102 bs->total_sectors = le64_to_cpu(ph.nb_sectors);
104 if (le32_to_cpu(ph.version) != HEADER_VERSION) {
105 goto fail_format;
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);
112 } else {
113 goto fail_format;
116 s->tracks = le32_to_cpu(ph.tracks);
117 if (s->tracks == 0) {
118 error_setg(errp, "Invalid image: Zero sectors per track");
119 ret = -EINVAL;
120 goto fail;
122 if (s->tracks > INT32_MAX/513) {
123 error_setg(errp, "Invalid image: Too big cluster");
124 ret = -EFBIG;
125 goto fail;
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");
131 ret = -EFBIG;
132 goto fail;
134 s->bat_bitmap = g_try_new(uint32_t, s->bat_size);
135 if (s->bat_size && s->bat_bitmap == NULL) {
136 ret = -ENOMEM;
137 goto fail;
140 ret = bdrv_pread(bs->file, sizeof(ParallelsHeader),
141 s->bat_bitmap, s->bat_size * sizeof(uint32_t));
142 if (ret < 0) {
143 goto fail;
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);
154 return 0;
156 fail_format:
157 error_setg(errp, "Image not in Parallels format");
158 ret = -EINVAL;
159 fail:
160 g_free(s->bat_bitmap);
161 return ret;
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;
171 /* not allocated */
172 if ((index >= s->bat_size) || (s->bat_bitmap[index] == 0)) {
173 return -1;
175 return (uint64_t)s->bat_bitmap[index] * s->off_multiplier + offset;
178 static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num,
179 int nb_sectors)
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;
189 int64_t pos;
190 int ret;
192 idx = sector_num / s->tracks;
193 offset = sector_num % s->tracks;
195 if (idx >= s->bat_size) {
196 return -EINVAL;
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);
205 } else {
206 ret = bdrv_write_zeroes(bs->file, pos, s->tracks, 0);
208 if (ret < 0) {
209 return ret;
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));
218 if (ret < 0) {
219 s->bat_bitmap[idx] = 0;
220 return ret;
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;
229 int64_t offset;
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);
237 if (offset < 0) {
238 return 0;
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;
251 int ret = 0;
253 qemu_iovec_init(&hd_qiov, qiov->niov);
255 while (nb_sectors > 0) {
256 int64_t position;
257 int n, nbytes;
259 qemu_co_mutex_lock(&s->lock);
260 position = allocate_cluster(bs, sector_num);
261 qemu_co_mutex_unlock(&s->lock);
262 if (position < 0) {
263 ret = (int)position;
264 break;
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);
274 if (ret < 0) {
275 break;
278 nb_sectors -= n;
279 sector_num += n;
280 bytes_done += nbytes;
283 qemu_iovec_destroy(&hd_qiov);
284 return ret;
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;
293 int ret = 0;
295 qemu_iovec_init(&hd_qiov, qiov->niov);
297 while (nb_sectors > 0) {
298 int64_t position;
299 int n, nbytes;
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;
308 if (position < 0) {
309 qemu_iovec_memset(qiov, bytes_done, 0, nbytes);
310 } else {
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);
315 if (ret < 0) {
316 break;
320 nb_sectors -= n;
321 sector_num += n;
322 bytes_done += nbytes;
325 qemu_iovec_destroy(&hd_qiov);
326 return ret;
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;
337 int ret;
339 total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
340 BDRV_SECTOR_SIZE);
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);
345 if (ret < 0) {
346 error_propagate(errp, local_err);
347 return ret;
350 file = NULL;
351 ret = bdrv_open(&file, filename, NULL, NULL,
352 BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err);
353 if (ret < 0) {
354 error_propagate(errp, local_err);
355 return ret;
357 ret = bdrv_truncate(file, 0);
358 if (ret < 0) {
359 goto exit;
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);
383 if (ret < 0) {
384 goto exit;
386 ret = bdrv_write_zeroes(file, 1, bat_sectors - 1, 0);
387 if (ret < 0) {
388 goto exit;
390 ret = 0;
392 done:
393 bdrv_unref(file);
394 return ret;
396 exit:
397 error_setg_errno(errp, -ret, "Failed to create Parallels image");
398 goto done;
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),
410 .desc = {
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 = &parallels_create_opts,
441 static void bdrv_parallels_init(void)
443 bdrv_register(&bdrv_parallels);
446 block_init(bdrv_parallels_init);