Statistics
| Branch: | Revision:

root / block / vdi.c @ e4fc8781

History | View | Annotate | Download (29.9 kB)

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