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(¶llels_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 = ¶llels_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