xref: /qemu/block/parallels.c (revision 2d68e22e)
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    = &parallels_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