Statistics
| Branch: | Revision:

root / block / vdi.c @ e685b4eb

History | View | Annotate | Download (29.2 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 9aebd98a Stefan Weil
91 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
92 9aebd98a Stefan Weil
#define logout(fmt, ...) \
93 9aebd98a Stefan Weil
                fprintf(stderr, "vdi\t%-24s" fmt, __func__, ##__VA_ARGS__)
94 9aebd98a Stefan Weil
#else
95 9aebd98a Stefan Weil
#define logout(fmt, ...) ((void)0)
96 9aebd98a Stefan Weil
#endif
97 9aebd98a Stefan Weil
98 9aebd98a Stefan Weil
/* Image signature. */
99 9aebd98a Stefan Weil
#define VDI_SIGNATURE 0xbeda107f
100 9aebd98a Stefan Weil
101 9aebd98a Stefan Weil
/* Image version. */
102 9aebd98a Stefan Weil
#define VDI_VERSION_1_1 0x00010001
103 9aebd98a Stefan Weil
104 9aebd98a Stefan Weil
/* Image type. */
105 9aebd98a Stefan Weil
#define VDI_TYPE_DYNAMIC 1
106 9aebd98a Stefan Weil
#define VDI_TYPE_STATIC  2
107 9aebd98a Stefan Weil
108 9aebd98a Stefan Weil
/* Innotek / SUN images use these strings in header.text:
109 9aebd98a Stefan Weil
 * "<<< innotek VirtualBox Disk Image >>>\n"
110 9aebd98a Stefan Weil
 * "<<< Sun xVM VirtualBox Disk Image >>>\n"
111 9aebd98a Stefan Weil
 * "<<< Sun VirtualBox Disk Image >>>\n"
112 9aebd98a Stefan Weil
 * The value does not matter, so QEMU created images use a different text.
113 9aebd98a Stefan Weil
 */
114 9aebd98a Stefan Weil
#define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
115 9aebd98a Stefan Weil
116 9aebd98a Stefan Weil
/* Unallocated blocks use this index (no need to convert endianess). */
117 9aebd98a Stefan Weil
#define VDI_UNALLOCATED UINT32_MAX
118 9aebd98a Stefan Weil
119 ee682d27 Stefan Weil
#if !defined(CONFIG_UUID)
120 9aebd98a Stefan Weil
void uuid_generate(uuid_t out)
121 9aebd98a Stefan Weil
{
122 9aebd98a Stefan Weil
    memset(out, 0, sizeof(out));
123 9aebd98a Stefan Weil
}
124 9aebd98a Stefan Weil
125 9aebd98a Stefan Weil
int uuid_is_null(const uuid_t uu)
126 9aebd98a Stefan Weil
{
127 9aebd98a Stefan Weil
    uuid_t null_uuid = { 0 };
128 9aebd98a Stefan Weil
    return memcmp(uu, null_uuid, sizeof(uu)) == 0;
129 9aebd98a Stefan Weil
}
130 9aebd98a Stefan Weil
131 9aebd98a Stefan Weil
void uuid_unparse(const uuid_t uu, char *out)
132 9aebd98a Stefan Weil
{
133 9aebd98a Stefan Weil
    snprintf(out, 37, UUID_FMT,
134 9aebd98a Stefan Weil
            uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7],
135 9aebd98a Stefan Weil
            uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
136 9aebd98a Stefan Weil
}
137 9aebd98a Stefan Weil
#endif
138 9aebd98a Stefan Weil
139 9aebd98a Stefan Weil
typedef struct {
140 9aebd98a Stefan Weil
    BlockDriverAIOCB common;
141 9aebd98a Stefan Weil
    int64_t sector_num;
142 9aebd98a Stefan Weil
    QEMUIOVector *qiov;
143 9aebd98a Stefan Weil
    uint8_t *buf;
144 9aebd98a Stefan Weil
    /* Total number of sectors. */
145 9aebd98a Stefan Weil
    int nb_sectors;
146 9aebd98a Stefan Weil
    /* Number of sectors for current AIO. */
147 9aebd98a Stefan Weil
    int n_sectors;
148 9aebd98a Stefan Weil
    /* New allocated block map entry. */
149 9aebd98a Stefan Weil
    uint32_t bmap_first;
150 9aebd98a Stefan Weil
    uint32_t bmap_last;
151 9aebd98a Stefan Weil
    /* Buffer for new allocated block. */
152 9aebd98a Stefan Weil
    void *block_buffer;
153 9aebd98a Stefan Weil
    void *orig_buf;
154 9aebd98a Stefan Weil
    int header_modified;
155 9aebd98a Stefan Weil
    BlockDriverAIOCB *hd_aiocb;
156 9aebd98a Stefan Weil
    struct iovec hd_iov;
157 9aebd98a Stefan Weil
    QEMUIOVector hd_qiov;
158 9aebd98a Stefan Weil
    QEMUBH *bh;
159 9aebd98a Stefan Weil
} VdiAIOCB;
160 9aebd98a Stefan Weil
161 9aebd98a Stefan Weil
typedef struct {
162 9aebd98a Stefan Weil
    char text[0x40];
163 9aebd98a Stefan Weil
    uint32_t signature;
164 9aebd98a Stefan Weil
    uint32_t version;
165 9aebd98a Stefan Weil
    uint32_t header_size;
166 9aebd98a Stefan Weil
    uint32_t image_type;
167 9aebd98a Stefan Weil
    uint32_t image_flags;
168 9aebd98a Stefan Weil
    char description[256];
169 9aebd98a Stefan Weil
    uint32_t offset_bmap;
170 9aebd98a Stefan Weil
    uint32_t offset_data;
171 9aebd98a Stefan Weil
    uint32_t cylinders;         /* disk geometry, unused here */
172 9aebd98a Stefan Weil
    uint32_t heads;             /* disk geometry, unused here */
173 9aebd98a Stefan Weil
    uint32_t sectors;           /* disk geometry, unused here */
174 9aebd98a Stefan Weil
    uint32_t sector_size;
175 9aebd98a Stefan Weil
    uint32_t unused1;
176 9aebd98a Stefan Weil
    uint64_t disk_size;
177 9aebd98a Stefan Weil
    uint32_t block_size;
178 9aebd98a Stefan Weil
    uint32_t block_extra;       /* unused here */
179 9aebd98a Stefan Weil
    uint32_t blocks_in_image;
180 9aebd98a Stefan Weil
    uint32_t blocks_allocated;
181 9aebd98a Stefan Weil
    uuid_t uuid_image;
182 9aebd98a Stefan Weil
    uuid_t uuid_last_snap;
183 9aebd98a Stefan Weil
    uuid_t uuid_link;
184 9aebd98a Stefan Weil
    uuid_t uuid_parent;
185 9aebd98a Stefan Weil
    uint64_t unused2[7];
186 9aebd98a Stefan Weil
} VdiHeader;
187 9aebd98a Stefan Weil
188 9aebd98a Stefan Weil
typedef struct {
189 9aebd98a Stefan Weil
    BlockDriverState *hd;
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 9aebd98a Stefan Weil
    /* VDI header (converted to host endianess). */
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 9aebd98a Stefan Weil
            goto done;
615 9aebd98a Stefan Weil
        }
616 9aebd98a Stefan Weil
    }
617 9aebd98a Stefan Weil
    return;
618 9aebd98a Stefan Weil
done:
619 9aebd98a Stefan Weil
    if (acb->qiov->niov > 1) {
620 9aebd98a Stefan Weil
        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
621 9aebd98a Stefan Weil
        qemu_vfree(acb->orig_buf);
622 9aebd98a Stefan Weil
    }
623 9aebd98a Stefan Weil
    acb->common.cb(acb->common.opaque, ret);
624 9aebd98a Stefan Weil
    qemu_aio_release(acb);
625 9aebd98a Stefan Weil
}
626 9aebd98a Stefan Weil
627 9aebd98a Stefan Weil
static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
628 9aebd98a Stefan Weil
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
629 9aebd98a Stefan Weil
        BlockDriverCompletionFunc *cb, void *opaque)
630 9aebd98a Stefan Weil
{
631 9aebd98a Stefan Weil
    VdiAIOCB *acb;
632 9aebd98a Stefan Weil
    logout("\n");
633 9aebd98a Stefan Weil
    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
634 9aebd98a Stefan Weil
    if (!acb) {
635 9aebd98a Stefan Weil
        return NULL;
636 9aebd98a Stefan Weil
    }
637 9aebd98a Stefan Weil
    vdi_aio_read_cb(acb, 0);
638 9aebd98a Stefan Weil
    return &acb->common;
639 9aebd98a Stefan Weil
}
640 9aebd98a Stefan Weil
641 9aebd98a Stefan Weil
static void vdi_aio_write_cb(void *opaque, int ret)
642 9aebd98a Stefan Weil
{
643 9aebd98a Stefan Weil
    VdiAIOCB *acb = opaque;
644 9aebd98a Stefan Weil
    BlockDriverState *bs = acb->common.bs;
645 9aebd98a Stefan Weil
    BDRVVdiState *s = bs->opaque;
646 9aebd98a Stefan Weil
    uint32_t bmap_entry;
647 9aebd98a Stefan Weil
    uint32_t block_index;
648 9aebd98a Stefan Weil
    uint32_t sector_in_block;
649 9aebd98a Stefan Weil
    uint32_t n_sectors;
650 9aebd98a Stefan Weil
651 9aebd98a Stefan Weil
    acb->hd_aiocb = NULL;
652 9aebd98a Stefan Weil
653 9aebd98a Stefan Weil
    if (ret < 0) {
654 9aebd98a Stefan Weil
        goto done;
655 9aebd98a Stefan Weil
    }
656 9aebd98a Stefan Weil
657 9aebd98a Stefan Weil
    acb->nb_sectors -= acb->n_sectors;
658 9aebd98a Stefan Weil
    acb->sector_num += acb->n_sectors;
659 9aebd98a Stefan Weil
    acb->buf += acb->n_sectors * SECTOR_SIZE;
660 9aebd98a Stefan Weil
661 9aebd98a Stefan Weil
    if (acb->nb_sectors == 0) {
662 9aebd98a Stefan Weil
        logout("finished data write\n");
663 9aebd98a Stefan Weil
        acb->n_sectors = 0;
664 9aebd98a Stefan Weil
        if (acb->header_modified) {
665 9aebd98a Stefan Weil
            VdiHeader *header = acb->block_buffer;
666 9aebd98a Stefan Weil
            logout("now writing modified header\n");
667 9aebd98a Stefan Weil
            assert(acb->bmap_first != VDI_UNALLOCATED);
668 9aebd98a Stefan Weil
            *header = s->header;
669 9aebd98a Stefan Weil
            vdi_header_to_le(header);
670 9aebd98a Stefan Weil
            acb->header_modified = 0;
671 9aebd98a Stefan Weil
            acb->hd_iov.iov_base = acb->block_buffer;
672 9aebd98a Stefan Weil
            acb->hd_iov.iov_len = SECTOR_SIZE;
673 9aebd98a Stefan Weil
            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
674 66f82cee Kevin Wolf
            acb->hd_aiocb = bdrv_aio_writev(bs->file, 0, &acb->hd_qiov, 1,
675 9aebd98a Stefan Weil
                                            vdi_aio_write_cb, acb);
676 9aebd98a Stefan Weil
            if (acb->hd_aiocb == NULL) {
677 9aebd98a Stefan Weil
                goto done;
678 9aebd98a Stefan Weil
            }
679 9aebd98a Stefan Weil
            return;
680 9aebd98a Stefan Weil
        } else if (acb->bmap_first != VDI_UNALLOCATED) {
681 9aebd98a Stefan Weil
            /* One or more new blocks were allocated. */
682 9aebd98a Stefan Weil
            uint64_t offset;
683 9aebd98a Stefan Weil
            uint32_t bmap_first;
684 9aebd98a Stefan Weil
            uint32_t bmap_last;
685 9aebd98a Stefan Weil
            qemu_free(acb->block_buffer);
686 9aebd98a Stefan Weil
            acb->block_buffer = NULL;
687 9aebd98a Stefan Weil
            bmap_first = acb->bmap_first;
688 9aebd98a Stefan Weil
            bmap_last = acb->bmap_last;
689 9aebd98a Stefan Weil
            logout("now writing modified block map entry %u...%u\n",
690 9aebd98a Stefan Weil
                   bmap_first, bmap_last);
691 9aebd98a Stefan Weil
            /* Write modified sectors from block map. */
692 9aebd98a Stefan Weil
            bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
693 9aebd98a Stefan Weil
            bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
694 9aebd98a Stefan Weil
            n_sectors = bmap_last - bmap_first + 1;
695 9aebd98a Stefan Weil
            offset = s->bmap_sector + bmap_first;
696 9aebd98a Stefan Weil
            acb->bmap_first = VDI_UNALLOCATED;
697 a2a45a26 Blue Swirl
            acb->hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
698 a2a45a26 Blue Swirl
                                            bmap_first * SECTOR_SIZE);
699 9aebd98a Stefan Weil
            acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
700 9aebd98a Stefan Weil
            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
701 9aebd98a Stefan Weil
            logout("will write %u block map sectors starting from entry %u\n",
702 9aebd98a Stefan Weil
                   n_sectors, bmap_first);
703 66f82cee Kevin Wolf
            acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
704 9aebd98a Stefan Weil
                                            n_sectors, vdi_aio_write_cb, acb);
705 9aebd98a Stefan Weil
            if (acb->hd_aiocb == NULL) {
706 9aebd98a Stefan Weil
                goto done;
707 9aebd98a Stefan Weil
            }
708 9aebd98a Stefan Weil
            return;
709 9aebd98a Stefan Weil
        }
710 9aebd98a Stefan Weil
        ret = 0;
711 9aebd98a Stefan Weil
        goto done;
712 9aebd98a Stefan Weil
    }
713 9aebd98a Stefan Weil
714 9aebd98a Stefan Weil
    logout("%u sectors written\n", acb->n_sectors);
715 9aebd98a Stefan Weil
716 9aebd98a Stefan Weil
    block_index = acb->sector_num / s->block_sectors;
717 9aebd98a Stefan Weil
    sector_in_block = acb->sector_num % s->block_sectors;
718 9aebd98a Stefan Weil
    n_sectors = s->block_sectors - sector_in_block;
719 9aebd98a Stefan Weil
    if (n_sectors > acb->nb_sectors) {
720 9aebd98a Stefan Weil
        n_sectors = acb->nb_sectors;
721 9aebd98a Stefan Weil
    }
722 9aebd98a Stefan Weil
723 9aebd98a Stefan Weil
    logout("will write %u sectors starting at sector %" PRIu64 "\n",
724 9aebd98a Stefan Weil
           n_sectors, acb->sector_num);
725 9aebd98a Stefan Weil
726 9aebd98a Stefan Weil
    /* prepare next AIO request */
727 9aebd98a Stefan Weil
    acb->n_sectors = n_sectors;
728 9aebd98a Stefan Weil
    bmap_entry = le32_to_cpu(s->bmap[block_index]);
729 9aebd98a Stefan Weil
    if (bmap_entry == VDI_UNALLOCATED) {
730 9aebd98a Stefan Weil
        /* Allocate new block and write to it. */
731 9aebd98a Stefan Weil
        uint64_t offset;
732 9aebd98a Stefan Weil
        uint8_t *block;
733 9aebd98a Stefan Weil
        bmap_entry = s->header.blocks_allocated;
734 9aebd98a Stefan Weil
        s->bmap[block_index] = cpu_to_le32(bmap_entry);
735 9aebd98a Stefan Weil
        s->header.blocks_allocated++;
736 9aebd98a Stefan Weil
        offset = s->header.offset_data / SECTOR_SIZE +
737 9aebd98a Stefan Weil
                 (uint64_t)bmap_entry * s->block_sectors;
738 9aebd98a Stefan Weil
        block = acb->block_buffer;
739 9aebd98a Stefan Weil
        if (block == NULL) {
740 9aebd98a Stefan Weil
            block = qemu_mallocz(s->block_size);
741 9aebd98a Stefan Weil
            acb->block_buffer = block;
742 9aebd98a Stefan Weil
            acb->bmap_first = block_index;
743 9aebd98a Stefan Weil
            assert(!acb->header_modified);
744 9aebd98a Stefan Weil
            acb->header_modified = 1;
745 9aebd98a Stefan Weil
        }
746 9aebd98a Stefan Weil
        acb->bmap_last = block_index;
747 9aebd98a Stefan Weil
        memcpy(block + sector_in_block * SECTOR_SIZE,
748 9aebd98a Stefan Weil
               acb->buf, n_sectors * SECTOR_SIZE);
749 a2a45a26 Blue Swirl
        acb->hd_iov.iov_base = (void *)block;
750 9aebd98a Stefan Weil
        acb->hd_iov.iov_len = s->block_size;
751 9aebd98a Stefan Weil
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
752 66f82cee Kevin Wolf
        acb->hd_aiocb = bdrv_aio_writev(bs->file, offset,
753 9aebd98a Stefan Weil
                                        &acb->hd_qiov, s->block_sectors,
754 9aebd98a Stefan Weil
                                        vdi_aio_write_cb, acb);
755 9aebd98a Stefan Weil
        if (acb->hd_aiocb == NULL) {
756 9aebd98a Stefan Weil
            goto done;
757 9aebd98a Stefan Weil
        }
758 9aebd98a Stefan Weil
    } else {
759 9aebd98a Stefan Weil
        uint64_t offset = s->header.offset_data / SECTOR_SIZE +
760 9aebd98a Stefan Weil
                          (uint64_t)bmap_entry * s->block_sectors +
761 9aebd98a Stefan Weil
                          sector_in_block;
762 a2a45a26 Blue Swirl
        acb->hd_iov.iov_base = (void *)acb->buf;
763 9aebd98a Stefan Weil
        acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
764 9aebd98a Stefan Weil
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
765 66f82cee Kevin Wolf
        acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
766 9aebd98a Stefan Weil
                                        n_sectors, vdi_aio_write_cb, acb);
767 9aebd98a Stefan Weil
        if (acb->hd_aiocb == NULL) {
768 9aebd98a Stefan Weil
            goto done;
769 9aebd98a Stefan Weil
        }
770 9aebd98a Stefan Weil
    }
771 9aebd98a Stefan Weil
772 9aebd98a Stefan Weil
    return;
773 9aebd98a Stefan Weil
774 9aebd98a Stefan Weil
done:
775 9aebd98a Stefan Weil
    if (acb->qiov->niov > 1) {
776 9aebd98a Stefan Weil
        qemu_vfree(acb->orig_buf);
777 9aebd98a Stefan Weil
    }
778 9aebd98a Stefan Weil
    acb->common.cb(acb->common.opaque, ret);
779 9aebd98a Stefan Weil
    qemu_aio_release(acb);
780 9aebd98a Stefan Weil
}
781 9aebd98a Stefan Weil
782 9aebd98a Stefan Weil
static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
783 9aebd98a Stefan Weil
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
784 9aebd98a Stefan Weil
        BlockDriverCompletionFunc *cb, void *opaque)
785 9aebd98a Stefan Weil
{
786 9aebd98a Stefan Weil
    VdiAIOCB *acb;
787 9aebd98a Stefan Weil
    logout("\n");
788 9aebd98a Stefan Weil
    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
789 9aebd98a Stefan Weil
    if (!acb) {
790 9aebd98a Stefan Weil
        return NULL;
791 9aebd98a Stefan Weil
    }
792 9aebd98a Stefan Weil
    vdi_aio_write_cb(acb, 0);
793 9aebd98a Stefan Weil
    return &acb->common;
794 9aebd98a Stefan Weil
}
795 9aebd98a Stefan Weil
796 9aebd98a Stefan Weil
static int vdi_create(const char *filename, QEMUOptionParameter *options)
797 9aebd98a Stefan Weil
{
798 9aebd98a Stefan Weil
    int fd;
799 9aebd98a Stefan Weil
    int result = 0;
800 9aebd98a Stefan Weil
    uint64_t bytes = 0;
801 9aebd98a Stefan Weil
    uint32_t blocks;
802 9aebd98a Stefan Weil
    size_t block_size = 1 * MiB;
803 9aebd98a Stefan Weil
    uint32_t image_type = VDI_TYPE_DYNAMIC;
804 9aebd98a Stefan Weil
    VdiHeader header;
805 9aebd98a Stefan Weil
    size_t i;
806 9aebd98a Stefan Weil
    size_t bmap_size;
807 9aebd98a Stefan Weil
    uint32_t *bmap;
808 9aebd98a Stefan Weil
809 9aebd98a Stefan Weil
    logout("\n");
810 9aebd98a Stefan Weil
811 9aebd98a Stefan Weil
    /* Read out options. */
812 9aebd98a Stefan Weil
    while (options && options->name) {
813 9aebd98a Stefan Weil
        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
814 9aebd98a Stefan Weil
            bytes = options->value.n;
815 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_BLOCK_SIZE)
816 9aebd98a Stefan Weil
        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
817 9aebd98a Stefan Weil
            if (options->value.n) {
818 9aebd98a Stefan Weil
                /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
819 9aebd98a Stefan Weil
                block_size = options->value.n;
820 9aebd98a Stefan Weil
            }
821 9aebd98a Stefan Weil
#endif
822 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_STATIC_IMAGE)
823 9aebd98a Stefan Weil
        } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
824 6eea90eb Stefan Weil
            if (options->value.n) {
825 6eea90eb Stefan Weil
                image_type = VDI_TYPE_STATIC;
826 6eea90eb Stefan Weil
            }
827 9aebd98a Stefan Weil
#endif
828 9aebd98a Stefan Weil
        }
829 9aebd98a Stefan Weil
        options++;
830 9aebd98a Stefan Weil
    }
831 9aebd98a Stefan Weil
832 9aebd98a Stefan Weil
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
833 9aebd98a Stefan Weil
              0644);
834 9aebd98a Stefan Weil
    if (fd < 0) {
835 9aebd98a Stefan Weil
        return -errno;
836 9aebd98a Stefan Weil
    }
837 9aebd98a Stefan Weil
838 f21dc3a4 Stefan Weil
    /* We need enough blocks to store the given disk size,
839 f21dc3a4 Stefan Weil
       so always round up. */
840 f21dc3a4 Stefan Weil
    blocks = (bytes + block_size - 1) / block_size;
841 f21dc3a4 Stefan Weil
842 9aebd98a Stefan Weil
    bmap_size = blocks * sizeof(uint32_t);
843 9aebd98a Stefan Weil
    bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
844 9aebd98a Stefan Weil
845 9aebd98a Stefan Weil
    memset(&header, 0, sizeof(header));
846 1786dc15 Blue Swirl
    pstrcpy(header.text, sizeof(header.text), VDI_TEXT);
847 9aebd98a Stefan Weil
    header.signature = VDI_SIGNATURE;
848 9aebd98a Stefan Weil
    header.version = VDI_VERSION_1_1;
849 9aebd98a Stefan Weil
    header.header_size = 0x180;
850 9aebd98a Stefan Weil
    header.image_type = image_type;
851 9aebd98a Stefan Weil
    header.offset_bmap = 0x200;
852 9aebd98a Stefan Weil
    header.offset_data = 0x200 + bmap_size;
853 9aebd98a Stefan Weil
    header.sector_size = SECTOR_SIZE;
854 9aebd98a Stefan Weil
    header.disk_size = bytes;
855 9aebd98a Stefan Weil
    header.block_size = block_size;
856 9aebd98a Stefan Weil
    header.blocks_in_image = blocks;
857 6eea90eb Stefan Weil
    if (image_type == VDI_TYPE_STATIC) {
858 6eea90eb Stefan Weil
        header.blocks_allocated = blocks;
859 6eea90eb Stefan Weil
    }
860 9aebd98a Stefan Weil
    uuid_generate(header.uuid_image);
861 9aebd98a Stefan Weil
    uuid_generate(header.uuid_last_snap);
862 9aebd98a Stefan Weil
    /* There is no need to set header.uuid_link or header.uuid_parent here. */
863 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
864 9aebd98a Stefan Weil
    vdi_header_print(&header);
865 9aebd98a Stefan Weil
#endif
866 9aebd98a Stefan Weil
    vdi_header_to_le(&header);
867 9aebd98a Stefan Weil
    if (write(fd, &header, sizeof(header)) < 0) {
868 9aebd98a Stefan Weil
        result = -errno;
869 9aebd98a Stefan Weil
    }
870 9aebd98a Stefan Weil
871 b76b6e95 Stefan Weil
    bmap = NULL;
872 b76b6e95 Stefan Weil
    if (bmap_size > 0) {
873 b76b6e95 Stefan Weil
        bmap = (uint32_t *)qemu_mallocz(bmap_size);
874 b76b6e95 Stefan Weil
    }
875 9aebd98a Stefan Weil
    for (i = 0; i < blocks; i++) {
876 9aebd98a Stefan Weil
        if (image_type == VDI_TYPE_STATIC) {
877 9aebd98a Stefan Weil
            bmap[i] = i;
878 9aebd98a Stefan Weil
        } else {
879 9aebd98a Stefan Weil
            bmap[i] = VDI_UNALLOCATED;
880 9aebd98a Stefan Weil
        }
881 9aebd98a Stefan Weil
    }
882 9aebd98a Stefan Weil
    if (write(fd, bmap, bmap_size) < 0) {
883 9aebd98a Stefan Weil
        result = -errno;
884 9aebd98a Stefan Weil
    }
885 9aebd98a Stefan Weil
    qemu_free(bmap);
886 9aebd98a Stefan Weil
    if (image_type == VDI_TYPE_STATIC) {
887 9aebd98a Stefan Weil
        if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
888 9aebd98a Stefan Weil
            result = -errno;
889 9aebd98a Stefan Weil
        }
890 9aebd98a Stefan Weil
    }
891 9aebd98a Stefan Weil
892 9aebd98a Stefan Weil
    if (close(fd) < 0) {
893 9aebd98a Stefan Weil
        result = -errno;
894 9aebd98a Stefan Weil
    }
895 9aebd98a Stefan Weil
896 9aebd98a Stefan Weil
    return result;
897 9aebd98a Stefan Weil
}
898 9aebd98a Stefan Weil
899 9aebd98a Stefan Weil
static void vdi_close(BlockDriverState *bs)
900 9aebd98a Stefan Weil
{
901 9aebd98a Stefan Weil
}
902 9aebd98a Stefan Weil
903 9aebd98a Stefan Weil
static void vdi_flush(BlockDriverState *bs)
904 9aebd98a Stefan Weil
{
905 9aebd98a Stefan Weil
    logout("\n");
906 66f82cee Kevin Wolf
    bdrv_flush(bs->file);
907 9aebd98a Stefan Weil
}
908 9aebd98a Stefan Weil
909 9aebd98a Stefan Weil
910 9aebd98a Stefan Weil
static QEMUOptionParameter vdi_create_options[] = {
911 9aebd98a Stefan Weil
    {
912 9aebd98a Stefan Weil
        .name = BLOCK_OPT_SIZE,
913 9aebd98a Stefan Weil
        .type = OPT_SIZE,
914 9aebd98a Stefan Weil
        .help = "Virtual disk size"
915 9aebd98a Stefan Weil
    },
916 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_BLOCK_SIZE)
917 9aebd98a Stefan Weil
    {
918 9aebd98a Stefan Weil
        .name = BLOCK_OPT_CLUSTER_SIZE,
919 9aebd98a Stefan Weil
        .type = OPT_SIZE,
920 9aebd98a Stefan Weil
        .help = "VDI cluster (block) size"
921 9aebd98a Stefan Weil
    },
922 9aebd98a Stefan Weil
#endif
923 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_STATIC_IMAGE)
924 9aebd98a Stefan Weil
    {
925 9aebd98a Stefan Weil
        .name = BLOCK_OPT_STATIC,
926 9aebd98a Stefan Weil
        .type = OPT_FLAG,
927 9aebd98a Stefan Weil
        .help = "VDI static (pre-allocated) image"
928 9aebd98a Stefan Weil
    },
929 9aebd98a Stefan Weil
#endif
930 9aebd98a Stefan Weil
    /* TODO: An additional option to set UUID values might be useful. */
931 9aebd98a Stefan Weil
    { NULL }
932 9aebd98a Stefan Weil
};
933 9aebd98a Stefan Weil
934 9aebd98a Stefan Weil
static BlockDriver bdrv_vdi = {
935 9aebd98a Stefan Weil
    .format_name = "vdi",
936 9aebd98a Stefan Weil
    .instance_size = sizeof(BDRVVdiState),
937 9aebd98a Stefan Weil
    .bdrv_probe = vdi_probe,
938 9aebd98a Stefan Weil
    .bdrv_open = vdi_open,
939 9aebd98a Stefan Weil
    .bdrv_close = vdi_close,
940 9aebd98a Stefan Weil
    .bdrv_create = vdi_create,
941 9aebd98a Stefan Weil
    .bdrv_flush = vdi_flush,
942 9aebd98a Stefan Weil
    .bdrv_is_allocated = vdi_is_allocated,
943 9aebd98a Stefan Weil
    .bdrv_make_empty = vdi_make_empty,
944 9aebd98a Stefan Weil
945 9aebd98a Stefan Weil
    .bdrv_aio_readv = vdi_aio_readv,
946 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_WRITE)
947 9aebd98a Stefan Weil
    .bdrv_aio_writev = vdi_aio_writev,
948 9aebd98a Stefan Weil
#endif
949 9aebd98a Stefan Weil
950 9aebd98a Stefan Weil
    .bdrv_get_info = vdi_get_info,
951 9aebd98a Stefan Weil
952 9aebd98a Stefan Weil
    .create_options = vdi_create_options,
953 9aebd98a Stefan Weil
    .bdrv_check = vdi_check,
954 9aebd98a Stefan Weil
};
955 9aebd98a Stefan Weil
956 9aebd98a Stefan Weil
static void bdrv_vdi_init(void)
957 9aebd98a Stefan Weil
{
958 9aebd98a Stefan Weil
    logout("\n");
959 9aebd98a Stefan Weil
    bdrv_register(&bdrv_vdi);
960 9aebd98a Stefan Weil
}
961 9aebd98a Stefan Weil
962 9aebd98a Stefan Weil
block_init(bdrv_vdi_init);