Statistics
| Branch: | Revision:

root / block / vdi.c @ 57e69b7d

History | View | Annotate | Download (28.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 9aebd98a Stefan Weil
91 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
92 9aebd98a Stefan Weil
#define logout(fmt, ...) \
93 9aebd98a Stefan Weil
                fprintf(stderr, "vdi\t%-24s" fmt, __func__, ##__VA_ARGS__)
94 9aebd98a Stefan Weil
#else
95 9aebd98a Stefan Weil
#define logout(fmt, ...) ((void)0)
96 9aebd98a Stefan Weil
#endif
97 9aebd98a Stefan Weil
98 9aebd98a Stefan Weil
/* Image signature. */
99 9aebd98a Stefan Weil
#define VDI_SIGNATURE 0xbeda107f
100 9aebd98a Stefan Weil
101 9aebd98a Stefan Weil
/* Image version. */
102 9aebd98a Stefan Weil
#define VDI_VERSION_1_1 0x00010001
103 9aebd98a Stefan Weil
104 9aebd98a Stefan Weil
/* Image type. */
105 9aebd98a Stefan Weil
#define VDI_TYPE_DYNAMIC 1
106 9aebd98a Stefan Weil
#define VDI_TYPE_STATIC  2
107 9aebd98a Stefan Weil
108 9aebd98a Stefan Weil
/* Innotek / SUN images use these strings in header.text:
109 9aebd98a Stefan Weil
 * "<<< innotek VirtualBox Disk Image >>>\n"
110 9aebd98a Stefan Weil
 * "<<< Sun xVM VirtualBox Disk Image >>>\n"
111 9aebd98a Stefan Weil
 * "<<< Sun VirtualBox Disk Image >>>\n"
112 9aebd98a Stefan Weil
 * The value does not matter, so QEMU created images use a different text.
113 9aebd98a Stefan Weil
 */
114 9aebd98a Stefan Weil
#define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
115 9aebd98a Stefan Weil
116 9aebd98a Stefan Weil
/* Unallocated blocks use this index (no need to convert endianess). */
117 9aebd98a Stefan Weil
#define VDI_UNALLOCATED UINT32_MAX
118 9aebd98a Stefan Weil
119 ee682d27 Stefan Weil
#if !defined(CONFIG_UUID)
120 9aebd98a Stefan Weil
void uuid_generate(uuid_t out)
121 9aebd98a Stefan Weil
{
122 9aebd98a Stefan Weil
    memset(out, 0, sizeof(out));
123 9aebd98a Stefan Weil
}
124 9aebd98a Stefan Weil
125 9aebd98a Stefan Weil
int uuid_is_null(const uuid_t uu)
126 9aebd98a Stefan Weil
{
127 9aebd98a Stefan Weil
    uuid_t null_uuid = { 0 };
128 9aebd98a Stefan Weil
    return memcmp(uu, null_uuid, sizeof(uu)) == 0;
129 9aebd98a Stefan Weil
}
130 9aebd98a Stefan Weil
131 9aebd98a Stefan Weil
void uuid_unparse(const uuid_t uu, char *out)
132 9aebd98a Stefan Weil
{
133 9aebd98a Stefan Weil
    snprintf(out, 37, UUID_FMT,
134 9aebd98a Stefan Weil
            uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7],
135 9aebd98a Stefan Weil
            uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
136 9aebd98a Stefan Weil
}
137 9aebd98a Stefan Weil
#endif
138 9aebd98a Stefan Weil
139 9aebd98a Stefan Weil
typedef struct {
140 9aebd98a Stefan Weil
    BlockDriverAIOCB common;
141 9aebd98a Stefan Weil
    int64_t sector_num;
142 9aebd98a Stefan Weil
    QEMUIOVector *qiov;
143 9aebd98a Stefan Weil
    uint8_t *buf;
144 9aebd98a Stefan Weil
    /* Total number of sectors. */
145 9aebd98a Stefan Weil
    int nb_sectors;
146 9aebd98a Stefan Weil
    /* Number of sectors for current AIO. */
147 9aebd98a Stefan Weil
    int n_sectors;
148 9aebd98a Stefan Weil
    /* New allocated block map entry. */
149 9aebd98a Stefan Weil
    uint32_t bmap_first;
150 9aebd98a Stefan Weil
    uint32_t bmap_last;
151 9aebd98a Stefan Weil
    /* Buffer for new allocated block. */
152 9aebd98a Stefan Weil
    void *block_buffer;
153 9aebd98a Stefan Weil
    void *orig_buf;
154 9aebd98a Stefan Weil
    int header_modified;
155 9aebd98a Stefan Weil
    BlockDriverAIOCB *hd_aiocb;
156 9aebd98a Stefan Weil
    struct iovec hd_iov;
157 9aebd98a Stefan Weil
    QEMUIOVector hd_qiov;
158 9aebd98a Stefan Weil
    QEMUBH *bh;
159 9aebd98a Stefan Weil
} VdiAIOCB;
160 9aebd98a Stefan Weil
161 9aebd98a Stefan Weil
typedef struct {
162 9aebd98a Stefan Weil
    char text[0x40];
163 9aebd98a Stefan Weil
    uint32_t signature;
164 9aebd98a Stefan Weil
    uint32_t version;
165 9aebd98a Stefan Weil
    uint32_t header_size;
166 9aebd98a Stefan Weil
    uint32_t image_type;
167 9aebd98a Stefan Weil
    uint32_t image_flags;
168 9aebd98a Stefan Weil
    char description[256];
169 9aebd98a Stefan Weil
    uint32_t offset_bmap;
170 9aebd98a Stefan Weil
    uint32_t offset_data;
171 9aebd98a Stefan Weil
    uint32_t cylinders;         /* disk geometry, unused here */
172 9aebd98a Stefan Weil
    uint32_t heads;             /* disk geometry, unused here */
173 9aebd98a Stefan Weil
    uint32_t sectors;           /* disk geometry, unused here */
174 9aebd98a Stefan Weil
    uint32_t sector_size;
175 9aebd98a Stefan Weil
    uint32_t unused1;
176 9aebd98a Stefan Weil
    uint64_t disk_size;
177 9aebd98a Stefan Weil
    uint32_t block_size;
178 9aebd98a Stefan Weil
    uint32_t block_extra;       /* unused here */
179 9aebd98a Stefan Weil
    uint32_t blocks_in_image;
180 9aebd98a Stefan Weil
    uint32_t blocks_allocated;
181 9aebd98a Stefan Weil
    uuid_t uuid_image;
182 9aebd98a Stefan Weil
    uuid_t uuid_last_snap;
183 9aebd98a Stefan Weil
    uuid_t uuid_link;
184 9aebd98a Stefan Weil
    uuid_t uuid_parent;
185 9aebd98a Stefan Weil
    uint64_t unused2[7];
186 9aebd98a Stefan Weil
} VdiHeader;
187 9aebd98a Stefan Weil
188 9aebd98a Stefan Weil
typedef struct {
189 9aebd98a Stefan Weil
    BlockDriverState *hd;
190 9aebd98a Stefan Weil
    /* The block map entries are little endian (even in memory). */
191 9aebd98a Stefan Weil
    uint32_t *bmap;
192 9aebd98a Stefan Weil
    /* Size of block (bytes). */
193 9aebd98a Stefan Weil
    uint32_t block_size;
194 9aebd98a Stefan Weil
    /* Size of block (sectors). */
195 9aebd98a Stefan Weil
    uint32_t block_sectors;
196 9aebd98a Stefan Weil
    /* First sector of block map. */
197 9aebd98a Stefan Weil
    uint32_t bmap_sector;
198 9aebd98a Stefan Weil
    /* VDI header (converted to host endianess). */
199 9aebd98a Stefan Weil
    VdiHeader header;
200 9aebd98a Stefan Weil
} BDRVVdiState;
201 9aebd98a Stefan Weil
202 9aebd98a Stefan Weil
/* Change UUID from little endian (IPRT = VirtualBox format) to big endian
203 9aebd98a Stefan Weil
 * format (network byte order, standard, see RFC 4122) and vice versa.
204 9aebd98a Stefan Weil
 */
205 9aebd98a Stefan Weil
static void uuid_convert(uuid_t uuid)
206 9aebd98a Stefan Weil
{
207 9aebd98a Stefan Weil
    bswap32s((uint32_t *)&uuid[0]);
208 9aebd98a Stefan Weil
    bswap16s((uint16_t *)&uuid[4]);
209 9aebd98a Stefan Weil
    bswap16s((uint16_t *)&uuid[6]);
210 9aebd98a Stefan Weil
}
211 9aebd98a Stefan Weil
212 9aebd98a Stefan Weil
static void vdi_header_to_cpu(VdiHeader *header)
213 9aebd98a Stefan Weil
{
214 9aebd98a Stefan Weil
    le32_to_cpus(&header->signature);
215 9aebd98a Stefan Weil
    le32_to_cpus(&header->version);
216 9aebd98a Stefan Weil
    le32_to_cpus(&header->header_size);
217 9aebd98a Stefan Weil
    le32_to_cpus(&header->image_type);
218 9aebd98a Stefan Weil
    le32_to_cpus(&header->image_flags);
219 9aebd98a Stefan Weil
    le32_to_cpus(&header->offset_bmap);
220 9aebd98a Stefan Weil
    le32_to_cpus(&header->offset_data);
221 9aebd98a Stefan Weil
    le32_to_cpus(&header->cylinders);
222 9aebd98a Stefan Weil
    le32_to_cpus(&header->heads);
223 9aebd98a Stefan Weil
    le32_to_cpus(&header->sectors);
224 9aebd98a Stefan Weil
    le32_to_cpus(&header->sector_size);
225 9aebd98a Stefan Weil
    le64_to_cpus(&header->disk_size);
226 9aebd98a Stefan Weil
    le32_to_cpus(&header->block_size);
227 9aebd98a Stefan Weil
    le32_to_cpus(&header->block_extra);
228 9aebd98a Stefan Weil
    le32_to_cpus(&header->blocks_in_image);
229 9aebd98a Stefan Weil
    le32_to_cpus(&header->blocks_allocated);
230 9aebd98a Stefan Weil
    uuid_convert(header->uuid_image);
231 9aebd98a Stefan Weil
    uuid_convert(header->uuid_last_snap);
232 9aebd98a Stefan Weil
    uuid_convert(header->uuid_link);
233 9aebd98a Stefan Weil
    uuid_convert(header->uuid_parent);
234 9aebd98a Stefan Weil
}
235 9aebd98a Stefan Weil
236 9aebd98a Stefan Weil
static void vdi_header_to_le(VdiHeader *header)
237 9aebd98a Stefan Weil
{
238 9aebd98a Stefan Weil
    cpu_to_le32s(&header->signature);
239 9aebd98a Stefan Weil
    cpu_to_le32s(&header->version);
240 9aebd98a Stefan Weil
    cpu_to_le32s(&header->header_size);
241 9aebd98a Stefan Weil
    cpu_to_le32s(&header->image_type);
242 9aebd98a Stefan Weil
    cpu_to_le32s(&header->image_flags);
243 9aebd98a Stefan Weil
    cpu_to_le32s(&header->offset_bmap);
244 9aebd98a Stefan Weil
    cpu_to_le32s(&header->offset_data);
245 9aebd98a Stefan Weil
    cpu_to_le32s(&header->cylinders);
246 9aebd98a Stefan Weil
    cpu_to_le32s(&header->heads);
247 9aebd98a Stefan Weil
    cpu_to_le32s(&header->sectors);
248 9aebd98a Stefan Weil
    cpu_to_le32s(&header->sector_size);
249 9aebd98a Stefan Weil
    cpu_to_le64s(&header->disk_size);
250 9aebd98a Stefan Weil
    cpu_to_le32s(&header->block_size);
251 9aebd98a Stefan Weil
    cpu_to_le32s(&header->block_extra);
252 9aebd98a Stefan Weil
    cpu_to_le32s(&header->blocks_in_image);
253 9aebd98a Stefan Weil
    cpu_to_le32s(&header->blocks_allocated);
254 9aebd98a Stefan Weil
    cpu_to_le32s(&header->blocks_allocated);
255 9aebd98a Stefan Weil
    uuid_convert(header->uuid_image);
256 9aebd98a Stefan Weil
    uuid_convert(header->uuid_last_snap);
257 9aebd98a Stefan Weil
    uuid_convert(header->uuid_link);
258 9aebd98a Stefan Weil
    uuid_convert(header->uuid_parent);
259 9aebd98a Stefan Weil
}
260 9aebd98a Stefan Weil
261 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
262 9aebd98a Stefan Weil
static void vdi_header_print(VdiHeader *header)
263 9aebd98a Stefan Weil
{
264 9aebd98a Stefan Weil
    char uuid[37];
265 9aebd98a Stefan Weil
    logout("text        %s", header->text);
266 9aebd98a Stefan Weil
    logout("signature   0x%04x\n", header->signature);
267 9aebd98a Stefan Weil
    logout("header size 0x%04x\n", header->header_size);
268 9aebd98a Stefan Weil
    logout("image type  0x%04x\n", header->image_type);
269 9aebd98a Stefan Weil
    logout("image flags 0x%04x\n", header->image_flags);
270 9aebd98a Stefan Weil
    logout("description %s\n", header->description);
271 9aebd98a Stefan Weil
    logout("offset bmap 0x%04x\n", header->offset_bmap);
272 9aebd98a Stefan Weil
    logout("offset data 0x%04x\n", header->offset_data);
273 9aebd98a Stefan Weil
    logout("cylinders   0x%04x\n", header->cylinders);
274 9aebd98a Stefan Weil
    logout("heads       0x%04x\n", header->heads);
275 9aebd98a Stefan Weil
    logout("sectors     0x%04x\n", header->sectors);
276 9aebd98a Stefan Weil
    logout("sector size 0x%04x\n", header->sector_size);
277 9aebd98a Stefan Weil
    logout("image size  0x%" PRIx64 " B (%" PRIu64 " MiB)\n",
278 9aebd98a Stefan Weil
           header->disk_size, header->disk_size / MiB);
279 9aebd98a Stefan Weil
    logout("block size  0x%04x\n", header->block_size);
280 9aebd98a Stefan Weil
    logout("block extra 0x%04x\n", header->block_extra);
281 9aebd98a Stefan Weil
    logout("blocks tot. 0x%04x\n", header->blocks_in_image);
282 9aebd98a Stefan Weil
    logout("blocks all. 0x%04x\n", header->blocks_allocated);
283 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_image, uuid);
284 9aebd98a Stefan Weil
    logout("uuid image  %s\n", uuid);
285 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_last_snap, uuid);
286 9aebd98a Stefan Weil
    logout("uuid snap   %s\n", uuid);
287 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_link, uuid);
288 9aebd98a Stefan Weil
    logout("uuid link   %s\n", uuid);
289 9aebd98a Stefan Weil
    uuid_unparse(header->uuid_parent, uuid);
290 9aebd98a Stefan Weil
    logout("uuid parent %s\n", uuid);
291 9aebd98a Stefan Weil
}
292 9aebd98a Stefan Weil
#endif
293 9aebd98a Stefan Weil
294 9aebd98a Stefan Weil
static int vdi_check(BlockDriverState *bs)
295 9aebd98a Stefan Weil
{
296 9aebd98a Stefan Weil
    /* TODO: additional checks possible. */
297 9aebd98a Stefan Weil
    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
298 9aebd98a Stefan Weil
    int n_errors = 0;
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 9aebd98a Stefan Weil
    bmap = qemu_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 9aebd98a Stefan Weil
                }
319 9aebd98a Stefan Weil
            } else {
320 9aebd98a Stefan Weil
                fprintf(stderr, "ERROR: block index %" PRIu32
321 9aebd98a Stefan Weil
                        " too large, is %" PRIu32 "\n", block, bmap_entry);
322 9aebd98a Stefan Weil
                n_errors++;
323 9aebd98a Stefan Weil
            }
324 9aebd98a Stefan Weil
        }
325 9aebd98a Stefan Weil
    }
326 9aebd98a Stefan Weil
    if (blocks_allocated != s->header.blocks_allocated) {
327 9aebd98a Stefan Weil
        fprintf(stderr, "ERROR: allocated blocks mismatch, is %" PRIu32
328 9aebd98a Stefan Weil
               ", should be %" PRIu32 "\n",
329 9aebd98a Stefan Weil
               blocks_allocated, s->header.blocks_allocated);
330 9aebd98a Stefan Weil
        n_errors++;
331 9aebd98a Stefan Weil
    }
332 9aebd98a Stefan Weil
333 9aebd98a Stefan Weil
    qemu_free(bmap);
334 9aebd98a Stefan Weil
335 9aebd98a Stefan Weil
    return n_errors;
336 9aebd98a Stefan Weil
}
337 9aebd98a Stefan Weil
338 9aebd98a Stefan Weil
static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
339 9aebd98a Stefan Weil
{
340 9aebd98a Stefan Weil
    /* TODO: vdi_get_info would be needed for machine snapshots.
341 9aebd98a Stefan Weil
       vm_state_offset is still missing. */
342 9aebd98a Stefan Weil
    BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
343 9aebd98a Stefan Weil
    logout("\n");
344 9aebd98a Stefan Weil
    bdi->cluster_size = s->block_size;
345 9aebd98a Stefan Weil
    bdi->vm_state_offset = 0;
346 9aebd98a Stefan Weil
    return 0;
347 9aebd98a Stefan Weil
}
348 9aebd98a Stefan Weil
349 9aebd98a Stefan Weil
static int vdi_make_empty(BlockDriverState *bs)
350 9aebd98a Stefan Weil
{
351 9aebd98a Stefan Weil
    /* TODO: missing code. */
352 9aebd98a Stefan Weil
    logout("\n");
353 9aebd98a Stefan Weil
    /* The return value for missing code must be 0, see block.c. */
354 9aebd98a Stefan Weil
    return 0;
355 9aebd98a Stefan Weil
}
356 9aebd98a Stefan Weil
357 9aebd98a Stefan Weil
static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
358 9aebd98a Stefan Weil
{
359 9aebd98a Stefan Weil
    const VdiHeader *header = (const VdiHeader *)buf;
360 9aebd98a Stefan Weil
    int result = 0;
361 9aebd98a Stefan Weil
362 9aebd98a Stefan Weil
    logout("\n");
363 9aebd98a Stefan Weil
364 9aebd98a Stefan Weil
    if (buf_size < sizeof(*header)) {
365 9aebd98a Stefan Weil
        /* Header too small, no VDI. */
366 9aebd98a Stefan Weil
    } else if (le32_to_cpu(header->signature) == VDI_SIGNATURE) {
367 9aebd98a Stefan Weil
        result = 100;
368 9aebd98a Stefan Weil
    }
369 9aebd98a Stefan Weil
370 9aebd98a Stefan Weil
    if (result == 0) {
371 9aebd98a Stefan Weil
        logout("no vdi image\n");
372 9aebd98a Stefan Weil
    } else {
373 9aebd98a Stefan Weil
        logout("%s", header->text);
374 9aebd98a Stefan Weil
    }
375 9aebd98a Stefan Weil
376 9aebd98a Stefan Weil
    return result;
377 9aebd98a Stefan Weil
}
378 9aebd98a Stefan Weil
379 9aebd98a Stefan Weil
static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
380 9aebd98a Stefan Weil
{
381 9aebd98a Stefan Weil
    BDRVVdiState *s = bs->opaque;
382 9aebd98a Stefan Weil
    VdiHeader header;
383 9aebd98a Stefan Weil
    size_t bmap_size;
384 9aebd98a Stefan Weil
    int ret;
385 9aebd98a Stefan Weil
386 9aebd98a Stefan Weil
    logout("\n");
387 9aebd98a Stefan Weil
388 9aebd98a Stefan Weil
    ret = bdrv_file_open(&s->hd, filename, flags);
389 9aebd98a Stefan Weil
    if (ret < 0) {
390 9aebd98a Stefan Weil
        return ret;
391 9aebd98a Stefan Weil
    }
392 9aebd98a Stefan Weil
393 9aebd98a Stefan Weil
    if (bdrv_read(s->hd, 0, (uint8_t *)&header, 1) < 0) {
394 9aebd98a Stefan Weil
        goto fail;
395 9aebd98a Stefan Weil
    }
396 9aebd98a Stefan Weil
397 9aebd98a Stefan Weil
    vdi_header_to_cpu(&header);
398 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
399 9aebd98a Stefan Weil
    vdi_header_print(&header);
400 9aebd98a Stefan Weil
#endif
401 9aebd98a Stefan Weil
402 9aebd98a Stefan Weil
    if (header.version != VDI_VERSION_1_1) {
403 9aebd98a Stefan Weil
        logout("unsupported version %u.%u\n",
404 9aebd98a Stefan Weil
               header.version >> 16, header.version & 0xffff);
405 9aebd98a Stefan Weil
        goto fail;
406 9aebd98a Stefan Weil
    } else if (header.offset_bmap % SECTOR_SIZE != 0) {
407 9aebd98a Stefan Weil
        /* We only support block maps which start on a sector boundary. */
408 9aebd98a Stefan Weil
        logout("unsupported block map offset 0x%x B\n", header.offset_bmap);
409 9aebd98a Stefan Weil
        goto fail;
410 9aebd98a Stefan Weil
    } else if (header.offset_data % SECTOR_SIZE != 0) {
411 9aebd98a Stefan Weil
        /* We only support data blocks which start on a sector boundary. */
412 9aebd98a Stefan Weil
        logout("unsupported data offset 0x%x B\n", header.offset_data);
413 9aebd98a Stefan Weil
        goto fail;
414 95a2f9bc Franรงois Revol
    } else if (header.disk_size % SECTOR_SIZE != 0) {
415 95a2f9bc Franรงois Revol
        logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
416 95a2f9bc Franรงois Revol
        goto fail;
417 9aebd98a Stefan Weil
    } else if (header.sector_size != SECTOR_SIZE) {
418 9aebd98a Stefan Weil
        logout("unsupported sector size %u B\n", header.sector_size);
419 9aebd98a Stefan Weil
        goto fail;
420 9aebd98a Stefan Weil
    } else if (header.block_size != 1 * MiB) {
421 9aebd98a Stefan Weil
        logout("unsupported block size %u B\n", header.block_size);
422 9aebd98a Stefan Weil
        goto fail;
423 95a2f9bc Franรงois Revol
    } else if ((header.disk_size + header.block_size - 1) / header.block_size !=
424 95a2f9bc Franรงois Revol
               (uint64_t)header.blocks_in_image) {
425 9aebd98a Stefan Weil
        logout("unexpected block number %u B\n", header.blocks_in_image);
426 9aebd98a Stefan Weil
        goto fail;
427 9aebd98a Stefan Weil
    } else if (!uuid_is_null(header.uuid_link)) {
428 9aebd98a Stefan Weil
        logout("link uuid != 0, unsupported\n");
429 9aebd98a Stefan Weil
        goto fail;
430 9aebd98a Stefan Weil
    } else if (!uuid_is_null(header.uuid_parent)) {
431 9aebd98a Stefan Weil
        logout("parent uuid != 0, unsupported\n");
432 9aebd98a Stefan Weil
        goto fail;
433 9aebd98a Stefan Weil
    }
434 9aebd98a Stefan Weil
435 9aebd98a Stefan Weil
    bs->total_sectors = header.disk_size / SECTOR_SIZE;
436 9aebd98a Stefan Weil
437 9aebd98a Stefan Weil
    s->block_size = header.block_size;
438 9aebd98a Stefan Weil
    s->block_sectors = header.block_size / SECTOR_SIZE;
439 9aebd98a Stefan Weil
    s->bmap_sector = header.offset_bmap / SECTOR_SIZE;
440 9aebd98a Stefan Weil
    s->header = header;
441 9aebd98a Stefan Weil
442 9aebd98a Stefan Weil
    bmap_size = header.blocks_in_image * sizeof(uint32_t);
443 6eea90eb Stefan Weil
    bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
444 6eea90eb Stefan Weil
    s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
445 6eea90eb Stefan Weil
    if (bdrv_read(s->hd, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
446 9aebd98a Stefan Weil
        goto fail_free_bmap;
447 9aebd98a Stefan Weil
    }
448 9aebd98a Stefan Weil
449 9aebd98a Stefan Weil
    return 0;
450 9aebd98a Stefan Weil
451 9aebd98a Stefan Weil
 fail_free_bmap:
452 9aebd98a Stefan Weil
    qemu_free(s->bmap);
453 9aebd98a Stefan Weil
454 9aebd98a Stefan Weil
 fail:
455 9aebd98a Stefan Weil
    bdrv_delete(s->hd);
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 9aebd98a Stefan Weil
    VdiAIOCB *acb = (VdiAIOCB *)blockacb;
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 9aebd98a Stefan Weil
        acb->hd_aiocb = bdrv_aio_readv(s->hd, 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 9aebd98a Stefan Weil
            goto done;
614 9aebd98a Stefan Weil
        }
615 9aebd98a Stefan Weil
    }
616 9aebd98a Stefan Weil
    return;
617 9aebd98a Stefan Weil
done:
618 9aebd98a Stefan Weil
    if (acb->qiov->niov > 1) {
619 9aebd98a Stefan Weil
        qemu_iovec_from_buffer(acb->qiov, acb->orig_buf, acb->qiov->size);
620 9aebd98a Stefan Weil
        qemu_vfree(acb->orig_buf);
621 9aebd98a Stefan Weil
    }
622 9aebd98a Stefan Weil
    acb->common.cb(acb->common.opaque, ret);
623 9aebd98a Stefan Weil
    qemu_aio_release(acb);
624 9aebd98a Stefan Weil
}
625 9aebd98a Stefan Weil
626 9aebd98a Stefan Weil
static BlockDriverAIOCB *vdi_aio_readv(BlockDriverState *bs,
627 9aebd98a Stefan Weil
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
628 9aebd98a Stefan Weil
        BlockDriverCompletionFunc *cb, void *opaque)
629 9aebd98a Stefan Weil
{
630 9aebd98a Stefan Weil
    VdiAIOCB *acb;
631 9aebd98a Stefan Weil
    logout("\n");
632 9aebd98a Stefan Weil
    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);
633 9aebd98a Stefan Weil
    if (!acb) {
634 9aebd98a Stefan Weil
        return NULL;
635 9aebd98a Stefan Weil
    }
636 9aebd98a Stefan Weil
    vdi_aio_read_cb(acb, 0);
637 9aebd98a Stefan Weil
    return &acb->common;
638 9aebd98a Stefan Weil
}
639 9aebd98a Stefan Weil
640 9aebd98a Stefan Weil
static void vdi_aio_write_cb(void *opaque, int ret)
641 9aebd98a Stefan Weil
{
642 9aebd98a Stefan Weil
    VdiAIOCB *acb = opaque;
643 9aebd98a Stefan Weil
    BlockDriverState *bs = acb->common.bs;
644 9aebd98a Stefan Weil
    BDRVVdiState *s = bs->opaque;
645 9aebd98a Stefan Weil
    uint32_t bmap_entry;
646 9aebd98a Stefan Weil
    uint32_t block_index;
647 9aebd98a Stefan Weil
    uint32_t sector_in_block;
648 9aebd98a Stefan Weil
    uint32_t n_sectors;
649 9aebd98a Stefan Weil
650 9aebd98a Stefan Weil
    acb->hd_aiocb = NULL;
651 9aebd98a Stefan Weil
652 9aebd98a Stefan Weil
    if (ret < 0) {
653 9aebd98a Stefan Weil
        goto done;
654 9aebd98a Stefan Weil
    }
655 9aebd98a Stefan Weil
656 9aebd98a Stefan Weil
    acb->nb_sectors -= acb->n_sectors;
657 9aebd98a Stefan Weil
    acb->sector_num += acb->n_sectors;
658 9aebd98a Stefan Weil
    acb->buf += acb->n_sectors * SECTOR_SIZE;
659 9aebd98a Stefan Weil
660 9aebd98a Stefan Weil
    if (acb->nb_sectors == 0) {
661 9aebd98a Stefan Weil
        logout("finished data write\n");
662 9aebd98a Stefan Weil
        acb->n_sectors = 0;
663 9aebd98a Stefan Weil
        if (acb->header_modified) {
664 9aebd98a Stefan Weil
            VdiHeader *header = acb->block_buffer;
665 9aebd98a Stefan Weil
            logout("now writing modified header\n");
666 9aebd98a Stefan Weil
            assert(acb->bmap_first != VDI_UNALLOCATED);
667 9aebd98a Stefan Weil
            *header = s->header;
668 9aebd98a Stefan Weil
            vdi_header_to_le(header);
669 9aebd98a Stefan Weil
            acb->header_modified = 0;
670 9aebd98a Stefan Weil
            acb->hd_iov.iov_base = acb->block_buffer;
671 9aebd98a Stefan Weil
            acb->hd_iov.iov_len = SECTOR_SIZE;
672 9aebd98a Stefan Weil
            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
673 9aebd98a Stefan Weil
            acb->hd_aiocb = bdrv_aio_writev(s->hd, 0, &acb->hd_qiov, 1,
674 9aebd98a Stefan Weil
                                            vdi_aio_write_cb, acb);
675 9aebd98a Stefan Weil
            if (acb->hd_aiocb == NULL) {
676 9aebd98a Stefan Weil
                goto done;
677 9aebd98a Stefan Weil
            }
678 9aebd98a Stefan Weil
            return;
679 9aebd98a Stefan Weil
        } else if (acb->bmap_first != VDI_UNALLOCATED) {
680 9aebd98a Stefan Weil
            /* One or more new blocks were allocated. */
681 9aebd98a Stefan Weil
            uint64_t offset;
682 9aebd98a Stefan Weil
            uint32_t bmap_first;
683 9aebd98a Stefan Weil
            uint32_t bmap_last;
684 9aebd98a Stefan Weil
            qemu_free(acb->block_buffer);
685 9aebd98a Stefan Weil
            acb->block_buffer = NULL;
686 9aebd98a Stefan Weil
            bmap_first = acb->bmap_first;
687 9aebd98a Stefan Weil
            bmap_last = acb->bmap_last;
688 9aebd98a Stefan Weil
            logout("now writing modified block map entry %u...%u\n",
689 9aebd98a Stefan Weil
                   bmap_first, bmap_last);
690 9aebd98a Stefan Weil
            /* Write modified sectors from block map. */
691 9aebd98a Stefan Weil
            bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
692 9aebd98a Stefan Weil
            bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
693 9aebd98a Stefan Weil
            n_sectors = bmap_last - bmap_first + 1;
694 9aebd98a Stefan Weil
            offset = s->bmap_sector + bmap_first;
695 9aebd98a Stefan Weil
            acb->bmap_first = VDI_UNALLOCATED;
696 a2a45a26 Blue Swirl
            acb->hd_iov.iov_base = (void *)((uint8_t *)&s->bmap[0] +
697 a2a45a26 Blue Swirl
                                            bmap_first * SECTOR_SIZE);
698 9aebd98a Stefan Weil
            acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
699 9aebd98a Stefan Weil
            qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
700 9aebd98a Stefan Weil
            logout("will write %u block map sectors starting from entry %u\n",
701 9aebd98a Stefan Weil
                   n_sectors, bmap_first);
702 9aebd98a Stefan Weil
            acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov,
703 9aebd98a Stefan Weil
                                            n_sectors, vdi_aio_write_cb, acb);
704 9aebd98a Stefan Weil
            if (acb->hd_aiocb == NULL) {
705 9aebd98a Stefan Weil
                goto done;
706 9aebd98a Stefan Weil
            }
707 9aebd98a Stefan Weil
            return;
708 9aebd98a Stefan Weil
        }
709 9aebd98a Stefan Weil
        ret = 0;
710 9aebd98a Stefan Weil
        goto done;
711 9aebd98a Stefan Weil
    }
712 9aebd98a Stefan Weil
713 9aebd98a Stefan Weil
    logout("%u sectors written\n", acb->n_sectors);
714 9aebd98a Stefan Weil
715 9aebd98a Stefan Weil
    block_index = acb->sector_num / s->block_sectors;
716 9aebd98a Stefan Weil
    sector_in_block = acb->sector_num % s->block_sectors;
717 9aebd98a Stefan Weil
    n_sectors = s->block_sectors - sector_in_block;
718 9aebd98a Stefan Weil
    if (n_sectors > acb->nb_sectors) {
719 9aebd98a Stefan Weil
        n_sectors = acb->nb_sectors;
720 9aebd98a Stefan Weil
    }
721 9aebd98a Stefan Weil
722 9aebd98a Stefan Weil
    logout("will write %u sectors starting at sector %" PRIu64 "\n",
723 9aebd98a Stefan Weil
           n_sectors, acb->sector_num);
724 9aebd98a Stefan Weil
725 9aebd98a Stefan Weil
    /* prepare next AIO request */
726 9aebd98a Stefan Weil
    acb->n_sectors = n_sectors;
727 9aebd98a Stefan Weil
    bmap_entry = le32_to_cpu(s->bmap[block_index]);
728 9aebd98a Stefan Weil
    if (bmap_entry == VDI_UNALLOCATED) {
729 9aebd98a Stefan Weil
        /* Allocate new block and write to it. */
730 9aebd98a Stefan Weil
        uint64_t offset;
731 9aebd98a Stefan Weil
        uint8_t *block;
732 9aebd98a Stefan Weil
        bmap_entry = s->header.blocks_allocated;
733 9aebd98a Stefan Weil
        s->bmap[block_index] = cpu_to_le32(bmap_entry);
734 9aebd98a Stefan Weil
        s->header.blocks_allocated++;
735 9aebd98a Stefan Weil
        offset = s->header.offset_data / SECTOR_SIZE +
736 9aebd98a Stefan Weil
                 (uint64_t)bmap_entry * s->block_sectors;
737 9aebd98a Stefan Weil
        block = acb->block_buffer;
738 9aebd98a Stefan Weil
        if (block == NULL) {
739 9aebd98a Stefan Weil
            block = qemu_mallocz(s->block_size);
740 9aebd98a Stefan Weil
            acb->block_buffer = block;
741 9aebd98a Stefan Weil
            acb->bmap_first = block_index;
742 9aebd98a Stefan Weil
            assert(!acb->header_modified);
743 9aebd98a Stefan Weil
            acb->header_modified = 1;
744 9aebd98a Stefan Weil
        }
745 9aebd98a Stefan Weil
        acb->bmap_last = block_index;
746 9aebd98a Stefan Weil
        memcpy(block + sector_in_block * SECTOR_SIZE,
747 9aebd98a Stefan Weil
               acb->buf, n_sectors * SECTOR_SIZE);
748 a2a45a26 Blue Swirl
        acb->hd_iov.iov_base = (void *)block;
749 9aebd98a Stefan Weil
        acb->hd_iov.iov_len = s->block_size;
750 9aebd98a Stefan Weil
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
751 9aebd98a Stefan Weil
        acb->hd_aiocb = bdrv_aio_writev(s->hd, offset,
752 9aebd98a Stefan Weil
                                        &acb->hd_qiov, s->block_sectors,
753 9aebd98a Stefan Weil
                                        vdi_aio_write_cb, acb);
754 9aebd98a Stefan Weil
        if (acb->hd_aiocb == NULL) {
755 9aebd98a Stefan Weil
            goto done;
756 9aebd98a Stefan Weil
        }
757 9aebd98a Stefan Weil
    } else {
758 9aebd98a Stefan Weil
        uint64_t offset = s->header.offset_data / SECTOR_SIZE +
759 9aebd98a Stefan Weil
                          (uint64_t)bmap_entry * s->block_sectors +
760 9aebd98a Stefan Weil
                          sector_in_block;
761 a2a45a26 Blue Swirl
        acb->hd_iov.iov_base = (void *)acb->buf;
762 9aebd98a Stefan Weil
        acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE;
763 9aebd98a Stefan Weil
        qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1);
764 9aebd98a Stefan Weil
        acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov,
765 9aebd98a Stefan Weil
                                        n_sectors, vdi_aio_write_cb, acb);
766 9aebd98a Stefan Weil
        if (acb->hd_aiocb == NULL) {
767 9aebd98a Stefan Weil
            goto done;
768 9aebd98a Stefan Weil
        }
769 9aebd98a Stefan Weil
    }
770 9aebd98a Stefan Weil
771 9aebd98a Stefan Weil
    return;
772 9aebd98a Stefan Weil
773 9aebd98a Stefan Weil
done:
774 9aebd98a Stefan Weil
    if (acb->qiov->niov > 1) {
775 9aebd98a Stefan Weil
        qemu_vfree(acb->orig_buf);
776 9aebd98a Stefan Weil
    }
777 9aebd98a Stefan Weil
    acb->common.cb(acb->common.opaque, ret);
778 9aebd98a Stefan Weil
    qemu_aio_release(acb);
779 9aebd98a Stefan Weil
}
780 9aebd98a Stefan Weil
781 9aebd98a Stefan Weil
static BlockDriverAIOCB *vdi_aio_writev(BlockDriverState *bs,
782 9aebd98a Stefan Weil
        int64_t sector_num, QEMUIOVector *qiov, int nb_sectors,
783 9aebd98a Stefan Weil
        BlockDriverCompletionFunc *cb, void *opaque)
784 9aebd98a Stefan Weil
{
785 9aebd98a Stefan Weil
    VdiAIOCB *acb;
786 9aebd98a Stefan Weil
    logout("\n");
787 9aebd98a Stefan Weil
    acb = vdi_aio_setup(bs, sector_num, qiov, nb_sectors, cb, opaque, 1);
788 9aebd98a Stefan Weil
    if (!acb) {
789 9aebd98a Stefan Weil
        return NULL;
790 9aebd98a Stefan Weil
    }
791 9aebd98a Stefan Weil
    vdi_aio_write_cb(acb, 0);
792 9aebd98a Stefan Weil
    return &acb->common;
793 9aebd98a Stefan Weil
}
794 9aebd98a Stefan Weil
795 9aebd98a Stefan Weil
static int vdi_create(const char *filename, QEMUOptionParameter *options)
796 9aebd98a Stefan Weil
{
797 9aebd98a Stefan Weil
    int fd;
798 9aebd98a Stefan Weil
    int result = 0;
799 9aebd98a Stefan Weil
    uint64_t bytes = 0;
800 9aebd98a Stefan Weil
    uint32_t blocks;
801 9aebd98a Stefan Weil
    size_t block_size = 1 * MiB;
802 9aebd98a Stefan Weil
    uint32_t image_type = VDI_TYPE_DYNAMIC;
803 9aebd98a Stefan Weil
    VdiHeader header;
804 9aebd98a Stefan Weil
    size_t i;
805 9aebd98a Stefan Weil
    size_t bmap_size;
806 9aebd98a Stefan Weil
    uint32_t *bmap;
807 9aebd98a Stefan Weil
808 9aebd98a Stefan Weil
    logout("\n");
809 9aebd98a Stefan Weil
810 9aebd98a Stefan Weil
    /* Read out options. */
811 9aebd98a Stefan Weil
    while (options && options->name) {
812 9aebd98a Stefan Weil
        if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
813 9aebd98a Stefan Weil
            bytes = options->value.n;
814 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_BLOCK_SIZE)
815 9aebd98a Stefan Weil
        } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
816 9aebd98a Stefan Weil
            if (options->value.n) {
817 9aebd98a Stefan Weil
                /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
818 9aebd98a Stefan Weil
                block_size = options->value.n;
819 9aebd98a Stefan Weil
            }
820 9aebd98a Stefan Weil
#endif
821 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_STATIC_IMAGE)
822 9aebd98a Stefan Weil
        } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
823 6eea90eb Stefan Weil
            if (options->value.n) {
824 6eea90eb Stefan Weil
                image_type = VDI_TYPE_STATIC;
825 6eea90eb Stefan Weil
            }
826 9aebd98a Stefan Weil
#endif
827 9aebd98a Stefan Weil
        }
828 9aebd98a Stefan Weil
        options++;
829 9aebd98a Stefan Weil
    }
830 9aebd98a Stefan Weil
831 9aebd98a Stefan Weil
    fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
832 9aebd98a Stefan Weil
              0644);
833 9aebd98a Stefan Weil
    if (fd < 0) {
834 9aebd98a Stefan Weil
        return -errno;
835 9aebd98a Stefan Weil
    }
836 9aebd98a Stefan Weil
837 9aebd98a Stefan Weil
    blocks = bytes / block_size;
838 9aebd98a Stefan Weil
    bmap_size = blocks * sizeof(uint32_t);
839 9aebd98a Stefan Weil
    bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
840 9aebd98a Stefan Weil
841 9aebd98a Stefan Weil
    memset(&header, 0, sizeof(header));
842 1786dc15 Blue Swirl
    pstrcpy(header.text, sizeof(header.text), VDI_TEXT);
843 9aebd98a Stefan Weil
    header.signature = VDI_SIGNATURE;
844 9aebd98a Stefan Weil
    header.version = VDI_VERSION_1_1;
845 9aebd98a Stefan Weil
    header.header_size = 0x180;
846 9aebd98a Stefan Weil
    header.image_type = image_type;
847 9aebd98a Stefan Weil
    header.offset_bmap = 0x200;
848 9aebd98a Stefan Weil
    header.offset_data = 0x200 + bmap_size;
849 9aebd98a Stefan Weil
    header.sector_size = SECTOR_SIZE;
850 9aebd98a Stefan Weil
    header.disk_size = bytes;
851 9aebd98a Stefan Weil
    header.block_size = block_size;
852 9aebd98a Stefan Weil
    header.blocks_in_image = blocks;
853 6eea90eb Stefan Weil
    if (image_type == VDI_TYPE_STATIC) {
854 6eea90eb Stefan Weil
        header.blocks_allocated = blocks;
855 6eea90eb Stefan Weil
    }
856 9aebd98a Stefan Weil
    uuid_generate(header.uuid_image);
857 9aebd98a Stefan Weil
    uuid_generate(header.uuid_last_snap);
858 9aebd98a Stefan Weil
    /* There is no need to set header.uuid_link or header.uuid_parent here. */
859 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_DEBUG)
860 9aebd98a Stefan Weil
    vdi_header_print(&header);
861 9aebd98a Stefan Weil
#endif
862 9aebd98a Stefan Weil
    vdi_header_to_le(&header);
863 9aebd98a Stefan Weil
    if (write(fd, &header, sizeof(header)) < 0) {
864 9aebd98a Stefan Weil
        result = -errno;
865 9aebd98a Stefan Weil
    }
866 9aebd98a Stefan Weil
867 9aebd98a Stefan Weil
    bmap = (uint32_t *)qemu_mallocz(bmap_size);
868 9aebd98a Stefan Weil
    for (i = 0; i < blocks; i++) {
869 9aebd98a Stefan Weil
        if (image_type == VDI_TYPE_STATIC) {
870 9aebd98a Stefan Weil
            bmap[i] = i;
871 9aebd98a Stefan Weil
        } else {
872 9aebd98a Stefan Weil
            bmap[i] = VDI_UNALLOCATED;
873 9aebd98a Stefan Weil
        }
874 9aebd98a Stefan Weil
    }
875 9aebd98a Stefan Weil
    if (write(fd, bmap, bmap_size) < 0) {
876 9aebd98a Stefan Weil
        result = -errno;
877 9aebd98a Stefan Weil
    }
878 9aebd98a Stefan Weil
    qemu_free(bmap);
879 9aebd98a Stefan Weil
    if (image_type == VDI_TYPE_STATIC) {
880 9aebd98a Stefan Weil
        if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
881 9aebd98a Stefan Weil
            result = -errno;
882 9aebd98a Stefan Weil
        }
883 9aebd98a Stefan Weil
    }
884 9aebd98a Stefan Weil
885 9aebd98a Stefan Weil
    if (close(fd) < 0) {
886 9aebd98a Stefan Weil
        result = -errno;
887 9aebd98a Stefan Weil
    }
888 9aebd98a Stefan Weil
889 9aebd98a Stefan Weil
    return result;
890 9aebd98a Stefan Weil
}
891 9aebd98a Stefan Weil
892 9aebd98a Stefan Weil
static void vdi_close(BlockDriverState *bs)
893 9aebd98a Stefan Weil
{
894 9aebd98a Stefan Weil
    BDRVVdiState *s = bs->opaque;
895 9aebd98a Stefan Weil
    logout("\n");
896 9aebd98a Stefan Weil
    bdrv_delete(s->hd);
897 9aebd98a Stefan Weil
}
898 9aebd98a Stefan Weil
899 9aebd98a Stefan Weil
static void vdi_flush(BlockDriverState *bs)
900 9aebd98a Stefan Weil
{
901 9aebd98a Stefan Weil
    BDRVVdiState *s = bs->opaque;
902 9aebd98a Stefan Weil
    logout("\n");
903 9aebd98a Stefan Weil
    bdrv_flush(s->hd);
904 9aebd98a Stefan Weil
}
905 9aebd98a Stefan Weil
906 9aebd98a Stefan Weil
907 9aebd98a Stefan Weil
static QEMUOptionParameter vdi_create_options[] = {
908 9aebd98a Stefan Weil
    {
909 9aebd98a Stefan Weil
        .name = BLOCK_OPT_SIZE,
910 9aebd98a Stefan Weil
        .type = OPT_SIZE,
911 9aebd98a Stefan Weil
        .help = "Virtual disk size"
912 9aebd98a Stefan Weil
    },
913 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_BLOCK_SIZE)
914 9aebd98a Stefan Weil
    {
915 9aebd98a Stefan Weil
        .name = BLOCK_OPT_CLUSTER_SIZE,
916 9aebd98a Stefan Weil
        .type = OPT_SIZE,
917 9aebd98a Stefan Weil
        .help = "VDI cluster (block) size"
918 9aebd98a Stefan Weil
    },
919 9aebd98a Stefan Weil
#endif
920 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_STATIC_IMAGE)
921 9aebd98a Stefan Weil
    {
922 9aebd98a Stefan Weil
        .name = BLOCK_OPT_STATIC,
923 9aebd98a Stefan Weil
        .type = OPT_FLAG,
924 9aebd98a Stefan Weil
        .help = "VDI static (pre-allocated) image"
925 9aebd98a Stefan Weil
    },
926 9aebd98a Stefan Weil
#endif
927 9aebd98a Stefan Weil
    /* TODO: An additional option to set UUID values might be useful. */
928 9aebd98a Stefan Weil
    { NULL }
929 9aebd98a Stefan Weil
};
930 9aebd98a Stefan Weil
931 9aebd98a Stefan Weil
static BlockDriver bdrv_vdi = {
932 9aebd98a Stefan Weil
    .format_name = "vdi",
933 9aebd98a Stefan Weil
    .instance_size = sizeof(BDRVVdiState),
934 9aebd98a Stefan Weil
    .bdrv_probe = vdi_probe,
935 9aebd98a Stefan Weil
    .bdrv_open = vdi_open,
936 9aebd98a Stefan Weil
    .bdrv_close = vdi_close,
937 9aebd98a Stefan Weil
    .bdrv_create = vdi_create,
938 9aebd98a Stefan Weil
    .bdrv_flush = vdi_flush,
939 9aebd98a Stefan Weil
    .bdrv_is_allocated = vdi_is_allocated,
940 9aebd98a Stefan Weil
    .bdrv_make_empty = vdi_make_empty,
941 9aebd98a Stefan Weil
942 9aebd98a Stefan Weil
    .bdrv_aio_readv = vdi_aio_readv,
943 9aebd98a Stefan Weil
#if defined(CONFIG_VDI_WRITE)
944 9aebd98a Stefan Weil
    .bdrv_aio_writev = vdi_aio_writev,
945 9aebd98a Stefan Weil
#endif
946 9aebd98a Stefan Weil
947 9aebd98a Stefan Weil
    .bdrv_get_info = vdi_get_info,
948 9aebd98a Stefan Weil
949 9aebd98a Stefan Weil
    .create_options = vdi_create_options,
950 9aebd98a Stefan Weil
    .bdrv_check = vdi_check,
951 9aebd98a Stefan Weil
};
952 9aebd98a Stefan Weil
953 9aebd98a Stefan Weil
static void bdrv_vdi_init(void)
954 9aebd98a Stefan Weil
{
955 9aebd98a Stefan Weil
    logout("\n");
956 9aebd98a Stefan Weil
    bdrv_register(&bdrv_vdi);
957 9aebd98a Stefan Weil
}
958 9aebd98a Stefan Weil
959 9aebd98a Stefan Weil
block_init(bdrv_vdi_init);