Statistics
| Branch: | Revision:

root / block / vdi.c @ 99cce9fa

History | View | Annotate | Download (29.4 kB)

1 9aebd98a Stefan Weil
/*
2 9aebd98a Stefan Weil
 * Block driver for the Virtual Disk Image (VDI) format
3 9aebd98a Stefan Weil
 *
4 9aebd98a Stefan Weil
 * Copyright (c) 2009 Stefan Weil
5 9aebd98a Stefan Weil
 *
6 9aebd98a Stefan Weil
 * This program is free software: you can redistribute it and/or modify
7 9aebd98a Stefan Weil
 * it under the terms of the GNU General Public License as published by
8 9aebd98a Stefan Weil
 * the Free Software Foundation, either version 2 of the License, or
9 9aebd98a Stefan Weil
 * (at your option) version 3 or any later version.
10 9aebd98a Stefan Weil
 *
11 9aebd98a Stefan Weil
 * This program is distributed in the hope that it will be useful,
12 9aebd98a Stefan Weil
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 9aebd98a Stefan Weil
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 9aebd98a Stefan Weil
 * GNU General Public License for more details.
15 9aebd98a Stefan Weil
 *
16 9aebd98a Stefan Weil
 * You should have received a copy of the GNU General Public License
17 9aebd98a Stefan Weil
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18 9aebd98a Stefan Weil
 *
19 9aebd98a Stefan Weil
 * Reference:
20 9aebd98a Stefan Weil
 * http://forums.virtualbox.org/viewtopic.php?t=8046
21 9aebd98a Stefan Weil
 *
22 9aebd98a Stefan Weil
 * This driver supports create / read / write operations on VDI images.
23 9aebd98a Stefan Weil
 *
24 9aebd98a Stefan Weil
 * Todo (see also TODO in code):
25 9aebd98a Stefan Weil
 *
26 9aebd98a Stefan Weil
 * Some features like snapshots are still missing.
27 9aebd98a Stefan Weil
 *
28 9aebd98a Stefan Weil
 * Deallocation of zero-filled blocks and shrinking images are missing, too
29 9aebd98a Stefan Weil
 * (might be added to common block layer).
30 9aebd98a Stefan Weil
 *
31 9aebd98a Stefan Weil
 * Allocation of blocks could be optimized (less writes to block map and
32 9aebd98a Stefan Weil
 * header).
33 9aebd98a Stefan Weil
 *
34 9aebd98a Stefan Weil
 * Read and write of adjacents blocks could be done in one operation
35 9aebd98a Stefan Weil
 * (current code uses one operation per block (1 MiB).
36 9aebd98a Stefan Weil
 *
37 9aebd98a Stefan Weil
 * The code is not thread safe (missing locks for changes in header and
38 9aebd98a Stefan Weil
 * block table, no problem with current QEMU).
39 9aebd98a Stefan Weil
 *
40 9aebd98a Stefan Weil
 * Hints:
41 9aebd98a Stefan Weil
 *
42 9aebd98a Stefan Weil
 * Blocks (VDI documentation) correspond to clusters (QEMU).
43 9aebd98a Stefan Weil
 * QEMU's backing files could be implemented using VDI snapshot files (TODO).
44 9aebd98a Stefan Weil
 * VDI snapshot files may also contain the complete machine state.
45 9aebd98a Stefan Weil
 * Maybe this machine state can be converted to QEMU PC machine snapshot data.
46 9aebd98a Stefan Weil
 *
47 9aebd98a Stefan Weil
 * The driver keeps a block cache (little endian entries) in memory.
48 9aebd98a Stefan Weil
 * For the standard block size (1 MiB), a 1 TiB disk will use 4 MiB RAM,
49 9aebd98a Stefan Weil
 * so this seems to be reasonable.
50 9aebd98a Stefan Weil
 */
51 9aebd98a Stefan Weil
52 9aebd98a Stefan Weil
#include "qemu-common.h"
53 9aebd98a Stefan Weil
#include "block_int.h"
54 9aebd98a Stefan Weil
#include "module.h"
55 9aebd98a Stefan Weil
56 ee682d27 Stefan Weil
#if defined(CONFIG_UUID)
57 9aebd98a Stefan Weil
#include <uuid/uuid.h>
58 9aebd98a Stefan Weil
#else
59 9aebd98a Stefan Weil
/* TODO: move uuid emulation to some central place in QEMU. */
60 9aebd98a Stefan Weil
#include "sysemu.h"     /* UUID_FMT */
61 9aebd98a Stefan Weil
typedef unsigned char uuid_t[16];
62 9aebd98a Stefan Weil
void uuid_generate(uuid_t out);
63 9aebd98a Stefan Weil
int uuid_is_null(const uuid_t uu);
64 9aebd98a Stefan Weil
void uuid_unparse(const uuid_t uu, char *out);
65 9aebd98a Stefan Weil
#endif
66 9aebd98a Stefan Weil
67 9aebd98a Stefan Weil
/* Code configuration options. */
68 9aebd98a Stefan Weil
69 9aebd98a Stefan Weil
/* Enable debug messages. */
70 9aebd98a Stefan Weil
//~ #define CONFIG_VDI_DEBUG
71 9aebd98a Stefan Weil
72 9aebd98a Stefan Weil
/* Support write operations on VDI images. */
73 9aebd98a Stefan Weil
#define CONFIG_VDI_WRITE
74 9aebd98a Stefan Weil
75 9aebd98a Stefan Weil
/* Support non-standard block (cluster) size. This is untested.
76 9aebd98a Stefan Weil
 * Maybe it will be needed for very large images.
77 9aebd98a Stefan Weil
 */
78 9aebd98a Stefan Weil
//~ #define CONFIG_VDI_BLOCK_SIZE
79 9aebd98a Stefan Weil
80 9aebd98a Stefan Weil
/* Support static (fixed, pre-allocated) images. */
81 9aebd98a Stefan Weil
#define CONFIG_VDI_STATIC_IMAGE
82 9aebd98a Stefan Weil
83 9aebd98a Stefan Weil
/* Command line option for static images. */
84 9aebd98a Stefan Weil
#define BLOCK_OPT_STATIC "static"
85 9aebd98a Stefan Weil
86 9aebd98a Stefan Weil
#define KiB     1024
87 9aebd98a Stefan Weil
#define MiB     (KiB * KiB)
88 9aebd98a Stefan Weil
89 9aebd98a Stefan Weil
#define SECTOR_SIZE 512
90 99cce9fa Kevin Wolf
#define DEFAULT_CLUSTER_SIZE (1 * MiB)
91 9aebd98a Stefan Weil
92 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
93 9aebd98a Stefan Weil
#define logout(fmt, ...) \
94 9aebd98a Stefan Weil
                fprintf(stderr, "vdi\t%-24s" fmt, __func__, ##__VA_ARGS__)
95 9aebd98a Stefan Weil
#else
96 9aebd98a Stefan Weil
#define logout(fmt, ...) ((void)0)
97 9aebd98a Stefan Weil
#endif
98 9aebd98a Stefan Weil
99 9aebd98a Stefan Weil
/* Image signature. */
100 9aebd98a Stefan Weil
#define VDI_SIGNATURE 0xbeda107f
101 9aebd98a Stefan Weil
102 9aebd98a Stefan Weil
/* Image version. */
103 9aebd98a Stefan Weil
#define VDI_VERSION_1_1 0x00010001
104 9aebd98a Stefan Weil
105 9aebd98a Stefan Weil
/* Image type. */
106 9aebd98a Stefan Weil
#define VDI_TYPE_DYNAMIC 1
107 9aebd98a Stefan Weil
#define VDI_TYPE_STATIC  2
108 9aebd98a Stefan Weil
109 9aebd98a Stefan Weil
/* Innotek / SUN images use these strings in header.text:
110 9aebd98a Stefan Weil
 * "<<< innotek VirtualBox Disk Image >>>\n"
111 9aebd98a Stefan Weil
 * "<<< Sun xVM VirtualBox Disk Image >>>\n"
112 9aebd98a Stefan Weil
 * "<<< Sun VirtualBox Disk Image >>>\n"
113 9aebd98a Stefan Weil
 * The value does not matter, so QEMU created images use a different text.
114 9aebd98a Stefan Weil
 */
115 9aebd98a Stefan Weil
#define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
116 9aebd98a Stefan Weil
117 4ff9786c Stefan Weil
/* Unallocated blocks use this index (no need to convert endianness). */
118 9aebd98a Stefan Weil
#define VDI_UNALLOCATED UINT32_MAX
119 9aebd98a Stefan Weil
120 ee682d27 Stefan Weil
#if !defined(CONFIG_UUID)
121 9aebd98a Stefan Weil
void uuid_generate(uuid_t out)
122 9aebd98a Stefan Weil
{
123 4f3669ea Stefan Weil
    memset(out, 0, sizeof(uuid_t));
124 9aebd98a Stefan Weil
}
125 9aebd98a Stefan Weil
126 9aebd98a Stefan Weil
int uuid_is_null(const uuid_t uu)
127 9aebd98a Stefan Weil
{
128 9aebd98a Stefan Weil
    uuid_t null_uuid = { 0 };
129 4f3669ea Stefan Weil
    return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0;
130 9aebd98a Stefan Weil
}
131 9aebd98a Stefan Weil
132 9aebd98a Stefan Weil
void uuid_unparse(const uuid_t uu, char *out)
133 9aebd98a Stefan Weil
{
134 9aebd98a Stefan Weil
    snprintf(out, 37, UUID_FMT,
135 9aebd98a Stefan Weil
            uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7],
136 9aebd98a Stefan Weil
            uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
137 9aebd98a Stefan Weil
}
138 9aebd98a Stefan Weil
#endif
139 9aebd98a Stefan Weil
140 9aebd98a Stefan Weil
typedef struct {
141 9aebd98a Stefan Weil
    BlockDriverAIOCB common;
142 9aebd98a Stefan Weil
    int64_t sector_num;
143 9aebd98a Stefan Weil
    QEMUIOVector *qiov;
144 9aebd98a Stefan Weil
    uint8_t *buf;
145 9aebd98a Stefan Weil
    /* Total number of sectors. */
146 9aebd98a Stefan Weil
    int nb_sectors;
147 9aebd98a Stefan Weil
    /* Number of sectors for current AIO. */
148 9aebd98a Stefan Weil
    int n_sectors;
149 9aebd98a Stefan Weil
    /* New allocated block map entry. */
150 9aebd98a Stefan Weil
    uint32_t bmap_first;
151 9aebd98a Stefan Weil
    uint32_t bmap_last;
152 9aebd98a Stefan Weil
    /* Buffer for new allocated block. */
153 9aebd98a Stefan Weil
    void *block_buffer;
154 9aebd98a Stefan Weil
    void *orig_buf;
155 9aebd98a Stefan Weil
    int header_modified;
156 9aebd98a Stefan Weil
    BlockDriverAIOCB *hd_aiocb;
157 9aebd98a Stefan Weil
    struct iovec hd_iov;
158 9aebd98a Stefan Weil
    QEMUIOVector hd_qiov;
159 9aebd98a Stefan Weil
    QEMUBH *bh;
160 9aebd98a Stefan Weil
} VdiAIOCB;
161 9aebd98a Stefan Weil
162 9aebd98a Stefan Weil
typedef struct {
163 9aebd98a Stefan Weil
    char text[0x40];
164 9aebd98a Stefan Weil
    uint32_t signature;
165 9aebd98a Stefan Weil
    uint32_t version;
166 9aebd98a Stefan Weil
    uint32_t header_size;
167 9aebd98a Stefan Weil
    uint32_t image_type;
168 9aebd98a Stefan Weil
    uint32_t image_flags;
169 9aebd98a Stefan Weil
    char description[256];
170 9aebd98a Stefan Weil
    uint32_t offset_bmap;
171 9aebd98a Stefan Weil
    uint32_t offset_data;
172 9aebd98a Stefan Weil
    uint32_t cylinders;         /* disk geometry, unused here */
173 9aebd98a Stefan Weil
    uint32_t heads;             /* disk geometry, unused here */
174 9aebd98a Stefan Weil
    uint32_t sectors;           /* disk geometry, unused here */
175 9aebd98a Stefan Weil
    uint32_t sector_size;
176 9aebd98a Stefan Weil
    uint32_t unused1;
177 9aebd98a Stefan Weil
    uint64_t disk_size;
178 9aebd98a Stefan Weil
    uint32_t block_size;
179 9aebd98a Stefan Weil
    uint32_t block_extra;       /* unused here */
180 9aebd98a Stefan Weil
    uint32_t blocks_in_image;
181 9aebd98a Stefan Weil
    uint32_t blocks_allocated;
182 9aebd98a Stefan Weil
    uuid_t uuid_image;
183 9aebd98a Stefan Weil
    uuid_t uuid_last_snap;
184 9aebd98a Stefan Weil
    uuid_t uuid_link;
185 9aebd98a Stefan Weil
    uuid_t uuid_parent;
186 9aebd98a Stefan Weil
    uint64_t unused2[7];
187 9aebd98a Stefan Weil
} VdiHeader;
188 9aebd98a Stefan Weil
189 9aebd98a Stefan Weil
typedef struct {
190 9aebd98a Stefan Weil
    /* The block map entries are little endian (even in memory). */
191 9aebd98a Stefan Weil
    uint32_t *bmap;
192 9aebd98a Stefan Weil
    /* Size of block (bytes). */
193 9aebd98a Stefan Weil
    uint32_t block_size;
194 9aebd98a Stefan Weil
    /* Size of block (sectors). */
195 9aebd98a Stefan Weil
    uint32_t block_sectors;
196 9aebd98a Stefan Weil
    /* First sector of block map. */
197 9aebd98a Stefan Weil
    uint32_t bmap_sector;
198 4ff9786c Stefan Weil
    /* VDI header (converted to host endianness). */
199 9aebd98a Stefan Weil
    VdiHeader header;
200 9aebd98a Stefan Weil
} BDRVVdiState;
201 9aebd98a Stefan Weil
202 9aebd98a Stefan Weil
/* Change UUID from little endian (IPRT = VirtualBox format) to big endian
203 9aebd98a Stefan Weil
 * format (network byte order, standard, see RFC 4122) and vice versa.
204 9aebd98a Stefan Weil
 */
205 9aebd98a Stefan Weil
static void uuid_convert(uuid_t uuid)
206 9aebd98a Stefan Weil
{
207 9aebd98a Stefan Weil
    bswap32s((uint32_t *)&uuid[0]);
208 9aebd98a Stefan Weil
    bswap16s((uint16_t *)&uuid[4]);
209 9aebd98a Stefan Weil
    bswap16s((uint16_t *)&uuid[6]);
210 9aebd98a Stefan Weil
}
211 9aebd98a Stefan Weil
212 9aebd98a Stefan Weil
static void vdi_header_to_cpu(VdiHeader *header)
213 9aebd98a Stefan Weil
{
214 9aebd98a Stefan Weil
    le32_to_cpus(&header->signature);
215 9aebd98a Stefan Weil
    le32_to_cpus(&header->version);
216 9aebd98a Stefan Weil
    le32_to_cpus(&header->header_size);
217 9aebd98a Stefan Weil
    le32_to_cpus(&header->image_type);
218 9aebd98a Stefan Weil
    le32_to_cpus(&header->image_flags);
219 9aebd98a Stefan Weil
    le32_to_cpus(&header->offset_bmap);
220 9aebd98a Stefan Weil
    le32_to_cpus(&header->offset_data);
221 9aebd98a Stefan Weil
    le32_to_cpus(&header->cylinders);
222 9aebd98a Stefan Weil
    le32_to_cpus(&header->heads);
223 9aebd98a Stefan Weil
    le32_to_cpus(&header->sectors);
224 9aebd98a Stefan Weil
    le32_to_cpus(&header->sector_size);
225 9aebd98a Stefan Weil
    le64_to_cpus(&header->disk_size);
226 9aebd98a Stefan Weil
    le32_to_cpus(&header->block_size);
227 9aebd98a Stefan Weil
    le32_to_cpus(&header->block_extra);
228 9aebd98a Stefan Weil
    le32_to_cpus(&header->blocks_in_image);
229 9aebd98a Stefan Weil
    le32_to_cpus(&header->blocks_allocated);
230 9aebd98a Stefan Weil
    uuid_convert(header->uuid_image);
231 9aebd98a Stefan Weil
    uuid_convert(header->uuid_last_snap);
232 9aebd98a Stefan Weil
    uuid_convert(header->uuid_link);
233 9aebd98a Stefan Weil
    uuid_convert(header->uuid_parent);
234 9aebd98a Stefan Weil
}
235 9aebd98a Stefan Weil
236 9aebd98a Stefan Weil
static void vdi_header_to_le(VdiHeader *header)
237 9aebd98a Stefan Weil
{
238 9aebd98a Stefan Weil
    cpu_to_le32s(&header->signature);
239 9aebd98a Stefan Weil
    cpu_to_le32s(&header->version);
240 9aebd98a Stefan Weil
    cpu_to_le32s(&header->header_size);
241 9aebd98a Stefan Weil
    cpu_to_le32s(&header->image_type);
242 9aebd98a Stefan Weil
    cpu_to_le32s(&header->image_flags);
243 9aebd98a Stefan Weil
    cpu_to_le32s(&header->offset_bmap);
244 9aebd98a Stefan Weil
    cpu_to_le32s(&header->offset_data);
245 9aebd98a Stefan Weil
    cpu_to_le32s(&header->cylinders);
246 9aebd98a Stefan Weil
    cpu_to_le32s(&header->heads);
247 9aebd98a Stefan Weil
    cpu_to_le32s(&header->sectors);
248 9aebd98a Stefan Weil
    cpu_to_le32s(&header->sector_size);
249 9aebd98a Stefan Weil
    cpu_to_le64s(&header->disk_size);
250 9aebd98a Stefan Weil
    cpu_to_le32s(&header->block_size);
251 9aebd98a Stefan Weil
    cpu_to_le32s(&header->block_extra);
252 9aebd98a Stefan Weil
    cpu_to_le32s(&header->blocks_in_image);
253 9aebd98a Stefan Weil
    cpu_to_le32s(&header->blocks_allocated);
254 9aebd98a Stefan Weil
    cpu_to_le32s(&header->blocks_allocated);
255 9aebd98a Stefan Weil
    uuid_convert(header->uuid_image);
256 9aebd98a Stefan Weil
    uuid_convert(header->uuid_last_snap);
257 9aebd98a Stefan Weil
    uuid_convert(header->uuid_link);
258 9aebd98a Stefan Weil
    uuid_convert(header->uuid_parent);
259 9aebd98a Stefan Weil
}
260 9aebd98a Stefan Weil
261 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
262 9aebd98a Stefan Weil
static void vdi_header_print(VdiHeader *header)
263 9aebd98a Stefan Weil
{
264 9aebd98a Stefan Weil
    char uuid[37];
265 9aebd98a Stefan Weil
    logout("text        %s", header->text);
266 9aebd98a Stefan Weil
    logout("signature   0x%04x\n", header->signature);
267 9aebd98a Stefan Weil
    logout("header size 0x%04x\n", header->header_size);
268 9aebd98a Stefan Weil
    logout("image type  0x%04x\n", header->image_type);
269 9aebd98a Stefan Weil
    logout("image flags 0x%04x\n", header->image_flags);
270 9aebd98a Stefan Weil
    logout("description %s\n", header->description);
271 9aebd98a Stefan Weil
    logout("offset bmap 0x%04x\n", header->offset_bmap);
272 9aebd98a Stefan Weil
    logout("offset data 0x%04x\n", header->offset_data);
273 9aebd98a Stefan Weil
    logout("cylinders   0x%04x\n", header->cylinders);
274 9aebd98a Stefan Weil
    logout("heads       0x%04x\n", header->heads);
275 9aebd98a Stefan Weil
    logout("sectors     0x%04x\n", header->sectors);
276 9aebd98a Stefan Weil
    logout("sector size 0x%04x\n", header->sector_size);
277 9aebd98a Stefan Weil
    logout("image size  0x%" PRIx64 " B (%" PRIu64 " MiB)\n",
278 9aebd98a Stefan Weil
           header->disk_size, header->disk_size / MiB);
279 9aebd98a Stefan Weil
    logout("block size  0x%04x\n", header->block_size);
280 9aebd98a Stefan Weil
    logout("block extra 0x%04x\n", header->block_extra);
281 9aebd98a Stefan Weil
    logout("blocks tot. 0x%04x\n", header->blocks_in_image);
282 9aebd98a Stefan Weil
    logout("blocks all. 0x%04x\n", header->blocks_allocated);
283 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_image, uuid);
284 9aebd98a Stefan Weil
    logout("uuid image  %s\n", uuid);
285 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_last_snap, uuid);
286 9aebd98a Stefan Weil
    logout("uuid snap   %s\n", uuid);
287 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_link, uuid);
288 9aebd98a Stefan Weil
    logout("uuid link   %s\n", uuid);
289 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_parent, uuid);
290 9aebd98a Stefan Weil
    logout("uuid parent %s\n", uuid);
291 9aebd98a Stefan Weil
}
292 9aebd98a Stefan Weil
#endif
293 9aebd98a Stefan Weil
294 9ac228e0 Kevin Wolf
static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
295 9aebd98a Stefan Weil
{
296 9aebd98a Stefan Weil
    /* TODO: additional checks possible. */
297 9aebd98a Stefan Weil
    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
298 9aebd98a Stefan Weil
    uint32_t blocks_allocated = 0;
299 9aebd98a Stefan Weil
    uint32_t block;
300 9aebd98a Stefan Weil
    uint32_t *bmap;
301 9aebd98a Stefan Weil
    logout("\n");
302 9aebd98a Stefan Weil
303 9aebd98a Stefan Weil
    bmap = qemu_malloc(s->header.blocks_in_image * sizeof(uint32_t));
304 9aebd98a Stefan Weil
    memset(bmap, 0xff, s->header.blocks_in_image * sizeof(uint32_t));
305 9aebd98a Stefan Weil
306 9aebd98a Stefan Weil
    /* Check block map and value of blocks_allocated. */
307 9aebd98a Stefan Weil
    for (block = 0; block < s->header.blocks_in_image; block++) {
308 9aebd98a Stefan Weil
        uint32_t bmap_entry = le32_to_cpu(s->bmap[block]);
309 9aebd98a Stefan Weil
        if (bmap_entry != VDI_UNALLOCATED) {
310 9aebd98a Stefan Weil
            if (bmap_entry < s->header.blocks_in_image) {
311 9aebd98a Stefan Weil
                blocks_allocated++;
312 9aebd98a Stefan Weil
                if (bmap[bmap_entry] == VDI_UNALLOCATED) {
313 9aebd98a Stefan Weil
                    bmap[bmap_entry] = bmap_entry;
314 9aebd98a Stefan Weil
                } else {
315 9aebd98a Stefan Weil
                    fprintf(stderr, "ERROR: block index %" PRIu32
316 9aebd98a Stefan Weil
                            " also used by %" PRIu32 "\n", bmap[bmap_entry], bmap_entry);
317 9ac228e0 Kevin Wolf
                    res->corruptions++;
318 9aebd98a Stefan Weil
                }
319 9aebd98a Stefan Weil
            } else {
320 9aebd98a Stefan Weil
                fprintf(stderr, "ERROR: block index %" PRIu32
321 9aebd98a Stefan Weil
                        " too large, is %" PRIu32 "\n", block, bmap_entry);
322 9ac228e0 Kevin Wolf
                res->corruptions++;
323 9aebd98a Stefan Weil
            }
324 9aebd98a Stefan Weil
        }
325 9aebd98a Stefan Weil
    }
326 9aebd98a Stefan Weil
    if (blocks_allocated != s->header.blocks_allocated) {
327 9aebd98a Stefan Weil
        fprintf(stderr, "ERROR: allocated blocks mismatch, is %" PRIu32
328 9aebd98a Stefan Weil
               ", should be %" PRIu32 "\n",
329 9aebd98a Stefan Weil
               blocks_allocated, s->header.blocks_allocated);
330 9ac228e0 Kevin Wolf
        res->corruptions++;
331 9aebd98a Stefan Weil
    }
332 9aebd98a Stefan Weil
333 9aebd98a Stefan Weil
    qemu_free(bmap);
334 9aebd98a Stefan Weil
335 9ac228e0 Kevin Wolf
    return 0;
336 9aebd98a Stefan Weil
}
337 9aebd98a Stefan Weil
338 9aebd98a Stefan Weil
static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
339 9aebd98a Stefan Weil
{
340 9aebd98a Stefan Weil
    /* TODO: vdi_get_info would be needed for machine snapshots.
341 9aebd98a Stefan Weil
       vm_state_offset is still missing. */
342 9aebd98a Stefan Weil
    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
343 9aebd98a Stefan Weil
    logout("\n");
344 9aebd98a Stefan Weil
    bdi->cluster_size = s->block_size;
345 9aebd98a Stefan Weil
    bdi->vm_state_offset = 0;
346 9aebd98a Stefan Weil
    return 0;
347 9aebd98a Stefan Weil
}
348 9aebd98a Stefan Weil
349 9aebd98a Stefan Weil
static int vdi_make_empty(BlockDriverState *bs)
350 9aebd98a Stefan Weil
{
351 9aebd98a Stefan Weil
    /* TODO: missing code. */
352 9aebd98a Stefan Weil
    logout("\n");
353 9aebd98a Stefan Weil
    /* The return value for missing code must be 0, see block.c. */
354 9aebd98a Stefan Weil
    return 0;
355 9aebd98a Stefan Weil
}
356 9aebd98a Stefan Weil
357 9aebd98a Stefan Weil
static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
358 9aebd98a Stefan Weil
{
359 9aebd98a Stefan Weil
    const VdiHeader *header = (const VdiHeader *)buf;
360 9aebd98a Stefan Weil
    int result = 0;
361 9aebd98a Stefan Weil
362 9aebd98a Stefan Weil
    logout("\n");
363 9aebd98a Stefan Weil
364 9aebd98a Stefan Weil
    if (buf_size < sizeof(*header)) {
365 9aebd98a Stefan Weil
        /* Header too small, no VDI. */
366 9aebd98a Stefan Weil
    } else if (le32_to_cpu(header->signature) == VDI_SIGNATURE) {
367 9aebd98a Stefan Weil
        result = 100;
368 9aebd98a Stefan Weil
    }
369 9aebd98a Stefan Weil
370 9aebd98a Stefan Weil
    if (result == 0) {
371 9aebd98a Stefan Weil
        logout("no vdi image\n");
372 9aebd98a Stefan Weil
    } else {
373 9aebd98a Stefan Weil
        logout("%s", header->text);
374 9aebd98a Stefan Weil
    }
375 9aebd98a Stefan Weil
376 9aebd98a Stefan Weil
    return result;
377 9aebd98a Stefan Weil
}
378 9aebd98a Stefan Weil
379 66f82cee Kevin Wolf
static int vdi_open(BlockDriverState *bs, int flags)
380 9aebd98a Stefan Weil
{
381 9aebd98a Stefan Weil
    BDRVVdiState *s = bs->opaque;
382 9aebd98a Stefan Weil
    VdiHeader header;
383 9aebd98a Stefan Weil
    size_t bmap_size;
384 9aebd98a Stefan Weil
385 9aebd98a Stefan Weil
    logout("\n");
386 9aebd98a Stefan Weil
387 66f82cee Kevin Wolf
    if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) {
388 9aebd98a Stefan Weil
        goto fail;
389 9aebd98a Stefan Weil
    }
390 9aebd98a Stefan Weil
391 9aebd98a Stefan Weil
    vdi_header_to_cpu(&header);
392 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
393 9aebd98a Stefan Weil
    vdi_header_print(&header);
394 9aebd98a Stefan Weil
#endif
395 9aebd98a Stefan Weil
396 f21dc3a4 Stefan Weil
    if (header.disk_size % SECTOR_SIZE != 0) {
397 f21dc3a4 Stefan Weil
        /* 'VBoxManage convertfromraw' can create images with odd disk sizes.
398 f21dc3a4 Stefan Weil
           We accept them but round the disk size to the next multiple of
399 f21dc3a4 Stefan Weil
           SECTOR_SIZE. */
400 f21dc3a4 Stefan Weil
        logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size);
401 f21dc3a4 Stefan Weil
        header.disk_size += SECTOR_SIZE - 1;
402 f21dc3a4 Stefan Weil
        header.disk_size &= ~(SECTOR_SIZE - 1);
403 f21dc3a4 Stefan Weil
    }
404 f21dc3a4 Stefan Weil
405 9aebd98a Stefan Weil
    if (header.version != VDI_VERSION_1_1) {
406 9aebd98a Stefan Weil
        logout("unsupported version %u.%u\n",
407 9aebd98a Stefan Weil
               header.version >> 16, header.version & 0xffff);
408 9aebd98a Stefan Weil
        goto fail;
409 9aebd98a Stefan Weil
    } else if (header.offset_bmap % SECTOR_SIZE != 0) {
410 9aebd98a Stefan Weil
        /* We only support block maps which start on a sector boundary. */
411 9aebd98a Stefan Weil
        logout("unsupported block map offset 0x%x B\n", header.offset_bmap);
412 9aebd98a Stefan Weil
        goto fail;
413 9aebd98a Stefan Weil
    } else if (header.offset_data % SECTOR_SIZE != 0) {
414 9aebd98a Stefan Weil
        /* We only support data blocks which start on a sector boundary. */
415 9aebd98a Stefan Weil
        logout("unsupported data offset 0x%x B\n", header.offset_data);
416 9aebd98a Stefan Weil
        goto fail;
417 9aebd98a Stefan Weil
    } else if (header.sector_size != SECTOR_SIZE) {
418 9aebd98a Stefan Weil
        logout("unsupported sector size %u B\n", header.sector_size);
419 9aebd98a Stefan Weil
        goto fail;
420 9aebd98a Stefan Weil
    } else if (header.block_size != 1 * MiB) {
421 9aebd98a Stefan Weil
        logout("unsupported block size %u B\n", header.block_size);
422 9aebd98a Stefan Weil
        goto fail;
423 f21dc3a4 Stefan Weil
    } else if (header.disk_size >
424 f21dc3a4 Stefan Weil
               (uint64_t)header.blocks_in_image * header.block_size) {
425 f21dc3a4 Stefan Weil
        logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
426 9aebd98a Stefan Weil
        goto fail;
427 9aebd98a Stefan Weil
    } else if (!uuid_is_null(header.uuid_link)) {
428 9aebd98a Stefan Weil
        logout("link uuid != 0, unsupported\n");
429 9aebd98a Stefan Weil
        goto fail;
430 9aebd98a Stefan Weil
    } else if (!uuid_is_null(header.uuid_parent)) {
431 9aebd98a Stefan Weil
        logout("parent uuid != 0, unsupported\n");
432 9aebd98a Stefan Weil
        goto fail;
433 9aebd98a Stefan Weil
    }
434 9aebd98a Stefan Weil
435 9aebd98a Stefan Weil
    bs->total_sectors = header.disk_size / SECTOR_SIZE;
436 9aebd98a Stefan Weil
437 9aebd98a Stefan Weil
    s->block_size = header.block_size;
438 9aebd98a Stefan Weil
    s->block_sectors = header.block_size / SECTOR_SIZE;
439 9aebd98a Stefan Weil
    s->bmap_sector = header.offset_bmap / SECTOR_SIZE;
440 9aebd98a Stefan Weil
    s->header = header;
441 9aebd98a Stefan Weil
442 9aebd98a Stefan Weil
    bmap_size = header.blocks_in_image * sizeof(uint32_t);
443 6eea90eb Stefan Weil
    bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
444 b76b6e95 Stefan Weil
    if (bmap_size > 0) {
445 b76b6e95 Stefan Weil
        s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
446 b76b6e95 Stefan Weil
    }
447 66f82cee Kevin Wolf
    if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
448 9aebd98a Stefan Weil
        goto fail_free_bmap;
449 9aebd98a Stefan Weil
    }
450 9aebd98a Stefan Weil
451 9aebd98a Stefan Weil
    return 0;
452 9aebd98a Stefan Weil
453 9aebd98a Stefan Weil
 fail_free_bmap:
454 9aebd98a Stefan Weil
    qemu_free(s->bmap);
455 9aebd98a Stefan Weil
456 9aebd98a Stefan Weil
 fail:
457 9aebd98a Stefan Weil
    return -1;
458 9aebd98a Stefan Weil
}
459 9aebd98a Stefan Weil
460 9aebd98a Stefan Weil
static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num,
461 9aebd98a Stefan Weil
                             int nb_sectors, int *pnum)
462 9aebd98a Stefan Weil
{
463 9aebd98a Stefan Weil
    /* TODO: Check for too large sector_num (in bdrv_is_allocated or here). */
464 9aebd98a Stefan Weil
    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
465 9aebd98a Stefan Weil
    size_t bmap_index = sector_num / s->block_sectors;
466 9aebd98a Stefan Weil
    size_t sector_in_block = sector_num % s->block_sectors;
467 9aebd98a Stefan Weil
    int n_sectors = s->block_sectors - sector_in_block;
468 9aebd98a Stefan Weil
    uint32_t bmap_entry = le32_to_cpu(s->bmap[bmap_index]);
469 9aebd98a Stefan Weil
    logout("%p, %" PRId64 ", %d, %p\n", bs, sector_num, nb_sectors, pnum);
470 9aebd98a Stefan Weil
    if (n_sectors > nb_sectors) {
471 9aebd98a Stefan Weil
        n_sectors = nb_sectors;
472 9aebd98a Stefan Weil
    }
473 9aebd98a Stefan Weil
    *pnum = n_sectors;
474 9aebd98a Stefan Weil
    return bmap_entry != VDI_UNALLOCATED;
475 9aebd98a Stefan Weil
}
476 9aebd98a Stefan Weil
477 9aebd98a Stefan Weil
static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
478 9aebd98a Stefan Weil
{
479 9aebd98a Stefan Weil
    /* TODO: This code is untested. How can I get it executed? */
480 b666d239 Kevin Wolf
    VdiAIOCB *acb = container_of(blockacb, VdiAIOCB, common);
481 9aebd98a Stefan Weil
    logout("\n");
482 9aebd98a Stefan Weil
    if (acb->hd_aiocb) {
483 9aebd98a Stefan Weil
        bdrv_aio_cancel(acb->hd_aiocb);
484 9aebd98a Stefan Weil
    }
485 9aebd98a Stefan Weil
    qemu_aio_release(acb);
486 9aebd98a Stefan Weil
}
487 9aebd98a Stefan Weil
488 9aebd98a Stefan Weil
static AIOPool vdi_aio_pool = {
489 9aebd98a Stefan Weil
    .aiocb_size = sizeof(VdiAIOCB),
490 9aebd98a Stefan Weil
    .cancel = vdi_aio_cancel,
491 9aebd98a Stefan Weil
};
492 9aebd98a Stefan Weil
493 9aebd98a Stefan Weil
static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
494 9aebd98a Stefan Weil
        QEMUIOVector *qiov, int nb_sectors,
495 9aebd98a Stefan Weil
        BlockDriverCompletionFunc *cb, void *opaque, int is_write)
496 9aebd98a Stefan Weil
{
497 9aebd98a Stefan Weil
    VdiAIOCB *acb;
498 9aebd98a Stefan Weil
499 9aebd98a Stefan Weil
    logout("%p, %" PRId64 ", %p, %d, %p, %p, %d\n",
500 9aebd98a Stefan Weil
           bs, sector_num, qiov, nb_sectors, cb, opaque, is_write);
501 9aebd98a Stefan Weil
502 9aebd98a Stefan Weil
    acb = qemu_aio_get(&vdi_aio_pool, bs, cb, opaque);
503 9aebd98a Stefan Weil
    if (acb) {
504 9aebd98a Stefan Weil
        acb->hd_aiocb = NULL;
505 9aebd98a Stefan Weil
        acb->sector_num = sector_num;
506 9aebd98a Stefan Weil
        acb->qiov = qiov;
507 9aebd98a Stefan Weil
        if (qiov->niov > 1) {
508 9aebd98a Stefan Weil
            acb->buf = qemu_blockalign(bs, qiov->size);
509 9aebd98a Stefan Weil
            acb->orig_buf = acb->buf;
510 9aebd98a Stefan Weil
            if (is_write) {
511 9aebd98a Stefan Weil
                qemu_iovec_to_buffer(qiov, acb->buf);
512 9aebd98a Stefan Weil
            }
513 9aebd98a Stefan Weil
        } else {
514 9aebd98a Stefan Weil
            acb->buf = (uint8_t *)qiov->iov->iov_base;
515 9aebd98a Stefan Weil
        }
516 9aebd98a Stefan Weil
        acb->nb_sectors = nb_sectors;
517 9aebd98a Stefan Weil
        acb->n_sectors = 0;
518 9aebd98a Stefan Weil
        acb->bmap_first = VDI_UNALLOCATED;
519 9aebd98a Stefan Weil
        acb->bmap_last = VDI_UNALLOCATED;
520 9aebd98a Stefan Weil
        acb->block_buffer = NULL;
521 9aebd98a Stefan Weil
        acb->header_modified = 0;
522 9aebd98a Stefan Weil
    }
523 9aebd98a Stefan Weil
    return acb;
524 9aebd98a Stefan Weil
}
525 9aebd98a Stefan Weil
526 9aebd98a Stefan Weil
static int vdi_schedule_bh(QEMUBHFunc *cb, VdiAIOCB *acb)
527 9aebd98a Stefan Weil
{
528 9aebd98a Stefan Weil
    logout("\n");
529 9aebd98a Stefan Weil
530 9aebd98a Stefan Weil
    if (acb->bh) {
531 9aebd98a Stefan Weil
        return -EIO;
532 9aebd98a Stefan Weil
    }
533 9aebd98a Stefan Weil
534 9aebd98a Stefan Weil
    acb->bh = qemu_bh_new(cb, acb);
535 9aebd98a Stefan Weil
    if (!acb->bh) {
536 9aebd98a Stefan Weil
        return -EIO;
537 9aebd98a Stefan Weil
    }
538 9aebd98a Stefan Weil
539 9aebd98a Stefan Weil
    qemu_bh_schedule(acb->bh);
540 9aebd98a Stefan Weil
541 9aebd98a Stefan Weil
    return 0;
542 9aebd98a Stefan Weil
}
543 9aebd98a Stefan Weil
544 9aebd98a Stefan Weil
static void vdi_aio_read_cb(void *opaque, int ret);
545 9aebd98a Stefan Weil
546 9aebd98a Stefan Weil
static void vdi_aio_read_bh(void *opaque)
547 9aebd98a Stefan Weil
{
548 9aebd98a Stefan Weil
    VdiAIOCB *acb = opaque;
549 9aebd98a Stefan Weil
    logout("\n");
550 9aebd98a Stefan Weil
    qemu_bh_delete(acb->bh);
551 9aebd98a Stefan Weil
    acb->bh = NULL;
552 9aebd98a Stefan Weil
    vdi_aio_read_cb(opaque, 0);
553 9aebd98a Stefan Weil
}
554 9aebd98a Stefan Weil
555 9aebd98a Stefan Weil
static void vdi_aio_read_cb(void *opaque, int ret)
556 9aebd98a Stefan Weil
{
557 9aebd98a Stefan Weil
    VdiAIOCB *acb = opaque;
558 9aebd98a Stefan Weil
    BlockDriverState *bs = acb->common.bs;
559 9aebd98a Stefan Weil
    BDRVVdiState *s = bs->opaque;
560 9aebd98a Stefan Weil
    uint32_t bmap_entry;
561 9aebd98a Stefan Weil
    uint32_t block_index;
562 9aebd98a Stefan Weil
    uint32_t sector_in_block;
563 9aebd98a Stefan Weil
    uint32_t n_sectors;
564 9aebd98a Stefan Weil
565 9aebd98a Stefan Weil
    logout("%u sectors read\n", acb->n_sectors);
566 9aebd98a Stefan Weil
567 9aebd98a Stefan Weil
    acb->hd_aiocb = NULL;
568 9aebd98a Stefan Weil
569 9aebd98a Stefan Weil
    if (ret < 0) {
570 9aebd98a Stefan Weil
        goto done;
571 9aebd98a Stefan Weil
    }
572 9aebd98a Stefan Weil
573 9aebd98a Stefan Weil
    acb->nb_sectors -= acb->n_sectors;
574 9aebd98a Stefan Weil
575 9aebd98a Stefan Weil
    if (acb->nb_sectors == 0) {
576 9aebd98a Stefan Weil
        /* request completed */
577 9aebd98a Stefan Weil
        ret = 0;
578 9aebd98a Stefan Weil
        goto done;
579 9aebd98a Stefan Weil
    }
580 9aebd98a Stefan Weil
581 9aebd98a Stefan Weil
    acb->sector_num += acb->n_sectors;
582 9aebd98a Stefan Weil
    acb->buf += acb->n_sectors * SECTOR_SIZE;
583 9aebd98a Stefan Weil
584 9aebd98a Stefan Weil
    block_index = acb->sector_num / s->block_sectors;
585 9aebd98a Stefan Weil
    sector_in_block = acb->sector_num % s->block_sectors;
586 9aebd98a Stefan Weil
    n_sectors = s->block_sectors - sector_in_block;
587 9aebd98a Stefan Weil
    if (n_sectors > acb->nb_sectors) {
588 9aebd98a Stefan Weil
        n_sectors = acb->nb_sectors;
589 9aebd98a Stefan Weil
    }
590 9aebd98a Stefan Weil
591 9aebd98a Stefan Weil
    logout("will read %u sectors starting at sector %" PRIu64 "\n",
592 9aebd98a Stefan Weil
           n_sectors, acb->sector_num);
593 9aebd98a Stefan Weil
594 9aebd98a Stefan Weil
    /* prepare next AIO request */
595 9aebd98a Stefan Weil
    acb->n_sectors = n_sectors;
596 9aebd98a Stefan Weil
    bmap_entry = le32_to_cpu(s->bmap[block_index]);
597 9aebd98a Stefan Weil
    if (bmap_entry == VDI_UNALLOCATED) {
598 9aebd98a Stefan Weil
        /* Block not allocated, return zeros, no need to wait. */
599 9aebd98a Stefan Weil
        memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
600 9aebd98a Stefan Weil
        ret = vdi_schedule_bh(vdi_aio_read_bh, acb);
601 9aebd98a Stefan Weil
        if (ret < 0) {
602 9aebd98a Stefan Weil
            goto done;
603 9aebd98a Stefan Weil
        }
604 9aebd98a Stefan Weil
    } else {
605 9aebd98a Stefan Weil
        uint64_t offset = s->header.offset_data / SECTOR_SIZE +
606 9aebd98a Stefan Weil
                          (uint64_t)bmap_entry * s->block_sectors +
607 9aebd98a Stefan Weil
                          sector_in_block;
608 9aebd98a Stefan Weil
        acb->hd_iov.iov_base = (void *)acb->buf;
609 9aebd98a Stefan Weil
        acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
610 9aebd98a Stefan Weil
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
611 66f82cee Kevin Wolf
        acb->hd_aiocb = bdrv_aio_readv(bs->file, offset, &acb->hd_qiov,
612 9aebd98a Stefan Weil
                                       n_sectors, vdi_aio_read_cb, acb);
613 9aebd98a Stefan Weil
        if (acb->hd_aiocb == NULL) {
614 40a892b7 Stefan Weil
            ret = -EIO;
615 9aebd98a Stefan Weil
            goto done;
616 9aebd98a Stefan Weil
        }
617 9aebd98a Stefan Weil
    }
618 9aebd98a Stefan Weil
    return;
619 9aebd98a Stefan Weil
done:
620 9aebd98a Stefan Weil
    if (acb->qiov->niov > 1) {
621 9aebd98a Stefan Weil
        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
622 9aebd98a Stefan Weil
        qemu_vfree(acb->orig_buf);
623 9aebd98a Stefan Weil
    }
624 9aebd98a Stefan Weil
    acb->common.cb(acb->common.opaque, ret);
625 9aebd98a Stefan Weil
    qemu_aio_release(acb);
626 9aebd98a Stefan Weil
}
627 9aebd98a Stefan Weil
628 9aebd98a Stefan Weil
static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
629 9aebd98a Stefan Weil
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
630 9aebd98a Stefan Weil
        BlockDriverCompletionFunc *cb, void *opaque)
631 9aebd98a Stefan Weil
{
632 9aebd98a Stefan Weil
    VdiAIOCB *acb;
633 9aebd98a Stefan Weil
    logout("\n");
634 9aebd98a Stefan Weil
    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
635 9aebd98a Stefan Weil
    if (!acb) {
636 9aebd98a Stefan Weil
        return NULL;
637 9aebd98a Stefan Weil
    }
638 9aebd98a Stefan Weil
    vdi_aio_read_cb(acb, 0);
639 9aebd98a Stefan Weil
    return &acb->common;
640 9aebd98a Stefan Weil
}
641 9aebd98a Stefan Weil
642 9aebd98a Stefan Weil
static void vdi_aio_write_cb(void *opaque, int ret)
643 9aebd98a Stefan Weil
{
644 9aebd98a Stefan Weil
    VdiAIOCB *acb = opaque;
645 9aebd98a Stefan Weil
    BlockDriverState *bs = acb->common.bs;
646 9aebd98a Stefan Weil
    BDRVVdiState *s = bs->opaque;
647 9aebd98a Stefan Weil
    uint32_t bmap_entry;
648 9aebd98a Stefan Weil
    uint32_t block_index;
649 9aebd98a Stefan Weil
    uint32_t sector_in_block;
650 9aebd98a Stefan Weil
    uint32_t n_sectors;
651 9aebd98a Stefan Weil
652 9aebd98a Stefan Weil
    acb->hd_aiocb = NULL;
653 9aebd98a Stefan Weil
654 9aebd98a Stefan Weil
    if (ret < 0) {
655 9aebd98a Stefan Weil
        goto done;
656 9aebd98a Stefan Weil
    }
657 9aebd98a Stefan Weil
658 9aebd98a Stefan Weil
    acb->nb_sectors -= acb->n_sectors;
659 9aebd98a Stefan Weil
    acb->sector_num += acb->n_sectors;
660 9aebd98a Stefan Weil
    acb->buf += acb->n_sectors * SECTOR_SIZE;
661 9aebd98a Stefan Weil
662 9aebd98a Stefan Weil
    if (acb->nb_sectors == 0) {
663 9aebd98a Stefan Weil
        logout("finished data write\n");
664 9aebd98a Stefan Weil
        acb->n_sectors = 0;
665 9aebd98a Stefan Weil
        if (acb->header_modified) {
666 9aebd98a Stefan Weil
            VdiHeader *header = acb->block_buffer;
667 9aebd98a Stefan Weil
            logout("now writing modified header\n");
668 9aebd98a Stefan Weil
            assert(acb->bmap_first != VDI_UNALLOCATED);
669 9aebd98a Stefan Weil
            *header = s->header;
670 9aebd98a Stefan Weil
            vdi_header_to_le(header);
671 9aebd98a Stefan Weil
            acb->header_modified = 0;
672 9aebd98a Stefan Weil
            acb->hd_iov.iov_base = acb->block_buffer;
673 9aebd98a Stefan Weil
            acb->hd_iov.iov_len = SECTOR_SIZE;
674 9aebd98a Stefan Weil
            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
675 66f82cee Kevin Wolf
            acb->hd_aiocb = bdrv_aio_writev(bs->file, 0, &acb->hd_qiov, 1,
676 9aebd98a Stefan Weil
                                            vdi_aio_write_cb, acb);
677 9aebd98a Stefan Weil
            if (acb->hd_aiocb == NULL) {
678 40a892b7 Stefan Weil
                ret = -EIO;
679 9aebd98a Stefan Weil
                goto done;
680 9aebd98a Stefan Weil
            }
681 9aebd98a Stefan Weil
            return;
682 9aebd98a Stefan Weil
        } else if (acb->bmap_first != VDI_UNALLOCATED) {
683 9aebd98a Stefan Weil
            /* One or more new blocks were allocated. */
684 9aebd98a Stefan Weil
            uint64_t offset;
685 9aebd98a Stefan Weil
            uint32_t bmap_first;
686 9aebd98a Stefan Weil
            uint32_t bmap_last;
687 9aebd98a Stefan Weil
            qemu_free(acb->block_buffer);
688 9aebd98a Stefan Weil
            acb->block_buffer = NULL;
689 9aebd98a Stefan Weil
            bmap_first = acb->bmap_first;
690 9aebd98a Stefan Weil
            bmap_last = acb->bmap_last;
691 9aebd98a Stefan Weil
            logout("now writing modified block map entry %u...%u\n",
692 9aebd98a Stefan Weil
                   bmap_first, bmap_last);
693 9aebd98a Stefan Weil
            /* Write modified sectors from block map. */
694 9aebd98a Stefan Weil
            bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
695 9aebd98a Stefan Weil
            bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
696 9aebd98a Stefan Weil
            n_sectors = bmap_last - bmap_first + 1;
697 9aebd98a Stefan Weil
            offset = s->bmap_sector + bmap_first;
698 9aebd98a Stefan Weil
            acb->bmap_first = VDI_UNALLOCATED;
699 a2a45a26 Blue Swirl
            acb->hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
700 a2a45a26 Blue Swirl
                                            bmap_first * SECTOR_SIZE);
701 9aebd98a Stefan Weil
            acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
702 9aebd98a Stefan Weil
            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
703 9aebd98a Stefan Weil
            logout("will write %u block map sectors starting from entry %u\n",
704 9aebd98a Stefan Weil
                   n_sectors, bmap_first);
705 66f82cee Kevin Wolf
            acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
706 9aebd98a Stefan Weil
                                            n_sectors, vdi_aio_write_cb, acb);
707 9aebd98a Stefan Weil
            if (acb->hd_aiocb == NULL) {
708 40a892b7 Stefan Weil
                ret = -EIO;
709 9aebd98a Stefan Weil
                goto done;
710 9aebd98a Stefan Weil
            }
711 9aebd98a Stefan Weil
            return;
712 9aebd98a Stefan Weil
        }
713 9aebd98a Stefan Weil
        ret = 0;
714 9aebd98a Stefan Weil
        goto done;
715 9aebd98a Stefan Weil
    }
716 9aebd98a Stefan Weil
717 9aebd98a Stefan Weil
    logout("%u sectors written\n", acb->n_sectors);
718 9aebd98a Stefan Weil
719 9aebd98a Stefan Weil
    block_index = acb->sector_num / s->block_sectors;
720 9aebd98a Stefan Weil
    sector_in_block = acb->sector_num % s->block_sectors;
721 9aebd98a Stefan Weil
    n_sectors = s->block_sectors - sector_in_block;
722 9aebd98a Stefan Weil
    if (n_sectors > acb->nb_sectors) {
723 9aebd98a Stefan Weil
        n_sectors = acb->nb_sectors;
724 9aebd98a Stefan Weil
    }
725 9aebd98a Stefan Weil
726 9aebd98a Stefan Weil
    logout("will write %u sectors starting at sector %" PRIu64 "\n",
727 9aebd98a Stefan Weil
           n_sectors, acb->sector_num);
728 9aebd98a Stefan Weil
729 9aebd98a Stefan Weil
    /* prepare next AIO request */
730 9aebd98a Stefan Weil
    acb->n_sectors = n_sectors;
731 9aebd98a Stefan Weil
    bmap_entry = le32_to_cpu(s->bmap[block_index]);
732 9aebd98a Stefan Weil
    if (bmap_entry == VDI_UNALLOCATED) {
733 9aebd98a Stefan Weil
        /* Allocate new block and write to it. */
734 9aebd98a Stefan Weil
        uint64_t offset;
735 9aebd98a Stefan Weil
        uint8_t *block;
736 9aebd98a Stefan Weil
        bmap_entry = s->header.blocks_allocated;
737 9aebd98a Stefan Weil
        s->bmap[block_index] = cpu_to_le32(bmap_entry);
738 9aebd98a Stefan Weil
        s->header.blocks_allocated++;
739 9aebd98a Stefan Weil
        offset = s->header.offset_data / SECTOR_SIZE +
740 9aebd98a Stefan Weil
                 (uint64_t)bmap_entry * s->block_sectors;
741 9aebd98a Stefan Weil
        block = acb->block_buffer;
742 9aebd98a Stefan Weil
        if (block == NULL) {
743 9aebd98a Stefan Weil
            block = qemu_mallocz(s->block_size);
744 9aebd98a Stefan Weil
            acb->block_buffer = block;
745 9aebd98a Stefan Weil
            acb->bmap_first = block_index;
746 9aebd98a Stefan Weil
            assert(!acb->header_modified);
747 9aebd98a Stefan Weil
            acb->header_modified = 1;
748 9aebd98a Stefan Weil
        }
749 9aebd98a Stefan Weil
        acb->bmap_last = block_index;
750 9aebd98a Stefan Weil
        memcpy(block + sector_in_block * SECTOR_SIZE,
751 9aebd98a Stefan Weil
               acb->buf, n_sectors * SECTOR_SIZE);
752 a2a45a26 Blue Swirl
        acb->hd_iov.iov_base = (void *)block;
753 9aebd98a Stefan Weil
        acb->hd_iov.iov_len = s->block_size;
754 9aebd98a Stefan Weil
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
755 66f82cee Kevin Wolf
        acb->hd_aiocb = bdrv_aio_writev(bs->file, offset,
756 9aebd98a Stefan Weil
                                        &acb->hd_qiov, s->block_sectors,
757 9aebd98a Stefan Weil
                                        vdi_aio_write_cb, acb);
758 9aebd98a Stefan Weil
        if (acb->hd_aiocb == NULL) {
759 40a892b7 Stefan Weil
            ret = -EIO;
760 9aebd98a Stefan Weil
            goto done;
761 9aebd98a Stefan Weil
        }
762 9aebd98a Stefan Weil
    } else {
763 9aebd98a Stefan Weil
        uint64_t offset = s->header.offset_data / SECTOR_SIZE +
764 9aebd98a Stefan Weil
                          (uint64_t)bmap_entry * s->block_sectors +
765 9aebd98a Stefan Weil
                          sector_in_block;
766 a2a45a26 Blue Swirl
        acb->hd_iov.iov_base = (void *)acb->buf;
767 9aebd98a Stefan Weil
        acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
768 9aebd98a Stefan Weil
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
769 66f82cee Kevin Wolf
        acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
770 9aebd98a Stefan Weil
                                        n_sectors, vdi_aio_write_cb, acb);
771 9aebd98a Stefan Weil
        if (acb->hd_aiocb == NULL) {
772 40a892b7 Stefan Weil
            ret = -EIO;
773 9aebd98a Stefan Weil
            goto done;
774 9aebd98a Stefan Weil
        }
775 9aebd98a Stefan Weil
    }
776 9aebd98a Stefan Weil
777 9aebd98a Stefan Weil
    return;
778 9aebd98a Stefan Weil
779 9aebd98a Stefan Weil
done:
780 9aebd98a Stefan Weil
    if (acb->qiov->niov > 1) {
781 9aebd98a Stefan Weil
        qemu_vfree(acb->orig_buf);
782 9aebd98a Stefan Weil
    }
783 9aebd98a Stefan Weil
    acb->common.cb(acb->common.opaque, ret);
784 9aebd98a Stefan Weil
    qemu_aio_release(acb);
785 9aebd98a Stefan Weil
}
786 9aebd98a Stefan Weil
787 9aebd98a Stefan Weil
static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
788 9aebd98a Stefan Weil
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
789 9aebd98a Stefan Weil
        BlockDriverCompletionFunc *cb, void *opaque)
790 9aebd98a Stefan Weil
{
791 9aebd98a Stefan Weil
    VdiAIOCB *acb;
792 9aebd98a Stefan Weil
    logout("\n");
793 9aebd98a Stefan Weil
    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
794 9aebd98a Stefan Weil
    if (!acb) {
795 9aebd98a Stefan Weil
        return NULL;
796 9aebd98a Stefan Weil
    }
797 9aebd98a Stefan Weil
    vdi_aio_write_cb(acb, 0);
798 9aebd98a Stefan Weil
    return &acb->common;
799 9aebd98a Stefan Weil
}
800 9aebd98a Stefan Weil
801 9aebd98a Stefan Weil
static int vdi_create(const char *filename, QEMUOptionParameter *options)
802 9aebd98a Stefan Weil
{
803 9aebd98a Stefan Weil
    int fd;
804 9aebd98a Stefan Weil
    int result = 0;
805 9aebd98a Stefan Weil
    uint64_t bytes = 0;
806 9aebd98a Stefan Weil
    uint32_t blocks;
807 99cce9fa Kevin Wolf
    size_t block_size = DEFAULT_CLUSTER_SIZE;
808 9aebd98a Stefan Weil
    uint32_t image_type = VDI_TYPE_DYNAMIC;
809 9aebd98a Stefan Weil
    VdiHeader header;
810 9aebd98a Stefan Weil
    size_t i;
811 9aebd98a Stefan Weil
    size_t bmap_size;
812 9aebd98a Stefan Weil
    uint32_t *bmap;
813 9aebd98a Stefan Weil
814 9aebd98a Stefan Weil
    logout("\n");
815 9aebd98a Stefan Weil
816 9aebd98a Stefan Weil
    /* Read out options. */
817 9aebd98a Stefan Weil
    while (options && options->name) {
818 9aebd98a Stefan Weil
        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
819 9aebd98a Stefan Weil
            bytes = options->value.n;
820 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_BLOCK_SIZE)
821 9aebd98a Stefan Weil
        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
822 9aebd98a Stefan Weil
            if (options->value.n) {
823 9aebd98a Stefan Weil
                /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
824 9aebd98a Stefan Weil
                block_size = options->value.n;
825 9aebd98a Stefan Weil
            }
826 9aebd98a Stefan Weil
#endif
827 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_STATIC_IMAGE)
828 9aebd98a Stefan Weil
        } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
829 6eea90eb Stefan Weil
            if (options->value.n) {
830 6eea90eb Stefan Weil
                image_type = VDI_TYPE_STATIC;
831 6eea90eb Stefan Weil
            }
832 9aebd98a Stefan Weil
#endif
833 9aebd98a Stefan Weil
        }
834 9aebd98a Stefan Weil
        options++;
835 9aebd98a Stefan Weil
    }
836 9aebd98a Stefan Weil
837 9aebd98a Stefan Weil
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
838 9aebd98a Stefan Weil
              0644);
839 9aebd98a Stefan Weil
    if (fd < 0) {
840 9aebd98a Stefan Weil
        return -errno;
841 9aebd98a Stefan Weil
    }
842 9aebd98a Stefan Weil
843 f21dc3a4 Stefan Weil
    /* We need enough blocks to store the given disk size,
844 f21dc3a4 Stefan Weil
       so always round up. */
845 f21dc3a4 Stefan Weil
    blocks = (bytes + block_size - 1) / block_size;
846 f21dc3a4 Stefan Weil
847 9aebd98a Stefan Weil
    bmap_size = blocks * sizeof(uint32_t);
848 9aebd98a Stefan Weil
    bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
849 9aebd98a Stefan Weil
850 9aebd98a Stefan Weil
    memset(&header, 0, sizeof(header));
851 1786dc15 Blue Swirl
    pstrcpy(header.text, sizeof(header.text), VDI_TEXT);
852 9aebd98a Stefan Weil
    header.signature = VDI_SIGNATURE;
853 9aebd98a Stefan Weil
    header.version = VDI_VERSION_1_1;
854 9aebd98a Stefan Weil
    header.header_size = 0x180;
855 9aebd98a Stefan Weil
    header.image_type = image_type;
856 9aebd98a Stefan Weil
    header.offset_bmap = 0x200;
857 9aebd98a Stefan Weil
    header.offset_data = 0x200 + bmap_size;
858 9aebd98a Stefan Weil
    header.sector_size = SECTOR_SIZE;
859 9aebd98a Stefan Weil
    header.disk_size = bytes;
860 9aebd98a Stefan Weil
    header.block_size = block_size;
861 9aebd98a Stefan Weil
    header.blocks_in_image = blocks;
862 6eea90eb Stefan Weil
    if (image_type == VDI_TYPE_STATIC) {
863 6eea90eb Stefan Weil
        header.blocks_allocated = blocks;
864 6eea90eb Stefan Weil
    }
865 9aebd98a Stefan Weil
    uuid_generate(header.uuid_image);
866 9aebd98a Stefan Weil
    uuid_generate(header.uuid_last_snap);
867 9aebd98a Stefan Weil
    /* There is no need to set header.uuid_link or header.uuid_parent here. */
868 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
869 9aebd98a Stefan Weil
    vdi_header_print(&header);
870 9aebd98a Stefan Weil
#endif
871 9aebd98a Stefan Weil
    vdi_header_to_le(&header);
872 9aebd98a Stefan Weil
    if (write(fd, &header, sizeof(header)) < 0) {
873 9aebd98a Stefan Weil
        result = -errno;
874 9aebd98a Stefan Weil
    }
875 9aebd98a Stefan Weil
876 b76b6e95 Stefan Weil
    bmap = NULL;
877 b76b6e95 Stefan Weil
    if (bmap_size > 0) {
878 b76b6e95 Stefan Weil
        bmap = (uint32_t *)qemu_mallocz(bmap_size);
879 b76b6e95 Stefan Weil
    }
880 9aebd98a Stefan Weil
    for (i = 0; i < blocks; i++) {
881 9aebd98a Stefan Weil
        if (image_type == VDI_TYPE_STATIC) {
882 9aebd98a Stefan Weil
            bmap[i] = i;
883 9aebd98a Stefan Weil
        } else {
884 9aebd98a Stefan Weil
            bmap[i] = VDI_UNALLOCATED;
885 9aebd98a Stefan Weil
        }
886 9aebd98a Stefan Weil
    }
887 9aebd98a Stefan Weil
    if (write(fd, bmap, bmap_size) < 0) {
888 9aebd98a Stefan Weil
        result = -errno;
889 9aebd98a Stefan Weil
    }
890 9aebd98a Stefan Weil
    qemu_free(bmap);
891 9aebd98a Stefan Weil
    if (image_type == VDI_TYPE_STATIC) {
892 9aebd98a Stefan Weil
        if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
893 9aebd98a Stefan Weil
            result = -errno;
894 9aebd98a Stefan Weil
        }
895 9aebd98a Stefan Weil
    }
896 9aebd98a Stefan Weil
897 9aebd98a Stefan Weil
    if (close(fd) < 0) {
898 9aebd98a Stefan Weil
        result = -errno;
899 9aebd98a Stefan Weil
    }
900 9aebd98a Stefan Weil
901 9aebd98a Stefan Weil
    return result;
902 9aebd98a Stefan Weil
}
903 9aebd98a Stefan Weil
904 9aebd98a Stefan Weil
static void vdi_close(BlockDriverState *bs)
905 9aebd98a Stefan Weil
{
906 9aebd98a Stefan Weil
}
907 9aebd98a Stefan Weil
908 205ef796 Kevin Wolf
static int vdi_flush(BlockDriverState *bs)
909 9aebd98a Stefan Weil
{
910 9aebd98a Stefan Weil
    logout("\n");
911 205ef796 Kevin Wolf
    return bdrv_flush(bs->file);
912 9aebd98a Stefan Weil
}
913 9aebd98a Stefan Weil
914 9aebd98a Stefan Weil
915 9aebd98a Stefan Weil
static QEMUOptionParameter vdi_create_options[] = {
916 9aebd98a Stefan Weil
    {
917 9aebd98a Stefan Weil
        .name = BLOCK_OPT_SIZE,
918 9aebd98a Stefan Weil
        .type = OPT_SIZE,
919 9aebd98a Stefan Weil
        .help = "Virtual disk size"
920 9aebd98a Stefan Weil
    },
921 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_BLOCK_SIZE)
922 9aebd98a Stefan Weil
    {
923 9aebd98a Stefan Weil
        .name = BLOCK_OPT_CLUSTER_SIZE,
924 9aebd98a Stefan Weil
        .type = OPT_SIZE,
925 99cce9fa Kevin Wolf
        .help = "VDI cluster (block) size",
926 99cce9fa Kevin Wolf
        .value = { .n = DEFAULT_CLUSTER_SIZE },
927 9aebd98a Stefan Weil
    },
928 9aebd98a Stefan Weil
#endif
929 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_STATIC_IMAGE)
930 9aebd98a Stefan Weil
    {
931 9aebd98a Stefan Weil
        .name = BLOCK_OPT_STATIC,
932 9aebd98a Stefan Weil
        .type = OPT_FLAG,
933 9aebd98a Stefan Weil
        .help = "VDI static (pre-allocated) image"
934 9aebd98a Stefan Weil
    },
935 9aebd98a Stefan Weil
#endif
936 9aebd98a Stefan Weil
    /* TODO: An additional option to set UUID values might be useful. */
937 9aebd98a Stefan Weil
    { NULL }
938 9aebd98a Stefan Weil
};
939 9aebd98a Stefan Weil
940 9aebd98a Stefan Weil
static BlockDriver bdrv_vdi = {
941 9aebd98a Stefan Weil
    .format_name = "vdi",
942 9aebd98a Stefan Weil
    .instance_size = sizeof(BDRVVdiState),
943 9aebd98a Stefan Weil
    .bdrv_probe = vdi_probe,
944 9aebd98a Stefan Weil
    .bdrv_open = vdi_open,
945 9aebd98a Stefan Weil
    .bdrv_close = vdi_close,
946 9aebd98a Stefan Weil
    .bdrv_create = vdi_create,
947 9aebd98a Stefan Weil
    .bdrv_flush = vdi_flush,
948 9aebd98a Stefan Weil
    .bdrv_is_allocated = vdi_is_allocated,
949 9aebd98a Stefan Weil
    .bdrv_make_empty = vdi_make_empty,
950 9aebd98a Stefan Weil
951 9aebd98a Stefan Weil
    .bdrv_aio_readv = vdi_aio_readv,
952 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_WRITE)
953 9aebd98a Stefan Weil
    .bdrv_aio_writev = vdi_aio_writev,
954 9aebd98a Stefan Weil
#endif
955 9aebd98a Stefan Weil
956 9aebd98a Stefan Weil
    .bdrv_get_info = vdi_get_info,
957 9aebd98a Stefan Weil
958 9aebd98a Stefan Weil
    .create_options = vdi_create_options,
959 9aebd98a Stefan Weil
    .bdrv_check = vdi_check,
960 9aebd98a Stefan Weil
};
961 9aebd98a Stefan Weil
962 9aebd98a Stefan Weil
static void bdrv_vdi_init(void)
963 9aebd98a Stefan Weil
{
964 9aebd98a Stefan Weil
    logout("\n");
965 9aebd98a Stefan Weil
    bdrv_register(&bdrv_vdi);
966 9aebd98a Stefan Weil
}
967 9aebd98a Stefan Weil
968 9aebd98a Stefan Weil
block_init(bdrv_vdi_init);