xref: /qemu/block/parallels.c (revision 06c60b6c)
1019d6b8fSAnthony Liguori /*
2019d6b8fSAnthony Liguori  * Block driver for Parallels disk image format
3019d6b8fSAnthony Liguori  *
4019d6b8fSAnthony Liguori  * Copyright (c) 2007 Alex Beregszaszi
5cc5690f2SDenis V. Lunev  * Copyright (c) 2015 Denis V. Lunev <den@openvz.org>
6019d6b8fSAnthony Liguori  *
7cc5690f2SDenis V. Lunev  * This code was originally based on comparing different disk images created
8cc5690f2SDenis V. Lunev  * by Parallels. Currently it is based on opened OpenVZ sources
9cc5690f2SDenis V. Lunev  * available at
10cc5690f2SDenis V. Lunev  *     http://git.openvz.org/?p=ploop;a=summary
11019d6b8fSAnthony Liguori  *
12019d6b8fSAnthony Liguori  * Permission is hereby granted, free of charge, to any person obtaining a copy
13019d6b8fSAnthony Liguori  * of this software and associated documentation files (the "Software"), to deal
14019d6b8fSAnthony Liguori  * in the Software without restriction, including without limitation the rights
15019d6b8fSAnthony Liguori  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
16019d6b8fSAnthony Liguori  * copies of the Software, and to permit persons to whom the Software is
17019d6b8fSAnthony Liguori  * furnished to do so, subject to the following conditions:
18019d6b8fSAnthony Liguori  *
19019d6b8fSAnthony Liguori  * The above copyright notice and this permission notice shall be included in
20019d6b8fSAnthony Liguori  * all copies or substantial portions of the Software.
21019d6b8fSAnthony Liguori  *
22019d6b8fSAnthony Liguori  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23019d6b8fSAnthony Liguori  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24019d6b8fSAnthony Liguori  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25019d6b8fSAnthony Liguori  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26019d6b8fSAnthony Liguori  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27019d6b8fSAnthony Liguori  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
28019d6b8fSAnthony Liguori  * THE SOFTWARE.
29019d6b8fSAnthony Liguori  */
3080c71a24SPeter Maydell #include "qemu/osdep.h"
31da34e65cSMarkus Armbruster #include "qapi/error.h"
32019d6b8fSAnthony Liguori #include "qemu-common.h"
33737e150eSPaolo Bonzini #include "block/block_int.h"
348942764fSKevin Wolf #include "sysemu/block-backend.h"
351de7afc9SPaolo Bonzini #include "qemu/module.h"
3658369e22SPaolo Bonzini #include "qemu/bswap.h"
370d31c7c2SDenis V. Lunev #include "qemu/bitmap.h"
38d6179011SDenis V. Lunev #include "qapi/util.h"
39019d6b8fSAnthony Liguori 
40019d6b8fSAnthony Liguori /**************************************************************/
41019d6b8fSAnthony Liguori 
42019d6b8fSAnthony Liguori #define HEADER_MAGIC "WithoutFreeSpace"
43d25d5980SDenis V. Lunev #define HEADER_MAGIC2 "WithouFreSpacExt"
44019d6b8fSAnthony Liguori #define HEADER_VERSION 2
456dd6b9f1SDenis V. Lunev #define HEADER_INUSE_MAGIC  (0x746F6E59)
46555a608cSKlim Kireev #define MAX_PARALLELS_IMAGE_FACTOR (1ull << 32)
47019d6b8fSAnthony Liguori 
4874cf6c50SDenis V. Lunev #define DEFAULT_CLUSTER_SIZE 1048576        /* 1 MiB */
4974cf6c50SDenis V. Lunev 
5074cf6c50SDenis V. Lunev 
51019d6b8fSAnthony Liguori // always little-endian
5207898904SDenis V. Lunev typedef struct ParallelsHeader {
53019d6b8fSAnthony Liguori     char magic[16]; // "WithoutFreeSpace"
54019d6b8fSAnthony Liguori     uint32_t version;
55019d6b8fSAnthony Liguori     uint32_t heads;
56019d6b8fSAnthony Liguori     uint32_t cylinders;
57019d6b8fSAnthony Liguori     uint32_t tracks;
58369f7de9SDenis V. Lunev     uint32_t bat_entries;
598c27d54fSDenis V. Lunev     uint64_t nb_sectors;
608c27d54fSDenis V. Lunev     uint32_t inuse;
618c27d54fSDenis V. Lunev     uint32_t data_off;
628c27d54fSDenis V. Lunev     char padding[12];
6307898904SDenis V. Lunev } QEMU_PACKED ParallelsHeader;
64019d6b8fSAnthony Liguori 
65d6179011SDenis V. Lunev 
66d6179011SDenis V. Lunev typedef enum ParallelsPreallocMode {
67d6179011SDenis V. Lunev     PRL_PREALLOC_MODE_FALLOCATE = 0,
68d6179011SDenis V. Lunev     PRL_PREALLOC_MODE_TRUNCATE = 1,
697fb1cf16SEric Blake     PRL_PREALLOC_MODE__MAX = 2,
70d6179011SDenis V. Lunev } ParallelsPreallocMode;
71d6179011SDenis V. Lunev 
72d6179011SDenis V. Lunev static const char *prealloc_mode_lookup[] = {
73d6179011SDenis V. Lunev     "falloc",
74d6179011SDenis V. Lunev     "truncate",
75d6179011SDenis V. Lunev     NULL,
76d6179011SDenis V. Lunev };
77d6179011SDenis V. Lunev 
78d6179011SDenis V. Lunev 
79019d6b8fSAnthony Liguori typedef struct BDRVParallelsState {
80481fb9cfSDenis V. Lunev     /** Locking is conservative, the lock protects
81481fb9cfSDenis V. Lunev      *   - image file extending (truncate, fallocate)
82481fb9cfSDenis V. Lunev      *   - any access to block allocation table
83481fb9cfSDenis V. Lunev      */
84848c66e8SPaolo Bonzini     CoMutex lock;
85019d6b8fSAnthony Liguori 
869eae9ccaSDenis V. Lunev     ParallelsHeader *header;
879eae9ccaSDenis V. Lunev     uint32_t header_size;
886dd6b9f1SDenis V. Lunev     bool header_unclean;
896dd6b9f1SDenis V. Lunev 
900d31c7c2SDenis V. Lunev     unsigned long *bat_dirty_bmap;
910d31c7c2SDenis V. Lunev     unsigned int  bat_dirty_block;
920d31c7c2SDenis V. Lunev 
93369f7de9SDenis V. Lunev     uint32_t *bat_bitmap;
94369f7de9SDenis V. Lunev     unsigned int bat_size;
95019d6b8fSAnthony Liguori 
9619f5dc15SDenis V. Lunev     int64_t  data_end;
97d6179011SDenis V. Lunev     uint64_t prealloc_size;
98d6179011SDenis V. Lunev     ParallelsPreallocMode prealloc_mode;
99d6179011SDenis V. Lunev 
1009302e863SKevin Wolf     unsigned int tracks;
101d25d5980SDenis V. Lunev 
102d25d5980SDenis V. Lunev     unsigned int off_multiplier;
103019d6b8fSAnthony Liguori } BDRVParallelsState;
104019d6b8fSAnthony Liguori 
105555cc9d9SDenis V. Lunev 
106d6179011SDenis V. Lunev #define PARALLELS_OPT_PREALLOC_MODE     "prealloc-mode"
107d6179011SDenis V. Lunev #define PARALLELS_OPT_PREALLOC_SIZE     "prealloc-size"
108d6179011SDenis V. Lunev 
109d6179011SDenis V. Lunev static QemuOptsList parallels_runtime_opts = {
110d6179011SDenis V. Lunev     .name = "parallels",
111d6179011SDenis V. Lunev     .head = QTAILQ_HEAD_INITIALIZER(parallels_runtime_opts.head),
112d6179011SDenis V. Lunev     .desc = {
113d6179011SDenis V. Lunev         {
114d6179011SDenis V. Lunev             .name = PARALLELS_OPT_PREALLOC_SIZE,
115d6179011SDenis V. Lunev             .type = QEMU_OPT_SIZE,
116d6179011SDenis V. Lunev             .help = "Preallocation size on image expansion",
117ff5bbe56SEdgar Kaziahmedov             .def_value_str = "128M",
118d6179011SDenis V. Lunev         },
119d6179011SDenis V. Lunev         {
120d6179011SDenis V. Lunev             .name = PARALLELS_OPT_PREALLOC_MODE,
121d6179011SDenis V. Lunev             .type = QEMU_OPT_STRING,
122d6179011SDenis V. Lunev             .help = "Preallocation mode on image expansion "
123d6179011SDenis V. Lunev                     "(allowed values: falloc, truncate)",
124d6179011SDenis V. Lunev             .def_value_str = "falloc",
125d6179011SDenis V. Lunev         },
126d6179011SDenis V. Lunev         { /* end of list */ },
127d6179011SDenis V. Lunev     },
128d6179011SDenis V. Lunev };
129d6179011SDenis V. Lunev 
130d6179011SDenis V. Lunev 
131555cc9d9SDenis V. Lunev static int64_t bat2sect(BDRVParallelsState *s, uint32_t idx)
132555cc9d9SDenis V. Lunev {
133dd97cdc0SDenis V. Lunev     return (uint64_t)le32_to_cpu(s->bat_bitmap[idx]) * s->off_multiplier;
134555cc9d9SDenis V. Lunev }
135555cc9d9SDenis V. Lunev 
1362d68e22eSDenis V. Lunev static uint32_t bat_entry_off(uint32_t idx)
1372d68e22eSDenis V. Lunev {
1382d68e22eSDenis V. Lunev     return sizeof(ParallelsHeader) + sizeof(uint32_t) * idx;
1392d68e22eSDenis V. Lunev }
1402d68e22eSDenis V. Lunev 
14129442569SRoman Kagan static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num)
142019d6b8fSAnthony Liguori {
143c34d2451SDavid Woodhouse     uint32_t index, offset;
144019d6b8fSAnthony Liguori 
145019d6b8fSAnthony Liguori     index = sector_num / s->tracks;
146019d6b8fSAnthony Liguori     offset = sector_num % s->tracks;
147019d6b8fSAnthony Liguori 
1489d8b88f6SChristoph Hellwig     /* not allocated */
149369f7de9SDenis V. Lunev     if ((index >= s->bat_size) || (s->bat_bitmap[index] == 0)) {
150019d6b8fSAnthony Liguori         return -1;
151369f7de9SDenis V. Lunev     }
152555cc9d9SDenis V. Lunev     return bat2sect(s, index) + offset;
153019d6b8fSAnthony Liguori }
154019d6b8fSAnthony Liguori 
1559de9da17SRoman Kagan static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num,
1569de9da17SRoman Kagan         int nb_sectors)
1579de9da17SRoman Kagan {
1589de9da17SRoman Kagan     int ret = s->tracks - sector_num % s->tracks;
1599de9da17SRoman Kagan     return MIN(nb_sectors, ret);
1609de9da17SRoman Kagan }
1619de9da17SRoman Kagan 
1626953d920SDenis V. Lunev static int64_t block_status(BDRVParallelsState *s, int64_t sector_num,
1636953d920SDenis V. Lunev                             int nb_sectors, int *pnum)
1646953d920SDenis V. Lunev {
1656953d920SDenis V. Lunev     int64_t start_off = -2, prev_end_off = -2;
1666953d920SDenis V. Lunev 
1676953d920SDenis V. Lunev     *pnum = 0;
1686953d920SDenis V. Lunev     while (nb_sectors > 0 || start_off == -2) {
1696953d920SDenis V. Lunev         int64_t offset = seek_to_sector(s, sector_num);
1706953d920SDenis V. Lunev         int to_end;
1716953d920SDenis V. Lunev 
1726953d920SDenis V. Lunev         if (start_off == -2) {
1736953d920SDenis V. Lunev             start_off = offset;
1746953d920SDenis V. Lunev             prev_end_off = offset;
1756953d920SDenis V. Lunev         } else if (offset != prev_end_off) {
1766953d920SDenis V. Lunev             break;
1776953d920SDenis V. Lunev         }
1786953d920SDenis V. Lunev 
1796953d920SDenis V. Lunev         to_end = cluster_remainder(s, sector_num, nb_sectors);
1806953d920SDenis V. Lunev         nb_sectors -= to_end;
1816953d920SDenis V. Lunev         sector_num += to_end;
1826953d920SDenis V. Lunev         *pnum += to_end;
1836953d920SDenis V. Lunev 
1846953d920SDenis V. Lunev         if (offset > 0) {
1856953d920SDenis V. Lunev             prev_end_off += to_end;
1866953d920SDenis V. Lunev         }
1876953d920SDenis V. Lunev     }
1886953d920SDenis V. Lunev     return start_off;
1896953d920SDenis V. Lunev }
1906953d920SDenis V. Lunev 
191ddd2ef2cSDenis V. Lunev static int64_t allocate_clusters(BlockDriverState *bs, int64_t sector_num,
192ddd2ef2cSDenis V. Lunev                                  int nb_sectors, int *pnum)
1935a41e1faSDenis V. Lunev {
1945a41e1faSDenis V. Lunev     BDRVParallelsState *s = bs->opaque;
195d8b83e37SDenis V. Lunev     int64_t pos, space, idx, to_allocate, i, len;
196ddd2ef2cSDenis V. Lunev 
197ddd2ef2cSDenis V. Lunev     pos = block_status(s, sector_num, nb_sectors, pnum);
198ddd2ef2cSDenis V. Lunev     if (pos > 0) {
199ddd2ef2cSDenis V. Lunev         return pos;
200ddd2ef2cSDenis V. Lunev     }
2015a41e1faSDenis V. Lunev 
2025a41e1faSDenis V. Lunev     idx = sector_num / s->tracks;
203969401feSLaurent Vivier     to_allocate = DIV_ROUND_UP(sector_num + *pnum, s->tracks) - idx;
20486d1bd70SMax Reitz 
20586d1bd70SMax Reitz     /* This function is called only by parallels_co_writev(), which will never
20686d1bd70SMax Reitz      * pass a sector_num at or beyond the end of the image (because the block
20786d1bd70SMax Reitz      * layer never passes such a sector_num to that function). Therefore, idx
20886d1bd70SMax Reitz      * is always below s->bat_size.
20986d1bd70SMax Reitz      * block_status() will limit *pnum so that sector_num + *pnum will not
21086d1bd70SMax Reitz      * exceed the image end. Therefore, idx + to_allocate cannot exceed
21186d1bd70SMax Reitz      * s->bat_size.
21286d1bd70SMax Reitz      * Note that s->bat_size is an unsigned int, therefore idx + to_allocate
21386d1bd70SMax Reitz      * will always fit into a uint32_t. */
21486d1bd70SMax Reitz     assert(idx < s->bat_size && idx + to_allocate <= s->bat_size);
21586d1bd70SMax Reitz 
216ddd2ef2cSDenis V. Lunev     space = to_allocate * s->tracks;
217d8b83e37SDenis V. Lunev     len = bdrv_getlength(bs->file->bs);
218d8b83e37SDenis V. Lunev     if (len < 0) {
219d8b83e37SDenis V. Lunev         return len;
220d8b83e37SDenis V. Lunev     }
221d8b83e37SDenis V. Lunev     if (s->data_end + space > (len >> BDRV_SECTOR_BITS)) {
22219f5dc15SDenis V. Lunev         int ret;
223ddd2ef2cSDenis V. Lunev         space += s->prealloc_size;
22419f5dc15SDenis V. Lunev         if (s->prealloc_mode == PRL_PREALLOC_MODE_FALLOCATE) {
225720ff280SKevin Wolf             ret = bdrv_pwrite_zeroes(bs->file,
22674021bc4SEric Blake                                      s->data_end << BDRV_SECTOR_BITS,
22774021bc4SEric Blake                                      space << BDRV_SECTOR_BITS, 0);
2285a41e1faSDenis V. Lunev         } else {
22952cdbc58SKevin Wolf             ret = bdrv_truncate(bs->file,
230ed3d2ec9SMax Reitz                                 (s->data_end + space) << BDRV_SECTOR_BITS,
2317ea37c30SMax Reitz                                 PREALLOC_MODE_OFF, NULL);
2325a41e1faSDenis V. Lunev         }
2335a41e1faSDenis V. Lunev         if (ret < 0) {
2345a41e1faSDenis V. Lunev             return ret;
2355a41e1faSDenis V. Lunev         }
23619f5dc15SDenis V. Lunev     }
237ddd2ef2cSDenis V. Lunev 
238ddd2ef2cSDenis V. Lunev     for (i = 0; i < to_allocate; i++) {
239ddd2ef2cSDenis V. Lunev         s->bat_bitmap[idx + i] = cpu_to_le32(s->data_end / s->off_multiplier);
24019f5dc15SDenis V. Lunev         s->data_end += s->tracks;
241ddd2ef2cSDenis V. Lunev         bitmap_set(s->bat_dirty_bmap,
242c9f6856dSVladimir Sementsov-Ogievskiy                    bat_entry_off(idx + i) / s->bat_dirty_block, 1);
243ddd2ef2cSDenis V. Lunev     }
2445a41e1faSDenis V. Lunev 
245ddd2ef2cSDenis V. Lunev     return bat2sect(s, idx) + sector_num % s->tracks;
2465a41e1faSDenis V. Lunev }
2475a41e1faSDenis V. Lunev 
2480d31c7c2SDenis V. Lunev 
2490d31c7c2SDenis V. Lunev static coroutine_fn int parallels_co_flush_to_os(BlockDriverState *bs)
2500d31c7c2SDenis V. Lunev {
2510d31c7c2SDenis V. Lunev     BDRVParallelsState *s = bs->opaque;
2520d31c7c2SDenis V. Lunev     unsigned long size = DIV_ROUND_UP(s->header_size, s->bat_dirty_block);
2530d31c7c2SDenis V. Lunev     unsigned long bit;
2540d31c7c2SDenis V. Lunev 
2550d31c7c2SDenis V. Lunev     qemu_co_mutex_lock(&s->lock);
2560d31c7c2SDenis V. Lunev 
2570d31c7c2SDenis V. Lunev     bit = find_first_bit(s->bat_dirty_bmap, size);
2580d31c7c2SDenis V. Lunev     while (bit < size) {
2590d31c7c2SDenis V. Lunev         uint32_t off = bit * s->bat_dirty_block;
2600d31c7c2SDenis V. Lunev         uint32_t to_write = s->bat_dirty_block;
2610d31c7c2SDenis V. Lunev         int ret;
2620d31c7c2SDenis V. Lunev 
2630d31c7c2SDenis V. Lunev         if (off + to_write > s->header_size) {
2640d31c7c2SDenis V. Lunev             to_write = s->header_size - off;
2650d31c7c2SDenis V. Lunev         }
266d9ca2ea2SKevin Wolf         ret = bdrv_pwrite(bs->file, off, (uint8_t *)s->header + off,
2679a4f4c31SKevin Wolf                           to_write);
2680d31c7c2SDenis V. Lunev         if (ret < 0) {
2690d31c7c2SDenis V. Lunev             qemu_co_mutex_unlock(&s->lock);
2700d31c7c2SDenis V. Lunev             return ret;
2710d31c7c2SDenis V. Lunev         }
2720d31c7c2SDenis V. Lunev         bit = find_next_bit(s->bat_dirty_bmap, size, bit + 1);
2730d31c7c2SDenis V. Lunev     }
2740d31c7c2SDenis V. Lunev     bitmap_zero(s->bat_dirty_bmap, size);
2750d31c7c2SDenis V. Lunev 
2760d31c7c2SDenis V. Lunev     qemu_co_mutex_unlock(&s->lock);
2770d31c7c2SDenis V. Lunev     return 0;
2780d31c7c2SDenis V. Lunev }
2790d31c7c2SDenis V. Lunev 
2800d31c7c2SDenis V. Lunev 
281dd3bed16SRoman Kagan static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs,
28267a0fd2aSFam Zheng         int64_t sector_num, int nb_sectors, int *pnum, BlockDriverState **file)
283dd3bed16SRoman Kagan {
284dd3bed16SRoman Kagan     BDRVParallelsState *s = bs->opaque;
285dd3bed16SRoman Kagan     int64_t offset;
286dd3bed16SRoman Kagan 
287dd3bed16SRoman Kagan     qemu_co_mutex_lock(&s->lock);
2886953d920SDenis V. Lunev     offset = block_status(s, sector_num, nb_sectors, pnum);
289dd3bed16SRoman Kagan     qemu_co_mutex_unlock(&s->lock);
290dd3bed16SRoman Kagan 
291dd3bed16SRoman Kagan     if (offset < 0) {
292dd3bed16SRoman Kagan         return 0;
293dd3bed16SRoman Kagan     }
294dd3bed16SRoman Kagan 
295ddf4987dSFam Zheng     *file = bs->file->bs;
296dd3bed16SRoman Kagan     return (offset << BDRV_SECTOR_BITS) |
297dd3bed16SRoman Kagan         BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID;
298dd3bed16SRoman Kagan }
299dd3bed16SRoman Kagan 
3005a41e1faSDenis V. Lunev static coroutine_fn int parallels_co_writev(BlockDriverState *bs,
3015a41e1faSDenis V. Lunev         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
3025a41e1faSDenis V. Lunev {
3035a41e1faSDenis V. Lunev     BDRVParallelsState *s = bs->opaque;
3045a41e1faSDenis V. Lunev     uint64_t bytes_done = 0;
3055a41e1faSDenis V. Lunev     QEMUIOVector hd_qiov;
3065a41e1faSDenis V. Lunev     int ret = 0;
3075a41e1faSDenis V. Lunev 
3085a41e1faSDenis V. Lunev     qemu_iovec_init(&hd_qiov, qiov->niov);
3095a41e1faSDenis V. Lunev 
3105a41e1faSDenis V. Lunev     while (nb_sectors > 0) {
3115a41e1faSDenis V. Lunev         int64_t position;
3125a41e1faSDenis V. Lunev         int n, nbytes;
3135a41e1faSDenis V. Lunev 
3145a41e1faSDenis V. Lunev         qemu_co_mutex_lock(&s->lock);
315ddd2ef2cSDenis V. Lunev         position = allocate_clusters(bs, sector_num, nb_sectors, &n);
3165a41e1faSDenis V. Lunev         qemu_co_mutex_unlock(&s->lock);
3175a41e1faSDenis V. Lunev         if (position < 0) {
3185a41e1faSDenis V. Lunev             ret = (int)position;
3195a41e1faSDenis V. Lunev             break;
3205a41e1faSDenis V. Lunev         }
3215a41e1faSDenis V. Lunev 
3225a41e1faSDenis V. Lunev         nbytes = n << BDRV_SECTOR_BITS;
3235a41e1faSDenis V. Lunev 
3245a41e1faSDenis V. Lunev         qemu_iovec_reset(&hd_qiov);
3255a41e1faSDenis V. Lunev         qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
3265a41e1faSDenis V. Lunev 
32725ec177dSKevin Wolf         ret = bdrv_co_writev(bs->file, position, n, &hd_qiov);
3285a41e1faSDenis V. Lunev         if (ret < 0) {
3295a41e1faSDenis V. Lunev             break;
3305a41e1faSDenis V. Lunev         }
3315a41e1faSDenis V. Lunev 
3325a41e1faSDenis V. Lunev         nb_sectors -= n;
3335a41e1faSDenis V. Lunev         sector_num += n;
3345a41e1faSDenis V. Lunev         bytes_done += nbytes;
3355a41e1faSDenis V. Lunev     }
3365a41e1faSDenis V. Lunev 
3375a41e1faSDenis V. Lunev     qemu_iovec_destroy(&hd_qiov);
3385a41e1faSDenis V. Lunev     return ret;
3395a41e1faSDenis V. Lunev }
3405a41e1faSDenis V. Lunev 
341481fb9cfSDenis V. Lunev static coroutine_fn int parallels_co_readv(BlockDriverState *bs,
342481fb9cfSDenis V. Lunev         int64_t sector_num, int nb_sectors, QEMUIOVector *qiov)
343019d6b8fSAnthony Liguori {
34429442569SRoman Kagan     BDRVParallelsState *s = bs->opaque;
345481fb9cfSDenis V. Lunev     uint64_t bytes_done = 0;
346481fb9cfSDenis V. Lunev     QEMUIOVector hd_qiov;
347481fb9cfSDenis V. Lunev     int ret = 0;
348481fb9cfSDenis V. Lunev 
349481fb9cfSDenis V. Lunev     qemu_iovec_init(&hd_qiov, qiov->niov);
35029442569SRoman Kagan 
351019d6b8fSAnthony Liguori     while (nb_sectors > 0) {
352481fb9cfSDenis V. Lunev         int64_t position;
353481fb9cfSDenis V. Lunev         int n, nbytes;
354481fb9cfSDenis V. Lunev 
355481fb9cfSDenis V. Lunev         qemu_co_mutex_lock(&s->lock);
3566953d920SDenis V. Lunev         position = block_status(s, sector_num, nb_sectors, &n);
357481fb9cfSDenis V. Lunev         qemu_co_mutex_unlock(&s->lock);
358481fb9cfSDenis V. Lunev 
359481fb9cfSDenis V. Lunev         nbytes = n << BDRV_SECTOR_BITS;
360481fb9cfSDenis V. Lunev 
361481fb9cfSDenis V. Lunev         if (position < 0) {
362481fb9cfSDenis V. Lunev             qemu_iovec_memset(qiov, bytes_done, 0, nbytes);
3639d8b88f6SChristoph Hellwig         } else {
364481fb9cfSDenis V. Lunev             qemu_iovec_reset(&hd_qiov);
365481fb9cfSDenis V. Lunev             qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes);
366481fb9cfSDenis V. Lunev 
36728b04a8fSKevin Wolf             ret = bdrv_co_readv(bs->file, position, n, &hd_qiov);
368481fb9cfSDenis V. Lunev             if (ret < 0) {
369481fb9cfSDenis V. Lunev                 break;
3709d8b88f6SChristoph Hellwig             }
371019d6b8fSAnthony Liguori         }
372019d6b8fSAnthony Liguori 
373481fb9cfSDenis V. Lunev         nb_sectors -= n;
374481fb9cfSDenis V. Lunev         sector_num += n;
375481fb9cfSDenis V. Lunev         bytes_done += nbytes;
376481fb9cfSDenis V. Lunev     }
377481fb9cfSDenis V. Lunev 
378481fb9cfSDenis V. Lunev     qemu_iovec_destroy(&hd_qiov);
3792914caa0SPaolo Bonzini     return ret;
3802914caa0SPaolo Bonzini }
3812914caa0SPaolo Bonzini 
38249ad6467SDenis V. Lunev 
38349ad6467SDenis V. Lunev static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res,
38449ad6467SDenis V. Lunev                            BdrvCheckMode fix)
38549ad6467SDenis V. Lunev {
38649ad6467SDenis V. Lunev     BDRVParallelsState *s = bs->opaque;
38749ad6467SDenis V. Lunev     int64_t size, prev_off, high_off;
38849ad6467SDenis V. Lunev     int ret;
38949ad6467SDenis V. Lunev     uint32_t i;
39049ad6467SDenis V. Lunev     bool flush_bat = false;
39149ad6467SDenis V. Lunev     int cluster_size = s->tracks << BDRV_SECTOR_BITS;
39249ad6467SDenis V. Lunev 
3939a4f4c31SKevin Wolf     size = bdrv_getlength(bs->file->bs);
39449ad6467SDenis V. Lunev     if (size < 0) {
39549ad6467SDenis V. Lunev         res->check_errors++;
39649ad6467SDenis V. Lunev         return size;
39749ad6467SDenis V. Lunev     }
39849ad6467SDenis V. Lunev 
3996dd6b9f1SDenis V. Lunev     if (s->header_unclean) {
4006dd6b9f1SDenis V. Lunev         fprintf(stderr, "%s image was not closed correctly\n",
4016dd6b9f1SDenis V. Lunev                 fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR");
4026dd6b9f1SDenis V. Lunev         res->corruptions++;
4036dd6b9f1SDenis V. Lunev         if (fix & BDRV_FIX_ERRORS) {
4046dd6b9f1SDenis V. Lunev             /* parallels_close will do the job right */
4056dd6b9f1SDenis V. Lunev             res->corruptions_fixed++;
4066dd6b9f1SDenis V. Lunev             s->header_unclean = false;
4076dd6b9f1SDenis V. Lunev         }
4086dd6b9f1SDenis V. Lunev     }
4096dd6b9f1SDenis V. Lunev 
41049ad6467SDenis V. Lunev     res->bfi.total_clusters = s->bat_size;
41149ad6467SDenis V. Lunev     res->bfi.compressed_clusters = 0; /* compression is not supported */
41249ad6467SDenis V. Lunev 
41349ad6467SDenis V. Lunev     high_off = 0;
41449ad6467SDenis V. Lunev     prev_off = 0;
41549ad6467SDenis V. Lunev     for (i = 0; i < s->bat_size; i++) {
41649ad6467SDenis V. Lunev         int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS;
41749ad6467SDenis V. Lunev         if (off == 0) {
41849ad6467SDenis V. Lunev             prev_off = 0;
41949ad6467SDenis V. Lunev             continue;
42049ad6467SDenis V. Lunev         }
42149ad6467SDenis V. Lunev 
42249ad6467SDenis V. Lunev         /* cluster outside the image */
42349ad6467SDenis V. Lunev         if (off > size) {
42449ad6467SDenis V. Lunev             fprintf(stderr, "%s cluster %u is outside image\n",
42549ad6467SDenis V. Lunev                     fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i);
42649ad6467SDenis V. Lunev             res->corruptions++;
42749ad6467SDenis V. Lunev             if (fix & BDRV_FIX_ERRORS) {
42849ad6467SDenis V. Lunev                 prev_off = 0;
42949ad6467SDenis V. Lunev                 s->bat_bitmap[i] = 0;
43049ad6467SDenis V. Lunev                 res->corruptions_fixed++;
43149ad6467SDenis V. Lunev                 flush_bat = true;
43249ad6467SDenis V. Lunev                 continue;
43349ad6467SDenis V. Lunev             }
43449ad6467SDenis V. Lunev         }
43549ad6467SDenis V. Lunev 
43649ad6467SDenis V. Lunev         res->bfi.allocated_clusters++;
43749ad6467SDenis V. Lunev         if (off > high_off) {
43849ad6467SDenis V. Lunev             high_off = off;
43949ad6467SDenis V. Lunev         }
44049ad6467SDenis V. Lunev 
44149ad6467SDenis V. Lunev         if (prev_off != 0 && (prev_off + cluster_size) != off) {
44249ad6467SDenis V. Lunev             res->bfi.fragmented_clusters++;
44349ad6467SDenis V. Lunev         }
44449ad6467SDenis V. Lunev         prev_off = off;
44549ad6467SDenis V. Lunev     }
44649ad6467SDenis V. Lunev 
44749ad6467SDenis V. Lunev     if (flush_bat) {
448d9ca2ea2SKevin Wolf         ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size);
44949ad6467SDenis V. Lunev         if (ret < 0) {
45049ad6467SDenis V. Lunev             res->check_errors++;
45149ad6467SDenis V. Lunev             return ret;
45249ad6467SDenis V. Lunev         }
45349ad6467SDenis V. Lunev     }
45449ad6467SDenis V. Lunev 
45549ad6467SDenis V. Lunev     res->image_end_offset = high_off + cluster_size;
45649ad6467SDenis V. Lunev     if (size > res->image_end_offset) {
45749ad6467SDenis V. Lunev         int64_t count;
45849ad6467SDenis V. Lunev         count = DIV_ROUND_UP(size - res->image_end_offset, cluster_size);
45949ad6467SDenis V. Lunev         fprintf(stderr, "%s space leaked at the end of the image %" PRId64 "\n",
46049ad6467SDenis V. Lunev                 fix & BDRV_FIX_LEAKS ? "Repairing" : "ERROR",
46149ad6467SDenis V. Lunev                 size - res->image_end_offset);
46249ad6467SDenis V. Lunev         res->leaks += count;
46349ad6467SDenis V. Lunev         if (fix & BDRV_FIX_LEAKS) {
464ed3d2ec9SMax Reitz             Error *local_err = NULL;
4657ea37c30SMax Reitz             ret = bdrv_truncate(bs->file, res->image_end_offset,
4667ea37c30SMax Reitz                                 PREALLOC_MODE_OFF, &local_err);
46749ad6467SDenis V. Lunev             if (ret < 0) {
468ed3d2ec9SMax Reitz                 error_report_err(local_err);
46949ad6467SDenis V. Lunev                 res->check_errors++;
47049ad6467SDenis V. Lunev                 return ret;
47149ad6467SDenis V. Lunev             }
47249ad6467SDenis V. Lunev             res->leaks_fixed += count;
47349ad6467SDenis V. Lunev         }
47449ad6467SDenis V. Lunev     }
47549ad6467SDenis V. Lunev 
47649ad6467SDenis V. Lunev     return 0;
47749ad6467SDenis V. Lunev }
47849ad6467SDenis V. Lunev 
47949ad6467SDenis V. Lunev 
48074cf6c50SDenis V. Lunev static int parallels_create(const char *filename, QemuOpts *opts, Error **errp)
48174cf6c50SDenis V. Lunev {
48274cf6c50SDenis V. Lunev     int64_t total_size, cl_size;
48374cf6c50SDenis V. Lunev     uint8_t tmp[BDRV_SECTOR_SIZE];
48474cf6c50SDenis V. Lunev     Error *local_err = NULL;
4858942764fSKevin Wolf     BlockBackend *file;
486369f7de9SDenis V. Lunev     uint32_t bat_entries, bat_sectors;
48774cf6c50SDenis V. Lunev     ParallelsHeader header;
48874cf6c50SDenis V. Lunev     int ret;
48974cf6c50SDenis V. Lunev 
49074cf6c50SDenis V. Lunev     total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0),
49174cf6c50SDenis V. Lunev                           BDRV_SECTOR_SIZE);
49274cf6c50SDenis V. Lunev     cl_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE,
49374cf6c50SDenis V. Lunev                           DEFAULT_CLUSTER_SIZE), BDRV_SECTOR_SIZE);
494555a608cSKlim Kireev     if (total_size >= MAX_PARALLELS_IMAGE_FACTOR * cl_size) {
495555a608cSKlim Kireev         error_propagate(errp, local_err);
496555a608cSKlim Kireev         return -E2BIG;
497555a608cSKlim Kireev     }
49874cf6c50SDenis V. Lunev 
49974cf6c50SDenis V. Lunev     ret = bdrv_create_file(filename, opts, &local_err);
50074cf6c50SDenis V. Lunev     if (ret < 0) {
50174cf6c50SDenis V. Lunev         error_propagate(errp, local_err);
50274cf6c50SDenis V. Lunev         return ret;
50374cf6c50SDenis V. Lunev     }
50474cf6c50SDenis V. Lunev 
505efaa7c4eSMax Reitz     file = blk_new_open(filename, NULL, NULL,
50655880601SKevin Wolf                         BDRV_O_RDWR | BDRV_O_RESIZE | BDRV_O_PROTOCOL,
50755880601SKevin Wolf                         &local_err);
5088942764fSKevin Wolf     if (file == NULL) {
50974cf6c50SDenis V. Lunev         error_propagate(errp, local_err);
5108942764fSKevin Wolf         return -EIO;
51174cf6c50SDenis V. Lunev     }
5128942764fSKevin Wolf 
5138942764fSKevin Wolf     blk_set_allow_write_beyond_eof(file, true);
5148942764fSKevin Wolf 
5153a691c50SMax Reitz     ret = blk_truncate(file, 0, PREALLOC_MODE_OFF, errp);
51674cf6c50SDenis V. Lunev     if (ret < 0) {
51774cf6c50SDenis V. Lunev         goto exit;
51874cf6c50SDenis V. Lunev     }
51974cf6c50SDenis V. Lunev 
520369f7de9SDenis V. Lunev     bat_entries = DIV_ROUND_UP(total_size, cl_size);
5212d68e22eSDenis V. Lunev     bat_sectors = DIV_ROUND_UP(bat_entry_off(bat_entries), cl_size);
522369f7de9SDenis V. Lunev     bat_sectors = (bat_sectors *  cl_size) >> BDRV_SECTOR_BITS;
52374cf6c50SDenis V. Lunev 
52474cf6c50SDenis V. Lunev     memset(&header, 0, sizeof(header));
52574cf6c50SDenis V. Lunev     memcpy(header.magic, HEADER_MAGIC2, sizeof(header.magic));
52674cf6c50SDenis V. Lunev     header.version = cpu_to_le32(HEADER_VERSION);
52774cf6c50SDenis V. Lunev     /* don't care much about geometry, it is not used on image level */
52874cf6c50SDenis V. Lunev     header.heads = cpu_to_le32(16);
52974cf6c50SDenis V. Lunev     header.cylinders = cpu_to_le32(total_size / BDRV_SECTOR_SIZE / 16 / 32);
53074cf6c50SDenis V. Lunev     header.tracks = cpu_to_le32(cl_size >> BDRV_SECTOR_BITS);
531369f7de9SDenis V. Lunev     header.bat_entries = cpu_to_le32(bat_entries);
53274cf6c50SDenis V. Lunev     header.nb_sectors = cpu_to_le64(DIV_ROUND_UP(total_size, BDRV_SECTOR_SIZE));
533369f7de9SDenis V. Lunev     header.data_off = cpu_to_le32(bat_sectors);
53474cf6c50SDenis V. Lunev 
53574cf6c50SDenis V. Lunev     /* write all the data */
53674cf6c50SDenis V. Lunev     memset(tmp, 0, sizeof(tmp));
53774cf6c50SDenis V. Lunev     memcpy(tmp, &header, sizeof(header));
53874cf6c50SDenis V. Lunev 
5398341f00dSEric Blake     ret = blk_pwrite(file, 0, tmp, BDRV_SECTOR_SIZE, 0);
54074cf6c50SDenis V. Lunev     if (ret < 0) {
54174cf6c50SDenis V. Lunev         goto exit;
54274cf6c50SDenis V. Lunev     }
543d004bd52SEric Blake     ret = blk_pwrite_zeroes(file, BDRV_SECTOR_SIZE,
544983a1600SEric Blake                             (bat_sectors - 1) << BDRV_SECTOR_BITS, 0);
54574cf6c50SDenis V. Lunev     if (ret < 0) {
54674cf6c50SDenis V. Lunev         goto exit;
54774cf6c50SDenis V. Lunev     }
54874cf6c50SDenis V. Lunev     ret = 0;
54974cf6c50SDenis V. Lunev 
55074cf6c50SDenis V. Lunev done:
5518942764fSKevin Wolf     blk_unref(file);
55274cf6c50SDenis V. Lunev     return ret;
55374cf6c50SDenis V. Lunev 
55474cf6c50SDenis V. Lunev exit:
55574cf6c50SDenis V. Lunev     error_setg_errno(errp, -ret, "Failed to create Parallels image");
55674cf6c50SDenis V. Lunev     goto done;
55774cf6c50SDenis V. Lunev }
55874cf6c50SDenis V. Lunev 
55923d6bd3bSDenis V. Lunev 
56023d6bd3bSDenis V. Lunev static int parallels_probe(const uint8_t *buf, int buf_size,
56123d6bd3bSDenis V. Lunev                            const char *filename)
56223d6bd3bSDenis V. Lunev {
56323d6bd3bSDenis V. Lunev     const ParallelsHeader *ph = (const void *)buf;
56423d6bd3bSDenis V. Lunev 
56523d6bd3bSDenis V. Lunev     if (buf_size < sizeof(ParallelsHeader)) {
56623d6bd3bSDenis V. Lunev         return 0;
56723d6bd3bSDenis V. Lunev     }
56823d6bd3bSDenis V. Lunev 
56923d6bd3bSDenis V. Lunev     if ((!memcmp(ph->magic, HEADER_MAGIC, 16) ||
57023d6bd3bSDenis V. Lunev            !memcmp(ph->magic, HEADER_MAGIC2, 16)) &&
57123d6bd3bSDenis V. Lunev            (le32_to_cpu(ph->version) == HEADER_VERSION)) {
57223d6bd3bSDenis V. Lunev         return 100;
57323d6bd3bSDenis V. Lunev     }
57423d6bd3bSDenis V. Lunev 
57523d6bd3bSDenis V. Lunev     return 0;
57623d6bd3bSDenis V. Lunev }
57723d6bd3bSDenis V. Lunev 
5786dd6b9f1SDenis V. Lunev static int parallels_update_header(BlockDriverState *bs)
5796dd6b9f1SDenis V. Lunev {
5806dd6b9f1SDenis V. Lunev     BDRVParallelsState *s = bs->opaque;
5819a4f4c31SKevin Wolf     unsigned size = MAX(bdrv_opt_mem_align(bs->file->bs),
5829a4f4c31SKevin Wolf                         sizeof(ParallelsHeader));
5836dd6b9f1SDenis V. Lunev 
5846dd6b9f1SDenis V. Lunev     if (size > s->header_size) {
5856dd6b9f1SDenis V. Lunev         size = s->header_size;
5866dd6b9f1SDenis V. Lunev     }
587d9ca2ea2SKevin Wolf     return bdrv_pwrite_sync(bs->file, 0, s->header, size);
5886dd6b9f1SDenis V. Lunev }
5896dd6b9f1SDenis V. Lunev 
59023d6bd3bSDenis V. Lunev static int parallels_open(BlockDriverState *bs, QDict *options, int flags,
59123d6bd3bSDenis V. Lunev                           Error **errp)
59223d6bd3bSDenis V. Lunev {
59323d6bd3bSDenis V. Lunev     BDRVParallelsState *s = bs->opaque;
59423d6bd3bSDenis V. Lunev     ParallelsHeader ph;
59519f5dc15SDenis V. Lunev     int ret, size, i;
596d6179011SDenis V. Lunev     QemuOpts *opts = NULL;
597d6179011SDenis V. Lunev     Error *local_err = NULL;
598d6179011SDenis V. Lunev     char *buf;
59923d6bd3bSDenis V. Lunev 
6004e4bf5c4SKevin Wolf     bs->file = bdrv_open_child(NULL, options, "file", bs, &child_file,
6014e4bf5c4SKevin Wolf                                false, errp);
6024e4bf5c4SKevin Wolf     if (!bs->file) {
6034e4bf5c4SKevin Wolf         return -EINVAL;
6044e4bf5c4SKevin Wolf     }
6054e4bf5c4SKevin Wolf 
606cf2ab8fcSKevin Wolf     ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph));
60723d6bd3bSDenis V. Lunev     if (ret < 0) {
60823d6bd3bSDenis V. Lunev         goto fail;
60923d6bd3bSDenis V. Lunev     }
61023d6bd3bSDenis V. Lunev 
61123d6bd3bSDenis V. Lunev     bs->total_sectors = le64_to_cpu(ph.nb_sectors);
61223d6bd3bSDenis V. Lunev 
61323d6bd3bSDenis V. Lunev     if (le32_to_cpu(ph.version) != HEADER_VERSION) {
61423d6bd3bSDenis V. Lunev         goto fail_format;
61523d6bd3bSDenis V. Lunev     }
61623d6bd3bSDenis V. Lunev     if (!memcmp(ph.magic, HEADER_MAGIC, 16)) {
61723d6bd3bSDenis V. Lunev         s->off_multiplier = 1;
61823d6bd3bSDenis V. Lunev         bs->total_sectors = 0xffffffff & bs->total_sectors;
61923d6bd3bSDenis V. Lunev     } else if (!memcmp(ph.magic, HEADER_MAGIC2, 16)) {
62023d6bd3bSDenis V. Lunev         s->off_multiplier = le32_to_cpu(ph.tracks);
62123d6bd3bSDenis V. Lunev     } else {
62223d6bd3bSDenis V. Lunev         goto fail_format;
62323d6bd3bSDenis V. Lunev     }
62423d6bd3bSDenis V. Lunev 
62523d6bd3bSDenis V. Lunev     s->tracks = le32_to_cpu(ph.tracks);
62623d6bd3bSDenis V. Lunev     if (s->tracks == 0) {
62723d6bd3bSDenis V. Lunev         error_setg(errp, "Invalid image: Zero sectors per track");
62823d6bd3bSDenis V. Lunev         ret = -EINVAL;
62923d6bd3bSDenis V. Lunev         goto fail;
63023d6bd3bSDenis V. Lunev     }
63123d6bd3bSDenis V. Lunev     if (s->tracks > INT32_MAX/513) {
63223d6bd3bSDenis V. Lunev         error_setg(errp, "Invalid image: Too big cluster");
63323d6bd3bSDenis V. Lunev         ret = -EFBIG;
63423d6bd3bSDenis V. Lunev         goto fail;
63523d6bd3bSDenis V. Lunev     }
63623d6bd3bSDenis V. Lunev 
63723d6bd3bSDenis V. Lunev     s->bat_size = le32_to_cpu(ph.bat_entries);
63823d6bd3bSDenis V. Lunev     if (s->bat_size > INT_MAX / sizeof(uint32_t)) {
63923d6bd3bSDenis V. Lunev         error_setg(errp, "Catalog too large");
64023d6bd3bSDenis V. Lunev         ret = -EFBIG;
64123d6bd3bSDenis V. Lunev         goto fail;
64223d6bd3bSDenis V. Lunev     }
64323d6bd3bSDenis V. Lunev 
6442d68e22eSDenis V. Lunev     size = bat_entry_off(s->bat_size);
6459a4f4c31SKevin Wolf     s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file->bs));
6469a4f4c31SKevin Wolf     s->header = qemu_try_blockalign(bs->file->bs, s->header_size);
64723d6bd3bSDenis V. Lunev     if (s->header == NULL) {
64823d6bd3bSDenis V. Lunev         ret = -ENOMEM;
64923d6bd3bSDenis V. Lunev         goto fail;
65023d6bd3bSDenis V. Lunev     }
65119f5dc15SDenis V. Lunev     s->data_end = le32_to_cpu(ph.data_off);
65219f5dc15SDenis V. Lunev     if (s->data_end == 0) {
65319f5dc15SDenis V. Lunev         s->data_end = ROUND_UP(bat_entry_off(s->bat_size), BDRV_SECTOR_SIZE);
65419f5dc15SDenis V. Lunev     }
65519f5dc15SDenis V. Lunev     if (s->data_end < s->header_size) {
65623d6bd3bSDenis V. Lunev         /* there is not enough unused space to fit to block align between BAT
65723d6bd3bSDenis V. Lunev            and actual data. We can't avoid read-modify-write... */
65823d6bd3bSDenis V. Lunev         s->header_size = size;
65923d6bd3bSDenis V. Lunev     }
66023d6bd3bSDenis V. Lunev 
661cf2ab8fcSKevin Wolf     ret = bdrv_pread(bs->file, 0, s->header, s->header_size);
66223d6bd3bSDenis V. Lunev     if (ret < 0) {
66323d6bd3bSDenis V. Lunev         goto fail;
66423d6bd3bSDenis V. Lunev     }
66523d6bd3bSDenis V. Lunev     s->bat_bitmap = (uint32_t *)(s->header + 1);
66623d6bd3bSDenis V. Lunev 
66719f5dc15SDenis V. Lunev     for (i = 0; i < s->bat_size; i++) {
66819f5dc15SDenis V. Lunev         int64_t off = bat2sect(s, i);
66919f5dc15SDenis V. Lunev         if (off >= s->data_end) {
67019f5dc15SDenis V. Lunev             s->data_end = off + s->tracks;
67119f5dc15SDenis V. Lunev         }
67219f5dc15SDenis V. Lunev     }
67319f5dc15SDenis V. Lunev 
6746dd6b9f1SDenis V. Lunev     if (le32_to_cpu(ph.inuse) == HEADER_INUSE_MAGIC) {
6756dd6b9f1SDenis V. Lunev         /* Image was not closed correctly. The check is mandatory */
6766dd6b9f1SDenis V. Lunev         s->header_unclean = true;
6776dd6b9f1SDenis V. Lunev         if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_CHECK)) {
6786dd6b9f1SDenis V. Lunev             error_setg(errp, "parallels: Image was not closed correctly; "
6796dd6b9f1SDenis V. Lunev                        "cannot be opened read/write");
6806dd6b9f1SDenis V. Lunev             ret = -EACCES;
6816dd6b9f1SDenis V. Lunev             goto fail;
6826dd6b9f1SDenis V. Lunev         }
6836dd6b9f1SDenis V. Lunev     }
6846dd6b9f1SDenis V. Lunev 
685d6179011SDenis V. Lunev     opts = qemu_opts_create(&parallels_runtime_opts, NULL, 0, &local_err);
686d6179011SDenis V. Lunev     if (local_err != NULL) {
687d6179011SDenis V. Lunev         goto fail_options;
688d6179011SDenis V. Lunev     }
689d6179011SDenis V. Lunev 
690d6179011SDenis V. Lunev     qemu_opts_absorb_qdict(opts, options, &local_err);
691d6179011SDenis V. Lunev     if (local_err != NULL) {
692d6179011SDenis V. Lunev         goto fail_options;
693d6179011SDenis V. Lunev     }
694d6179011SDenis V. Lunev 
695d6179011SDenis V. Lunev     s->prealloc_size =
696d6179011SDenis V. Lunev         qemu_opt_get_size_del(opts, PARALLELS_OPT_PREALLOC_SIZE, 0);
697d6179011SDenis V. Lunev     s->prealloc_size = MAX(s->tracks, s->prealloc_size >> BDRV_SECTOR_BITS);
698d6179011SDenis V. Lunev     buf = qemu_opt_get_del(opts, PARALLELS_OPT_PREALLOC_MODE);
699d6179011SDenis V. Lunev     s->prealloc_mode = qapi_enum_parse(prealloc_mode_lookup, buf,
700*06c60b6cSMarkus Armbruster                                        PRL_PREALLOC_MODE_FALLOCATE,
701*06c60b6cSMarkus Armbruster                                        &local_err);
702d6179011SDenis V. Lunev     g_free(buf);
703d6179011SDenis V. Lunev     if (local_err != NULL) {
704d6179011SDenis V. Lunev         goto fail_options;
705d6179011SDenis V. Lunev     }
706dc62da88SDenis V. Lunev 
707e5e62683SDenis V. Lunev     if (!bdrv_has_zero_init(bs->file->bs)) {
708d6179011SDenis V. Lunev         s->prealloc_mode = PRL_PREALLOC_MODE_FALLOCATE;
709d6179011SDenis V. Lunev     }
710d6179011SDenis V. Lunev 
7116dd6b9f1SDenis V. Lunev     if (flags & BDRV_O_RDWR) {
7126dd6b9f1SDenis V. Lunev         s->header->inuse = cpu_to_le32(HEADER_INUSE_MAGIC);
7136dd6b9f1SDenis V. Lunev         ret = parallels_update_header(bs);
7146dd6b9f1SDenis V. Lunev         if (ret < 0) {
7156dd6b9f1SDenis V. Lunev             goto fail;
7166dd6b9f1SDenis V. Lunev         }
7176dd6b9f1SDenis V. Lunev     }
7186dd6b9f1SDenis V. Lunev 
7190d31c7c2SDenis V. Lunev     s->bat_dirty_block = 4 * getpagesize();
7200d31c7c2SDenis V. Lunev     s->bat_dirty_bmap =
7210d31c7c2SDenis V. Lunev         bitmap_new(DIV_ROUND_UP(s->header_size, s->bat_dirty_block));
7220d31c7c2SDenis V. Lunev 
72323d6bd3bSDenis V. Lunev     qemu_co_mutex_init(&s->lock);
72423d6bd3bSDenis V. Lunev     return 0;
72523d6bd3bSDenis V. Lunev 
72623d6bd3bSDenis V. Lunev fail_format:
72723d6bd3bSDenis V. Lunev     error_setg(errp, "Image not in Parallels format");
72823d6bd3bSDenis V. Lunev     ret = -EINVAL;
72923d6bd3bSDenis V. Lunev fail:
73023d6bd3bSDenis V. Lunev     qemu_vfree(s->header);
73123d6bd3bSDenis V. Lunev     return ret;
732d6179011SDenis V. Lunev 
733d6179011SDenis V. Lunev fail_options:
734d6179011SDenis V. Lunev     error_propagate(errp, local_err);
735d6179011SDenis V. Lunev     ret = -EINVAL;
736d6179011SDenis V. Lunev     goto fail;
73723d6bd3bSDenis V. Lunev }
73823d6bd3bSDenis V. Lunev 
73923d6bd3bSDenis V. Lunev 
740019d6b8fSAnthony Liguori static void parallels_close(BlockDriverState *bs)
741019d6b8fSAnthony Liguori {
742019d6b8fSAnthony Liguori     BDRVParallelsState *s = bs->opaque;
7436dd6b9f1SDenis V. Lunev 
7446dd6b9f1SDenis V. Lunev     if (bs->open_flags & BDRV_O_RDWR) {
7456dd6b9f1SDenis V. Lunev         s->header->inuse = 0;
7466dd6b9f1SDenis V. Lunev         parallels_update_header(bs);
7476dd6b9f1SDenis V. Lunev     }
7486dd6b9f1SDenis V. Lunev 
74919f5dc15SDenis V. Lunev     if (bs->open_flags & BDRV_O_RDWR) {
7507ea37c30SMax Reitz         bdrv_truncate(bs->file, s->data_end << BDRV_SECTOR_BITS,
7517ea37c30SMax Reitz                       PREALLOC_MODE_OFF, NULL);
75219f5dc15SDenis V. Lunev     }
75319f5dc15SDenis V. Lunev 
7540d31c7c2SDenis V. Lunev     g_free(s->bat_dirty_bmap);
7559eae9ccaSDenis V. Lunev     qemu_vfree(s->header);
756019d6b8fSAnthony Liguori }
757019d6b8fSAnthony Liguori 
75874cf6c50SDenis V. Lunev static QemuOptsList parallels_create_opts = {
75974cf6c50SDenis V. Lunev     .name = "parallels-create-opts",
76074cf6c50SDenis V. Lunev     .head = QTAILQ_HEAD_INITIALIZER(parallels_create_opts.head),
76174cf6c50SDenis V. Lunev     .desc = {
76274cf6c50SDenis V. Lunev         {
76374cf6c50SDenis V. Lunev             .name = BLOCK_OPT_SIZE,
76474cf6c50SDenis V. Lunev             .type = QEMU_OPT_SIZE,
76574cf6c50SDenis V. Lunev             .help = "Virtual disk size",
76674cf6c50SDenis V. Lunev         },
76774cf6c50SDenis V. Lunev         {
76874cf6c50SDenis V. Lunev             .name = BLOCK_OPT_CLUSTER_SIZE,
76974cf6c50SDenis V. Lunev             .type = QEMU_OPT_SIZE,
77074cf6c50SDenis V. Lunev             .help = "Parallels image cluster size",
77174cf6c50SDenis V. Lunev             .def_value_str = stringify(DEFAULT_CLUSTER_SIZE),
77274cf6c50SDenis V. Lunev         },
77374cf6c50SDenis V. Lunev         { /* end of list */ }
77474cf6c50SDenis V. Lunev     }
77574cf6c50SDenis V. Lunev };
77674cf6c50SDenis V. Lunev 
777019d6b8fSAnthony Liguori static BlockDriver bdrv_parallels = {
778019d6b8fSAnthony Liguori     .format_name	= "parallels",
779019d6b8fSAnthony Liguori     .instance_size	= sizeof(BDRVParallelsState),
780019d6b8fSAnthony Liguori     .bdrv_probe		= parallels_probe,
7811dec5a70SChristoph Hellwig     .bdrv_open		= parallels_open,
782019d6b8fSAnthony Liguori     .bdrv_close		= parallels_close,
783862f215fSKevin Wolf     .bdrv_child_perm          = bdrv_format_default_perms,
784dd3bed16SRoman Kagan     .bdrv_co_get_block_status = parallels_co_get_block_status,
785d0e61ce5SDenis V. Lunev     .bdrv_has_zero_init       = bdrv_has_zero_init_1,
7860d31c7c2SDenis V. Lunev     .bdrv_co_flush_to_os      = parallels_co_flush_to_os,
787481fb9cfSDenis V. Lunev     .bdrv_co_readv  = parallels_co_readv,
7885a41e1faSDenis V. Lunev     .bdrv_co_writev = parallels_co_writev,
78974cf6c50SDenis V. Lunev 
79074cf6c50SDenis V. Lunev     .bdrv_create    = parallels_create,
79149ad6467SDenis V. Lunev     .bdrv_check     = parallels_check,
79274cf6c50SDenis V. Lunev     .create_opts    = &parallels_create_opts,
793019d6b8fSAnthony Liguori };
794019d6b8fSAnthony Liguori 
795019d6b8fSAnthony Liguori static void bdrv_parallels_init(void)
796019d6b8fSAnthony Liguori {
797019d6b8fSAnthony Liguori     bdrv_register(&bdrv_parallels);
798019d6b8fSAnthony Liguori }
799019d6b8fSAnthony Liguori 
800019d6b8fSAnthony Liguori block_init(bdrv_parallels_init);
801