Annotation of qemu/block/vdi.c, revision 1.1.1.7

1.1       root        1: /*
                      2:  * Block driver for the Virtual Disk Image (VDI) format
                      3:  *
1.1.1.7 ! root        4:  * Copyright (c) 2009, 2012 Stefan Weil
1.1       root        5:  *
                      6:  * This program is free software: you can redistribute it and/or modify
                      7:  * it under the terms of the GNU General Public License as published by
                      8:  * the Free Software Foundation, either version 2 of the License, or
                      9:  * (at your option) version 3 or any later version.
                     10:  *
                     11:  * This program is distributed in the hope that it will be useful,
                     12:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14:  * GNU General Public License for more details.
                     15:  *
                     16:  * You should have received a copy of the GNU General Public License
                     17:  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
                     18:  *
                     19:  * Reference:
                     20:  * http://forums.virtualbox.org/viewtopic.php?t=8046
                     21:  *
                     22:  * This driver supports create / read / write operations on VDI images.
                     23:  *
                     24:  * Todo (see also TODO in code):
                     25:  *
                     26:  * Some features like snapshots are still missing.
                     27:  *
                     28:  * Deallocation of zero-filled blocks and shrinking images are missing, too
                     29:  * (might be added to common block layer).
                     30:  *
                     31:  * Allocation of blocks could be optimized (less writes to block map and
                     32:  * header).
                     33:  *
                     34:  * Read and write of adjacents blocks could be done in one operation
                     35:  * (current code uses one operation per block (1 MiB).
                     36:  *
                     37:  * The code is not thread safe (missing locks for changes in header and
                     38:  * block table, no problem with current QEMU).
                     39:  *
                     40:  * Hints:
                     41:  *
                     42:  * Blocks (VDI documentation) correspond to clusters (QEMU).
                     43:  * QEMU's backing files could be implemented using VDI snapshot files (TODO).
                     44:  * VDI snapshot files may also contain the complete machine state.
                     45:  * Maybe this machine state can be converted to QEMU PC machine snapshot data.
                     46:  *
                     47:  * The driver keeps a block cache (little endian entries) in memory.
                     48:  * For the standard block size (1 MiB), a 1 TiB disk will use 4 MiB RAM,
                     49:  * so this seems to be reasonable.
                     50:  */
                     51: 
                     52: #include "qemu-common.h"
                     53: #include "block_int.h"
                     54: #include "module.h"
1.1.1.6   root       55: #include "migration.h"
1.1       root       56: 
                     57: #if defined(CONFIG_UUID)
                     58: #include <uuid/uuid.h>
                     59: #else
                     60: /* TODO: move uuid emulation to some central place in QEMU. */
                     61: #include "sysemu.h"     /* UUID_FMT */
                     62: typedef unsigned char uuid_t[16];
                     63: void uuid_generate(uuid_t out);
                     64: int uuid_is_null(const uuid_t uu);
                     65: void uuid_unparse(const uuid_t uu, char *out);
                     66: #endif
                     67: 
                     68: /* Code configuration options. */
                     69: 
                     70: /* Enable debug messages. */
                     71: //~ #define CONFIG_VDI_DEBUG
                     72: 
                     73: /* Support write operations on VDI images. */
                     74: #define CONFIG_VDI_WRITE
                     75: 
                     76: /* Support non-standard block (cluster) size. This is untested.
                     77:  * Maybe it will be needed for very large images.
                     78:  */
                     79: //~ #define CONFIG_VDI_BLOCK_SIZE
                     80: 
                     81: /* Support static (fixed, pre-allocated) images. */
                     82: #define CONFIG_VDI_STATIC_IMAGE
                     83: 
                     84: /* Command line option for static images. */
                     85: #define BLOCK_OPT_STATIC "static"
                     86: 
                     87: #define KiB     1024
                     88: #define MiB     (KiB * KiB)
                     89: 
                     90: #define SECTOR_SIZE 512
1.1.1.5   root       91: #define DEFAULT_CLUSTER_SIZE (1 * MiB)
1.1       root       92: 
                     93: #if defined(CONFIG_VDI_DEBUG)
                     94: #define logout(fmt, ...) \
                     95:                 fprintf(stderr, "vdi\t%-24s" fmt, __func__, ##__VA_ARGS__)
                     96: #else
                     97: #define logout(fmt, ...) ((void)0)
                     98: #endif
                     99: 
                    100: /* Image signature. */
                    101: #define VDI_SIGNATURE 0xbeda107f
                    102: 
                    103: /* Image version. */
                    104: #define VDI_VERSION_1_1 0x00010001
                    105: 
                    106: /* Image type. */
                    107: #define VDI_TYPE_DYNAMIC 1
                    108: #define VDI_TYPE_STATIC  2
                    109: 
                    110: /* Innotek / SUN images use these strings in header.text:
                    111:  * "<<< innotek VirtualBox Disk Image >>>\n"
                    112:  * "<<< Sun xVM VirtualBox Disk Image >>>\n"
                    113:  * "<<< Sun VirtualBox Disk Image >>>\n"
                    114:  * The value does not matter, so QEMU created images use a different text.
                    115:  */
                    116: #define VDI_TEXT "<<< QEMU VM Virtual Disk Image >>>\n"
                    117: 
1.1.1.6   root      118: /* A never-allocated block; semantically arbitrary content. */
                    119: #define VDI_UNALLOCATED 0xffffffffU
                    120: 
                    121: /* A discarded (no longer allocated) block; semantically zero-filled. */
                    122: #define VDI_DISCARDED   0xfffffffeU
                    123: 
                    124: #define VDI_IS_ALLOCATED(X) ((X) < VDI_DISCARDED)
1.1       root      125: 
                    126: #if !defined(CONFIG_UUID)
                    127: void uuid_generate(uuid_t out)
                    128: {
1.1.1.4   root      129:     memset(out, 0, sizeof(uuid_t));
1.1       root      130: }
                    131: 
                    132: int uuid_is_null(const uuid_t uu)
                    133: {
                    134:     uuid_t null_uuid = { 0 };
1.1.1.4   root      135:     return memcmp(uu, null_uuid, sizeof(uuid_t)) == 0;
1.1       root      136: }
                    137: 
                    138: void uuid_unparse(const uuid_t uu, char *out)
                    139: {
                    140:     snprintf(out, 37, UUID_FMT,
                    141:             uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7],
                    142:             uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]);
                    143: }
                    144: #endif
                    145: 
                    146: typedef struct {
                    147:     char text[0x40];
                    148:     uint32_t signature;
                    149:     uint32_t version;
                    150:     uint32_t header_size;
                    151:     uint32_t image_type;
                    152:     uint32_t image_flags;
                    153:     char description[256];
                    154:     uint32_t offset_bmap;
                    155:     uint32_t offset_data;
                    156:     uint32_t cylinders;         /* disk geometry, unused here */
                    157:     uint32_t heads;             /* disk geometry, unused here */
                    158:     uint32_t sectors;           /* disk geometry, unused here */
                    159:     uint32_t sector_size;
                    160:     uint32_t unused1;
                    161:     uint64_t disk_size;
                    162:     uint32_t block_size;
                    163:     uint32_t block_extra;       /* unused here */
                    164:     uint32_t blocks_in_image;
                    165:     uint32_t blocks_allocated;
                    166:     uuid_t uuid_image;
                    167:     uuid_t uuid_last_snap;
                    168:     uuid_t uuid_link;
                    169:     uuid_t uuid_parent;
                    170:     uint64_t unused2[7];
                    171: } VdiHeader;
                    172: 
                    173: typedef struct {
                    174:     /* The block map entries are little endian (even in memory). */
                    175:     uint32_t *bmap;
                    176:     /* Size of block (bytes). */
                    177:     uint32_t block_size;
                    178:     /* Size of block (sectors). */
                    179:     uint32_t block_sectors;
                    180:     /* First sector of block map. */
                    181:     uint32_t bmap_sector;
1.1.1.5   root      182:     /* VDI header (converted to host endianness). */
1.1       root      183:     VdiHeader header;
1.1.1.6   root      184: 
                    185:     Error *migration_blocker;
1.1       root      186: } BDRVVdiState;
                    187: 
                    188: /* Change UUID from little endian (IPRT = VirtualBox format) to big endian
                    189:  * format (network byte order, standard, see RFC 4122) and vice versa.
                    190:  */
                    191: static void uuid_convert(uuid_t uuid)
                    192: {
                    193:     bswap32s((uint32_t *)&uuid[0]);
                    194:     bswap16s((uint16_t *)&uuid[4]);
                    195:     bswap16s((uint16_t *)&uuid[6]);
                    196: }
                    197: 
                    198: static void vdi_header_to_cpu(VdiHeader *header)
                    199: {
                    200:     le32_to_cpus(&header->signature);
                    201:     le32_to_cpus(&header->version);
                    202:     le32_to_cpus(&header->header_size);
                    203:     le32_to_cpus(&header->image_type);
                    204:     le32_to_cpus(&header->image_flags);
                    205:     le32_to_cpus(&header->offset_bmap);
                    206:     le32_to_cpus(&header->offset_data);
                    207:     le32_to_cpus(&header->cylinders);
                    208:     le32_to_cpus(&header->heads);
                    209:     le32_to_cpus(&header->sectors);
                    210:     le32_to_cpus(&header->sector_size);
                    211:     le64_to_cpus(&header->disk_size);
                    212:     le32_to_cpus(&header->block_size);
                    213:     le32_to_cpus(&header->block_extra);
                    214:     le32_to_cpus(&header->blocks_in_image);
                    215:     le32_to_cpus(&header->blocks_allocated);
                    216:     uuid_convert(header->uuid_image);
                    217:     uuid_convert(header->uuid_last_snap);
                    218:     uuid_convert(header->uuid_link);
                    219:     uuid_convert(header->uuid_parent);
                    220: }
                    221: 
                    222: static void vdi_header_to_le(VdiHeader *header)
                    223: {
                    224:     cpu_to_le32s(&header->signature);
                    225:     cpu_to_le32s(&header->version);
                    226:     cpu_to_le32s(&header->header_size);
                    227:     cpu_to_le32s(&header->image_type);
                    228:     cpu_to_le32s(&header->image_flags);
                    229:     cpu_to_le32s(&header->offset_bmap);
                    230:     cpu_to_le32s(&header->offset_data);
                    231:     cpu_to_le32s(&header->cylinders);
                    232:     cpu_to_le32s(&header->heads);
                    233:     cpu_to_le32s(&header->sectors);
                    234:     cpu_to_le32s(&header->sector_size);
                    235:     cpu_to_le64s(&header->disk_size);
                    236:     cpu_to_le32s(&header->block_size);
                    237:     cpu_to_le32s(&header->block_extra);
                    238:     cpu_to_le32s(&header->blocks_in_image);
                    239:     cpu_to_le32s(&header->blocks_allocated);
                    240:     cpu_to_le32s(&header->blocks_allocated);
                    241:     uuid_convert(header->uuid_image);
                    242:     uuid_convert(header->uuid_last_snap);
                    243:     uuid_convert(header->uuid_link);
                    244:     uuid_convert(header->uuid_parent);
                    245: }
                    246: 
                    247: #if defined(CONFIG_VDI_DEBUG)
                    248: static void vdi_header_print(VdiHeader *header)
                    249: {
                    250:     char uuid[37];
                    251:     logout("text        %s", header->text);
                    252:     logout("signature   0x%04x\n", header->signature);
                    253:     logout("header size 0x%04x\n", header->header_size);
                    254:     logout("image type  0x%04x\n", header->image_type);
                    255:     logout("image flags 0x%04x\n", header->image_flags);
                    256:     logout("description %s\n", header->description);
                    257:     logout("offset bmap 0x%04x\n", header->offset_bmap);
                    258:     logout("offset data 0x%04x\n", header->offset_data);
                    259:     logout("cylinders   0x%04x\n", header->cylinders);
                    260:     logout("heads       0x%04x\n", header->heads);
                    261:     logout("sectors     0x%04x\n", header->sectors);
                    262:     logout("sector size 0x%04x\n", header->sector_size);
                    263:     logout("image size  0x%" PRIx64 " B (%" PRIu64 " MiB)\n",
                    264:            header->disk_size, header->disk_size / MiB);
                    265:     logout("block size  0x%04x\n", header->block_size);
                    266:     logout("block extra 0x%04x\n", header->block_extra);
                    267:     logout("blocks tot. 0x%04x\n", header->blocks_in_image);
                    268:     logout("blocks all. 0x%04x\n", header->blocks_allocated);
                    269:     uuid_unparse(header->uuid_image, uuid);
                    270:     logout("uuid image  %s\n", uuid);
                    271:     uuid_unparse(header->uuid_last_snap, uuid);
                    272:     logout("uuid snap   %s\n", uuid);
                    273:     uuid_unparse(header->uuid_link, uuid);
                    274:     logout("uuid link   %s\n", uuid);
                    275:     uuid_unparse(header->uuid_parent, uuid);
                    276:     logout("uuid parent %s\n", uuid);
                    277: }
                    278: #endif
                    279: 
1.1.1.3   root      280: static int vdi_check(BlockDriverState *bs, BdrvCheckResult *res)
1.1       root      281: {
                    282:     /* TODO: additional checks possible. */
                    283:     BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
                    284:     uint32_t blocks_allocated = 0;
                    285:     uint32_t block;
                    286:     uint32_t *bmap;
                    287:     logout("\n");
                    288: 
1.1.1.6   root      289:     bmap = g_malloc(s->header.blocks_in_image * sizeof(uint32_t));
1.1       root      290:     memset(bmap, 0xff, s->header.blocks_in_image * sizeof(uint32_t));
                    291: 
                    292:     /* Check block map and value of blocks_allocated. */
                    293:     for (block = 0; block < s->header.blocks_in_image; block++) {
                    294:         uint32_t bmap_entry = le32_to_cpu(s->bmap[block]);
1.1.1.6   root      295:         if (VDI_IS_ALLOCATED(bmap_entry)) {
1.1       root      296:             if (bmap_entry < s->header.blocks_in_image) {
                    297:                 blocks_allocated++;
1.1.1.6   root      298:                 if (!VDI_IS_ALLOCATED(bmap[bmap_entry])) {
1.1       root      299:                     bmap[bmap_entry] = bmap_entry;
                    300:                 } else {
                    301:                     fprintf(stderr, "ERROR: block index %" PRIu32
                    302:                             " also used by %" PRIu32 "\n", bmap[bmap_entry], bmap_entry);
1.1.1.3   root      303:                     res->corruptions++;
1.1       root      304:                 }
                    305:             } else {
                    306:                 fprintf(stderr, "ERROR: block index %" PRIu32
                    307:                         " too large, is %" PRIu32 "\n", block, bmap_entry);
1.1.1.3   root      308:                 res->corruptions++;
1.1       root      309:             }
                    310:         }
                    311:     }
                    312:     if (blocks_allocated != s->header.blocks_allocated) {
                    313:         fprintf(stderr, "ERROR: allocated blocks mismatch, is %" PRIu32
                    314:                ", should be %" PRIu32 "\n",
                    315:                blocks_allocated, s->header.blocks_allocated);
1.1.1.3   root      316:         res->corruptions++;
1.1       root      317:     }
                    318: 
1.1.1.6   root      319:     g_free(bmap);
1.1       root      320: 
1.1.1.3   root      321:     return 0;
1.1       root      322: }
                    323: 
                    324: static int vdi_get_info(BlockDriverState *bs, BlockDriverInfo *bdi)
                    325: {
                    326:     /* TODO: vdi_get_info would be needed for machine snapshots.
                    327:        vm_state_offset is still missing. */
                    328:     BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
                    329:     logout("\n");
                    330:     bdi->cluster_size = s->block_size;
                    331:     bdi->vm_state_offset = 0;
                    332:     return 0;
                    333: }
                    334: 
                    335: static int vdi_make_empty(BlockDriverState *bs)
                    336: {
                    337:     /* TODO: missing code. */
                    338:     logout("\n");
                    339:     /* The return value for missing code must be 0, see block.c. */
                    340:     return 0;
                    341: }
                    342: 
                    343: static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename)
                    344: {
                    345:     const VdiHeader *header = (const VdiHeader *)buf;
                    346:     int result = 0;
                    347: 
                    348:     logout("\n");
                    349: 
                    350:     if (buf_size < sizeof(*header)) {
                    351:         /* Header too small, no VDI. */
                    352:     } else if (le32_to_cpu(header->signature) == VDI_SIGNATURE) {
                    353:         result = 100;
                    354:     }
                    355: 
                    356:     if (result == 0) {
                    357:         logout("no vdi image\n");
                    358:     } else {
                    359:         logout("%s", header->text);
                    360:     }
                    361: 
                    362:     return result;
                    363: }
                    364: 
1.1.1.3   root      365: static int vdi_open(BlockDriverState *bs, int flags)
1.1       root      366: {
                    367:     BDRVVdiState *s = bs->opaque;
                    368:     VdiHeader header;
                    369:     size_t bmap_size;
                    370: 
                    371:     logout("\n");
                    372: 
1.1.1.3   root      373:     if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) {
1.1       root      374:         goto fail;
                    375:     }
                    376: 
                    377:     vdi_header_to_cpu(&header);
                    378: #if defined(CONFIG_VDI_DEBUG)
                    379:     vdi_header_print(&header);
                    380: #endif
                    381: 
1.1.1.2   root      382:     if (header.disk_size % SECTOR_SIZE != 0) {
                    383:         /* 'VBoxManage convertfromraw' can create images with odd disk sizes.
                    384:            We accept them but round the disk size to the next multiple of
                    385:            SECTOR_SIZE. */
                    386:         logout("odd disk size %" PRIu64 " B, round up\n", header.disk_size);
                    387:         header.disk_size += SECTOR_SIZE - 1;
                    388:         header.disk_size &= ~(SECTOR_SIZE - 1);
                    389:     }
                    390: 
1.1       root      391:     if (header.version != VDI_VERSION_1_1) {
                    392:         logout("unsupported version %u.%u\n",
                    393:                header.version >> 16, header.version & 0xffff);
                    394:         goto fail;
                    395:     } else if (header.offset_bmap % SECTOR_SIZE != 0) {
                    396:         /* We only support block maps which start on a sector boundary. */
                    397:         logout("unsupported block map offset 0x%x B\n", header.offset_bmap);
                    398:         goto fail;
                    399:     } else if (header.offset_data % SECTOR_SIZE != 0) {
                    400:         /* We only support data blocks which start on a sector boundary. */
                    401:         logout("unsupported data offset 0x%x B\n", header.offset_data);
                    402:         goto fail;
                    403:     } else if (header.sector_size != SECTOR_SIZE) {
                    404:         logout("unsupported sector size %u B\n", header.sector_size);
                    405:         goto fail;
                    406:     } else if (header.block_size != 1 * MiB) {
                    407:         logout("unsupported block size %u B\n", header.block_size);
                    408:         goto fail;
1.1.1.2   root      409:     } else if (header.disk_size >
1.1       root      410:                (uint64_t)header.blocks_in_image * header.block_size) {
1.1.1.2   root      411:         logout("unsupported disk size %" PRIu64 " B\n", header.disk_size);
1.1       root      412:         goto fail;
                    413:     } else if (!uuid_is_null(header.uuid_link)) {
                    414:         logout("link uuid != 0, unsupported\n");
                    415:         goto fail;
                    416:     } else if (!uuid_is_null(header.uuid_parent)) {
                    417:         logout("parent uuid != 0, unsupported\n");
                    418:         goto fail;
                    419:     }
                    420: 
                    421:     bs->total_sectors = header.disk_size / SECTOR_SIZE;
                    422: 
                    423:     s->block_size = header.block_size;
                    424:     s->block_sectors = header.block_size / SECTOR_SIZE;
                    425:     s->bmap_sector = header.offset_bmap / SECTOR_SIZE;
                    426:     s->header = header;
                    427: 
                    428:     bmap_size = header.blocks_in_image * sizeof(uint32_t);
                    429:     bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
1.1.1.3   root      430:     if (bmap_size > 0) {
1.1.1.6   root      431:         s->bmap = g_malloc(bmap_size * SECTOR_SIZE);
1.1.1.3   root      432:     }
                    433:     if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
1.1       root      434:         goto fail_free_bmap;
                    435:     }
                    436: 
1.1.1.6   root      437:     /* Disable migration when vdi images are used */
                    438:     error_set(&s->migration_blocker,
                    439:               QERR_BLOCK_FORMAT_FEATURE_NOT_SUPPORTED,
                    440:               "vdi", bs->device_name, "live migration");
                    441:     migrate_add_blocker(s->migration_blocker);
                    442: 
1.1       root      443:     return 0;
                    444: 
                    445:  fail_free_bmap:
1.1.1.6   root      446:     g_free(s->bmap);
1.1       root      447: 
                    448:  fail:
                    449:     return -1;
                    450: }
                    451: 
1.1.1.7 ! root      452: static int coroutine_fn vdi_co_is_allocated(BlockDriverState *bs,
        !           453:         int64_t sector_num, int nb_sectors, int *pnum)
1.1       root      454: {
                    455:     /* TODO: Check for too large sector_num (in bdrv_is_allocated or here). */
                    456:     BDRVVdiState *s = (BDRVVdiState *)bs->opaque;
                    457:     size_t bmap_index = sector_num / s->block_sectors;
                    458:     size_t sector_in_block = sector_num % s->block_sectors;
                    459:     int n_sectors = s->block_sectors - sector_in_block;
                    460:     uint32_t bmap_entry = le32_to_cpu(s->bmap[bmap_index]);
                    461:     logout("%p, %" PRId64 ", %d, %p\n", bs, sector_num, nb_sectors, pnum);
                    462:     if (n_sectors > nb_sectors) {
                    463:         n_sectors = nb_sectors;
                    464:     }
                    465:     *pnum = n_sectors;
1.1.1.6   root      466:     return VDI_IS_ALLOCATED(bmap_entry);
1.1       root      467: }
                    468: 
1.1.1.7 ! root      469: static int vdi_co_read(BlockDriverState *bs,
        !           470:         int64_t sector_num, uint8_t *buf, int nb_sectors)
1.1       root      471: {
                    472:     BDRVVdiState *s = bs->opaque;
                    473:     uint32_t bmap_entry;
                    474:     uint32_t block_index;
                    475:     uint32_t sector_in_block;
                    476:     uint32_t n_sectors;
1.1.1.7 ! root      477:     int ret = 0;
1.1       root      478: 
1.1.1.7 ! root      479:     logout("\n");
1.1       root      480: 
1.1.1.7 ! root      481:     while (ret >= 0 && nb_sectors > 0) {
        !           482:         block_index = sector_num / s->block_sectors;
        !           483:         sector_in_block = sector_num % s->block_sectors;
        !           484:         n_sectors = s->block_sectors - sector_in_block;
        !           485:         if (n_sectors > nb_sectors) {
        !           486:             n_sectors = nb_sectors;
1.1       root      487:         }
1.1.1.5   root      488: 
1.1.1.7 ! root      489:         logout("will read %u sectors starting at sector %" PRIu64 "\n",
        !           490:                n_sectors, sector_num);
1.1.1.5   root      491: 
1.1.1.7 ! root      492:         /* prepare next AIO request */
        !           493:         bmap_entry = le32_to_cpu(s->bmap[block_index]);
        !           494:         if (!VDI_IS_ALLOCATED(bmap_entry)) {
        !           495:             /* Block not allocated, return zeros, no need to wait. */
        !           496:             memset(buf, 0, n_sectors * SECTOR_SIZE);
        !           497:             ret = 0;
        !           498:         } else {
        !           499:             uint64_t offset = s->header.offset_data / SECTOR_SIZE +
        !           500:                               (uint64_t)bmap_entry * s->block_sectors +
        !           501:                               sector_in_block;
        !           502:             ret = bdrv_read(bs->file, offset, buf, n_sectors);
1.1.1.5   root      503:         }
1.1.1.7 ! root      504:         logout("%u sectors read\n", n_sectors);
        !           505: 
        !           506:         nb_sectors -= n_sectors;
        !           507:         sector_num += n_sectors;
        !           508:         buf += n_sectors * SECTOR_SIZE;
1.1.1.5   root      509:     }
                    510: 
1.1.1.7 ! root      511:     return ret;
1.1       root      512: }
                    513: 
1.1.1.7 ! root      514: static int vdi_co_write(BlockDriverState *bs,
        !           515:         int64_t sector_num, const uint8_t *buf, int nb_sectors)
1.1       root      516: {
                    517:     BDRVVdiState *s = bs->opaque;
                    518:     uint32_t bmap_entry;
                    519:     uint32_t block_index;
                    520:     uint32_t sector_in_block;
                    521:     uint32_t n_sectors;
1.1.1.7 ! root      522:     uint32_t bmap_first = VDI_UNALLOCATED;
        !           523:     uint32_t bmap_last = VDI_UNALLOCATED;
        !           524:     uint8_t *block = NULL;
        !           525:     int ret = 0;
1.1       root      526: 
1.1.1.7 ! root      527:     logout("\n");
1.1       root      528: 
1.1.1.7 ! root      529:     while (ret >= 0 && nb_sectors > 0) {
        !           530:         block_index = sector_num / s->block_sectors;
        !           531:         sector_in_block = sector_num % s->block_sectors;
        !           532:         n_sectors = s->block_sectors - sector_in_block;
        !           533:         if (n_sectors > nb_sectors) {
        !           534:             n_sectors = nb_sectors;
        !           535:         }
1.1       root      536: 
1.1.1.7 ! root      537:         logout("will write %u sectors starting at sector %" PRIu64 "\n",
        !           538:                n_sectors, sector_num);
        !           539: 
        !           540:         /* prepare next AIO request */
        !           541:         bmap_entry = le32_to_cpu(s->bmap[block_index]);
        !           542:         if (!VDI_IS_ALLOCATED(bmap_entry)) {
        !           543:             /* Allocate new block and write to it. */
1.1       root      544:             uint64_t offset;
1.1.1.7 ! root      545:             bmap_entry = s->header.blocks_allocated;
        !           546:             s->bmap[block_index] = cpu_to_le32(bmap_entry);
        !           547:             s->header.blocks_allocated++;
        !           548:             offset = s->header.offset_data / SECTOR_SIZE +
        !           549:                      (uint64_t)bmap_entry * s->block_sectors;
        !           550:             if (block == NULL) {
        !           551:                 block = g_malloc(s->block_size);
        !           552:                 bmap_first = block_index;
1.1       root      553:             }
1.1.1.7 ! root      554:             bmap_last = block_index;
        !           555:             /* Copy data to be written to new block and zero unused parts. */
        !           556:             memset(block, 0, sector_in_block * SECTOR_SIZE);
        !           557:             memcpy(block + sector_in_block * SECTOR_SIZE,
        !           558:                    buf, n_sectors * SECTOR_SIZE);
        !           559:             memset(block + (sector_in_block + n_sectors) * SECTOR_SIZE, 0,
        !           560:                    (s->block_sectors - n_sectors - sector_in_block) * SECTOR_SIZE);
        !           561:             ret = bdrv_write(bs->file, offset, block, s->block_sectors);
        !           562:         } else {
        !           563:             uint64_t offset = s->header.offset_data / SECTOR_SIZE +
        !           564:                               (uint64_t)bmap_entry * s->block_sectors +
        !           565:                               sector_in_block;
        !           566:             ret = bdrv_write(bs->file, offset, buf, n_sectors);
1.1       root      567:         }
                    568: 
1.1.1.7 ! root      569:         nb_sectors -= n_sectors;
        !           570:         sector_num += n_sectors;
        !           571:         buf += n_sectors * SECTOR_SIZE;
1.1       root      572: 
1.1.1.7 ! root      573:         logout("%u sectors written\n", n_sectors);
1.1       root      574:     }
                    575: 
1.1.1.7 ! root      576:     logout("finished data write\n");
        !           577:     if (ret < 0) {
        !           578:         return ret;
1.1       root      579:     }
                    580: 
1.1.1.7 ! root      581:     if (block) {
        !           582:         /* One or more new blocks were allocated. */
        !           583:         VdiHeader *header = (VdiHeader *) block;
        !           584:         uint8_t *base;
        !           585:         uint64_t offset;
1.1       root      586: 
1.1.1.7 ! root      587:         logout("now writing modified header\n");
        !           588:         assert(VDI_IS_ALLOCATED(bmap_first));
        !           589:         *header = s->header;
        !           590:         vdi_header_to_le(header);
        !           591:         ret = bdrv_write(bs->file, 0, block, 1);
        !           592:         g_free(block);
        !           593:         block = NULL;
1.1.1.5   root      594: 
1.1.1.7 ! root      595:         if (ret < 0) {
        !           596:             return ret;
1.1.1.5   root      597:         }
1.1.1.7 ! root      598: 
        !           599:         logout("now writing modified block map entry %u...%u\n",
        !           600:                bmap_first, bmap_last);
        !           601:         /* Write modified sectors from block map. */
        !           602:         bmap_first /= (SECTOR_SIZE / sizeof(uint32_t));
        !           603:         bmap_last /= (SECTOR_SIZE / sizeof(uint32_t));
        !           604:         n_sectors = bmap_last - bmap_first + 1;
        !           605:         offset = s->bmap_sector + bmap_first;
        !           606:         base = ((uint8_t *)&s->bmap[0]) + bmap_first * SECTOR_SIZE;
        !           607:         logout("will write %u block map sectors starting from entry %u\n",
        !           608:                n_sectors, bmap_first);
        !           609:         ret = bdrv_write(bs->file, offset, base, n_sectors);
1.1.1.5   root      610:     }
                    611: 
1.1.1.7 ! root      612:     return ret;
1.1       root      613: }
                    614: 
                    615: static int vdi_create(const char *filename, QEMUOptionParameter *options)
                    616: {
                    617:     int fd;
                    618:     int result = 0;
                    619:     uint64_t bytes = 0;
                    620:     uint32_t blocks;
1.1.1.5   root      621:     size_t block_size = DEFAULT_CLUSTER_SIZE;
1.1       root      622:     uint32_t image_type = VDI_TYPE_DYNAMIC;
                    623:     VdiHeader header;
                    624:     size_t i;
                    625:     size_t bmap_size;
                    626:     uint32_t *bmap;
                    627: 
                    628:     logout("\n");
                    629: 
                    630:     /* Read out options. */
                    631:     while (options && options->name) {
                    632:         if (!strcmp(options->name, BLOCK_OPT_SIZE)) {
                    633:             bytes = options->value.n;
                    634: #if defined(CONFIG_VDI_BLOCK_SIZE)
                    635:         } else if (!strcmp(options->name, BLOCK_OPT_CLUSTER_SIZE)) {
                    636:             if (options->value.n) {
                    637:                 /* TODO: Additional checks (SECTOR_SIZE * 2^n, ...). */
                    638:                 block_size = options->value.n;
                    639:             }
                    640: #endif
                    641: #if defined(CONFIG_VDI_STATIC_IMAGE)
                    642:         } else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
                    643:             if (options->value.n) {
                    644:                 image_type = VDI_TYPE_STATIC;
                    645:             }
                    646: #endif
                    647:         }
                    648:         options++;
                    649:     }
                    650: 
                    651:     fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
                    652:               0644);
                    653:     if (fd < 0) {
                    654:         return -errno;
                    655:     }
                    656: 
1.1.1.2   root      657:     /* We need enough blocks to store the given disk size,
                    658:        so always round up. */
                    659:     blocks = (bytes + block_size - 1) / block_size;
                    660: 
1.1       root      661:     bmap_size = blocks * sizeof(uint32_t);
                    662:     bmap_size = ((bmap_size + SECTOR_SIZE - 1) & ~(SECTOR_SIZE -1));
                    663: 
                    664:     memset(&header, 0, sizeof(header));
                    665:     pstrcpy(header.text, sizeof(header.text), VDI_TEXT);
                    666:     header.signature = VDI_SIGNATURE;
                    667:     header.version = VDI_VERSION_1_1;
                    668:     header.header_size = 0x180;
                    669:     header.image_type = image_type;
                    670:     header.offset_bmap = 0x200;
                    671:     header.offset_data = 0x200 + bmap_size;
                    672:     header.sector_size = SECTOR_SIZE;
                    673:     header.disk_size = bytes;
                    674:     header.block_size = block_size;
                    675:     header.blocks_in_image = blocks;
                    676:     if (image_type == VDI_TYPE_STATIC) {
                    677:         header.blocks_allocated = blocks;
                    678:     }
                    679:     uuid_generate(header.uuid_image);
                    680:     uuid_generate(header.uuid_last_snap);
                    681:     /* There is no need to set header.uuid_link or header.uuid_parent here. */
                    682: #if defined(CONFIG_VDI_DEBUG)
                    683:     vdi_header_print(&header);
                    684: #endif
                    685:     vdi_header_to_le(&header);
                    686:     if (write(fd, &header, sizeof(header)) < 0) {
                    687:         result = -errno;
                    688:     }
                    689: 
1.1.1.3   root      690:     bmap = NULL;
                    691:     if (bmap_size > 0) {
1.1.1.6   root      692:         bmap = (uint32_t *)g_malloc0(bmap_size);
1.1.1.3   root      693:     }
1.1       root      694:     for (i = 0; i < blocks; i++) {
                    695:         if (image_type == VDI_TYPE_STATIC) {
                    696:             bmap[i] = i;
                    697:         } else {
                    698:             bmap[i] = VDI_UNALLOCATED;
                    699:         }
                    700:     }
                    701:     if (write(fd, bmap, bmap_size) < 0) {
                    702:         result = -errno;
                    703:     }
1.1.1.6   root      704:     g_free(bmap);
1.1       root      705:     if (image_type == VDI_TYPE_STATIC) {
                    706:         if (ftruncate(fd, sizeof(header) + bmap_size + blocks * block_size)) {
                    707:             result = -errno;
                    708:         }
                    709:     }
                    710: 
                    711:     if (close(fd) < 0) {
                    712:         result = -errno;
                    713:     }
                    714: 
                    715:     return result;
                    716: }
                    717: 
                    718: static void vdi_close(BlockDriverState *bs)
                    719: {
1.1.1.6   root      720:     BDRVVdiState *s = bs->opaque;
                    721: 
                    722:     g_free(s->bmap);
                    723: 
                    724:     migrate_del_blocker(s->migration_blocker);
                    725:     error_free(s->migration_blocker);
1.1       root      726: }
                    727: 
                    728: static QEMUOptionParameter vdi_create_options[] = {
                    729:     {
                    730:         .name = BLOCK_OPT_SIZE,
                    731:         .type = OPT_SIZE,
                    732:         .help = "Virtual disk size"
                    733:     },
                    734: #if defined(CONFIG_VDI_BLOCK_SIZE)
                    735:     {
                    736:         .name = BLOCK_OPT_CLUSTER_SIZE,
                    737:         .type = OPT_SIZE,
1.1.1.5   root      738:         .help = "VDI cluster (block) size",
                    739:         .value = { .n = DEFAULT_CLUSTER_SIZE },
1.1       root      740:     },
                    741: #endif
                    742: #if defined(CONFIG_VDI_STATIC_IMAGE)
                    743:     {
                    744:         .name = BLOCK_OPT_STATIC,
                    745:         .type = OPT_FLAG,
                    746:         .help = "VDI static (pre-allocated) image"
                    747:     },
                    748: #endif
                    749:     /* TODO: An additional option to set UUID values might be useful. */
                    750:     { NULL }
                    751: };
                    752: 
                    753: static BlockDriver bdrv_vdi = {
                    754:     .format_name = "vdi",
                    755:     .instance_size = sizeof(BDRVVdiState),
                    756:     .bdrv_probe = vdi_probe,
                    757:     .bdrv_open = vdi_open,
                    758:     .bdrv_close = vdi_close,
                    759:     .bdrv_create = vdi_create,
1.1.1.7 ! root      760:     .bdrv_co_is_allocated = vdi_co_is_allocated,
1.1       root      761:     .bdrv_make_empty = vdi_make_empty,
                    762: 
1.1.1.7 ! root      763:     .bdrv_read = vdi_co_read,
1.1       root      764: #if defined(CONFIG_VDI_WRITE)
1.1.1.7 ! root      765:     .bdrv_write = vdi_co_write,
1.1       root      766: #endif
                    767: 
                    768:     .bdrv_get_info = vdi_get_info,
                    769: 
                    770:     .create_options = vdi_create_options,
                    771:     .bdrv_check = vdi_check,
                    772: };
                    773: 
                    774: static void bdrv_vdi_init(void)
                    775: {
                    776:     logout("\n");
                    777:     bdrv_register(&bdrv_vdi);
                    778: }
                    779: 
                    780: block_init(bdrv_vdi_init);

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.