Statistics
| Branch: | Revision:

root / block / vdi.c @ c6df7102

History | View | Annotate | Download (29.3 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 4ff9786c Stefan Weil
/* Unallocated blocks use this index (no need to convert endianness). */
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 4f3669ea Stefan Weil
    memset(out, 0, sizeof(uuid_t));
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 4f3669ea Stefan Weil
    return memcmp(uu, null_uuid, sizeof(uuid_t)) == 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
    /* The block map entries are little endian (even in memory). */
190 9aebd98a Stefan Weil
    uint32_t *bmap;
191 9aebd98a Stefan Weil
    /* Size of block (bytes). */
192 9aebd98a Stefan Weil
    uint32_t block_size;
193 9aebd98a Stefan Weil
    /* Size of block (sectors). */
194 9aebd98a Stefan Weil
    uint32_t block_sectors;
195 9aebd98a Stefan Weil
    /* First sector of block map. */
196 9aebd98a Stefan Weil
    uint32_t bmap_sector;
197 4ff9786c Stefan Weil
    /* VDI header (converted to host endianness). */
198 9aebd98a Stefan Weil
    VdiHeader header;
199 9aebd98a Stefan Weil
} BDRVVdiState;
200 9aebd98a Stefan Weil
201 9aebd98a Stefan Weil
/* Change UUID from little endian (IPRT = VirtualBox format) to big endian
202 9aebd98a Stefan Weil
 * format (network byte order, standard, see RFC 4122) and vice versa.
203 9aebd98a Stefan Weil
 */
204 9aebd98a Stefan Weil
static void uuid_convert(uuid_t uuid)
205 9aebd98a Stefan Weil
{
206 9aebd98a Stefan Weil
    bswap32s((uint32_t *)&uuid[0]);
207 9aebd98a Stefan Weil
    bswap16s((uint16_t *)&uuid[4]);
208 9aebd98a Stefan Weil
    bswap16s((uint16_t *)&uuid[6]);
209 9aebd98a Stefan Weil
}
210 9aebd98a Stefan Weil
211 9aebd98a Stefan Weil
static void vdi_header_to_cpu(VdiHeader *header)
212 9aebd98a Stefan Weil
{
213 9aebd98a Stefan Weil
    le32_to_cpus(&header->signature);
214 9aebd98a Stefan Weil
    le32_to_cpus(&header->version);
215 9aebd98a Stefan Weil
    le32_to_cpus(&header->header_size);
216 9aebd98a Stefan Weil
    le32_to_cpus(&header->image_type);
217 9aebd98a Stefan Weil
    le32_to_cpus(&header->image_flags);
218 9aebd98a Stefan Weil
    le32_to_cpus(&header->offset_bmap);
219 9aebd98a Stefan Weil
    le32_to_cpus(&header->offset_data);
220 9aebd98a Stefan Weil
    le32_to_cpus(&header->cylinders);
221 9aebd98a Stefan Weil
    le32_to_cpus(&header->heads);
222 9aebd98a Stefan Weil
    le32_to_cpus(&header->sectors);
223 9aebd98a Stefan Weil
    le32_to_cpus(&header->sector_size);
224 9aebd98a Stefan Weil
    le64_to_cpus(&header->disk_size);
225 9aebd98a Stefan Weil
    le32_to_cpus(&header->block_size);
226 9aebd98a Stefan Weil
    le32_to_cpus(&header->block_extra);
227 9aebd98a Stefan Weil
    le32_to_cpus(&header->blocks_in_image);
228 9aebd98a Stefan Weil
    le32_to_cpus(&header->blocks_allocated);
229 9aebd98a Stefan Weil
    uuid_convert(header->uuid_image);
230 9aebd98a Stefan Weil
    uuid_convert(header->uuid_last_snap);
231 9aebd98a Stefan Weil
    uuid_convert(header->uuid_link);
232 9aebd98a Stefan Weil
    uuid_convert(header->uuid_parent);
233 9aebd98a Stefan Weil
}
234 9aebd98a Stefan Weil
235 9aebd98a Stefan Weil
static void vdi_header_to_le(VdiHeader *header)
236 9aebd98a Stefan Weil
{
237 9aebd98a Stefan Weil
    cpu_to_le32s(&header->signature);
238 9aebd98a Stefan Weil
    cpu_to_le32s(&header->version);
239 9aebd98a Stefan Weil
    cpu_to_le32s(&header->header_size);
240 9aebd98a Stefan Weil
    cpu_to_le32s(&header->image_type);
241 9aebd98a Stefan Weil
    cpu_to_le32s(&header->image_flags);
242 9aebd98a Stefan Weil
    cpu_to_le32s(&header->offset_bmap);
243 9aebd98a Stefan Weil
    cpu_to_le32s(&header->offset_data);
244 9aebd98a Stefan Weil
    cpu_to_le32s(&header->cylinders);
245 9aebd98a Stefan Weil
    cpu_to_le32s(&header->heads);
246 9aebd98a Stefan Weil
    cpu_to_le32s(&header->sectors);
247 9aebd98a Stefan Weil
    cpu_to_le32s(&header->sector_size);
248 9aebd98a Stefan Weil
    cpu_to_le64s(&header->disk_size);
249 9aebd98a Stefan Weil
    cpu_to_le32s(&header->block_size);
250 9aebd98a Stefan Weil
    cpu_to_le32s(&header->block_extra);
251 9aebd98a Stefan Weil
    cpu_to_le32s(&header->blocks_in_image);
252 9aebd98a Stefan Weil
    cpu_to_le32s(&header->blocks_allocated);
253 9aebd98a Stefan Weil
    cpu_to_le32s(&header->blocks_allocated);
254 9aebd98a Stefan Weil
    uuid_convert(header->uuid_image);
255 9aebd98a Stefan Weil
    uuid_convert(header->uuid_last_snap);
256 9aebd98a Stefan Weil
    uuid_convert(header->uuid_link);
257 9aebd98a Stefan Weil
    uuid_convert(header->uuid_parent);
258 9aebd98a Stefan Weil
}
259 9aebd98a Stefan Weil
260 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
261 9aebd98a Stefan Weil
static void vdi_header_print(VdiHeader *header)
262 9aebd98a Stefan Weil
{
263 9aebd98a Stefan Weil
    char uuid[37];
264 9aebd98a Stefan Weil
    logout("text        %s", header->text);
265 9aebd98a Stefan Weil
    logout("signature   0x%04x\n", header->signature);
266 9aebd98a Stefan Weil
    logout("header size 0x%04x\n", header->header_size);
267 9aebd98a Stefan Weil
    logout("image type  0x%04x\n", header->image_type);
268 9aebd98a Stefan Weil
    logout("image flags 0x%04x\n", header->image_flags);
269 9aebd98a Stefan Weil
    logout("description %s\n", header->description);
270 9aebd98a Stefan Weil
    logout("offset bmap 0x%04x\n", header->offset_bmap);
271 9aebd98a Stefan Weil
    logout("offset data 0x%04x\n", header->offset_data);
272 9aebd98a Stefan Weil
    logout("cylinders   0x%04x\n", header->cylinders);
273 9aebd98a Stefan Weil
    logout("heads       0x%04x\n", header->heads);
274 9aebd98a Stefan Weil
    logout("sectors     0x%04x\n", header->sectors);
275 9aebd98a Stefan Weil
    logout("sector size 0x%04x\n", header->sector_size);
276 9aebd98a Stefan Weil
    logout("image size  0x%" PRIx64 " B (%" PRIu64 " MiB)\n",
277 9aebd98a Stefan Weil
           header->disk_size, header->disk_size / MiB);
278 9aebd98a Stefan Weil
    logout("block size  0x%04x\n", header->block_size);
279 9aebd98a Stefan Weil
    logout("block extra 0x%04x\n", header->block_extra);
280 9aebd98a Stefan Weil
    logout("blocks tot. 0x%04x\n", header->blocks_in_image);
281 9aebd98a Stefan Weil
    logout("blocks all. 0x%04x\n", header->blocks_allocated);
282 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_image, uuid);
283 9aebd98a Stefan Weil
    logout("uuid image  %s\n", uuid);
284 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_last_snap, uuid);
285 9aebd98a Stefan Weil
    logout("uuid snap   %s\n", uuid);
286 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_link, uuid);
287 9aebd98a Stefan Weil
    logout("uuid link   %s\n", uuid);
288 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_parent, uuid);
289 9aebd98a Stefan Weil
    logout("uuid parent %s\n", uuid);
290 9aebd98a Stefan Weil
}
291 9aebd98a Stefan Weil
#endif
292 9aebd98a Stefan Weil
293 9ac228e0 Kevin Wolf
static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
294 9aebd98a Stefan Weil
{
295 9aebd98a Stefan Weil
    /* TODO: additional checks possible. */
296 9aebd98a Stefan Weil
    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
297 9aebd98a Stefan Weil
    uint32_t blocks_allocated = 0;
298 9aebd98a Stefan Weil
    uint32_t block;
299 9aebd98a Stefan Weil
    uint32_t *bmap;
300 9aebd98a Stefan Weil
    logout("\n");
301 9aebd98a Stefan Weil
302 9aebd98a Stefan Weil
    bmap = qemu_malloc(s->header.blocks_in_image * sizeof(uint32_t));
303 9aebd98a Stefan Weil
    memset(bmap, 0xff, s->header.blocks_in_image * sizeof(uint32_t));
304 9aebd98a Stefan Weil
305 9aebd98a Stefan Weil
    /* Check block map and value of blocks_allocated. */
306 9aebd98a Stefan Weil
    for (block = 0; block < s->header.blocks_in_image; block++) {
307 9aebd98a Stefan Weil
        uint32_t bmap_entry = le32_to_cpu(s->bmap[block]);
308 9aebd98a Stefan Weil
        if (bmap_entry != VDI_UNALLOCATED) {
309 9aebd98a Stefan Weil
            if (bmap_entry < s->header.blocks_in_image) {
310 9aebd98a Stefan Weil
                blocks_allocated++;
311 9aebd98a Stefan Weil
                if (bmap[bmap_entry] == VDI_UNALLOCATED) {
312 9aebd98a Stefan Weil
                    bmap[bmap_entry] = bmap_entry;
313 9aebd98a Stefan Weil
                } else {
314 9aebd98a Stefan Weil
                    fprintf(stderr, "ERROR: block index %" PRIu32
315 9aebd98a Stefan Weil
                            " also used by %" PRIu32 "\n", bmap[bmap_entry], bmap_entry);
316 9ac228e0 Kevin Wolf
                    res->corruptions++;
317 9aebd98a Stefan Weil
                }
318 9aebd98a Stefan Weil
            } else {
319 9aebd98a Stefan Weil
                fprintf(stderr, "ERROR: block index %" PRIu32
320 9aebd98a Stefan Weil
                        " too large, is %" PRIu32 "\n", block, bmap_entry);
321 9ac228e0 Kevin Wolf
                res->corruptions++;
322 9aebd98a Stefan Weil
            }
323 9aebd98a Stefan Weil
        }
324 9aebd98a Stefan Weil
    }
325 9aebd98a Stefan Weil
    if (blocks_allocated != s->header.blocks_allocated) {
326 9aebd98a Stefan Weil
        fprintf(stderr, "ERROR: allocated blocks mismatch, is %" PRIu32
327 9aebd98a Stefan Weil
               ", should be %" PRIu32 "\n",
328 9aebd98a Stefan Weil
               blocks_allocated, s->header.blocks_allocated);
329 9ac228e0 Kevin Wolf
        res->corruptions++;
330 9aebd98a Stefan Weil
    }
331 9aebd98a Stefan Weil
332 9aebd98a Stefan Weil
    qemu_free(bmap);
333 9aebd98a Stefan Weil
334 9ac228e0 Kevin Wolf
    return 0;
335 9aebd98a Stefan Weil
}
336 9aebd98a Stefan Weil
337 9aebd98a Stefan Weil
static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
338 9aebd98a Stefan Weil
{
339 9aebd98a Stefan Weil
    /* TODO: vdi_get_info would be needed for machine snapshots.
340 9aebd98a Stefan Weil
       vm_state_offset is still missing. */
341 9aebd98a Stefan Weil
    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
342 9aebd98a Stefan Weil
    logout("\n");
343 9aebd98a Stefan Weil
    bdi->cluster_size = s->block_size;
344 9aebd98a Stefan Weil
    bdi->vm_state_offset = 0;
345 9aebd98a Stefan Weil
    return 0;
346 9aebd98a Stefan Weil
}
347 9aebd98a Stefan Weil
348 9aebd98a Stefan Weil
static int vdi_make_empty(BlockDriverState *bs)
349 9aebd98a Stefan Weil
{
350 9aebd98a Stefan Weil
    /* TODO: missing code. */
351 9aebd98a Stefan Weil
    logout("\n");
352 9aebd98a Stefan Weil
    /* The return value for missing code must be 0, see block.c. */
353 9aebd98a Stefan Weil
    return 0;
354 9aebd98a Stefan Weil
}
355 9aebd98a Stefan Weil
356 9aebd98a Stefan Weil
static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
357 9aebd98a Stefan Weil
{
358 9aebd98a Stefan Weil
    const VdiHeader *header = (const VdiHeader *)buf;
359 9aebd98a Stefan Weil
    int result = 0;
360 9aebd98a Stefan Weil
361 9aebd98a Stefan Weil
    logout("\n");
362 9aebd98a Stefan Weil
363 9aebd98a Stefan Weil
    if (buf_size < sizeof(*header)) {
364 9aebd98a Stefan Weil
        /* Header too small, no VDI. */
365 9aebd98a Stefan Weil
    } else if (le32_to_cpu(header->signature) == VDI_SIGNATURE) {
366 9aebd98a Stefan Weil
        result = 100;
367 9aebd98a Stefan Weil
    }
368 9aebd98a Stefan Weil
369 9aebd98a Stefan Weil
    if (result == 0) {
370 9aebd98a Stefan Weil
        logout("no vdi image\n");
371 9aebd98a Stefan Weil
    } else {
372 9aebd98a Stefan Weil
        logout("%s", header->text);
373 9aebd98a Stefan Weil
    }
374 9aebd98a Stefan Weil
375 9aebd98a Stefan Weil
    return result;
376 9aebd98a Stefan Weil
}
377 9aebd98a Stefan Weil
378 66f82cee Kevin Wolf
static int vdi_open(BlockDriverState *bs, int flags)
379 9aebd98a Stefan Weil
{
380 9aebd98a Stefan Weil
    BDRVVdiState *s = bs->opaque;
381 9aebd98a Stefan Weil
    VdiHeader header;
382 9aebd98a Stefan Weil
    size_t bmap_size;
383 9aebd98a Stefan Weil
384 9aebd98a Stefan Weil
    logout("\n");
385 9aebd98a Stefan Weil
386 66f82cee Kevin Wolf
    if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) {
387 9aebd98a Stefan Weil
        goto fail;
388 9aebd98a Stefan Weil
    }
389 9aebd98a Stefan Weil
390 9aebd98a Stefan Weil
    vdi_header_to_cpu(&header);
391 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
392 9aebd98a Stefan Weil
    vdi_header_print(&header);
393 9aebd98a Stefan Weil
#endif
394 9aebd98a Stefan Weil
395 f21dc3a4 Stefan Weil
    if (header.disk_size % SECTOR_SIZE != 0) {
396 f21dc3a4 Stefan Weil
        /* 'VBoxManage convertfromraw' can create images with odd disk sizes.
397 f21dc3a4 Stefan Weil
           We accept them but round the disk size to the next multiple of
398 f21dc3a4 Stefan Weil
           SECTOR_SIZE. */
399 f21dc3a4 Stefan Weil
        logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size);
400 f21dc3a4 Stefan Weil
        header.disk_size += SECTOR_SIZE - 1;
401 f21dc3a4 Stefan Weil
        header.disk_size &= ~(SECTOR_SIZE - 1);
402 f21dc3a4 Stefan Weil
    }
403 f21dc3a4 Stefan Weil
404 9aebd98a Stefan Weil
    if (header.version != VDI_VERSION_1_1) {
405 9aebd98a Stefan Weil
        logout("unsupported version %u.%u\n",
406 9aebd98a Stefan Weil
               header.version >> 16, header.version & 0xffff);
407 9aebd98a Stefan Weil
        goto fail;
408 9aebd98a Stefan Weil
    } else if (header.offset_bmap % SECTOR_SIZE != 0) {
409 9aebd98a Stefan Weil
        /* We only support block maps which start on a sector boundary. */
410 9aebd98a Stefan Weil
        logout("unsupported block map offset 0x%x B\n", header.offset_bmap);
411 9aebd98a Stefan Weil
        goto fail;
412 9aebd98a Stefan Weil
    } else if (header.offset_data % SECTOR_SIZE != 0) {
413 9aebd98a Stefan Weil
        /* We only support data blocks which start on a sector boundary. */
414 9aebd98a Stefan Weil
        logout("unsupported data offset 0x%x B\n", header.offset_data);
415 9aebd98a Stefan Weil
        goto fail;
416 9aebd98a Stefan Weil
    } else if (header.sector_size != SECTOR_SIZE) {
417 9aebd98a Stefan Weil
        logout("unsupported sector size %u B\n", header.sector_size);
418 9aebd98a Stefan Weil
        goto fail;
419 9aebd98a Stefan Weil
    } else if (header.block_size != 1 * MiB) {
420 9aebd98a Stefan Weil
        logout("unsupported block size %u B\n", header.block_size);
421 9aebd98a Stefan Weil
        goto fail;
422 f21dc3a4 Stefan Weil
    } else if (header.disk_size >
423 f21dc3a4 Stefan Weil
               (uint64_t)header.blocks_in_image * header.block_size) {
424 f21dc3a4 Stefan Weil
        logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
425 9aebd98a Stefan Weil
        goto fail;
426 9aebd98a Stefan Weil
    } else if (!uuid_is_null(header.uuid_link)) {
427 9aebd98a Stefan Weil
        logout("link uuid != 0, unsupported\n");
428 9aebd98a Stefan Weil
        goto fail;
429 9aebd98a Stefan Weil
    } else if (!uuid_is_null(header.uuid_parent)) {
430 9aebd98a Stefan Weil
        logout("parent uuid != 0, unsupported\n");
431 9aebd98a Stefan Weil
        goto fail;
432 9aebd98a Stefan Weil
    }
433 9aebd98a Stefan Weil
434 9aebd98a Stefan Weil
    bs->total_sectors = header.disk_size / SECTOR_SIZE;
435 9aebd98a Stefan Weil
436 9aebd98a Stefan Weil
    s->block_size = header.block_size;
437 9aebd98a Stefan Weil
    s->block_sectors = header.block_size / SECTOR_SIZE;
438 9aebd98a Stefan Weil
    s->bmap_sector = header.offset_bmap / SECTOR_SIZE;
439 9aebd98a Stefan Weil
    s->header = header;
440 9aebd98a Stefan Weil
441 9aebd98a Stefan Weil
    bmap_size = header.blocks_in_image * sizeof(uint32_t);
442 6eea90eb Stefan Weil
    bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
443 b76b6e95 Stefan Weil
    if (bmap_size > 0) {
444 b76b6e95 Stefan Weil
        s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
445 b76b6e95 Stefan Weil
    }
446 66f82cee Kevin Wolf
    if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
447 9aebd98a Stefan Weil
        goto fail_free_bmap;
448 9aebd98a Stefan Weil
    }
449 9aebd98a Stefan Weil
450 9aebd98a Stefan Weil
    return 0;
451 9aebd98a Stefan Weil
452 9aebd98a Stefan Weil
 fail_free_bmap:
453 9aebd98a Stefan Weil
    qemu_free(s->bmap);
454 9aebd98a Stefan Weil
455 9aebd98a Stefan Weil
 fail:
456 9aebd98a Stefan Weil
    return -1;
457 9aebd98a Stefan Weil
}
458 9aebd98a Stefan Weil
459 9aebd98a Stefan Weil
static int vdi_is_allocated(BlockDriverState *bs, int64_t sector_num,
460 9aebd98a Stefan Weil
                             int nb_sectors, int *pnum)
461 9aebd98a Stefan Weil
{
462 9aebd98a Stefan Weil
    /* TODO: Check for too large sector_num (in bdrv_is_allocated or here). */
463 9aebd98a Stefan Weil
    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
464 9aebd98a Stefan Weil
    size_t bmap_index = sector_num / s->block_sectors;
465 9aebd98a Stefan Weil
    size_t sector_in_block = sector_num % s->block_sectors;
466 9aebd98a Stefan Weil
    int n_sectors = s->block_sectors - sector_in_block;
467 9aebd98a Stefan Weil
    uint32_t bmap_entry = le32_to_cpu(s->bmap[bmap_index]);
468 9aebd98a Stefan Weil
    logout("%p, %" PRId64 ", %d, %p\n", bs, sector_num, nb_sectors, pnum);
469 9aebd98a Stefan Weil
    if (n_sectors > nb_sectors) {
470 9aebd98a Stefan Weil
        n_sectors = nb_sectors;
471 9aebd98a Stefan Weil
    }
472 9aebd98a Stefan Weil
    *pnum = n_sectors;
473 9aebd98a Stefan Weil
    return bmap_entry != VDI_UNALLOCATED;
474 9aebd98a Stefan Weil
}
475 9aebd98a Stefan Weil
476 9aebd98a Stefan Weil
static void vdi_aio_cancel(BlockDriverAIOCB *blockacb)
477 9aebd98a Stefan Weil
{
478 9aebd98a Stefan Weil
    /* TODO: This code is untested. How can I get it executed? */
479 b666d239 Kevin Wolf
    VdiAIOCB *acb = container_of(blockacb, VdiAIOCB, common);
480 9aebd98a Stefan Weil
    logout("\n");
481 9aebd98a Stefan Weil
    if (acb->hd_aiocb) {
482 9aebd98a Stefan Weil
        bdrv_aio_cancel(acb->hd_aiocb);
483 9aebd98a Stefan Weil
    }
484 9aebd98a Stefan Weil
    qemu_aio_release(acb);
485 9aebd98a Stefan Weil
}
486 9aebd98a Stefan Weil
487 9aebd98a Stefan Weil
static AIOPool vdi_aio_pool = {
488 9aebd98a Stefan Weil
    .aiocb_size = sizeof(VdiAIOCB),
489 9aebd98a Stefan Weil
    .cancel = vdi_aio_cancel,
490 9aebd98a Stefan Weil
};
491 9aebd98a Stefan Weil
492 9aebd98a Stefan Weil
static VdiAIOCB *vdi_aio_setup(BlockDriverState *bs, int64_t sector_num,
493 9aebd98a Stefan Weil
        QEMUIOVector *qiov, int nb_sectors,
494 9aebd98a Stefan Weil
        BlockDriverCompletionFunc *cb, void *opaque, int is_write)
495 9aebd98a Stefan Weil
{
496 9aebd98a Stefan Weil
    VdiAIOCB *acb;
497 9aebd98a Stefan Weil
498 9aebd98a Stefan Weil
    logout("%p, %" PRId64 ", %p, %d, %p, %p, %d\n",
499 9aebd98a Stefan Weil
           bs, sector_num, qiov, nb_sectors, cb, opaque, is_write);
500 9aebd98a Stefan Weil
501 9aebd98a Stefan Weil
    acb = qemu_aio_get(&vdi_aio_pool, bs, cb, opaque);
502 9aebd98a Stefan Weil
    if (acb) {
503 9aebd98a Stefan Weil
        acb->hd_aiocb = NULL;
504 9aebd98a Stefan Weil
        acb->sector_num = sector_num;
505 9aebd98a Stefan Weil
        acb->qiov = qiov;
506 9aebd98a Stefan Weil
        if (qiov->niov > 1) {
507 9aebd98a Stefan Weil
            acb->buf = qemu_blockalign(bs, qiov->size);
508 9aebd98a Stefan Weil
            acb->orig_buf = acb->buf;
509 9aebd98a Stefan Weil
            if (is_write) {
510 9aebd98a Stefan Weil
                qemu_iovec_to_buffer(qiov, acb->buf);
511 9aebd98a Stefan Weil
            }
512 9aebd98a Stefan Weil
        } else {
513 9aebd98a Stefan Weil
            acb->buf = (uint8_t *)qiov->iov->iov_base;
514 9aebd98a Stefan Weil
        }
515 9aebd98a Stefan Weil
        acb->nb_sectors = nb_sectors;
516 9aebd98a Stefan Weil
        acb->n_sectors = 0;
517 9aebd98a Stefan Weil
        acb->bmap_first = VDI_UNALLOCATED;
518 9aebd98a Stefan Weil
        acb->bmap_last = VDI_UNALLOCATED;
519 9aebd98a Stefan Weil
        acb->block_buffer = NULL;
520 9aebd98a Stefan Weil
        acb->header_modified = 0;
521 9aebd98a Stefan Weil
    }
522 9aebd98a Stefan Weil
    return acb;
523 9aebd98a Stefan Weil
}
524 9aebd98a Stefan Weil
525 9aebd98a Stefan Weil
static int vdi_schedule_bh(QEMUBHFunc *cb, VdiAIOCB *acb)
526 9aebd98a Stefan Weil
{
527 9aebd98a Stefan Weil
    logout("\n");
528 9aebd98a Stefan Weil
529 9aebd98a Stefan Weil
    if (acb->bh) {
530 9aebd98a Stefan Weil
        return -EIO;
531 9aebd98a Stefan Weil
    }
532 9aebd98a Stefan Weil
533 9aebd98a Stefan Weil
    acb->bh = qemu_bh_new(cb, acb);
534 9aebd98a Stefan Weil
    if (!acb->bh) {
535 9aebd98a Stefan Weil
        return -EIO;
536 9aebd98a Stefan Weil
    }
537 9aebd98a Stefan Weil
538 9aebd98a Stefan Weil
    qemu_bh_schedule(acb->bh);
539 9aebd98a Stefan Weil
540 9aebd98a Stefan Weil
    return 0;
541 9aebd98a Stefan Weil
}
542 9aebd98a Stefan Weil
543 9aebd98a Stefan Weil
static void vdi_aio_read_cb(void *opaque, int ret);
544 9aebd98a Stefan Weil
545 9aebd98a Stefan Weil
static void vdi_aio_read_bh(void *opaque)
546 9aebd98a Stefan Weil
{
547 9aebd98a Stefan Weil
    VdiAIOCB *acb = opaque;
548 9aebd98a Stefan Weil
    logout("\n");
549 9aebd98a Stefan Weil
    qemu_bh_delete(acb->bh);
550 9aebd98a Stefan Weil
    acb->bh = NULL;
551 9aebd98a Stefan Weil
    vdi_aio_read_cb(opaque, 0);
552 9aebd98a Stefan Weil
}
553 9aebd98a Stefan Weil
554 9aebd98a Stefan Weil
static void vdi_aio_read_cb(void *opaque, int ret)
555 9aebd98a Stefan Weil
{
556 9aebd98a Stefan Weil
    VdiAIOCB *acb = opaque;
557 9aebd98a Stefan Weil
    BlockDriverState *bs = acb->common.bs;
558 9aebd98a Stefan Weil
    BDRVVdiState *s = bs->opaque;
559 9aebd98a Stefan Weil
    uint32_t bmap_entry;
560 9aebd98a Stefan Weil
    uint32_t block_index;
561 9aebd98a Stefan Weil
    uint32_t sector_in_block;
562 9aebd98a Stefan Weil
    uint32_t n_sectors;
563 9aebd98a Stefan Weil
564 9aebd98a Stefan Weil
    logout("%u sectors read\n", acb->n_sectors);
565 9aebd98a Stefan Weil
566 9aebd98a Stefan Weil
    acb->hd_aiocb = NULL;
567 9aebd98a Stefan Weil
568 9aebd98a Stefan Weil
    if (ret < 0) {
569 9aebd98a Stefan Weil
        goto done;
570 9aebd98a Stefan Weil
    }
571 9aebd98a Stefan Weil
572 9aebd98a Stefan Weil
    acb->nb_sectors -= acb->n_sectors;
573 9aebd98a Stefan Weil
574 9aebd98a Stefan Weil
    if (acb->nb_sectors == 0) {
575 9aebd98a Stefan Weil
        /* request completed */
576 9aebd98a Stefan Weil
        ret = 0;
577 9aebd98a Stefan Weil
        goto done;
578 9aebd98a Stefan Weil
    }
579 9aebd98a Stefan Weil
580 9aebd98a Stefan Weil
    acb->sector_num += acb->n_sectors;
581 9aebd98a Stefan Weil
    acb->buf += acb->n_sectors * SECTOR_SIZE;
582 9aebd98a Stefan Weil
583 9aebd98a Stefan Weil
    block_index = acb->sector_num / s->block_sectors;
584 9aebd98a Stefan Weil
    sector_in_block = acb->sector_num % s->block_sectors;
585 9aebd98a Stefan Weil
    n_sectors = s->block_sectors - sector_in_block;
586 9aebd98a Stefan Weil
    if (n_sectors > acb->nb_sectors) {
587 9aebd98a Stefan Weil
        n_sectors = acb->nb_sectors;
588 9aebd98a Stefan Weil
    }
589 9aebd98a Stefan Weil
590 9aebd98a Stefan Weil
    logout("will read %u sectors starting at sector %" PRIu64 "\n",
591 9aebd98a Stefan Weil
           n_sectors, acb->sector_num);
592 9aebd98a Stefan Weil
593 9aebd98a Stefan Weil
    /* prepare next AIO request */
594 9aebd98a Stefan Weil
    acb->n_sectors = n_sectors;
595 9aebd98a Stefan Weil
    bmap_entry = le32_to_cpu(s->bmap[block_index]);
596 9aebd98a Stefan Weil
    if (bmap_entry == VDI_UNALLOCATED) {
597 9aebd98a Stefan Weil
        /* Block not allocated, return zeros, no need to wait. */
598 9aebd98a Stefan Weil
        memset(acb->buf, 0, n_sectors * SECTOR_SIZE);
599 9aebd98a Stefan Weil
        ret = vdi_schedule_bh(vdi_aio_read_bh, acb);
600 9aebd98a Stefan Weil
        if (ret < 0) {
601 9aebd98a Stefan Weil
            goto done;
602 9aebd98a Stefan Weil
        }
603 9aebd98a Stefan Weil
    } else {
604 9aebd98a Stefan Weil
        uint64_t offset = s->header.offset_data / SECTOR_SIZE +
605 9aebd98a Stefan Weil
                          (uint64_t)bmap_entry * s->block_sectors +
606 9aebd98a Stefan Weil
                          sector_in_block;
607 9aebd98a Stefan Weil
        acb->hd_iov.iov_base = (void *)acb->buf;
608 9aebd98a Stefan Weil
        acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
609 9aebd98a Stefan Weil
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
610 66f82cee Kevin Wolf
        acb->hd_aiocb = bdrv_aio_readv(bs->file, offset, &acb->hd_qiov,
611 9aebd98a Stefan Weil
                                       n_sectors, vdi_aio_read_cb, acb);
612 9aebd98a Stefan Weil
        if (acb->hd_aiocb == NULL) {
613 40a892b7 Stefan Weil
            ret = -EIO;
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 40a892b7 Stefan Weil
                ret = -EIO;
678 9aebd98a Stefan Weil
                goto done;
679 9aebd98a Stefan Weil
            }
680 9aebd98a Stefan Weil
            return;
681 9aebd98a Stefan Weil
        } else if (acb->bmap_first != VDI_UNALLOCATED) {
682 9aebd98a Stefan Weil
            /* One or more new blocks were allocated. */
683 9aebd98a Stefan Weil
            uint64_t offset;
684 9aebd98a Stefan Weil
            uint32_t bmap_first;
685 9aebd98a Stefan Weil
            uint32_t bmap_last;
686 9aebd98a Stefan Weil
            qemu_free(acb->block_buffer);
687 9aebd98a Stefan Weil
            acb->block_buffer = NULL;
688 9aebd98a Stefan Weil
            bmap_first = acb->bmap_first;
689 9aebd98a Stefan Weil
            bmap_last = acb->bmap_last;
690 9aebd98a Stefan Weil
            logout("now writing modified block map entry %u...%u\n",
691 9aebd98a Stefan Weil
                   bmap_first, bmap_last);
692 9aebd98a Stefan Weil
            /* Write modified sectors from block map. */
693 9aebd98a Stefan Weil
            bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
694 9aebd98a Stefan Weil
            bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
695 9aebd98a Stefan Weil
            n_sectors = bmap_last - bmap_first + 1;
696 9aebd98a Stefan Weil
            offset = s->bmap_sector + bmap_first;
697 9aebd98a Stefan Weil
            acb->bmap_first = VDI_UNALLOCATED;
698 a2a45a26 Blue Swirl
            acb->hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
699 a2a45a26 Blue Swirl
                                            bmap_first * SECTOR_SIZE);
700 9aebd98a Stefan Weil
            acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
701 9aebd98a Stefan Weil
            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
702 9aebd98a Stefan Weil
            logout("will write %u block map sectors starting from entry %u\n",
703 9aebd98a Stefan Weil
                   n_sectors, bmap_first);
704 66f82cee Kevin Wolf
            acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
705 9aebd98a Stefan Weil
                                            n_sectors, vdi_aio_write_cb, acb);
706 9aebd98a Stefan Weil
            if (acb->hd_aiocb == NULL) {
707 40a892b7 Stefan Weil
                ret = -EIO;
708 9aebd98a Stefan Weil
                goto done;
709 9aebd98a Stefan Weil
            }
710 9aebd98a Stefan Weil
            return;
711 9aebd98a Stefan Weil
        }
712 9aebd98a Stefan Weil
        ret = 0;
713 9aebd98a Stefan Weil
        goto done;
714 9aebd98a Stefan Weil
    }
715 9aebd98a Stefan Weil
716 9aebd98a Stefan Weil
    logout("%u sectors written\n", acb->n_sectors);
717 9aebd98a Stefan Weil
718 9aebd98a Stefan Weil
    block_index = acb->sector_num / s->block_sectors;
719 9aebd98a Stefan Weil
    sector_in_block = acb->sector_num % s->block_sectors;
720 9aebd98a Stefan Weil
    n_sectors = s->block_sectors - sector_in_block;
721 9aebd98a Stefan Weil
    if (n_sectors > acb->nb_sectors) {
722 9aebd98a Stefan Weil
        n_sectors = acb->nb_sectors;
723 9aebd98a Stefan Weil
    }
724 9aebd98a Stefan Weil
725 9aebd98a Stefan Weil
    logout("will write %u sectors starting at sector %" PRIu64 "\n",
726 9aebd98a Stefan Weil
           n_sectors, acb->sector_num);
727 9aebd98a Stefan Weil
728 9aebd98a Stefan Weil
    /* prepare next AIO request */
729 9aebd98a Stefan Weil
    acb->n_sectors = n_sectors;
730 9aebd98a Stefan Weil
    bmap_entry = le32_to_cpu(s->bmap[block_index]);
731 9aebd98a Stefan Weil
    if (bmap_entry == VDI_UNALLOCATED) {
732 9aebd98a Stefan Weil
        /* Allocate new block and write to it. */
733 9aebd98a Stefan Weil
        uint64_t offset;
734 9aebd98a Stefan Weil
        uint8_t *block;
735 9aebd98a Stefan Weil
        bmap_entry = s->header.blocks_allocated;
736 9aebd98a Stefan Weil
        s->bmap[block_index] = cpu_to_le32(bmap_entry);
737 9aebd98a Stefan Weil
        s->header.blocks_allocated++;
738 9aebd98a Stefan Weil
        offset = s->header.offset_data / SECTOR_SIZE +
739 9aebd98a Stefan Weil
                 (uint64_t)bmap_entry * s->block_sectors;
740 9aebd98a Stefan Weil
        block = acb->block_buffer;
741 9aebd98a Stefan Weil
        if (block == NULL) {
742 9aebd98a Stefan Weil
            block = qemu_mallocz(s->block_size);
743 9aebd98a Stefan Weil
            acb->block_buffer = block;
744 9aebd98a Stefan Weil
            acb->bmap_first = block_index;
745 9aebd98a Stefan Weil
            assert(!acb->header_modified);
746 9aebd98a Stefan Weil
            acb->header_modified = 1;
747 9aebd98a Stefan Weil
        }
748 9aebd98a Stefan Weil
        acb->bmap_last = block_index;
749 9aebd98a Stefan Weil
        memcpy(block + sector_in_block * SECTOR_SIZE,
750 9aebd98a Stefan Weil
               acb->buf, n_sectors * SECTOR_SIZE);
751 a2a45a26 Blue Swirl
        acb->hd_iov.iov_base = (void *)block;
752 9aebd98a Stefan Weil
        acb->hd_iov.iov_len = s->block_size;
753 9aebd98a Stefan Weil
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
754 66f82cee Kevin Wolf
        acb->hd_aiocb = bdrv_aio_writev(bs->file, offset,
755 9aebd98a Stefan Weil
                                        &acb->hd_qiov, s->block_sectors,
756 9aebd98a Stefan Weil
                                        vdi_aio_write_cb, acb);
757 9aebd98a Stefan Weil
        if (acb->hd_aiocb == NULL) {
758 40a892b7 Stefan Weil
            ret = -EIO;
759 9aebd98a Stefan Weil
            goto done;
760 9aebd98a Stefan Weil
        }
761 9aebd98a Stefan Weil
    } else {
762 9aebd98a Stefan Weil
        uint64_t offset = s->header.offset_data / SECTOR_SIZE +
763 9aebd98a Stefan Weil
                          (uint64_t)bmap_entry * s->block_sectors +
764 9aebd98a Stefan Weil
                          sector_in_block;
765 a2a45a26 Blue Swirl
        acb->hd_iov.iov_base = (void *)acb->buf;
766 9aebd98a Stefan Weil
        acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
767 9aebd98a Stefan Weil
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
768 66f82cee Kevin Wolf
        acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov,
769 9aebd98a Stefan Weil
                                        n_sectors, vdi_aio_write_cb, acb);
770 9aebd98a Stefan Weil
        if (acb->hd_aiocb == NULL) {
771 40a892b7 Stefan Weil
            ret = -EIO;
772 9aebd98a Stefan Weil
            goto done;
773 9aebd98a Stefan Weil
        }
774 9aebd98a Stefan Weil
    }
775 9aebd98a Stefan Weil
776 9aebd98a Stefan Weil
    return;
777 9aebd98a Stefan Weil
778 9aebd98a Stefan Weil
done:
779 9aebd98a Stefan Weil
    if (acb->qiov->niov > 1) {
780 9aebd98a Stefan Weil
        qemu_vfree(acb->orig_buf);
781 9aebd98a Stefan Weil
    }
782 9aebd98a Stefan Weil
    acb->common.cb(acb->common.opaque, ret);
783 9aebd98a Stefan Weil
    qemu_aio_release(acb);
784 9aebd98a Stefan Weil
}
785 9aebd98a Stefan Weil
786 9aebd98a Stefan Weil
static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
787 9aebd98a Stefan Weil
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
788 9aebd98a Stefan Weil
        BlockDriverCompletionFunc *cb, void *opaque)
789 9aebd98a Stefan Weil
{
790 9aebd98a Stefan Weil
    VdiAIOCB *acb;
791 9aebd98a Stefan Weil
    logout("\n");
792 9aebd98a Stefan Weil
    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
793 9aebd98a Stefan Weil
    if (!acb) {
794 9aebd98a Stefan Weil
        return NULL;
795 9aebd98a Stefan Weil
    }
796 9aebd98a Stefan Weil
    vdi_aio_write_cb(acb, 0);
797 9aebd98a Stefan Weil
    return &acb->common;
798 9aebd98a Stefan Weil
}
799 9aebd98a Stefan Weil
800 9aebd98a Stefan Weil
static int vdi_create(const char *filename, QEMUOptionParameter *options)
801 9aebd98a Stefan Weil
{
802 9aebd98a Stefan Weil
    int fd;
803 9aebd98a Stefan Weil
    int result = 0;
804 9aebd98a Stefan Weil
    uint64_t bytes = 0;
805 9aebd98a Stefan Weil
    uint32_t blocks;
806 9aebd98a Stefan Weil
    size_t block_size = 1 * MiB;
807 9aebd98a Stefan Weil
    uint32_t image_type = VDI_TYPE_DYNAMIC;
808 9aebd98a Stefan Weil
    VdiHeader header;
809 9aebd98a Stefan Weil
    size_t i;
810 9aebd98a Stefan Weil
    size_t bmap_size;
811 9aebd98a Stefan Weil
    uint32_t *bmap;
812 9aebd98a Stefan Weil
813 9aebd98a Stefan Weil
    logout("\n");
814 9aebd98a Stefan Weil
815 9aebd98a Stefan Weil
    /* Read out options. */
816 9aebd98a Stefan Weil
    while (options && options->name) {
817 9aebd98a Stefan Weil
        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
818 9aebd98a Stefan Weil
            bytes = options->value.n;
819 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_BLOCK_SIZE)
820 9aebd98a Stefan Weil
        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
821 9aebd98a Stefan Weil
            if (options->value.n) {
822 9aebd98a Stefan Weil
                /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
823 9aebd98a Stefan Weil
                block_size = options->value.n;
824 9aebd98a Stefan Weil
            }
825 9aebd98a Stefan Weil
#endif
826 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_STATIC_IMAGE)
827 9aebd98a Stefan Weil
        } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
828 6eea90eb Stefan Weil
            if (options->value.n) {
829 6eea90eb Stefan Weil
                image_type = VDI_TYPE_STATIC;
830 6eea90eb Stefan Weil
            }
831 9aebd98a Stefan Weil
#endif
832 9aebd98a Stefan Weil
        }
833 9aebd98a Stefan Weil
        options++;
834 9aebd98a Stefan Weil
    }
835 9aebd98a Stefan Weil
836 9aebd98a Stefan Weil
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
837 9aebd98a Stefan Weil
              0644);
838 9aebd98a Stefan Weil
    if (fd < 0) {
839 9aebd98a Stefan Weil
        return -errno;
840 9aebd98a Stefan Weil
    }
841 9aebd98a Stefan Weil
842 f21dc3a4 Stefan Weil
    /* We need enough blocks to store the given disk size,
843 f21dc3a4 Stefan Weil
       so always round up. */
844 f21dc3a4 Stefan Weil
    blocks = (bytes + block_size - 1) / block_size;
845 f21dc3a4 Stefan Weil
846 9aebd98a Stefan Weil
    bmap_size = blocks * sizeof(uint32_t);
847 9aebd98a Stefan Weil
    bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
848 9aebd98a Stefan Weil
849 9aebd98a Stefan Weil
    memset(&header, 0, sizeof(header));
850 1786dc15 Blue Swirl
    pstrcpy(header.text, sizeof(header.text), VDI_TEXT);
851 9aebd98a Stefan Weil
    header.signature = VDI_SIGNATURE;
852 9aebd98a Stefan Weil
    header.version = VDI_VERSION_1_1;
853 9aebd98a Stefan Weil
    header.header_size = 0x180;
854 9aebd98a Stefan Weil
    header.image_type = image_type;
855 9aebd98a Stefan Weil
    header.offset_bmap = 0x200;
856 9aebd98a Stefan Weil
    header.offset_data = 0x200 + bmap_size;
857 9aebd98a Stefan Weil
    header.sector_size = SECTOR_SIZE;
858 9aebd98a Stefan Weil
    header.disk_size = bytes;
859 9aebd98a Stefan Weil
    header.block_size = block_size;
860 9aebd98a Stefan Weil
    header.blocks_in_image = blocks;
861 6eea90eb Stefan Weil
    if (image_type == VDI_TYPE_STATIC) {
862 6eea90eb Stefan Weil
        header.blocks_allocated = blocks;
863 6eea90eb Stefan Weil
    }
864 9aebd98a Stefan Weil
    uuid_generate(header.uuid_image);
865 9aebd98a Stefan Weil
    uuid_generate(header.uuid_last_snap);
866 9aebd98a Stefan Weil
    /* There is no need to set header.uuid_link or header.uuid_parent here. */
867 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
868 9aebd98a Stefan Weil
    vdi_header_print(&header);
869 9aebd98a Stefan Weil
#endif
870 9aebd98a Stefan Weil
    vdi_header_to_le(&header);
871 9aebd98a Stefan Weil
    if (write(fd, &header, sizeof(header)) < 0) {
872 9aebd98a Stefan Weil
        result = -errno;
873 9aebd98a Stefan Weil
    }
874 9aebd98a Stefan Weil
875 b76b6e95 Stefan Weil
    bmap = NULL;
876 b76b6e95 Stefan Weil
    if (bmap_size > 0) {
877 b76b6e95 Stefan Weil
        bmap = (uint32_t *)qemu_mallocz(bmap_size);
878 b76b6e95 Stefan Weil
    }
879 9aebd98a Stefan Weil
    for (i = 0; i < blocks; i++) {
880 9aebd98a Stefan Weil
        if (image_type == VDI_TYPE_STATIC) {
881 9aebd98a Stefan Weil
            bmap[i] = i;
882 9aebd98a Stefan Weil
        } else {
883 9aebd98a Stefan Weil
            bmap[i] = VDI_UNALLOCATED;
884 9aebd98a Stefan Weil
        }
885 9aebd98a Stefan Weil
    }
886 9aebd98a Stefan Weil
    if (write(fd, bmap, bmap_size) < 0) {
887 9aebd98a Stefan Weil
        result = -errno;
888 9aebd98a Stefan Weil
    }
889 9aebd98a Stefan Weil
    qemu_free(bmap);
890 9aebd98a Stefan Weil
    if (image_type == VDI_TYPE_STATIC) {
891 9aebd98a Stefan Weil
        if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
892 9aebd98a Stefan Weil
            result = -errno;
893 9aebd98a Stefan Weil
        }
894 9aebd98a Stefan Weil
    }
895 9aebd98a Stefan Weil
896 9aebd98a Stefan Weil
    if (close(fd) < 0) {
897 9aebd98a Stefan Weil
        result = -errno;
898 9aebd98a Stefan Weil
    }
899 9aebd98a Stefan Weil
900 9aebd98a Stefan Weil
    return result;
901 9aebd98a Stefan Weil
}
902 9aebd98a Stefan Weil
903 9aebd98a Stefan Weil
static void vdi_close(BlockDriverState *bs)
904 9aebd98a Stefan Weil
{
905 9aebd98a Stefan Weil
}
906 9aebd98a Stefan Weil
907 205ef796 Kevin Wolf
static int vdi_flush(BlockDriverState *bs)
908 9aebd98a Stefan Weil
{
909 9aebd98a Stefan Weil
    logout("\n");
910 205ef796 Kevin Wolf
    return bdrv_flush(bs->file);
911 9aebd98a Stefan Weil
}
912 9aebd98a Stefan Weil
913 9aebd98a Stefan Weil
914 9aebd98a Stefan Weil
static QEMUOptionParameter vdi_create_options[] = {
915 9aebd98a Stefan Weil
    {
916 9aebd98a Stefan Weil
        .name = BLOCK_OPT_SIZE,
917 9aebd98a Stefan Weil
        .type = OPT_SIZE,
918 9aebd98a Stefan Weil
        .help = "Virtual disk size"
919 9aebd98a Stefan Weil
    },
920 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_BLOCK_SIZE)
921 9aebd98a Stefan Weil
    {
922 9aebd98a Stefan Weil
        .name = BLOCK_OPT_CLUSTER_SIZE,
923 9aebd98a Stefan Weil
        .type = OPT_SIZE,
924 9aebd98a Stefan Weil
        .help = "VDI cluster (block) size"
925 9aebd98a Stefan Weil
    },
926 9aebd98a Stefan Weil
#endif
927 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_STATIC_IMAGE)
928 9aebd98a Stefan Weil
    {
929 9aebd98a Stefan Weil
        .name = BLOCK_OPT_STATIC,
930 9aebd98a Stefan Weil
        .type = OPT_FLAG,
931 9aebd98a Stefan Weil
        .help = "VDI static (pre-allocated) image"
932 9aebd98a Stefan Weil
    },
933 9aebd98a Stefan Weil
#endif
934 9aebd98a Stefan Weil
    /* TODO: An additional option to set UUID values might be useful. */
935 9aebd98a Stefan Weil
    { NULL }
936 9aebd98a Stefan Weil
};
937 9aebd98a Stefan Weil
938 9aebd98a Stefan Weil
static BlockDriver bdrv_vdi = {
939 9aebd98a Stefan Weil
    .format_name = "vdi",
940 9aebd98a Stefan Weil
    .instance_size = sizeof(BDRVVdiState),
941 9aebd98a Stefan Weil
    .bdrv_probe = vdi_probe,
942 9aebd98a Stefan Weil
    .bdrv_open = vdi_open,
943 9aebd98a Stefan Weil
    .bdrv_close = vdi_close,
944 9aebd98a Stefan Weil
    .bdrv_create = vdi_create,
945 9aebd98a Stefan Weil
    .bdrv_flush = vdi_flush,
946 9aebd98a Stefan Weil
    .bdrv_is_allocated = vdi_is_allocated,
947 9aebd98a Stefan Weil
    .bdrv_make_empty = vdi_make_empty,
948 9aebd98a Stefan Weil
949 9aebd98a Stefan Weil
    .bdrv_aio_readv = vdi_aio_readv,
950 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_WRITE)
951 9aebd98a Stefan Weil
    .bdrv_aio_writev = vdi_aio_writev,
952 9aebd98a Stefan Weil
#endif
953 9aebd98a Stefan Weil
954 9aebd98a Stefan Weil
    .bdrv_get_info = vdi_get_info,
955 9aebd98a Stefan Weil
956 9aebd98a Stefan Weil
    .create_options = vdi_create_options,
957 9aebd98a Stefan Weil
    .bdrv_check = vdi_check,
958 9aebd98a Stefan Weil
};
959 9aebd98a Stefan Weil
960 9aebd98a Stefan Weil
static void bdrv_vdi_init(void)
961 9aebd98a Stefan Weil
{
962 9aebd98a Stefan Weil
    logout("\n");
963 9aebd98a Stefan Weil
    bdrv_register(&bdrv_vdi);
964 9aebd98a Stefan Weil
}
965 9aebd98a Stefan Weil
966 9aebd98a Stefan Weil
block_init(bdrv_vdi_init);