Statistics
| Branch: | Revision:

root / block / vdi.c @ 18ebcc86

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