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 */ 30019d6b8fSAnthony Liguori #include "qemu-common.h" 31737e150eSPaolo Bonzini #include "block/block_int.h" 321de7afc9SPaolo Bonzini #include "qemu/module.h" 33019d6b8fSAnthony Liguori 34019d6b8fSAnthony Liguori /**************************************************************/ 35019d6b8fSAnthony Liguori 36019d6b8fSAnthony Liguori #define HEADER_MAGIC "WithoutFreeSpace" 37d25d5980SDenis V. Lunev #define HEADER_MAGIC2 "WithouFreSpacExt" 38019d6b8fSAnthony Liguori #define HEADER_VERSION 2 396dd6b9f1SDenis V. Lunev #define HEADER_INUSE_MAGIC (0x746F6E59) 40019d6b8fSAnthony Liguori 4174cf6c50SDenis V. Lunev #define DEFAULT_CLUSTER_SIZE 1048576 /* 1 MiB */ 4274cf6c50SDenis V. Lunev 4374cf6c50SDenis V. Lunev 44019d6b8fSAnthony Liguori // always little-endian 4507898904SDenis V. Lunev typedef struct ParallelsHeader { 46019d6b8fSAnthony Liguori char magic[16]; // "WithoutFreeSpace" 47019d6b8fSAnthony Liguori uint32_t version; 48019d6b8fSAnthony Liguori uint32_t heads; 49019d6b8fSAnthony Liguori uint32_t cylinders; 50019d6b8fSAnthony Liguori uint32_t tracks; 51369f7de9SDenis V. Lunev uint32_t bat_entries; 528c27d54fSDenis V. Lunev uint64_t nb_sectors; 538c27d54fSDenis V. Lunev uint32_t inuse; 548c27d54fSDenis V. Lunev uint32_t data_off; 558c27d54fSDenis V. Lunev char padding[12]; 5607898904SDenis V. Lunev } QEMU_PACKED ParallelsHeader; 57019d6b8fSAnthony Liguori 58019d6b8fSAnthony Liguori typedef struct BDRVParallelsState { 59481fb9cfSDenis V. Lunev /** Locking is conservative, the lock protects 60481fb9cfSDenis V. Lunev * - image file extending (truncate, fallocate) 61481fb9cfSDenis V. Lunev * - any access to block allocation table 62481fb9cfSDenis V. Lunev */ 63848c66e8SPaolo Bonzini CoMutex lock; 64019d6b8fSAnthony Liguori 659eae9ccaSDenis V. Lunev ParallelsHeader *header; 669eae9ccaSDenis V. Lunev uint32_t header_size; 676dd6b9f1SDenis V. Lunev bool header_unclean; 686dd6b9f1SDenis V. Lunev 69369f7de9SDenis V. Lunev uint32_t *bat_bitmap; 70369f7de9SDenis V. Lunev unsigned int bat_size; 71019d6b8fSAnthony Liguori 729302e863SKevin Wolf unsigned int tracks; 73d25d5980SDenis V. Lunev 74d25d5980SDenis V. Lunev unsigned int off_multiplier; 755a41e1faSDenis V. Lunev 765a41e1faSDenis V. Lunev bool has_truncate; 77019d6b8fSAnthony Liguori } BDRVParallelsState; 78019d6b8fSAnthony Liguori 79555cc9d9SDenis V. Lunev 80555cc9d9SDenis V. Lunev static int64_t bat2sect(BDRVParallelsState *s, uint32_t idx) 81555cc9d9SDenis V. Lunev { 82dd97cdc0SDenis V. Lunev return (uint64_t)le32_to_cpu(s->bat_bitmap[idx]) * s->off_multiplier; 83555cc9d9SDenis V. Lunev } 84555cc9d9SDenis V. Lunev 85*2d68e22eSDenis V. Lunev static uint32_t bat_entry_off(uint32_t idx) 86*2d68e22eSDenis V. Lunev { 87*2d68e22eSDenis V. Lunev return sizeof(ParallelsHeader) + sizeof(uint32_t) * idx; 88*2d68e22eSDenis V. Lunev } 89*2d68e22eSDenis V. Lunev 9029442569SRoman Kagan static int64_t seek_to_sector(BDRVParallelsState *s, int64_t sector_num) 91019d6b8fSAnthony Liguori { 92c34d2451SDavid Woodhouse uint32_t index, offset; 93019d6b8fSAnthony Liguori 94019d6b8fSAnthony Liguori index = sector_num / s->tracks; 95019d6b8fSAnthony Liguori offset = sector_num % s->tracks; 96019d6b8fSAnthony Liguori 979d8b88f6SChristoph Hellwig /* not allocated */ 98369f7de9SDenis V. Lunev if ((index >= s->bat_size) || (s->bat_bitmap[index] == 0)) { 99019d6b8fSAnthony Liguori return -1; 100369f7de9SDenis V. Lunev } 101555cc9d9SDenis V. Lunev return bat2sect(s, index) + offset; 102019d6b8fSAnthony Liguori } 103019d6b8fSAnthony Liguori 1049de9da17SRoman Kagan static int cluster_remainder(BDRVParallelsState *s, int64_t sector_num, 1059de9da17SRoman Kagan int nb_sectors) 1069de9da17SRoman Kagan { 1079de9da17SRoman Kagan int ret = s->tracks - sector_num % s->tracks; 1089de9da17SRoman Kagan return MIN(nb_sectors, ret); 1099de9da17SRoman Kagan } 1109de9da17SRoman Kagan 1116953d920SDenis V. Lunev static int64_t block_status(BDRVParallelsState *s, int64_t sector_num, 1126953d920SDenis V. Lunev int nb_sectors, int *pnum) 1136953d920SDenis V. Lunev { 1146953d920SDenis V. Lunev int64_t start_off = -2, prev_end_off = -2; 1156953d920SDenis V. Lunev 1166953d920SDenis V. Lunev *pnum = 0; 1176953d920SDenis V. Lunev while (nb_sectors > 0 || start_off == -2) { 1186953d920SDenis V. Lunev int64_t offset = seek_to_sector(s, sector_num); 1196953d920SDenis V. Lunev int to_end; 1206953d920SDenis V. Lunev 1216953d920SDenis V. Lunev if (start_off == -2) { 1226953d920SDenis V. Lunev start_off = offset; 1236953d920SDenis V. Lunev prev_end_off = offset; 1246953d920SDenis V. Lunev } else if (offset != prev_end_off) { 1256953d920SDenis V. Lunev break; 1266953d920SDenis V. Lunev } 1276953d920SDenis V. Lunev 1286953d920SDenis V. Lunev to_end = cluster_remainder(s, sector_num, nb_sectors); 1296953d920SDenis V. Lunev nb_sectors -= to_end; 1306953d920SDenis V. Lunev sector_num += to_end; 1316953d920SDenis V. Lunev *pnum += to_end; 1326953d920SDenis V. Lunev 1336953d920SDenis V. Lunev if (offset > 0) { 1346953d920SDenis V. Lunev prev_end_off += to_end; 1356953d920SDenis V. Lunev } 1366953d920SDenis V. Lunev } 1376953d920SDenis V. Lunev return start_off; 1386953d920SDenis V. Lunev } 1396953d920SDenis V. Lunev 1405a41e1faSDenis V. Lunev static int64_t allocate_cluster(BlockDriverState *bs, int64_t sector_num) 1415a41e1faSDenis V. Lunev { 1425a41e1faSDenis V. Lunev BDRVParallelsState *s = bs->opaque; 143dd97cdc0SDenis V. Lunev uint32_t idx, offset; 1445a41e1faSDenis V. Lunev int64_t pos; 1455a41e1faSDenis V. Lunev int ret; 1465a41e1faSDenis V. Lunev 1475a41e1faSDenis V. Lunev idx = sector_num / s->tracks; 1485a41e1faSDenis V. Lunev offset = sector_num % s->tracks; 1495a41e1faSDenis V. Lunev 150369f7de9SDenis V. Lunev if (idx >= s->bat_size) { 1515a41e1faSDenis V. Lunev return -EINVAL; 1525a41e1faSDenis V. Lunev } 153369f7de9SDenis V. Lunev if (s->bat_bitmap[idx] != 0) { 154555cc9d9SDenis V. Lunev return bat2sect(s, idx) + offset; 1555a41e1faSDenis V. Lunev } 1565a41e1faSDenis V. Lunev 1575a41e1faSDenis V. Lunev pos = bdrv_getlength(bs->file) >> BDRV_SECTOR_BITS; 1585a41e1faSDenis V. Lunev if (s->has_truncate) { 1595a41e1faSDenis V. Lunev ret = bdrv_truncate(bs->file, (pos + s->tracks) << BDRV_SECTOR_BITS); 1605a41e1faSDenis V. Lunev } else { 1615a41e1faSDenis V. Lunev ret = bdrv_write_zeroes(bs->file, pos, s->tracks, 0); 1625a41e1faSDenis V. Lunev } 1635a41e1faSDenis V. Lunev if (ret < 0) { 1645a41e1faSDenis V. Lunev return ret; 1655a41e1faSDenis V. Lunev } 1665a41e1faSDenis V. Lunev 167dd97cdc0SDenis V. Lunev s->bat_bitmap[idx] = cpu_to_le32(pos / s->off_multiplier); 168*2d68e22eSDenis V. Lunev ret = bdrv_pwrite(bs->file, bat_entry_off(idx), s->bat_bitmap + idx, 169*2d68e22eSDenis V. Lunev sizeof(s->bat_bitmap[idx])); 1705a41e1faSDenis V. Lunev if (ret < 0) { 171369f7de9SDenis V. Lunev s->bat_bitmap[idx] = 0; 1725a41e1faSDenis V. Lunev return ret; 1735a41e1faSDenis V. Lunev } 174555cc9d9SDenis V. Lunev return bat2sect(s, idx) + offset; 1755a41e1faSDenis V. Lunev } 1765a41e1faSDenis V. Lunev 177dd3bed16SRoman Kagan static int64_t coroutine_fn parallels_co_get_block_status(BlockDriverState *bs, 178dd3bed16SRoman Kagan int64_t sector_num, int nb_sectors, int *pnum) 179dd3bed16SRoman Kagan { 180dd3bed16SRoman Kagan BDRVParallelsState *s = bs->opaque; 181dd3bed16SRoman Kagan int64_t offset; 182dd3bed16SRoman Kagan 183dd3bed16SRoman Kagan qemu_co_mutex_lock(&s->lock); 1846953d920SDenis V. Lunev offset = block_status(s, sector_num, nb_sectors, pnum); 185dd3bed16SRoman Kagan qemu_co_mutex_unlock(&s->lock); 186dd3bed16SRoman Kagan 187dd3bed16SRoman Kagan if (offset < 0) { 188dd3bed16SRoman Kagan return 0; 189dd3bed16SRoman Kagan } 190dd3bed16SRoman Kagan 191dd3bed16SRoman Kagan return (offset << BDRV_SECTOR_BITS) | 192dd3bed16SRoman Kagan BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID; 193dd3bed16SRoman Kagan } 194dd3bed16SRoman Kagan 1955a41e1faSDenis V. Lunev static coroutine_fn int parallels_co_writev(BlockDriverState *bs, 1965a41e1faSDenis V. Lunev int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) 1975a41e1faSDenis V. Lunev { 1985a41e1faSDenis V. Lunev BDRVParallelsState *s = bs->opaque; 1995a41e1faSDenis V. Lunev uint64_t bytes_done = 0; 2005a41e1faSDenis V. Lunev QEMUIOVector hd_qiov; 2015a41e1faSDenis V. Lunev int ret = 0; 2025a41e1faSDenis V. Lunev 2035a41e1faSDenis V. Lunev qemu_iovec_init(&hd_qiov, qiov->niov); 2045a41e1faSDenis V. Lunev 2055a41e1faSDenis V. Lunev while (nb_sectors > 0) { 2065a41e1faSDenis V. Lunev int64_t position; 2075a41e1faSDenis V. Lunev int n, nbytes; 2085a41e1faSDenis V. Lunev 2095a41e1faSDenis V. Lunev qemu_co_mutex_lock(&s->lock); 2105a41e1faSDenis V. Lunev position = allocate_cluster(bs, sector_num); 2115a41e1faSDenis V. Lunev qemu_co_mutex_unlock(&s->lock); 2125a41e1faSDenis V. Lunev if (position < 0) { 2135a41e1faSDenis V. Lunev ret = (int)position; 2145a41e1faSDenis V. Lunev break; 2155a41e1faSDenis V. Lunev } 2165a41e1faSDenis V. Lunev 2175a41e1faSDenis V. Lunev n = cluster_remainder(s, sector_num, nb_sectors); 2185a41e1faSDenis V. Lunev nbytes = n << BDRV_SECTOR_BITS; 2195a41e1faSDenis V. Lunev 2205a41e1faSDenis V. Lunev qemu_iovec_reset(&hd_qiov); 2215a41e1faSDenis V. Lunev qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes); 2225a41e1faSDenis V. Lunev 2235a41e1faSDenis V. Lunev ret = bdrv_co_writev(bs->file, position, n, &hd_qiov); 2245a41e1faSDenis V. Lunev if (ret < 0) { 2255a41e1faSDenis V. Lunev break; 2265a41e1faSDenis V. Lunev } 2275a41e1faSDenis V. Lunev 2285a41e1faSDenis V. Lunev nb_sectors -= n; 2295a41e1faSDenis V. Lunev sector_num += n; 2305a41e1faSDenis V. Lunev bytes_done += nbytes; 2315a41e1faSDenis V. Lunev } 2325a41e1faSDenis V. Lunev 2335a41e1faSDenis V. Lunev qemu_iovec_destroy(&hd_qiov); 2345a41e1faSDenis V. Lunev return ret; 2355a41e1faSDenis V. Lunev } 2365a41e1faSDenis V. Lunev 237481fb9cfSDenis V. Lunev static coroutine_fn int parallels_co_readv(BlockDriverState *bs, 238481fb9cfSDenis V. Lunev int64_t sector_num, int nb_sectors, QEMUIOVector *qiov) 239019d6b8fSAnthony Liguori { 24029442569SRoman Kagan BDRVParallelsState *s = bs->opaque; 241481fb9cfSDenis V. Lunev uint64_t bytes_done = 0; 242481fb9cfSDenis V. Lunev QEMUIOVector hd_qiov; 243481fb9cfSDenis V. Lunev int ret = 0; 244481fb9cfSDenis V. Lunev 245481fb9cfSDenis V. Lunev qemu_iovec_init(&hd_qiov, qiov->niov); 24629442569SRoman Kagan 247019d6b8fSAnthony Liguori while (nb_sectors > 0) { 248481fb9cfSDenis V. Lunev int64_t position; 249481fb9cfSDenis V. Lunev int n, nbytes; 250481fb9cfSDenis V. Lunev 251481fb9cfSDenis V. Lunev qemu_co_mutex_lock(&s->lock); 2526953d920SDenis V. Lunev position = block_status(s, sector_num, nb_sectors, &n); 253481fb9cfSDenis V. Lunev qemu_co_mutex_unlock(&s->lock); 254481fb9cfSDenis V. Lunev 255481fb9cfSDenis V. Lunev nbytes = n << BDRV_SECTOR_BITS; 256481fb9cfSDenis V. Lunev 257481fb9cfSDenis V. Lunev if (position < 0) { 258481fb9cfSDenis V. Lunev qemu_iovec_memset(qiov, bytes_done, 0, nbytes); 2599d8b88f6SChristoph Hellwig } else { 260481fb9cfSDenis V. Lunev qemu_iovec_reset(&hd_qiov); 261481fb9cfSDenis V. Lunev qemu_iovec_concat(&hd_qiov, qiov, bytes_done, nbytes); 262481fb9cfSDenis V. Lunev 263481fb9cfSDenis V. Lunev ret = bdrv_co_readv(bs->file, position, n, &hd_qiov); 264481fb9cfSDenis V. Lunev if (ret < 0) { 265481fb9cfSDenis V. Lunev break; 2669d8b88f6SChristoph Hellwig } 267019d6b8fSAnthony Liguori } 268019d6b8fSAnthony Liguori 269481fb9cfSDenis V. Lunev nb_sectors -= n; 270481fb9cfSDenis V. Lunev sector_num += n; 271481fb9cfSDenis V. Lunev bytes_done += nbytes; 272481fb9cfSDenis V. Lunev } 273481fb9cfSDenis V. Lunev 274481fb9cfSDenis V. Lunev qemu_iovec_destroy(&hd_qiov); 2752914caa0SPaolo Bonzini return ret; 2762914caa0SPaolo Bonzini } 2772914caa0SPaolo Bonzini 27849ad6467SDenis V. Lunev 27949ad6467SDenis V. Lunev static int parallels_check(BlockDriverState *bs, BdrvCheckResult *res, 28049ad6467SDenis V. Lunev BdrvCheckMode fix) 28149ad6467SDenis V. Lunev { 28249ad6467SDenis V. Lunev BDRVParallelsState *s = bs->opaque; 28349ad6467SDenis V. Lunev int64_t size, prev_off, high_off; 28449ad6467SDenis V. Lunev int ret; 28549ad6467SDenis V. Lunev uint32_t i; 28649ad6467SDenis V. Lunev bool flush_bat = false; 28749ad6467SDenis V. Lunev int cluster_size = s->tracks << BDRV_SECTOR_BITS; 28849ad6467SDenis V. Lunev 28949ad6467SDenis V. Lunev size = bdrv_getlength(bs->file); 29049ad6467SDenis V. Lunev if (size < 0) { 29149ad6467SDenis V. Lunev res->check_errors++; 29249ad6467SDenis V. Lunev return size; 29349ad6467SDenis V. Lunev } 29449ad6467SDenis V. Lunev 2956dd6b9f1SDenis V. Lunev if (s->header_unclean) { 2966dd6b9f1SDenis V. Lunev fprintf(stderr, "%s image was not closed correctly\n", 2976dd6b9f1SDenis V. Lunev fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR"); 2986dd6b9f1SDenis V. Lunev res->corruptions++; 2996dd6b9f1SDenis V. Lunev if (fix & BDRV_FIX_ERRORS) { 3006dd6b9f1SDenis V. Lunev /* parallels_close will do the job right */ 3016dd6b9f1SDenis V. Lunev res->corruptions_fixed++; 3026dd6b9f1SDenis V. Lunev s->header_unclean = false; 3036dd6b9f1SDenis V. Lunev } 3046dd6b9f1SDenis V. Lunev } 3056dd6b9f1SDenis V. Lunev 30649ad6467SDenis V. Lunev res->bfi.total_clusters = s->bat_size; 30749ad6467SDenis V. Lunev res->bfi.compressed_clusters = 0; /* compression is not supported */ 30849ad6467SDenis V. Lunev 30949ad6467SDenis V. Lunev high_off = 0; 31049ad6467SDenis V. Lunev prev_off = 0; 31149ad6467SDenis V. Lunev for (i = 0; i < s->bat_size; i++) { 31249ad6467SDenis V. Lunev int64_t off = bat2sect(s, i) << BDRV_SECTOR_BITS; 31349ad6467SDenis V. Lunev if (off == 0) { 31449ad6467SDenis V. Lunev prev_off = 0; 31549ad6467SDenis V. Lunev continue; 31649ad6467SDenis V. Lunev } 31749ad6467SDenis V. Lunev 31849ad6467SDenis V. Lunev /* cluster outside the image */ 31949ad6467SDenis V. Lunev if (off > size) { 32049ad6467SDenis V. Lunev fprintf(stderr, "%s cluster %u is outside image\n", 32149ad6467SDenis V. Lunev fix & BDRV_FIX_ERRORS ? "Repairing" : "ERROR", i); 32249ad6467SDenis V. Lunev res->corruptions++; 32349ad6467SDenis V. Lunev if (fix & BDRV_FIX_ERRORS) { 32449ad6467SDenis V. Lunev prev_off = 0; 32549ad6467SDenis V. Lunev s->bat_bitmap[i] = 0; 32649ad6467SDenis V. Lunev res->corruptions_fixed++; 32749ad6467SDenis V. Lunev flush_bat = true; 32849ad6467SDenis V. Lunev continue; 32949ad6467SDenis V. Lunev } 33049ad6467SDenis V. Lunev } 33149ad6467SDenis V. Lunev 33249ad6467SDenis V. Lunev res->bfi.allocated_clusters++; 33349ad6467SDenis V. Lunev if (off > high_off) { 33449ad6467SDenis V. Lunev high_off = off; 33549ad6467SDenis V. Lunev } 33649ad6467SDenis V. Lunev 33749ad6467SDenis V. Lunev if (prev_off != 0 && (prev_off + cluster_size) != off) { 33849ad6467SDenis V. Lunev res->bfi.fragmented_clusters++; 33949ad6467SDenis V. Lunev } 34049ad6467SDenis V. Lunev prev_off = off; 34149ad6467SDenis V. Lunev } 34249ad6467SDenis V. Lunev 34349ad6467SDenis V. Lunev if (flush_bat) { 34449ad6467SDenis V. Lunev ret = bdrv_pwrite_sync(bs->file, 0, s->header, s->header_size); 34549ad6467SDenis V. Lunev if (ret < 0) { 34649ad6467SDenis V. Lunev res->check_errors++; 34749ad6467SDenis V. Lunev return ret; 34849ad6467SDenis V. Lunev } 34949ad6467SDenis V. Lunev } 35049ad6467SDenis V. Lunev 35149ad6467SDenis V. Lunev res->image_end_offset = high_off + cluster_size; 35249ad6467SDenis V. Lunev if (size > res->image_end_offset) { 35349ad6467SDenis V. Lunev int64_t count; 35449ad6467SDenis V. Lunev count = DIV_ROUND_UP(size - res->image_end_offset, cluster_size); 35549ad6467SDenis V. Lunev fprintf(stderr, "%s space leaked at the end of the image %" PRId64 "\n", 35649ad6467SDenis V. Lunev fix & BDRV_FIX_LEAKS ? "Repairing" : "ERROR", 35749ad6467SDenis V. Lunev size - res->image_end_offset); 35849ad6467SDenis V. Lunev res->leaks += count; 35949ad6467SDenis V. Lunev if (fix & BDRV_FIX_LEAKS) { 36049ad6467SDenis V. Lunev ret = bdrv_truncate(bs->file, res->image_end_offset); 36149ad6467SDenis V. Lunev if (ret < 0) { 36249ad6467SDenis V. Lunev res->check_errors++; 36349ad6467SDenis V. Lunev return ret; 36449ad6467SDenis V. Lunev } 36549ad6467SDenis V. Lunev res->leaks_fixed += count; 36649ad6467SDenis V. Lunev } 36749ad6467SDenis V. Lunev } 36849ad6467SDenis V. Lunev 36949ad6467SDenis V. Lunev return 0; 37049ad6467SDenis V. Lunev } 37149ad6467SDenis V. Lunev 37249ad6467SDenis V. Lunev 37374cf6c50SDenis V. Lunev static int parallels_create(const char *filename, QemuOpts *opts, Error **errp) 37474cf6c50SDenis V. Lunev { 37574cf6c50SDenis V. Lunev int64_t total_size, cl_size; 37674cf6c50SDenis V. Lunev uint8_t tmp[BDRV_SECTOR_SIZE]; 37774cf6c50SDenis V. Lunev Error *local_err = NULL; 37874cf6c50SDenis V. Lunev BlockDriverState *file; 379369f7de9SDenis V. Lunev uint32_t bat_entries, bat_sectors; 38074cf6c50SDenis V. Lunev ParallelsHeader header; 38174cf6c50SDenis V. Lunev int ret; 38274cf6c50SDenis V. Lunev 38374cf6c50SDenis V. Lunev total_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), 38474cf6c50SDenis V. Lunev BDRV_SECTOR_SIZE); 38574cf6c50SDenis V. Lunev cl_size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_CLUSTER_SIZE, 38674cf6c50SDenis V. Lunev DEFAULT_CLUSTER_SIZE), BDRV_SECTOR_SIZE); 38774cf6c50SDenis V. Lunev 38874cf6c50SDenis V. Lunev ret = bdrv_create_file(filename, opts, &local_err); 38974cf6c50SDenis V. Lunev if (ret < 0) { 39074cf6c50SDenis V. Lunev error_propagate(errp, local_err); 39174cf6c50SDenis V. Lunev return ret; 39274cf6c50SDenis V. Lunev } 39374cf6c50SDenis V. Lunev 39474cf6c50SDenis V. Lunev file = NULL; 39574cf6c50SDenis V. Lunev ret = bdrv_open(&file, filename, NULL, NULL, 39674cf6c50SDenis V. Lunev BDRV_O_RDWR | BDRV_O_PROTOCOL, NULL, &local_err); 39774cf6c50SDenis V. Lunev if (ret < 0) { 39874cf6c50SDenis V. Lunev error_propagate(errp, local_err); 39974cf6c50SDenis V. Lunev return ret; 40074cf6c50SDenis V. Lunev } 40174cf6c50SDenis V. Lunev ret = bdrv_truncate(file, 0); 40274cf6c50SDenis V. Lunev if (ret < 0) { 40374cf6c50SDenis V. Lunev goto exit; 40474cf6c50SDenis V. Lunev } 40574cf6c50SDenis V. Lunev 406369f7de9SDenis V. Lunev bat_entries = DIV_ROUND_UP(total_size, cl_size); 407*2d68e22eSDenis V. Lunev bat_sectors = DIV_ROUND_UP(bat_entry_off(bat_entries), cl_size); 408369f7de9SDenis V. Lunev bat_sectors = (bat_sectors * cl_size) >> BDRV_SECTOR_BITS; 40974cf6c50SDenis V. Lunev 41074cf6c50SDenis V. Lunev memset(&header, 0, sizeof(header)); 41174cf6c50SDenis V. Lunev memcpy(header.magic, HEADER_MAGIC2, sizeof(header.magic)); 41274cf6c50SDenis V. Lunev header.version = cpu_to_le32(HEADER_VERSION); 41374cf6c50SDenis V. Lunev /* don't care much about geometry, it is not used on image level */ 41474cf6c50SDenis V. Lunev header.heads = cpu_to_le32(16); 41574cf6c50SDenis V. Lunev header.cylinders = cpu_to_le32(total_size / BDRV_SECTOR_SIZE / 16 / 32); 41674cf6c50SDenis V. Lunev header.tracks = cpu_to_le32(cl_size >> BDRV_SECTOR_BITS); 417369f7de9SDenis V. Lunev header.bat_entries = cpu_to_le32(bat_entries); 41874cf6c50SDenis V. Lunev header.nb_sectors = cpu_to_le64(DIV_ROUND_UP(total_size, BDRV_SECTOR_SIZE)); 419369f7de9SDenis V. Lunev header.data_off = cpu_to_le32(bat_sectors); 42074cf6c50SDenis V. Lunev 42174cf6c50SDenis V. Lunev /* write all the data */ 42274cf6c50SDenis V. Lunev memset(tmp, 0, sizeof(tmp)); 42374cf6c50SDenis V. Lunev memcpy(tmp, &header, sizeof(header)); 42474cf6c50SDenis V. Lunev 42574cf6c50SDenis V. Lunev ret = bdrv_pwrite(file, 0, tmp, BDRV_SECTOR_SIZE); 42674cf6c50SDenis V. Lunev if (ret < 0) { 42774cf6c50SDenis V. Lunev goto exit; 42874cf6c50SDenis V. Lunev } 429369f7de9SDenis V. Lunev ret = bdrv_write_zeroes(file, 1, bat_sectors - 1, 0); 43074cf6c50SDenis V. Lunev if (ret < 0) { 43174cf6c50SDenis V. Lunev goto exit; 43274cf6c50SDenis V. Lunev } 43374cf6c50SDenis V. Lunev ret = 0; 43474cf6c50SDenis V. Lunev 43574cf6c50SDenis V. Lunev done: 43674cf6c50SDenis V. Lunev bdrv_unref(file); 43774cf6c50SDenis V. Lunev return ret; 43874cf6c50SDenis V. Lunev 43974cf6c50SDenis V. Lunev exit: 44074cf6c50SDenis V. Lunev error_setg_errno(errp, -ret, "Failed to create Parallels image"); 44174cf6c50SDenis V. Lunev goto done; 44274cf6c50SDenis V. Lunev } 44374cf6c50SDenis V. Lunev 44423d6bd3bSDenis V. Lunev 44523d6bd3bSDenis V. Lunev static int parallels_probe(const uint8_t *buf, int buf_size, 44623d6bd3bSDenis V. Lunev const char *filename) 44723d6bd3bSDenis V. Lunev { 44823d6bd3bSDenis V. Lunev const ParallelsHeader *ph = (const void *)buf; 44923d6bd3bSDenis V. Lunev 45023d6bd3bSDenis V. Lunev if (buf_size < sizeof(ParallelsHeader)) { 45123d6bd3bSDenis V. Lunev return 0; 45223d6bd3bSDenis V. Lunev } 45323d6bd3bSDenis V. Lunev 45423d6bd3bSDenis V. Lunev if ((!memcmp(ph->magic, HEADER_MAGIC, 16) || 45523d6bd3bSDenis V. Lunev !memcmp(ph->magic, HEADER_MAGIC2, 16)) && 45623d6bd3bSDenis V. Lunev (le32_to_cpu(ph->version) == HEADER_VERSION)) { 45723d6bd3bSDenis V. Lunev return 100; 45823d6bd3bSDenis V. Lunev } 45923d6bd3bSDenis V. Lunev 46023d6bd3bSDenis V. Lunev return 0; 46123d6bd3bSDenis V. Lunev } 46223d6bd3bSDenis V. Lunev 4636dd6b9f1SDenis V. Lunev static int parallels_update_header(BlockDriverState *bs) 4646dd6b9f1SDenis V. Lunev { 4656dd6b9f1SDenis V. Lunev BDRVParallelsState *s = bs->opaque; 4666dd6b9f1SDenis V. Lunev unsigned size = MAX(bdrv_opt_mem_align(bs->file), sizeof(ParallelsHeader)); 4676dd6b9f1SDenis V. Lunev 4686dd6b9f1SDenis V. Lunev if (size > s->header_size) { 4696dd6b9f1SDenis V. Lunev size = s->header_size; 4706dd6b9f1SDenis V. Lunev } 4716dd6b9f1SDenis V. Lunev return bdrv_pwrite_sync(bs->file, 0, s->header, size); 4726dd6b9f1SDenis V. Lunev } 4736dd6b9f1SDenis V. Lunev 47423d6bd3bSDenis V. Lunev static int parallels_open(BlockDriverState *bs, QDict *options, int flags, 47523d6bd3bSDenis V. Lunev Error **errp) 47623d6bd3bSDenis V. Lunev { 47723d6bd3bSDenis V. Lunev BDRVParallelsState *s = bs->opaque; 47823d6bd3bSDenis V. Lunev ParallelsHeader ph; 47923d6bd3bSDenis V. Lunev int ret, size; 48023d6bd3bSDenis V. Lunev 48123d6bd3bSDenis V. Lunev ret = bdrv_pread(bs->file, 0, &ph, sizeof(ph)); 48223d6bd3bSDenis V. Lunev if (ret < 0) { 48323d6bd3bSDenis V. Lunev goto fail; 48423d6bd3bSDenis V. Lunev } 48523d6bd3bSDenis V. Lunev 48623d6bd3bSDenis V. Lunev bs->total_sectors = le64_to_cpu(ph.nb_sectors); 48723d6bd3bSDenis V. Lunev 48823d6bd3bSDenis V. Lunev if (le32_to_cpu(ph.version) != HEADER_VERSION) { 48923d6bd3bSDenis V. Lunev goto fail_format; 49023d6bd3bSDenis V. Lunev } 49123d6bd3bSDenis V. Lunev if (!memcmp(ph.magic, HEADER_MAGIC, 16)) { 49223d6bd3bSDenis V. Lunev s->off_multiplier = 1; 49323d6bd3bSDenis V. Lunev bs->total_sectors = 0xffffffff & bs->total_sectors; 49423d6bd3bSDenis V. Lunev } else if (!memcmp(ph.magic, HEADER_MAGIC2, 16)) { 49523d6bd3bSDenis V. Lunev s->off_multiplier = le32_to_cpu(ph.tracks); 49623d6bd3bSDenis V. Lunev } else { 49723d6bd3bSDenis V. Lunev goto fail_format; 49823d6bd3bSDenis V. Lunev } 49923d6bd3bSDenis V. Lunev 50023d6bd3bSDenis V. Lunev s->tracks = le32_to_cpu(ph.tracks); 50123d6bd3bSDenis V. Lunev if (s->tracks == 0) { 50223d6bd3bSDenis V. Lunev error_setg(errp, "Invalid image: Zero sectors per track"); 50323d6bd3bSDenis V. Lunev ret = -EINVAL; 50423d6bd3bSDenis V. Lunev goto fail; 50523d6bd3bSDenis V. Lunev } 50623d6bd3bSDenis V. Lunev if (s->tracks > INT32_MAX/513) { 50723d6bd3bSDenis V. Lunev error_setg(errp, "Invalid image: Too big cluster"); 50823d6bd3bSDenis V. Lunev ret = -EFBIG; 50923d6bd3bSDenis V. Lunev goto fail; 51023d6bd3bSDenis V. Lunev } 51123d6bd3bSDenis V. Lunev 51223d6bd3bSDenis V. Lunev s->bat_size = le32_to_cpu(ph.bat_entries); 51323d6bd3bSDenis V. Lunev if (s->bat_size > INT_MAX / sizeof(uint32_t)) { 51423d6bd3bSDenis V. Lunev error_setg(errp, "Catalog too large"); 51523d6bd3bSDenis V. Lunev ret = -EFBIG; 51623d6bd3bSDenis V. Lunev goto fail; 51723d6bd3bSDenis V. Lunev } 51823d6bd3bSDenis V. Lunev 519*2d68e22eSDenis V. Lunev size = bat_entry_off(s->bat_size); 52023d6bd3bSDenis V. Lunev s->header_size = ROUND_UP(size, bdrv_opt_mem_align(bs->file)); 52123d6bd3bSDenis V. Lunev s->header = qemu_try_blockalign(bs->file, s->header_size); 52223d6bd3bSDenis V. Lunev if (s->header == NULL) { 52323d6bd3bSDenis V. Lunev ret = -ENOMEM; 52423d6bd3bSDenis V. Lunev goto fail; 52523d6bd3bSDenis V. Lunev } 52623d6bd3bSDenis V. Lunev if (le32_to_cpu(ph.data_off) < s->header_size) { 52723d6bd3bSDenis V. Lunev /* there is not enough unused space to fit to block align between BAT 52823d6bd3bSDenis V. Lunev and actual data. We can't avoid read-modify-write... */ 52923d6bd3bSDenis V. Lunev s->header_size = size; 53023d6bd3bSDenis V. Lunev } 53123d6bd3bSDenis V. Lunev 53223d6bd3bSDenis V. Lunev ret = bdrv_pread(bs->file, 0, s->header, s->header_size); 53323d6bd3bSDenis V. Lunev if (ret < 0) { 53423d6bd3bSDenis V. Lunev goto fail; 53523d6bd3bSDenis V. Lunev } 53623d6bd3bSDenis V. Lunev s->bat_bitmap = (uint32_t *)(s->header + 1); 53723d6bd3bSDenis V. Lunev 53823d6bd3bSDenis V. Lunev s->has_truncate = bdrv_has_zero_init(bs->file) && 53923d6bd3bSDenis V. Lunev bdrv_truncate(bs->file, bdrv_getlength(bs->file)) == 0; 54023d6bd3bSDenis V. Lunev 5416dd6b9f1SDenis V. Lunev if (le32_to_cpu(ph.inuse) == HEADER_INUSE_MAGIC) { 5426dd6b9f1SDenis V. Lunev /* Image was not closed correctly. The check is mandatory */ 5436dd6b9f1SDenis V. Lunev s->header_unclean = true; 5446dd6b9f1SDenis V. Lunev if ((flags & BDRV_O_RDWR) && !(flags & BDRV_O_CHECK)) { 5456dd6b9f1SDenis V. Lunev error_setg(errp, "parallels: Image was not closed correctly; " 5466dd6b9f1SDenis V. Lunev "cannot be opened read/write"); 5476dd6b9f1SDenis V. Lunev ret = -EACCES; 5486dd6b9f1SDenis V. Lunev goto fail; 5496dd6b9f1SDenis V. Lunev } 5506dd6b9f1SDenis V. Lunev } 5516dd6b9f1SDenis V. Lunev 5526dd6b9f1SDenis V. Lunev if (flags & BDRV_O_RDWR) { 5536dd6b9f1SDenis V. Lunev s->header->inuse = cpu_to_le32(HEADER_INUSE_MAGIC); 5546dd6b9f1SDenis V. Lunev ret = parallels_update_header(bs); 5556dd6b9f1SDenis V. Lunev if (ret < 0) { 5566dd6b9f1SDenis V. Lunev goto fail; 5576dd6b9f1SDenis V. Lunev } 5586dd6b9f1SDenis V. Lunev } 5596dd6b9f1SDenis V. Lunev 56023d6bd3bSDenis V. Lunev qemu_co_mutex_init(&s->lock); 56123d6bd3bSDenis V. Lunev return 0; 56223d6bd3bSDenis V. Lunev 56323d6bd3bSDenis V. Lunev fail_format: 56423d6bd3bSDenis V. Lunev error_setg(errp, "Image not in Parallels format"); 56523d6bd3bSDenis V. Lunev ret = -EINVAL; 56623d6bd3bSDenis V. Lunev fail: 56723d6bd3bSDenis V. Lunev qemu_vfree(s->header); 56823d6bd3bSDenis V. Lunev return ret; 56923d6bd3bSDenis V. Lunev } 57023d6bd3bSDenis V. Lunev 57123d6bd3bSDenis V. Lunev 572019d6b8fSAnthony Liguori static void parallels_close(BlockDriverState *bs) 573019d6b8fSAnthony Liguori { 574019d6b8fSAnthony Liguori BDRVParallelsState *s = bs->opaque; 5756dd6b9f1SDenis V. Lunev 5766dd6b9f1SDenis V. Lunev if (bs->open_flags & BDRV_O_RDWR) { 5776dd6b9f1SDenis V. Lunev s->header->inuse = 0; 5786dd6b9f1SDenis V. Lunev parallels_update_header(bs); 5796dd6b9f1SDenis V. Lunev } 5806dd6b9f1SDenis V. Lunev 5819eae9ccaSDenis V. Lunev qemu_vfree(s->header); 582019d6b8fSAnthony Liguori } 583019d6b8fSAnthony Liguori 58474cf6c50SDenis V. Lunev static QemuOptsList parallels_create_opts = { 58574cf6c50SDenis V. Lunev .name = "parallels-create-opts", 58674cf6c50SDenis V. Lunev .head = QTAILQ_HEAD_INITIALIZER(parallels_create_opts.head), 58774cf6c50SDenis V. Lunev .desc = { 58874cf6c50SDenis V. Lunev { 58974cf6c50SDenis V. Lunev .name = BLOCK_OPT_SIZE, 59074cf6c50SDenis V. Lunev .type = QEMU_OPT_SIZE, 59174cf6c50SDenis V. Lunev .help = "Virtual disk size", 59274cf6c50SDenis V. Lunev }, 59374cf6c50SDenis V. Lunev { 59474cf6c50SDenis V. Lunev .name = BLOCK_OPT_CLUSTER_SIZE, 59574cf6c50SDenis V. Lunev .type = QEMU_OPT_SIZE, 59674cf6c50SDenis V. Lunev .help = "Parallels image cluster size", 59774cf6c50SDenis V. Lunev .def_value_str = stringify(DEFAULT_CLUSTER_SIZE), 59874cf6c50SDenis V. Lunev }, 59974cf6c50SDenis V. Lunev { /* end of list */ } 60074cf6c50SDenis V. Lunev } 60174cf6c50SDenis V. Lunev }; 60274cf6c50SDenis V. Lunev 603019d6b8fSAnthony Liguori static BlockDriver bdrv_parallels = { 604019d6b8fSAnthony Liguori .format_name = "parallels", 605019d6b8fSAnthony Liguori .instance_size = sizeof(BDRVParallelsState), 606019d6b8fSAnthony Liguori .bdrv_probe = parallels_probe, 6071dec5a70SChristoph Hellwig .bdrv_open = parallels_open, 608019d6b8fSAnthony Liguori .bdrv_close = parallels_close, 609dd3bed16SRoman Kagan .bdrv_co_get_block_status = parallels_co_get_block_status, 610d0e61ce5SDenis V. Lunev .bdrv_has_zero_init = bdrv_has_zero_init_1, 611481fb9cfSDenis V. Lunev .bdrv_co_readv = parallels_co_readv, 6125a41e1faSDenis V. Lunev .bdrv_co_writev = parallels_co_writev, 61374cf6c50SDenis V. Lunev 61474cf6c50SDenis V. Lunev .bdrv_create = parallels_create, 61549ad6467SDenis V. Lunev .bdrv_check = parallels_check, 61674cf6c50SDenis V. Lunev .create_opts = ¶llels_create_opts, 617019d6b8fSAnthony Liguori }; 618019d6b8fSAnthony Liguori 619019d6b8fSAnthony Liguori static void bdrv_parallels_init(void) 620019d6b8fSAnthony Liguori { 621019d6b8fSAnthony Liguori bdrv_register(&bdrv_parallels); 622019d6b8fSAnthony Liguori } 623019d6b8fSAnthony Liguori 624019d6b8fSAnthony Liguori block_init(bdrv_parallels_init); 625