diff options
-rw-r--r-- | Makefile.objs | 2 | ||||
-rw-r--r-- | block.c | 384 | ||||
-rw-r--r-- | block.h | 2 | ||||
-rw-r--r-- | block/blkdebug.c | 17 | ||||
-rw-r--r-- | block/bochs.c | 2 | ||||
-rw-r--r-- | block/cloop.c | 2 | ||||
-rw-r--r-- | block/cow.c | 2 | ||||
-rw-r--r-- | block/curl.c | 10 | ||||
-rw-r--r-- | block/dmg.c | 2 | ||||
-rw-r--r-- | block/nbd.c | 2 | ||||
-rw-r--r-- | block/parallels.c | 2 | ||||
-rw-r--r-- | block/qcow.c | 67 | ||||
-rw-r--r-- | block/qcow2-cluster.c | 64 | ||||
-rw-r--r-- | block/qcow2-refcount.c | 86 | ||||
-rw-r--r-- | block/qcow2-snapshot.c | 22 | ||||
-rw-r--r-- | block/qcow2.c | 110 | ||||
-rw-r--r-- | block/qcow2.h | 8 | ||||
-rw-r--r-- | block/raw-posix.c | 62 | ||||
-rw-r--r-- | block/raw-win32.c | 16 | ||||
-rw-r--r-- | block/raw.c | 144 | ||||
-rw-r--r-- | block/vdi.c | 29 | ||||
-rw-r--r-- | block/vmdk.c | 140 | ||||
-rw-r--r-- | block/vpc.c | 32 | ||||
-rw-r--r-- | block/vvfat.c | 2 | ||||
-rw-r--r-- | block_int.h | 6 | ||||
-rw-r--r-- | qemu-img-cmds.hx | 6 | ||||
-rw-r--r-- | qemu-img.c | 104 | ||||
-rw-r--r-- | qemu-img.texi | 12 |
28 files changed, 843 insertions, 494 deletions
diff --git a/Makefile.objs b/Makefile.objs index 1c7c64b1d8..4f65bfbae5 100644 --- a/Makefile.objs +++ b/Makefile.objs @@ -12,7 +12,7 @@ block-obj-y += nbd.o block.o aio.o aes.o osdep.o qemu-config.o block-obj-$(CONFIG_POSIX) += posix-aio-compat.o block-obj-$(CONFIG_LINUX_AIO) += linux-aio.o -block-nested-y += cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o +block-nested-y += raw.o cow.o qcow.o vdi.o vmdk.o cloop.o dmg.o bochs.o vpc.o vvfat.o block-nested-y += qcow2.o qcow2-refcount.o qcow2-cluster.o qcow2-snapshot.o block-nested-y += parallels.o nbd.o blkdebug.o block-nested-$(CONFIG_WIN32) += raw-win32.o @@ -54,6 +54,7 @@ static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); static int bdrv_write_em(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors); +static BlockDriver *find_protocol(const char *filename); static QTAILQ_HEAD(, BlockDriverState) bdrv_states = QTAILQ_HEAD_INITIALIZER(bdrv_states); @@ -203,6 +204,18 @@ int bdrv_create(BlockDriver *drv, const char* filename, return drv->bdrv_create(filename, options); } +int bdrv_create_file(const char* filename, QEMUOptionParameter *options) +{ + BlockDriver *drv; + + drv = find_protocol(filename); + if (drv == NULL) { + drv = bdrv_find_format("file"); + } + + return bdrv_create(drv, filename, options); +} + #ifdef _WIN32 void get_tmp_filename(char *filename, int size) { @@ -246,6 +259,28 @@ int is_windows_drive(const char *filename) } #endif +/* + * Detect host devices. By convention, /dev/cdrom[N] is always + * recognized as a host CDROM. + */ +static BlockDriver *find_hdev_driver(const char *filename) +{ + int score_max = 0, score; + BlockDriver *drv = NULL, *d; + + QLIST_FOREACH(d, &bdrv_drivers, list) { + if (d->bdrv_probe_device) { + score = d->bdrv_probe_device(filename); + if (score > score_max) { + score_max = score; + drv = d; + } + } + } + + return drv; +} + static BlockDriver *find_protocol(const char *filename) { BlockDriver *drv1; @@ -253,14 +288,21 @@ static BlockDriver *find_protocol(const char *filename) int len; const char *p; + /* TODO Drivers without bdrv_file_open must be specified explicitly */ + #ifdef _WIN32 if (is_windows_drive(filename) || is_windows_drive_prefix(filename)) - return bdrv_find_format("raw"); + return bdrv_find_format("file"); #endif p = strchr(filename, ':'); - if (!p) - return bdrv_find_format("raw"); + if (!p) { + drv1 = find_hdev_driver(filename); + if (!drv1) { + drv1 = bdrv_find_format("file"); + } + return drv1; + } len = p - filename; if (len > sizeof(protocol) - 1) len = sizeof(protocol) - 1; @@ -275,28 +317,6 @@ static BlockDriver *find_protocol(const char *filename) return NULL; } -/* - * Detect host devices. By convention, /dev/cdrom[N] is always - * recognized as a host CDROM. - */ -static BlockDriver *find_hdev_driver(const char *filename) -{ - int score_max = 0, score; - BlockDriver *drv = NULL, *d; - - QLIST_FOREACH(d, &bdrv_drivers, list) { - if (d->bdrv_probe_device) { - score = d->bdrv_probe_device(filename); - if (score > score_max) { - score_max = score; - drv = d; - } - } - } - - return drv; -} - static BlockDriver *find_image_format(const char *filename) { int ret, score, score_max; @@ -319,6 +339,7 @@ static BlockDriver *find_image_format(const char *filename) } score_max = 0; + drv = NULL; QLIST_FOREACH(drv1, &bdrv_drivers, list) { if (drv1->bdrv_probe) { score = drv1->bdrv_probe(buf, ret, filename); @@ -331,6 +352,118 @@ static BlockDriver *find_image_format(const char *filename) return drv; } +/** + * Set the current 'total_sectors' value + */ +static int refresh_total_sectors(BlockDriverState *bs, int64_t hint) +{ + BlockDriver *drv = bs->drv; + + /* query actual device if possible, otherwise just trust the hint */ + if (drv->bdrv_getlength) { + int64_t length = drv->bdrv_getlength(bs); + if (length < 0) { + return length; + } + hint = length >> BDRV_SECTOR_BITS; + } + + bs->total_sectors = hint; + return 0; +} + +/* + * Common part for opening disk images and files + */ +static int bdrv_open_common(BlockDriverState *bs, const char *filename, + int flags, BlockDriver *drv) +{ + int ret, open_flags; + + assert(drv != NULL); + + bs->file = NULL; + bs->total_sectors = 0; + bs->is_temporary = 0; + bs->encrypted = 0; + bs->valid_key = 0; + bs->open_flags = flags; + /* buffer_alignment defaulted to 512, drivers can change this value */ + bs->buffer_alignment = 512; + + pstrcpy(bs->filename, sizeof(bs->filename), filename); + + if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) { + return -ENOTSUP; + } + + bs->drv = drv; + bs->opaque = qemu_mallocz(drv->instance_size); + + /* + * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a + * write cache to the guest. We do need the fdatasync to flush + * out transactions for block allocations, and we maybe have a + * volatile write cache in our backing device to deal with. + */ + if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE)) + bs->enable_write_cache = 1; + + /* + * Clear flags that are internal to the block layer before opening the + * image. + */ + open_flags = flags & ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); + + /* + * Snapshots should be writeable. + */ + if (bs->is_temporary) { + open_flags |= BDRV_O_RDWR; + } + + /* Open the image, either directly or using a protocol */ + if (drv->bdrv_file_open) { + ret = drv->bdrv_file_open(bs, filename, open_flags); + } else { + ret = bdrv_file_open(&bs->file, filename, open_flags); + if (ret >= 0) { + ret = drv->bdrv_open(bs, open_flags); + } + } + + if (ret < 0) { + goto free_and_fail; + } + + bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR); + + ret = refresh_total_sectors(bs, bs->total_sectors); + if (ret < 0) { + goto free_and_fail; + } + +#ifndef _WIN32 + if (bs->is_temporary) { + unlink(filename); + } +#endif + return 0; + +free_and_fail: + if (bs->file) { + bdrv_delete(bs->file); + bs->file = NULL; + } + qemu_free(bs->opaque); + bs->opaque = NULL; + bs->drv = NULL; + return ret; +} + +/* + * Opens a file using a protocol (file, host_device, nbd, ...) + */ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags) { BlockDriverState *bs; @@ -343,7 +476,7 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags) } bs = bdrv_new(""); - ret = bdrv_open(bs, filename, flags, drv); + ret = bdrv_open_common(bs, filename, flags, drv); if (ret < 0) { bdrv_delete(bs); return ret; @@ -353,19 +486,13 @@ int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags) return 0; } +/* + * Opens a disk image (raw, qcow2, vmdk, ...) + */ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, BlockDriver *drv) { - int ret, open_flags; - char tmp_filename[PATH_MAX]; - char backing_filename[PATH_MAX]; - - bs->is_temporary = 0; - bs->encrypted = 0; - bs->valid_key = 0; - bs->open_flags = flags; - /* buffer_alignment defaulted to 512, drivers can change this value */ - bs->buffer_alignment = 512; + int ret; if (flags & BDRV_O_SNAPSHOT) { BlockDriverState *bs1; @@ -373,6 +500,8 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, int is_protocol = 0; BlockDriver *bdrv_qcow2; QEMUOptionParameter *options; + char tmp_filename[PATH_MAX]; + char backing_filename[PATH_MAX]; /* if snapshot, we create a temporary backing file and open it instead of opening 'filename' directly */ @@ -411,6 +540,7 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, } ret = bdrv_create(bdrv_qcow2, tmp_filename, options); + free_option_parameters(options); if (ret < 0) { return ret; } @@ -420,66 +550,28 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, bs->is_temporary = 1; } - pstrcpy(bs->filename, sizeof(bs->filename), filename); - + /* Find the right image format driver */ if (!drv) { - drv = find_hdev_driver(filename); - if (!drv) { - drv = find_image_format(filename); - } + drv = find_image_format(filename); } if (!drv) { ret = -ENOENT; goto unlink_and_fail; } - if (use_bdrv_whitelist && !bdrv_is_whitelisted(drv)) { - ret = -ENOTSUP; - goto unlink_and_fail; - } - bs->drv = drv; - bs->opaque = qemu_mallocz(drv->instance_size); - - /* - * Yes, BDRV_O_NOCACHE aka O_DIRECT means we have to present a - * write cache to the guest. We do need the fdatasync to flush - * out transactions for block allocations, and we maybe have a - * volatile write cache in our backing device to deal with. - */ - if (flags & (BDRV_O_CACHE_WB|BDRV_O_NOCACHE)) - bs->enable_write_cache = 1; - - /* - * Clear flags that are internal to the block layer before opening the - * image. - */ - open_flags = flags & ~(BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); - - /* - * Snapshots should be writeable. - */ - if (bs->is_temporary) { - open_flags |= BDRV_O_RDWR; - } - - ret = drv->bdrv_open(bs, filename, open_flags); + /* Open the image */ + ret = bdrv_open_common(bs, filename, flags, drv); if (ret < 0) { - goto free_and_fail; + goto unlink_and_fail; } - bs->keep_read_only = bs->read_only = !(open_flags & BDRV_O_RDWR); - if (drv->bdrv_getlength) { - bs->total_sectors = bdrv_getlength(bs) >> BDRV_SECTOR_BITS; - } -#ifndef _WIN32 - if (bs->is_temporary) { - unlink(filename); - } -#endif + /* If there is a backing file, use it */ if ((flags & BDRV_O_NO_BACKING) == 0 && bs->backing_file[0] != '\0') { - /* if there is a backing file, use it */ + char backing_filename[PATH_MAX]; + int back_flags; BlockDriver *back_drv = NULL; + bs->backing_hd = bdrv_new(""); path_combine(backing_filename, sizeof(backing_filename), filename, bs->backing_file); @@ -487,9 +579,10 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, back_drv = bdrv_find_format(bs->backing_format); /* backing files always opened read-only */ - open_flags &= ~BDRV_O_RDWR; + back_flags = + flags & ~(BDRV_O_RDWR | BDRV_O_SNAPSHOT | BDRV_O_NO_BACKING); - ret = bdrv_open(bs->backing_hd, backing_filename, open_flags, back_drv); + ret = bdrv_open(bs->backing_hd, backing_filename, back_flags, back_drv); if (ret < 0) { bdrv_close(bs); return ret; @@ -508,23 +601,23 @@ int bdrv_open(BlockDriverState *bs, const char *filename, int flags, if (bs->change_cb) bs->change_cb(bs->change_opaque); } + return 0; -free_and_fail: - qemu_free(bs->opaque); - bs->opaque = NULL; - bs->drv = NULL; unlink_and_fail: - if (bs->is_temporary) + if (bs->is_temporary) { unlink(filename); + } return ret; } void bdrv_close(BlockDriverState *bs) { if (bs->drv) { - if (bs->backing_hd) + if (bs->backing_hd) { bdrv_delete(bs->backing_hd); + bs->backing_hd = NULL; + } bs->drv->bdrv_close(bs); qemu_free(bs->opaque); #ifdef _WIN32 @@ -535,6 +628,10 @@ void bdrv_close(BlockDriverState *bs) bs->opaque = NULL; bs->drv = NULL; + if (bs->file != NULL) { + bdrv_close(bs->file); + } + /* call the change callback */ bs->media_changed = 1; if (bs->change_cb) @@ -550,6 +647,10 @@ void bdrv_delete(BlockDriverState *bs) } bdrv_close(bs); + if (bs->file != NULL) { + bdrv_delete(bs->file); + } + qemu_free(bs); } @@ -780,6 +881,10 @@ int bdrv_write(BlockDriverState *bs, int64_t sector_num, set_dirty_bitmap(bs, sector_num, nb_sectors, 1); } + if (bs->wr_highest_sector < sector_num + nb_sectors - 1) { + bs->wr_highest_sector = sector_num + nb_sectors - 1; + } + return drv->bdrv_write(bs, sector_num, buf, nb_sectors); } @@ -883,13 +988,18 @@ int bdrv_pwrite(BlockDriverState *bs, int64_t offset, int bdrv_truncate(BlockDriverState *bs, int64_t offset) { BlockDriver *drv = bs->drv; + int ret; if (!drv) return -ENOMEDIUM; if (!drv->bdrv_truncate) return -ENOTSUP; if (bs->read_only) return -EACCES; - return drv->bdrv_truncate(bs, offset); + ret = drv->bdrv_truncate(bs, offset); + if (ret == 0) { + ret = refresh_total_sectors(bs, offset >> BDRV_SECTOR_BITS); + } + return ret; } /** @@ -900,8 +1010,12 @@ int64_t bdrv_getlength(BlockDriverState *bs) BlockDriver *drv = bs->drv; if (!drv) return -ENOMEDIUM; - if (!drv->bdrv_getlength) { - /* legacy mode */ + + /* Fixed size devices use the total_sectors value for speed instead of + issuing a length query (like lseek) on each call. Also, legacy block + drivers don't provide a bdrv_getlength function and must use + total_sectors. */ + if (!bs->growable || !drv->bdrv_getlength) { return bs->total_sectors * BDRV_SECTOR_SIZE; } return drv->bdrv_getlength(bs); @@ -1208,6 +1322,19 @@ void bdrv_flush_all(void) } } +int bdrv_has_zero_init(BlockDriverState *bs) +{ + assert(bs->drv); + + if (bs->drv->no_zero_init) { + return 0; + } else if (bs->file) { + return bdrv_has_zero_init(bs->file); + } + + return 1; +} + /* * Returns true iff the specified sector is present in the disk image. Drivers * not implementing the functionality are assumed to not support backing files, @@ -1408,6 +1535,35 @@ void bdrv_stats_print(Monitor *mon, const QObject *data) qlist_iter(qobject_to_qlist(data), bdrv_stats_iter, mon); } +static QObject* bdrv_info_stats_bs(BlockDriverState *bs) +{ + QObject *res; + QDict *dict; + + res = qobject_from_jsonf("{ 'stats': {" + "'rd_bytes': %" PRId64 "," + "'wr_bytes': %" PRId64 "," + "'rd_operations': %" PRId64 "," + "'wr_operations': %" PRId64 "," + "'wr_highest_offset': %" PRId64 + "} }", + bs->rd_bytes, bs->wr_bytes, + bs->rd_ops, bs->wr_ops, + bs->wr_highest_sector * 512); + dict = qobject_to_qdict(res); + + if (*bs->device_name) { + qdict_put(dict, "device", qstring_from_str(bs->device_name)); + } + + if (bs->file) { + QObject *parent = bdrv_info_stats_bs(bs->file); + qdict_put_obj(dict, "parent", parent); + } + + return res; +} + /** * bdrv_info_stats(): show block device statistics * @@ -1422,19 +1578,34 @@ void bdrv_stats_print(Monitor *mon, const QObject *data) * - "wr_bytes": bytes written * - "rd_operations": read operations * - "wr_operations": write operations - * + * - "wr_highest_offset": Highest offset of a sector written since the + * BlockDriverState has been opened + * - "parent": Contains recursively the statistics of the underlying + * protocol (e.g. the host file for a qcow2 image). If there is no + * underlying protocol, this field is omitted. + * * Example: * * [ { "device": "ide0-hd0", * "stats": { "rd_bytes": 512, * "wr_bytes": 0, * "rd_operations": 1, - * "wr_operations": 0 } }, + * "wr_operations": 0, + * "wr_highest_offset": 0, + * "parent": { + * "stats": { "rd_bytes": 1024, + * "wr_bytes": 0, + * "rd_operations": 2, + * "wr_operations": 0, + * "wr_highest_offset": 0, + * } + * } } }, * { "device": "ide1-cd0", * "stats": { "rd_bytes": 0, * "wr_bytes": 0, * "rd_operations": 0, - * "wr_operations": 0 } } ] + * "wr_operations": 0, + * "wr_highest_offset": 0 } }, */ void bdrv_info_stats(Monitor *mon, QObject **ret_data) { @@ -1445,15 +1616,7 @@ void bdrv_info_stats(Monitor *mon, QObject **ret_data) devices = qlist_new(); QTAILQ_FOREACH(bs, &bdrv_states, list) { - obj = qobject_from_jsonf("{ 'device': %s, 'stats': {" - "'rd_bytes': %" PRId64 "," - "'wr_bytes': %" PRId64 "," - "'rd_operations': %" PRId64 "," - "'wr_operations': %" PRId64 - "} }", - bs->device_name, - bs->rd_bytes, bs->wr_bytes, - bs->rd_ops, bs->wr_ops); + obj = bdrv_info_stats_bs(bs); qlist_append_obj(devices, obj); } @@ -1712,9 +1875,12 @@ BlockDriverAIOCB *bdrv_aio_writev(BlockDriverState *bs, int64_t sector_num, cb, opaque); if (ret) { - /* Update stats even though technically transfer has not happened. */ - bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE; - bs->wr_ops ++; + /* Update stats even though technically transfer has not happened. */ + bs->wr_bytes += (unsigned) nb_sectors * BDRV_SECTOR_SIZE; + bs->wr_ops ++; + if (bs->wr_highest_sector < sector_num + nb_sectors - 1) { + bs->wr_highest_sector = sector_num + nb_sectors - 1; + } } return ret; @@ -57,6 +57,7 @@ BlockDriver *bdrv_find_format(const char *format_name); BlockDriver *bdrv_find_whitelisted_format(const char *format_name); int bdrv_create(BlockDriver *drv, const char* filename, QEMUOptionParameter *options); +int bdrv_create_file(const char* filename, QEMUOptionParameter *options); BlockDriverState *bdrv_new(const char *device_name); void bdrv_delete(BlockDriverState *bs); int bdrv_file_open(BlockDriverState **pbs, const char *filename, int flags); @@ -121,6 +122,7 @@ BlockDriverAIOCB *bdrv_aio_ioctl(BlockDriverState *bs, void bdrv_flush(BlockDriverState *bs); void bdrv_flush_all(void); +int bdrv_has_zero_init(BlockDriverState *bs); int bdrv_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum); diff --git a/block/blkdebug.c b/block/blkdebug.c index 643c3978f8..bb4a91abc7 100644 --- a/block/blkdebug.c +++ b/block/blkdebug.c @@ -44,7 +44,6 @@ typedef struct BlkdebugVars { } BlkdebugVars; typedef struct BDRVBlkdebugState { - BlockDriverState *hd; BlkdebugVars vars; QLIST_HEAD(list, BlkdebugRule) rules[BLKDBG_EVENT_MAX]; } BDRVBlkdebugState; @@ -303,7 +302,7 @@ static int blkdebug_open(BlockDriverState *bs, const char *filename, int flags) filename = c + 1; /* Open the backing file */ - ret = bdrv_file_open(&s->hd, filename, flags); + ret = bdrv_file_open(&bs->file, filename, flags); if (ret < 0) { return ret; } @@ -362,7 +361,7 @@ static BlockDriverAIOCB *blkdebug_aio_readv(BlockDriverState *bs, } BlockDriverAIOCB *acb = - bdrv_aio_readv(s->hd, sector_num, qiov, nb_sectors, cb, opaque); + bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); return acb; } @@ -377,7 +376,7 @@ static BlockDriverAIOCB *blkdebug_aio_writev(BlockDriverState *bs, } BlockDriverAIOCB *acb = - bdrv_aio_writev(s->hd, sector_num, qiov, nb_sectors, cb, opaque); + bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); return acb; } @@ -393,21 +392,17 @@ static void blkdebug_close(BlockDriverState *bs) qemu_free(rule); } } - - bdrv_delete(s->hd); } static void blkdebug_flush(BlockDriverState *bs) { - BDRVBlkdebugState *s = bs->opaque; - bdrv_flush(s->hd); + bdrv_flush(bs->file); } static BlockDriverAIOCB *blkdebug_aio_flush(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque) { - BDRVBlkdebugState *s = bs->opaque; - return bdrv_aio_flush(s->hd, cb, opaque); + return bdrv_aio_flush(bs->file, cb, opaque); } static void process_rule(BlockDriverState *bs, struct BlkdebugRule *rule, @@ -456,7 +451,7 @@ static BlockDriver bdrv_blkdebug = { .instance_size = sizeof(BDRVBlkdebugState), - .bdrv_open = blkdebug_open, + .bdrv_file_open = blkdebug_open, .bdrv_close = blkdebug_close, .bdrv_flush = blkdebug_flush, diff --git a/block/bochs.c b/block/bochs.c index fb83594dba..e952670cd1 100644 --- a/block/bochs.c +++ b/block/bochs.c @@ -252,7 +252,7 @@ static BlockDriver bdrv_bochs = { .format_name = "bochs", .instance_size = sizeof(BDRVBochsState), .bdrv_probe = bochs_probe, - .bdrv_open = bochs_open, + .bdrv_file_open = bochs_open, .bdrv_read = bochs_read, .bdrv_close = bochs_close, }; diff --git a/block/cloop.c b/block/cloop.c index 06c687e690..e4f995b5d6 100644 --- a/block/cloop.c +++ b/block/cloop.c @@ -158,7 +158,7 @@ static BlockDriver bdrv_cloop = { .format_name = "cloop", .instance_size = sizeof(BDRVCloopState), .bdrv_probe = cloop_probe, - .bdrv_open = cloop_open, + .bdrv_file_open = cloop_open, .bdrv_read = cloop_read, .bdrv_close = cloop_close, }; diff --git a/block/cow.c b/block/cow.c index 97e9745fc9..fde066ec32 100644 --- a/block/cow.c +++ b/block/cow.c @@ -291,7 +291,7 @@ static BlockDriver bdrv_cow = { .format_name = "cow", .instance_size = sizeof(BDRVCowState), .bdrv_probe = cow_probe, - .bdrv_open = cow_open, + .bdrv_file_open = cow_open, .bdrv_read = cow_read, .bdrv_write = cow_write, .bdrv_close = cow_close, diff --git a/block/curl.c b/block/curl.c index 2cf72cb4e8..b944740fb9 100644 --- a/block/curl.c +++ b/block/curl.c @@ -495,7 +495,7 @@ static BlockDriver bdrv_http = { .protocol_name = "http", .instance_size = sizeof(BDRVCURLState), - .bdrv_open = curl_open, + .bdrv_file_open = curl_open, .bdrv_close = curl_close, .bdrv_getlength = curl_getlength, @@ -507,7 +507,7 @@ static BlockDriver bdrv_https = { .protocol_name = "https", .instance_size = sizeof(BDRVCURLState), - .bdrv_open = curl_open, + .bdrv_file_open = curl_open, .bdrv_close = curl_close, .bdrv_getlength = curl_getlength, @@ -519,7 +519,7 @@ static BlockDriver bdrv_ftp = { .protocol_name = "ftp", .instance_size = sizeof(BDRVCURLState), - .bdrv_open = curl_open, + .bdrv_file_open = curl_open, .bdrv_close = curl_close, .bdrv_getlength = curl_getlength, @@ -531,7 +531,7 @@ static BlockDriver bdrv_ftps = { .protocol_name = "ftps", .instance_size = sizeof(BDRVCURLState), - .bdrv_open = curl_open, + .bdrv_file_open = curl_open, .bdrv_close = curl_close, .bdrv_getlength = curl_getlength, @@ -543,7 +543,7 @@ static BlockDriver bdrv_tftp = { .protocol_name = "tftp", .instance_size = sizeof(BDRVCURLState), - .bdrv_open = curl_open, + .bdrv_file_open = curl_open, .bdrv_close = curl_close, .bdrv_getlength = curl_getlength, diff --git a/block/dmg.c b/block/dmg.c index f4c01c76b6..d5c1a687e4 100644 --- a/block/dmg.c +++ b/block/dmg.c @@ -288,7 +288,7 @@ static BlockDriver bdrv_dmg = { .format_name = "dmg", .instance_size = sizeof(BDRVDMGState), .bdrv_probe = dmg_probe, - .bdrv_open = dmg_open, + .bdrv_file_open = dmg_open, .bdrv_read = dmg_read, .bdrv_close = dmg_close, }; diff --git a/block/nbd.c b/block/nbd.c index 7bac38d086..a1ec123a63 100644 --- a/block/nbd.c +++ b/block/nbd.c @@ -177,7 +177,7 @@ static int64_t nbd_getlength(BlockDriverState *bs) static BlockDriver bdrv_nbd = { .format_name = "nbd", .instance_size = sizeof(BDRVNBDState), - .bdrv_open = nbd_open, + .bdrv_file_open = nbd_open, .bdrv_read = nbd_read, .bdrv_write = nbd_write, .bdrv_close = nbd_close, diff --git a/block/parallels.c b/block/parallels.c index 41b3a7c9db..b2171016f1 100644 --- a/block/parallels.c +++ b/block/parallels.c @@ -167,7 +167,7 @@ static BlockDriver bdrv_parallels = { .format_name = "parallels", .instance_size = sizeof(BDRVParallelsState), .bdrv_probe = parallels_probe, - .bdrv_open = parallels_open, + .bdrv_file_open = parallels_open, .bdrv_read = parallels_read, .bdrv_close = parallels_close, }; diff --git a/block/qcow.c b/block/qcow.c index c619984a03..2883c40f87 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -76,7 +76,7 @@ typedef struct BDRVQcowState { AES_KEY aes_decrypt_key; } BDRVQcowState; -static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); +static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) { @@ -90,16 +90,13 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int qcow_open(BlockDriverState *bs, const char *filename, int flags) +static int qcow_open(BlockDriverState *bs, int flags) { BDRVQcowState *s = bs->opaque; - int len, i, shift, ret; + int len, i, shift; QCowHeader header; - ret = bdrv_file_open(&s->hd, filename, flags); - if (ret < 0) - return ret; - if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header)) + if (bdrv_pread(bs->file, 0, &header, sizeof(header)) != sizeof(header)) goto fail; be32_to_cpus(&header.magic); be32_to_cpus(&header.version); @@ -135,7 +132,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) s->l1_table = qemu_malloc(s->l1_size * sizeof(uint64_t)); if (!s->l1_table) goto fail; - if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) != + if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) != s->l1_size * sizeof(uint64_t)) goto fail; for(i = 0;i < s->l1_size; i++) { @@ -158,7 +155,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) len = header.backing_file_size; if (len > 1023) len = 1023; - if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len) + if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len) goto fail; bs->backing_file[len] = '\0'; } @@ -169,7 +166,6 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) qemu_free(s->l2_cache); qemu_free(s->cluster_cache); qemu_free(s->cluster_data); - bdrv_delete(s->hd); return -1; } @@ -271,13 +267,13 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, if (!allocate) return 0; /* allocate a new l2 entry */ - l2_offset = bdrv_getlength(s->hd); + l2_offset = bdrv_getlength(bs->file); /* round to cluster size */ l2_offset = (l2_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); /* update the L1 entry */ s->l1_table[l1_index] = l2_offset; tmp = cpu_to_be64(l2_offset); - if (bdrv_pwrite(s->hd, s->l1_table_offset + l1_index * sizeof(tmp), + if (bdrv_pwrite(bs->file, s->l1_table_offset + l1_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp)) return 0; new_l2_table = 1; @@ -306,11 +302,11 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, l2_table = s->l2_cache + (min_index << s->l2_bits); if (new_l2_table) { memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); - if (bdrv_pwrite(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != + if (bdrv_pwrite(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != s->l2_size * sizeof(uint64_t)) return 0; } else { - if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != + if (bdrv_pread(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != s->l2_size * sizeof(uint64_t)) return 0; } @@ -329,22 +325,22 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, /* if the cluster is already compressed, we must decompress it in the case it is not completely overwritten */ - if (decompress_cluster(s, cluster_offset) < 0) + if (decompress_cluster(bs, cluster_offset) < 0) return 0; - cluster_offset = bdrv_getlength(s->hd); + cluster_offset = bdrv_getlength(bs->file); cluster_offset = (cluster_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); /* write the cluster content */ - if (bdrv_pwrite(s->hd, cluster_offset, s->cluster_cache, s->cluster_size) != + if (bdrv_pwrite(bs->file, cluster_offset, s->cluster_cache, s->cluster_size) != s->cluster_size) return -1; } else { - cluster_offset = bdrv_getlength(s->hd); + cluster_offset = bdrv_getlength(bs->file); if (allocate == 1) { /* round to cluster size */ cluster_offset = (cluster_offset + s->cluster_size - 1) & ~(s->cluster_size - 1); - bdrv_truncate(s->hd, cluster_offset + s->cluster_size); + bdrv_truncate(bs->file, cluster_offset + s->cluster_size); /* if encrypted, we must initialize the cluster content which won't be written */ if (s->crypt_method && @@ -358,7 +354,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, s->cluster_data, s->cluster_data + 512, 1, 1, &s->aes_encrypt_key); - if (bdrv_pwrite(s->hd, cluster_offset + i * 512, + if (bdrv_pwrite(bs->file, cluster_offset + i * 512, s->cluster_data, 512) != 512) return -1; } @@ -372,7 +368,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, /* update L2 table */ tmp = cpu_to_be64(cluster_offset); l2_table[l2_index] = tmp; - if (bdrv_pwrite(s->hd, + if (bdrv_pwrite(bs->file, l2_offset + l2_index * sizeof(tmp), &tmp, sizeof(tmp)) != sizeof(tmp)) return 0; } @@ -422,8 +418,9 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size, return 0; } -static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) +static int decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset) { + BDRVQcowState *s = bs->opaque; int ret, csize; uint64_t coffset; @@ -431,7 +428,7 @@ static int decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) if (s->cluster_cache_offset != coffset) { csize = cluster_offset >> (63 - s->cluster_bits); csize &= (s->cluster_size - 1); - ret = bdrv_pread(s->hd, coffset, s->cluster_data, csize); + ret = bdrv_pread(bs->file, coffset, s->cluster_data, csize); if (ret != csize) return -1; if (decompress_buffer(s->cluster_cache, s->cluster_size, @@ -468,11 +465,11 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, memset(buf, 0, 512 * n); } } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) { - if (decompress_cluster(s, cluster_offset) < 0) + if (decompress_cluster(bs, cluster_offset) < 0) return -1; memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n); } else { - ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); + ret = bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512); if (ret != n * 512) return -1; if (s->crypt_method) { @@ -601,7 +598,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) } } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { /* add AIO support for compressed blocks ? */ - if (decompress_cluster(s, acb->cluster_offset) < 0) + if (decompress_cluster(bs, acb->cluster_offset) < 0) goto done; memcpy(acb->buf, s->cluster_cache + index_in_cluster * 512, 512 * acb->n); @@ -614,7 +611,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) acb->hd_iov.iov_base = (void *)acb->buf; acb->hd_iov.iov_len = acb->n * 512; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - acb->hd_aiocb = bdrv_aio_readv(s->hd, + acb->hd_aiocb = bdrv_aio_readv(bs->file, (acb->cluster_offset >> 9) + index_in_cluster, &acb->hd_qiov, acb->n, qcow_aio_read_cb, acb); if (acb->hd_aiocb == NULL) @@ -699,7 +696,7 @@ static void qcow_aio_write_cb(void *opaque, int ret) acb->hd_iov.iov_base = (void *)src_buf; acb->hd_iov.iov_len = acb->n * 512; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - acb->hd_aiocb = bdrv_aio_writev(s->hd, + acb->hd_aiocb = bdrv_aio_writev(bs->file, (cluster_offset >> 9) + index_in_cluster, &acb->hd_qiov, acb->n, qcow_aio_write_cb, acb); @@ -739,7 +736,6 @@ static void qcow_close(BlockDriverState *bs) qemu_free(s->l2_cache); qemu_free(s->cluster_cache); qemu_free(s->cluster_data); - bdrv_delete(s->hd); } static int qcow_create(const char *filename, QEMUOptionParameter *options) @@ -839,9 +835,9 @@ static int qcow_make_empty(BlockDriverState *bs) int ret; memset(s->l1_table, 0, l1_length); - if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0) + if (bdrv_pwrite(bs->file, s->l1_table_offset, s->l1_table, l1_length) < 0) return -1; - ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length); + ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length); if (ret < 0) return ret; @@ -902,7 +898,7 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, cluster_offset = get_cluster_offset(bs, sector_num << 9, 2, out_len, 0, 0); cluster_offset &= s->cluster_offset_mask; - if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) { + if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) { qemu_free(out_buf); return -1; } @@ -914,16 +910,13 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, static void qcow_flush(BlockDriverState *bs) { - BDRVQcowState *s = bs->opaque; - bdrv_flush(s->hd); + bdrv_flush(bs->file); } static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque) { - BDRVQcowState *s = bs->opaque; - - return bdrv_aio_flush(s->hd, cb, opaque); + return bdrv_aio_flush(bs->file, cb, opaque); } static int qcow_get_info(BlockDriverState *bs, BlockDriverInfo *bdi) diff --git a/block/qcow2-cluster.c b/block/qcow2-cluster.c index 639e05e989..c11680d12a 100644 --- a/block/qcow2-cluster.c +++ b/block/qcow2-cluster.c @@ -54,27 +54,27 @@ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size) memcpy(new_l1_table, s->l1_table, s->l1_size * sizeof(uint64_t)); /* write new table (align to cluster) */ - BLKDBG_EVENT(s->hd, BLKDBG_L1_GROW_ALLOC_TABLE); + BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ALLOC_TABLE); new_l1_table_offset = qcow2_alloc_clusters(bs, new_l1_size2); if (new_l1_table_offset < 0) { qemu_free(new_l1_table); return new_l1_table_offset; } - BLKDBG_EVENT(s->hd, BLKDBG_L1_GROW_WRITE_TABLE); + BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_WRITE_TABLE); for(i = 0; i < s->l1_size; i++) new_l1_table[i] = cpu_to_be64(new_l1_table[i]); - ret = bdrv_pwrite(s->hd, new_l1_table_offset, new_l1_table, new_l1_size2); + ret = bdrv_pwrite(bs->file, new_l1_table_offset, new_l1_table, new_l1_size2); if (ret != new_l1_size2) goto fail; for(i = 0; i < s->l1_size; i++) new_l1_table[i] = be64_to_cpu(new_l1_table[i]); /* set new table */ - BLKDBG_EVENT(s->hd, BLKDBG_L1_GROW_ACTIVATE_TABLE); + BLKDBG_EVENT(bs->file, BLKDBG_L1_GROW_ACTIVATE_TABLE); cpu_to_be32w((uint32_t*)data, new_l1_size); cpu_to_be64w((uint64_t*)(data + 4), new_l1_table_offset); - ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, l1_size), data,sizeof(data)); + ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, l1_size), data,sizeof(data)); if (ret != sizeof(data)) { goto fail; } @@ -174,8 +174,8 @@ static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset) min_index = l2_cache_new_entry(bs); l2_table = s->l2_cache + (min_index << s->l2_bits); - BLKDBG_EVENT(s->hd, BLKDBG_L2_LOAD); - if (bdrv_pread(s->hd, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != + BLKDBG_EVENT(bs->file, BLKDBG_L2_LOAD); + if (bdrv_pread(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)) != s->l2_size * sizeof(uint64_t)) return NULL; s->l2_cache_offsets[min_index] = l2_offset; @@ -189,8 +189,9 @@ static uint64_t *l2_load(BlockDriverState *bs, uint64_t l2_offset) * and we really don't want bdrv_pread to perform a read-modify-write) */ #define L1_ENTRIES_PER_SECTOR (512 / 8) -static int write_l1_entry(BDRVQcowState *s, int l1_index) +static int write_l1_entry(BlockDriverState *bs, int l1_index) { + BDRVQcowState *s = bs->opaque; uint64_t buf[L1_ENTRIES_PER_SECTOR]; int l1_start_index; int i, ret; @@ -200,8 +201,8 @@ static int write_l1_entry(BDRVQcowState *s, int l1_index) buf[i] = cpu_to_be64(s->l1_table[l1_start_index + i]); } - BLKDBG_EVENT(s->hd, BLKDBG_L1_UPDATE); - ret = bdrv_pwrite(s->hd, s->l1_table_offset + 8 * l1_start_index, + BLKDBG_EVENT(bs->file, BLKDBG_L1_UPDATE); + ret = bdrv_pwrite(bs->file, s->l1_table_offset + 8 * l1_start_index, buf, sizeof(buf)); if (ret < 0) { return ret; @@ -241,7 +242,7 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table) /* update the L1 entry */ s->l1_table[l1_index] = l2_offset | QCOW_OFLAG_COPIED; - ret = write_l1_entry(s, l1_index); + ret = write_l1_entry(bs, l1_index); if (ret < 0) { return ret; } @@ -256,16 +257,16 @@ static int l2_allocate(BlockDriverState *bs, int l1_index, uint64_t **table) memset(l2_table, 0, s->l2_size * sizeof(uint64_t)); } else { /* if there was an old l2 table, read it from the disk */ - BLKDBG_EVENT(s->hd, BLKDBG_L2_ALLOC_COW_READ); - ret = bdrv_pread(s->hd, old_l2_offset, l2_table, + BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_COW_READ); + ret = bdrv_pread(bs->file, old_l2_offset, l2_table, s->l2_size * sizeof(uint64_t)); if (ret < 0) { return ret; } } /* write the l2 table to the file */ - BLKDBG_EVENT(s->hd, BLKDBG_L2_ALLOC_WRITE); - ret = bdrv_pwrite(s->hd, l2_offset, l2_table, + BLKDBG_EVENT(bs->file, BLKDBG_L2_ALLOC_WRITE); + ret = bdrv_pwrite(bs->file, l2_offset, l2_table, s->l2_size * sizeof(uint64_t)); if (ret < 0) { return ret; @@ -348,7 +349,7 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, /* read from the base image */ n1 = qcow2_backing_read1(bs->backing_hd, sector_num, buf, n); if (n1 > 0) { - BLKDBG_EVENT(s->hd, BLKDBG_READ_BACKING); + BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING); ret = bdrv_read(bs->backing_hd, sector_num, buf, n1); if (ret < 0) return -1; @@ -357,12 +358,12 @@ static int qcow_read(BlockDriverState *bs, int64_t sector_num, memset(buf, 0, 512 * n); } } else if (cluster_offset & QCOW_OFLAG_COMPRESSED) { - if (qcow2_decompress_cluster(s, cluster_offset) < 0) + if (qcow2_decompress_cluster(bs, cluster_offset) < 0) return -1; memcpy(buf, s->cluster_cache + index_in_cluster * 512, 512 * n); } else { - BLKDBG_EVENT(s->hd, BLKDBG_READ); - ret = bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512); + BLKDBG_EVENT(bs->file, BLKDBG_READ); + ret = bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512); if (ret != n * 512) return -1; if (s->crypt_method) { @@ -386,7 +387,7 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect, n = n_end - n_start; if (n <= 0) return 0; - BLKDBG_EVENT(s->hd, BLKDBG_COW_READ); + BLKDBG_EVENT(bs->file, BLKDBG_COW_READ); ret = qcow_read(bs, start_sect + n_start, s->cluster_data, n); if (ret < 0) return ret; @@ -396,8 +397,8 @@ static int copy_sectors(BlockDriverState *bs, uint64_t start_sect, s->cluster_data, n, 1, &s->aes_encrypt_key); } - BLKDBG_EVENT(s->hd, BLKDBG_COW_WRITE); - ret = bdrv_write(s->hd, (cluster_offset >> 9) + n_start, + BLKDBG_EVENT(bs->file, BLKDBG_COW_WRITE); + ret = bdrv_write(bs->file, (cluster_offset >> 9) + n_start, s->cluster_data, n); if (ret < 0) return ret; @@ -610,9 +611,9 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, /* compressed clusters never have the copied flag */ - BLKDBG_EVENT(s->hd, BLKDBG_L2_UPDATE_COMPRESSED); + BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE_COMPRESSED); l2_table[l2_index] = cpu_to_be64(cluster_offset); - if (bdrv_pwrite(s->hd, + if (bdrv_pwrite(bs->file, l2_offset + l2_index * sizeof(uint64_t), l2_table + l2_index, sizeof(uint64_t)) != sizeof(uint64_t)) @@ -626,7 +627,7 @@ uint64_t qcow2_alloc_compressed_cluster_offset(BlockDriverState *bs, * read-modify-write in bdrv_pwrite */ #define L2_ENTRIES_PER_SECTOR (512 / 8) -static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table, +static int write_l2_entries(BlockDriverState *bs, uint64_t *l2_table, uint64_t l2_offset, int l2_index, int num) { int l2_start_index = l2_index & ~(L1_ENTRIES_PER_SECTOR - 1); @@ -635,8 +636,8 @@ static int write_l2_entries(BDRVQcowState *s, uint64_t *l2_table, size_t len = end_offset - start_offset; int ret; - BLKDBG_EVENT(s->hd, BLKDBG_L2_UPDATE); - ret = bdrv_pwrite(s->hd, l2_offset + start_offset, + BLKDBG_EVENT(bs->file, BLKDBG_L2_UPDATE); + ret = bdrv_pwrite(bs->file, l2_offset + start_offset, &l2_table[l2_start_index], len); if (ret < 0) { return ret; @@ -693,7 +694,7 @@ int qcow2_alloc_cluster_link_l2(BlockDriverState *bs, QCowL2Meta *m) (i << s->cluster_bits)) | QCOW_OFLAG_COPIED); } - ret = write_l2_entries(s, l2_table, l2_offset, l2_index, m->nb_clusters); + ret = write_l2_entries(bs, l2_table, l2_offset, l2_index, m->nb_clusters); if (ret < 0) { goto err; } @@ -877,8 +878,9 @@ static int decompress_buffer(uint8_t *out_buf, int out_buf_size, return 0; } -int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) +int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset) { + BDRVQcowState *s = bs->opaque; int ret, csize, nb_csectors, sector_offset; uint64_t coffset; @@ -887,8 +889,8 @@ int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset) nb_csectors = ((cluster_offset >> s->csize_shift) & s->csize_mask) + 1; sector_offset = coffset & 511; csize = nb_csectors * 512 - sector_offset; - BLKDBG_EVENT(s->hd, BLKDBG_READ_COMPRESSED); - ret = bdrv_read(s->hd, coffset >> 9, s->cluster_data, nb_csectors); + BLKDBG_EVENT(bs->file, BLKDBG_READ_COMPRESSED); + ret = bdrv_read(bs->file, coffset >> 9, s->cluster_data, nb_csectors); if (ret < 0) { return -1; } diff --git a/block/qcow2-refcount.c b/block/qcow2-refcount.c index 47c9978845..744107cd1d 100644 --- a/block/qcow2-refcount.c +++ b/block/qcow2-refcount.c @@ -34,16 +34,17 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, static int cache_refcount_updates = 0; -static int write_refcount_block(BDRVQcowState *s) +static int write_refcount_block(BlockDriverState *bs) { + BDRVQcowState *s = bs->opaque; size_t size = s->cluster_size; if (s->refcount_block_cache_offset == 0) { return 0; } - BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_UPDATE); - if (bdrv_pwrite(s->hd, s->refcount_block_cache_offset, + BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE); + if (bdrv_pwrite(bs->file, s->refcount_block_cache_offset, s->refcount_block_cache, size) != size) { return -EIO; @@ -64,8 +65,8 @@ int qcow2_refcount_init(BlockDriverState *bs) refcount_table_size2 = s->refcount_table_size * sizeof(uint64_t); s->refcount_table = qemu_malloc(refcount_table_size2); if (s->refcount_table_size > 0) { - BLKDBG_EVENT(s->hd, BLKDBG_REFTABLE_LOAD); - ret = bdrv_pread(s->hd, s->refcount_table_offset, + BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_LOAD); + ret = bdrv_pread(bs->file, s->refcount_table_offset, s->refcount_table, refcount_table_size2); if (ret != refcount_table_size2) goto fail; @@ -92,11 +93,11 @@ static int load_refcount_block(BlockDriverState *bs, int ret; if (cache_refcount_updates) { - write_refcount_block(s); + write_refcount_block(bs); } - BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_LOAD); - ret = bdrv_pread(s->hd, refcount_block_offset, s->refcount_block_cache, + BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_LOAD); + ret = bdrv_pread(bs->file, refcount_block_offset, s->refcount_block_cache, s->cluster_size); if (ret != s->cluster_size) return -EIO; @@ -167,7 +168,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) unsigned int refcount_table_index; int ret; - BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC); + BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC); /* Find the refcount block for the given cluster */ refcount_table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); @@ -212,7 +213,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) */ if (cache_refcount_updates) { - ret = write_refcount_block(s); + ret = write_refcount_block(bs); if (ret < 0) { return ret; } @@ -244,8 +245,8 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) } /* Now the new refcount block needs to be written to disk */ - BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC_WRITE); - ret = bdrv_pwrite(s->hd, new_block, s->refcount_block_cache, + BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE); + ret = bdrv_pwrite(bs->file, new_block, s->refcount_block_cache, s->cluster_size); if (ret < 0) { goto fail_block; @@ -254,8 +255,8 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) /* If the refcount table is big enough, just hook the block up there */ if (refcount_table_index < s->refcount_table_size) { uint64_t data64 = cpu_to_be64(new_block); - BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC_HOOKUP); - ret = bdrv_pwrite(s->hd, + BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_HOOKUP); + ret = bdrv_pwrite(bs->file, s->refcount_table_offset + refcount_table_index * sizeof(uint64_t), &data64, sizeof(data64)); if (ret < 0) { @@ -277,7 +278,7 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) * refcount table at once without producing an inconsistent state in * between. */ - BLKDBG_EVENT(s->hd, BLKDBG_REFTABLE_GROW); + BLKDBG_EVENT(bs->file, BLKDBG_REFTABLE_GROW); /* Calculate the number of refcount blocks needed so far */ uint64_t refcount_block_clusters = 1 << (s->cluster_bits - REFCOUNT_SHIFT); @@ -334,8 +335,8 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) } /* Write refcount blocks to disk */ - BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS); - ret = bdrv_pwrite(s->hd, meta_offset, new_blocks, + BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_BLOCKS); + ret = bdrv_pwrite(bs->file, meta_offset, new_blocks, blocks_clusters * s->cluster_size); qemu_free(new_blocks); if (ret < 0) { @@ -347,8 +348,8 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) cpu_to_be64s(&new_table[i]); } - BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE); - ret = bdrv_pwrite(s->hd, table_offset, new_table, + BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_WRITE_TABLE); + ret = bdrv_pwrite(bs->file, table_offset, new_table, table_size * sizeof(uint64_t)); if (ret < 0) { goto fail_table; @@ -362,8 +363,8 @@ static int64_t alloc_refcount_block(BlockDriverState *bs, int64_t cluster_index) uint8_t data[12]; cpu_to_be64w((uint64_t*)data, table_offset); cpu_to_be32w((uint32_t*)(data + 8), table_clusters); - BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE); - ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, refcount_table_offset), + BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_ALLOC_SWITCH_TABLE); + ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, refcount_table_offset), data, sizeof(data)); if (ret < 0) { goto fail_table; @@ -398,9 +399,10 @@ fail_block: } #define REFCOUNTS_PER_SECTOR (512 >> REFCOUNT_SHIFT) -static int write_refcount_block_entries(BDRVQcowState *s, +static int write_refcount_block_entries(BlockDriverState *bs, int64_t refcount_block_offset, int first_index, int last_index) { + BDRVQcowState *s = bs->opaque; size_t size; if (cache_refcount_updates) { @@ -412,8 +414,8 @@ static int write_refcount_block_entries(BDRVQcowState *s, & ~(REFCOUNTS_PER_SECTOR - 1); size = (last_index - first_index) << REFCOUNT_SHIFT; - BLKDBG_EVENT(s->hd, BLKDBG_REFBLOCK_UPDATE_PART); - if (bdrv_pwrite(s->hd, + BLKDBG_EVENT(bs->file, BLKDBG_REFBLOCK_UPDATE_PART); + if (bdrv_pwrite(bs->file, refcount_block_offset + (first_index << REFCOUNT_SHIFT), &s->refcount_block_cache[first_index], size) != size) { @@ -458,7 +460,7 @@ static int QEMU_WARN_UNUSED_RESULT update_refcount(BlockDriverState *bs, table_index = cluster_index >> (s->cluster_bits - REFCOUNT_SHIFT); if ((old_table_index >= 0) && (table_index != old_table_index)) { - if (write_refcount_block_entries(s, refcount_block_offset, + if (write_refcount_block_entries(bs, refcount_block_offset, first_index, last_index) < 0) { return -EIO; @@ -503,7 +505,7 @@ fail: /* Write last changed block to disk */ if (refcount_block_offset != 0) { - if (write_refcount_block_entries(s, refcount_block_offset, + if (write_refcount_block_entries(bs, refcount_block_offset, first_index, last_index) < 0) { return ret < 0 ? ret : -EIO; @@ -554,8 +556,8 @@ static int64_t alloc_clusters_noref(BlockDriverState *bs, int64_t size) nb_clusters = size_to_clusters(s, size); retry: for(i = 0; i < nb_clusters; i++) { - int64_t i = s->free_cluster_index++; - if (get_refcount(bs, i) != 0) + int64_t next_cluster_index = s->free_cluster_index++; + if (get_refcount(bs, next_cluster_index) != 0) goto retry; } #ifdef DEBUG_ALLOC2 @@ -568,11 +570,10 @@ retry: int64_t qcow2_alloc_clusters(BlockDriverState *bs, int64_t size) { - BDRVQcowState *s = bs->opaque; int64_t offset; int ret; - BLKDBG_EVENT(s->hd, BLKDBG_CLUSTER_ALLOC); + BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC); offset = alloc_clusters_noref(bs, size); ret = update_refcount(bs, offset, size, 1); if (ret < 0) { @@ -589,7 +590,7 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) int64_t offset, cluster_offset; int free_in_cluster; - BLKDBG_EVENT(s->hd, BLKDBG_CLUSTER_ALLOC_BYTES); + BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_ALLOC_BYTES); assert(size > 0 && size <= s->cluster_size); if (s->free_byte_offset == 0) { s->free_byte_offset = qcow2_alloc_clusters(bs, s->cluster_size); @@ -631,14 +632,13 @@ int64_t qcow2_alloc_bytes(BlockDriverState *bs, int size) void qcow2_free_clusters(BlockDriverState *bs, int64_t offset, int64_t size) { - BDRVQcowState *s = bs->opaque; int ret; - BLKDBG_EVENT(s->hd, BLKDBG_CLUSTER_FREE); + BLKDBG_EVENT(bs->file, BLKDBG_CLUSTER_FREE); ret = update_refcount(bs, offset, size, -1); if (ret < 0) { fprintf(stderr, "qcow2_free_clusters failed: %s\n", strerror(-ret)); - abort(); + /* TODO Remember the clusters to free them later and avoid leaking */ } } @@ -718,7 +718,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, l1_table = NULL; } l1_allocated = 1; - if (bdrv_pread(s->hd, l1_table_offset, + if (bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2) != l1_size2) goto fail; for(i = 0;i < l1_size; i++) @@ -738,7 +738,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, old_l2_offset = l2_offset; l2_offset &= ~QCOW_OFLAG_COPIED; l2_modified = 0; - if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size) + if (bdrv_pread(bs->file, l2_offset, l2_table, l2_size) != l2_size) goto fail; for(j = 0; j < s->l2_size; j++) { offset = be64_to_cpu(l2_table[j]); @@ -777,7 +777,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, } } if (l2_modified) { - if (bdrv_pwrite(s->hd, + if (bdrv_pwrite(bs->file, l2_offset, l2_table, l2_size) != l2_size) goto fail; } @@ -799,7 +799,7 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, if (l1_modified) { for(i = 0; i < l1_size; i++) cpu_to_be64s(&l1_table[i]); - if (bdrv_pwrite(s->hd, l1_table_offset, l1_table, + if (bdrv_pwrite(bs->file, l1_table_offset, l1_table, l1_size2) != l1_size2) goto fail; for(i = 0; i < l1_size; i++) @@ -809,14 +809,14 @@ int qcow2_update_snapshot_refcount(BlockDriverState *bs, qemu_free(l1_table); qemu_free(l2_table); cache_refcount_updates = 0; - write_refcount_block(s); + write_refcount_block(bs); return 0; fail: if (l1_allocated) qemu_free(l1_table); qemu_free(l2_table); cache_refcount_updates = 0; - write_refcount_block(s); + write_refcount_block(bs); return -EIO; } @@ -890,7 +890,7 @@ static int check_refcounts_l2(BlockDriverState *bs, l2_size = s->l2_size * sizeof(uint64_t); l2_table = qemu_malloc(l2_size); - if (bdrv_pread(s->hd, l2_offset, l2_table, l2_size) != l2_size) + if (bdrv_pread(bs->file, l2_offset, l2_table, l2_size) != l2_size) goto fail; /* Do the actual checks */ @@ -982,7 +982,7 @@ static int check_refcounts_l1(BlockDriverState *bs, l1_table = NULL; } else { l1_table = qemu_malloc(l1_size2); - if (bdrv_pread(s->hd, l1_table_offset, + if (bdrv_pread(bs->file, l1_table_offset, l1_table, l1_size2) != l1_size2) goto fail; for(i = 0;i < l1_size; i++) @@ -1051,7 +1051,7 @@ int qcow2_check_refcounts(BlockDriverState *bs) uint16_t *refcount_table; int ret, errors = 0; - size = bdrv_getlength(s->hd); + size = bdrv_getlength(bs->file); nb_clusters = size_to_clusters(s, size); refcount_table = qemu_mallocz(nb_clusters * sizeof(uint16_t)); diff --git a/block/qcow2-snapshot.c b/block/qcow2-snapshot.c index 8ddaea23b8..2a21c1723b 100644 --- a/block/qcow2-snapshot.c +++ b/block/qcow2-snapshot.c @@ -79,7 +79,7 @@ int qcow2_read_snapshots(BlockDriverState *bs) s->snapshots = qemu_mallocz(s->nb_snapshots * sizeof(QCowSnapshot)); for(i = 0; i < s->nb_snapshots; i++) { offset = align_offset(offset, 8); - if (bdrv_pread(s->hd, offset, &h, sizeof(h)) != sizeof(h)) + if (bdrv_pread(bs->file, offset, &h, sizeof(h)) != sizeof(h)) goto fail; offset += sizeof(h); sn = s->snapshots + i; @@ -97,13 +97,13 @@ int qcow2_read_snapshots(BlockDriverState *bs) offset += extra_data_size; sn->id_str = qemu_malloc(id_str_size + 1); - if (bdrv_pread(s->hd, offset, sn->id_str, id_str_size) != id_str_size) + if (bdrv_pread(bs->file, offset, sn->id_str, id_str_size) != id_str_size) goto fail; offset += id_str_size; sn->id_str[id_str_size] = '\0'; sn->name = qemu_malloc(name_size + 1); - if (bdrv_pread(s->hd, offset, sn->name, name_size) != name_size) + if (bdrv_pread(bs->file, offset, sn->name, name_size) != name_size) goto fail; offset += name_size; sn->name[name_size] = '\0'; @@ -158,24 +158,24 @@ static int qcow_write_snapshots(BlockDriverState *bs) h.id_str_size = cpu_to_be16(id_str_size); h.name_size = cpu_to_be16(name_size); offset = align_offset(offset, 8); - if (bdrv_pwrite(s->hd, offset, &h, sizeof(h)) != sizeof(h)) + if (bdrv_pwrite(bs->file, offset, &h, sizeof(h)) != sizeof(h)) goto fail; offset += sizeof(h); - if (bdrv_pwrite(s->hd, offset, sn->id_str, id_str_size) != id_str_size) + if (bdrv_pwrite(bs->file, offset, sn->id_str, id_str_size) != id_str_size) goto fail; offset += id_str_size; - if (bdrv_pwrite(s->hd, offset, sn->name, name_size) != name_size) + if (bdrv_pwrite(bs->file, offset, sn->name, name_size) != name_size) goto fail; offset += name_size; } /* update the various header fields */ data64 = cpu_to_be64(snapshots_offset); - if (bdrv_pwrite(s->hd, offsetof(QCowHeader, snapshots_offset), + if (bdrv_pwrite(bs->file, offsetof(QCowHeader, snapshots_offset), &data64, sizeof(data64)) != sizeof(data64)) goto fail; data32 = cpu_to_be32(s->nb_snapshots); - if (bdrv_pwrite(s->hd, offsetof(QCowHeader, nb_snapshots), + if (bdrv_pwrite(bs->file, offsetof(QCowHeader, nb_snapshots), &data32, sizeof(data32)) != sizeof(data32)) goto fail; @@ -284,7 +284,7 @@ int qcow2_snapshot_create(BlockDriverState *bs, QEMUSnapshotInfo *sn_info) for(i = 0; i < s->l1_size; i++) { l1_table[i] = cpu_to_be64(s->l1_table[i]); } - if (bdrv_pwrite(s->hd, sn->l1_table_offset, + if (bdrv_pwrite(bs->file, sn->l1_table_offset, l1_table, s->l1_size * sizeof(uint64_t)) != (s->l1_size * sizeof(uint64_t))) goto fail; @@ -332,10 +332,10 @@ int qcow2_snapshot_goto(BlockDriverState *bs, const char *snapshot_id) s->l1_size = sn->l1_size; l1_size2 = s->l1_size * sizeof(uint64_t); /* copy the snapshot l1 table to the current l1 table */ - if (bdrv_pread(s->hd, sn->l1_table_offset, + if (bdrv_pread(bs->file, sn->l1_table_offset, s->l1_table, l1_size2) != l1_size2) goto fail; - if (bdrv_pwrite(s->hd, s->l1_table_offset, + if (bdrv_pwrite(bs->file, s->l1_table_offset, s->l1_table, l1_size2) != l1_size2) goto fail; for(i = 0;i < s->l1_size; i++) { diff --git a/block/qcow2.c b/block/qcow2.c index 5436fec56d..21ed6f8753 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -77,7 +77,6 @@ static int qcow_probe(const uint8_t *buf, int buf_size, const char *filename) static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset, uint64_t end_offset) { - BDRVQcowState *s = bs->opaque; QCowExtension ext; uint64_t offset; @@ -95,7 +94,7 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset, printf("attemting to read extended header in offset %lu\n", offset); #endif - if (bdrv_pread(s->hd, offset, &ext, sizeof(ext)) != sizeof(ext)) { + if (bdrv_pread(bs->file, offset, &ext, sizeof(ext)) != sizeof(ext)) { fprintf(stderr, "qcow_handle_extension: ERROR: pread fail from offset %llu\n", (unsigned long long)offset); return 1; @@ -117,7 +116,7 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset, ext.len, sizeof(bs->backing_format)); return 2; } - if (bdrv_pread(s->hd, offset , bs->backing_format, + if (bdrv_pread(bs->file, offset , bs->backing_format, ext.len) != ext.len) return 3; bs->backing_format[ext.len] = '\0'; @@ -138,17 +137,14 @@ static int qcow_read_extensions(BlockDriverState *bs, uint64_t start_offset, } -static int qcow_open(BlockDriverState *bs, const char *filename, int flags) +static int qcow_open(BlockDriverState *bs, int flags) { BDRVQcowState *s = bs->opaque; - int len, i, shift, ret; + int len, i; QCowHeader header; uint64_t ext_end; - ret = bdrv_file_open(&s->hd, filename, flags); - if (ret < 0) - return ret; - if (bdrv_pread(s->hd, 0, &header, sizeof(header)) != sizeof(header)) + if (bdrv_pread(bs->file, 0, &header, sizeof(header)) != sizeof(header)) goto fail; be32_to_cpus(&header.magic); be32_to_cpus(&header.version); @@ -192,8 +188,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) /* read the level 1 table */ s->l1_size = header.l1_size; - shift = s->cluster_bits + s->l2_bits; - s->l1_vm_state_index = (header.size + (1LL << shift) - 1) >> shift; + s->l1_vm_state_index = size_to_l1(s, header.size); /* the L1 table must contain at least enough entries to put header.size bytes */ if (s->l1_size < s->l1_vm_state_index) @@ -202,7 +197,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) if (s->l1_size > 0) { s->l1_table = qemu_mallocz( align_offset(s->l1_size * sizeof(uint64_t), 512)); - if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) != + if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t)) != s->l1_size * sizeof(uint64_t)) goto fail; for(i = 0;i < s->l1_size; i++) { @@ -235,7 +230,7 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) len = header.backing_file_size; if (len > 1023) len = 1023; - if (bdrv_pread(s->hd, header.backing_file_offset, bs->backing_file, len) != len) + if (bdrv_pread(bs->file, header.backing_file_offset, bs->backing_file, len) != len) goto fail; bs->backing_file[len] = '\0'; } @@ -254,7 +249,6 @@ static int qcow_open(BlockDriverState *bs, const char *filename, int flags) qemu_free(s->l2_cache); qemu_free(s->cluster_cache); qemu_free(s->cluster_data); - bdrv_delete(s->hd); return -1; } @@ -429,7 +423,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) acb->hd_iov.iov_base = (void *)acb->buf; acb->hd_iov.iov_len = acb->cur_nr_sectors * 512; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - BLKDBG_EVENT(s->hd, BLKDBG_READ_BACKING_AIO); + BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO); acb->hd_aiocb = bdrv_aio_readv(bs->backing_hd, acb->sector_num, &acb->hd_qiov, acb->cur_nr_sectors, qcow_aio_read_cb, acb); @@ -449,7 +443,7 @@ static void qcow_aio_read_cb(void *opaque, int ret) } } else if (acb->cluster_offset & QCOW_OFLAG_COMPRESSED) { /* add AIO support for compressed blocks ? */ - if (qcow2_decompress_cluster(s, acb->cluster_offset) < 0) + if (qcow2_decompress_cluster(bs, acb->cluster_offset) < 0) goto done; memcpy(acb->buf, s->cluster_cache + index_in_cluster * 512, 512 * acb->cur_nr_sectors); @@ -465,8 +459,8 @@ static void qcow_aio_read_cb(void *opaque, int ret) acb->hd_iov.iov_base = (void *)acb->buf; acb->hd_iov.iov_len = acb->cur_nr_sectors * 512; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - BLKDBG_EVENT(s->hd, BLKDBG_READ_AIO); - acb->hd_aiocb = bdrv_aio_readv(s->hd, + BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO); + acb->hd_aiocb = bdrv_aio_readv(bs->file, (acb->cluster_offset >> 9) + index_in_cluster, &acb->hd_qiov, acb->cur_nr_sectors, qcow_aio_read_cb, acb); @@ -615,8 +609,8 @@ static void qcow_aio_write_cb(void *opaque, int ret) acb->hd_iov.iov_base = (void *)src_buf; acb->hd_iov.iov_len = acb->cur_nr_sectors * 512; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - BLKDBG_EVENT(s->hd, BLKDBG_WRITE_AIO); - acb->hd_aiocb = bdrv_aio_writev(s->hd, + BLKDBG_EVENT(bs->file, BLKDBG_WRITE_AIO); + acb->hd_aiocb = bdrv_aio_writev(bs->file, (acb->cluster_offset >> 9) + index_in_cluster, &acb->hd_qiov, acb->cur_nr_sectors, qcow_aio_write_cb, acb); @@ -663,7 +657,6 @@ static void qcow_close(BlockDriverState *bs) qemu_free(s->cluster_cache); qemu_free(s->cluster_data); qcow2_refcount_close(bs); - bdrv_delete(s->hd); } /* @@ -733,7 +726,7 @@ static int qcow2_update_ext_header(BlockDriverState *bs, backing_file_offset = sizeof(QCowHeader) + offset; } - ret = bdrv_pwrite(s->hd, sizeof(QCowHeader), buf, ext_size); + ret = bdrv_pwrite(bs->file, sizeof(QCowHeader), buf, ext_size); if (ret < 0) { goto fail; } @@ -742,13 +735,13 @@ static int qcow2_update_ext_header(BlockDriverState *bs, uint64_t be_backing_file_offset = cpu_to_be64(backing_file_offset); uint32_t be_backing_file_size = cpu_to_be32(backing_file_len); - ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, backing_file_offset), + ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, backing_file_offset), &be_backing_file_offset, sizeof(uint64_t)); if (ret < 0) { goto fail; } - ret = bdrv_pwrite(s->hd, offsetof(QCowHeader, backing_file_size), + ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, backing_file_size), &be_backing_file_size, sizeof(uint32_t)); if (ret < 0) { goto fail; @@ -789,7 +782,6 @@ static int get_bits_from_size(size_t size) static int preallocate(BlockDriverState *bs) { - BDRVQcowState *s = bs->opaque; uint64_t nb_sectors; uint64_t offset; int num; @@ -832,7 +824,7 @@ static int preallocate(BlockDriverState *bs) if (meta.cluster_offset != 0) { uint8_t buf[512]; memset(buf, 0, 512); - bdrv_write(s->hd, (meta.cluster_offset >> 9) + num - 1, buf, 1); + bdrv_write(bs->file, (meta.cluster_offset >> 9) + num - 1, buf, 1); } return 0; @@ -847,9 +839,9 @@ static int qcow_make_empty(BlockDriverState *bs) int ret; memset(s->l1_table, 0, l1_length); - if (bdrv_pwrite(s->hd, s->l1_table_offset, s->l1_table, l1_length) < 0) + if (bdrv_pwrite(bs->file, s->l1_table_offset, s->l1_table, l1_length) < 0) return -1; - ret = bdrv_truncate(s->hd, s->l1_table_offset + l1_length); + ret = bdrv_truncate(bs->file, s->l1_table_offset + l1_length); if (ret < 0) return ret; @@ -858,6 +850,43 @@ static int qcow_make_empty(BlockDriverState *bs) return 0; } +static int qcow2_truncate(BlockDriverState *bs, int64_t offset) +{ + BDRVQcowState *s = bs->opaque; + int ret, new_l1_size; + + if (offset & 511) { + return -EINVAL; + } + + /* cannot proceed if image has snapshots */ + if (s->nb_snapshots) { + return -ENOTSUP; + } + + /* shrinking is currently not supported */ + if (offset < bs->total_sectors * 512) { + return -ENOTSUP; + } + + new_l1_size = size_to_l1(s, offset); + ret = qcow2_grow_l1_table(bs, new_l1_size); + if (ret < 0) { + return ret; + } + + /* write updated header.size */ + offset = cpu_to_be64(offset); + ret = bdrv_pwrite(bs->file, offsetof(QCowHeader, size), + &offset, sizeof(uint64_t)); + if (ret < 0) { + return ret; + } + + s->l1_vm_state_index = new_l1_size; + return 0; +} + /* XXX: put compressed sectors first, then all the cluster aligned tables to avoid losing bytes in alignment */ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, @@ -872,9 +901,9 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, if (nb_sectors == 0) { /* align end of file to a sector boundary to ease reading with sector based I/Os */ - cluster_offset = bdrv_getlength(s->hd); + cluster_offset = bdrv_getlength(bs->file); cluster_offset = (cluster_offset + 511) & ~511; - bdrv_truncate(s->hd, cluster_offset); + bdrv_truncate(bs->file, cluster_offset); return 0; } @@ -917,8 +946,8 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, if (!cluster_offset) return -1; cluster_offset &= s->cluster_offset_mask; - BLKDBG_EVENT(s->hd, BLKDBG_WRITE_COMPRESSED); - if (bdrv_pwrite(s->hd, cluster_offset, out_buf, out_len) != out_len) { + BLKDBG_EVENT(bs->file, BLKDBG_WRITE_COMPRESSED); + if (bdrv_pwrite(bs->file, cluster_offset, out_buf, out_len) != out_len) { qemu_free(out_buf); return -1; } @@ -930,16 +959,13 @@ static int qcow_write_compressed(BlockDriverState *bs, int64_t sector_num, static void qcow_flush(BlockDriverState *bs) { - BDRVQcowState *s = bs->opaque; - bdrv_flush(s->hd); + bdrv_flush(bs->file); } static BlockDriverAIOCB *qcow_aio_flush(BlockDriverState *bs, BlockDriverCompletionFunc *cb, void *opaque) { - BDRVQcowState *s = bs->opaque; - - return bdrv_aio_flush(s->hd, cb, opaque); + return bdrv_aio_flush(bs->file, cb, opaque); } static int64_t qcow_vm_state_offset(BDRVQcowState *s) @@ -968,7 +994,7 @@ static void dump_refcounts(BlockDriverState *bs) int64_t nb_clusters, k, k1, size; int refcount; - size = bdrv_getlength(s->hd); + size = bdrv_getlength(bs->file); nb_clusters = size_to_clusters(s, size); for(k = 0; k < nb_clusters;) { k1 = k; @@ -988,7 +1014,7 @@ static int qcow_save_vmstate(BlockDriverState *bs, const uint8_t *buf, int growable = bs->growable; int ret; - BLKDBG_EVENT(s->hd, BLKDBG_VMSTATE_SAVE); + BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_SAVE); bs->growable = 1; ret = bdrv_pwrite(bs, qcow_vm_state_offset(s) + pos, buf, size); bs->growable = growable; @@ -1003,7 +1029,7 @@ static int qcow_load_vmstate(BlockDriverState *bs, uint8_t *buf, int growable = bs->growable; int ret; - BLKDBG_EVENT(s->hd, BLKDBG_VMSTATE_LOAD); + BLKDBG_EVENT(bs->file, BLKDBG_VMSTATE_LOAD); bs->growable = 1; ret = bdrv_pread(bs, qcow_vm_state_offset(s) + pos, buf, size); bs->growable = growable; @@ -1060,7 +1086,9 @@ static BlockDriver bdrv_qcow2 = { .bdrv_aio_readv = qcow_aio_readv, .bdrv_aio_writev = qcow_aio_writev, .bdrv_aio_flush = qcow_aio_flush, - .bdrv_write_compressed = qcow_write_compressed, + + .bdrv_truncate = qcow2_truncate, + .bdrv_write_compressed = qcow_write_compressed, .bdrv_snapshot_create = qcow2_snapshot_create, .bdrv_snapshot_goto = qcow2_snapshot_goto, diff --git a/block/qcow2.h b/block/qcow2.h index de9397a3d3..01053b79d9 100644 --- a/block/qcow2.h +++ b/block/qcow2.h @@ -150,6 +150,12 @@ static inline int size_to_clusters(BDRVQcowState *s, int64_t size) return (size + (s->cluster_size - 1)) >> s->cluster_bits; } +static inline int size_to_l1(BDRVQcowState *s, int64_t size) +{ + int shift = s->cluster_bits + s->l2_bits; + return (size + (1ULL << shift) - 1) >> shift; +} + static inline int64_t align_offset(int64_t offset, int n) { offset = (offset + n - 1) & ~(n - 1); @@ -184,7 +190,7 @@ int qcow2_check_refcounts(BlockDriverState *bs); /* qcow2-cluster.c functions */ int qcow2_grow_l1_table(BlockDriverState *bs, int min_size); void qcow2_l2_cache_reset(BlockDriverState *bs); -int qcow2_decompress_cluster(BDRVQcowState *s, uint64_t cluster_offset); +int qcow2_decompress_cluster(BlockDriverState *bs, uint64_t cluster_offset); void qcow2_encrypt_sectors(BDRVQcowState *s, int64_t sector_num, uint8_t *out_buf, const uint8_t *in_buf, int nb_sectors, int enc, diff --git a/block/raw-posix.c b/block/raw-posix.c index 4cda9c1f85..7541ed2abe 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -105,7 +105,6 @@ typedef struct BDRVRawState { int fd; int type; - unsigned int lseek_err_cnt; int open_flags; #if defined(__linux__) /* linux floppy specific */ @@ -134,8 +133,6 @@ static int raw_open_common(BlockDriverState *bs, const char *filename, BDRVRawState *s = bs->opaque; int fd, ret; - s->lseek_err_cnt = 0; - s->open_flags = open_flags | O_BINARY; s->open_flags &= ~O_ACCMODE; if (bdrv_flags & BDRV_O_RDWR) { @@ -243,19 +240,7 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset, if (ret < 0) return ret; - if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { - ++(s->lseek_err_cnt); - if(s->lseek_err_cnt <= 10) { - DEBUG_BLOCK_PRINT("raw_pread(%d:%s, %" PRId64 ", %p, %d) [%" PRId64 - "] lseek failed : %d = %s\n", - s->fd, bs->filename, offset, buf, count, - bs->total_sectors, errno, strerror(errno)); - } - return -1; - } - s->lseek_err_cnt=0; - - ret = read(s->fd, buf, count); + ret = pread(s->fd, buf, count, offset); if (ret == count) goto label__raw_read__success; @@ -276,12 +261,10 @@ static int raw_pread_aligned(BlockDriverState *bs, int64_t offset, /* Try harder for CDrom. */ if (bs->type == BDRV_TYPE_CDROM) { - lseek(s->fd, offset, SEEK_SET); - ret = read(s->fd, buf, count); + ret = pread(s->fd, buf, count, offset); if (ret == count) goto label__raw_read__success; - lseek(s->fd, offset, SEEK_SET); - ret = read(s->fd, buf, count); + ret = pread(s->fd, buf, count, offset); if (ret == count) goto label__raw_read__success; @@ -313,19 +296,7 @@ static int raw_pwrite_aligned(BlockDriverState *bs, int64_t offset, if (ret < 0) return -errno; - if (offset >= 0 && lseek(s->fd, offset, SEEK_SET) == (off_t)-1) { - ++(s->lseek_err_cnt); - if(s->lseek_err_cnt) { - DEBUG_BLOCK_PRINT("raw_pwrite(%d:%s, %" PRId64 ", %p, %d) [%" - PRId64 "] lseek failed : %d = %s\n", - s->fd, bs->filename, offset, buf, count, - bs->total_sectors, errno, strerror(errno)); - } - return -EIO; - } - s->lseek_err_cnt = 0; - - ret = write(s->fd, buf, count); + ret = pwrite(s->fd, buf, count, offset); if (ret == count) goto label__raw_write__success; @@ -768,11 +739,12 @@ static QEMUOptionParameter raw_create_options[] = { { NULL } }; -static BlockDriver bdrv_raw = { - .format_name = "raw", +static BlockDriver bdrv_file = { + .format_name = "file", + .protocol_name = "file", .instance_size = sizeof(BDRVRawState), .bdrv_probe = NULL, /* no probe for protocols */ - .bdrv_open = raw_open, + .bdrv_file_open = raw_open, .bdrv_read = raw_read, .bdrv_write = raw_write, .bdrv_close = raw_close, @@ -1026,9 +998,10 @@ static int hdev_create(const char *filename, QEMUOptionParameter *options) static BlockDriver bdrv_host_device = { .format_name = "host_device", + .protocol_name = "host_device", .instance_size = sizeof(BDRVRawState), .bdrv_probe_device = hdev_probe_device, - .bdrv_open = hdev_open, + .bdrv_file_open = hdev_open, .bdrv_close = raw_close, .bdrv_create = hdev_create, .create_options = raw_create_options, @@ -1140,9 +1113,10 @@ static int floppy_eject(BlockDriverState *bs, int eject_flag) static BlockDriver bdrv_host_floppy = { .format_name = "host_floppy", + .protocol_name = "host_floppy", .instance_size = sizeof(BDRVRawState), .bdrv_probe_device = floppy_probe_device, - .bdrv_open = floppy_open, + .bdrv_file_open = floppy_open, .bdrv_close = raw_close, .bdrv_create = hdev_create, .create_options = raw_create_options, @@ -1239,9 +1213,10 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked) static BlockDriver bdrv_host_cdrom = { .format_name = "host_cdrom", + .protocol_name = "host_cdrom", .instance_size = sizeof(BDRVRawState), .bdrv_probe_device = cdrom_probe_device, - .bdrv_open = cdrom_open, + .bdrv_file_open = cdrom_open, .bdrv_close = raw_close, .bdrv_create = hdev_create, .create_options = raw_create_options, @@ -1361,9 +1336,10 @@ static int cdrom_set_locked(BlockDriverState *bs, int locked) static BlockDriver bdrv_host_cdrom = { .format_name = "host_cdrom", + .protocol_name = "host_cdrom", .instance_size = sizeof(BDRVRawState), .bdrv_probe_device = cdrom_probe_device, - .bdrv_open = cdrom_open, + .bdrv_file_open = cdrom_open, .bdrv_close = raw_close, .bdrv_create = hdev_create, .create_options = raw_create_options, @@ -1385,13 +1361,13 @@ static BlockDriver bdrv_host_cdrom = { }; #endif /* __FreeBSD__ */ -static void bdrv_raw_init(void) +static void bdrv_file_init(void) { /* * Register all the drivers. Note that order is important, the driver * registered last will get probed first. */ - bdrv_register(&bdrv_raw); + bdrv_register(&bdrv_file); bdrv_register(&bdrv_host_device); #ifdef __linux__ bdrv_register(&bdrv_host_floppy); @@ -1402,4 +1378,4 @@ static void bdrv_raw_init(void) #endif } -block_init(bdrv_raw_init); +block_init(bdrv_file_init); diff --git a/block/raw-win32.c b/block/raw-win32.c index 526764f62f..745bbde673 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -238,10 +238,11 @@ static QEMUOptionParameter raw_create_options[] = { { NULL } }; -static BlockDriver bdrv_raw = { - .format_name = "raw", +static BlockDriver bdrv_file = { + .format_name = "file", + .protocol_name = "file", .instance_size = sizeof(BDRVRawState), - .bdrv_open = raw_open, + .bdrv_file_open = raw_open, .bdrv_close = raw_close, .bdrv_create = raw_create, .bdrv_flush = raw_flush, @@ -395,9 +396,10 @@ static int raw_set_locked(BlockDriverState *bs, int locked) static BlockDriver bdrv_host_device = { .format_name = "host_device", + .protocol_name = "host_device", .instance_size = sizeof(BDRVRawState), .bdrv_probe_device = hdev_probe_device, - .bdrv_open = hdev_open, + .bdrv_file_open = hdev_open, .bdrv_close = raw_close, .bdrv_flush = raw_flush, @@ -406,10 +408,10 @@ static BlockDriver bdrv_host_device = { .bdrv_getlength = raw_getlength, }; -static void bdrv_raw_init(void) +static void bdrv_file_init(void) { - bdrv_register(&bdrv_raw); + bdrv_register(&bdrv_file); bdrv_register(&bdrv_host_device); } -block_init(bdrv_raw_init); +block_init(bdrv_file_init); diff --git a/block/raw.c b/block/raw.c new file mode 100644 index 0000000000..4406b8c06b --- /dev/null +++ b/block/raw.c @@ -0,0 +1,144 @@ + +#include "qemu-common.h" +#include "block_int.h" +#include "module.h" + +static int raw_open(BlockDriverState *bs, int flags) +{ + bs->sg = bs->file->sg; + return 0; +} + +static int raw_read(BlockDriverState *bs, int64_t sector_num, + uint8_t *buf, int nb_sectors) +{ + return bdrv_read(bs->file, sector_num, buf, nb_sectors); +} + +static int raw_write(BlockDriverState *bs, int64_t sector_num, + const uint8_t *buf, int nb_sectors) +{ + return bdrv_write(bs->file, sector_num, buf, nb_sectors); +} + +static BlockDriverAIOCB *raw_aio_readv(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + return bdrv_aio_readv(bs->file, sector_num, qiov, nb_sectors, cb, opaque); +} + +static BlockDriverAIOCB *raw_aio_writev(BlockDriverState *bs, + int64_t sector_num, QEMUIOVector *qiov, int nb_sectors, + BlockDriverCompletionFunc *cb, void *opaque) +{ + return bdrv_aio_writev(bs->file, sector_num, qiov, nb_sectors, cb, opaque); +} + +static void raw_close(BlockDriverState *bs) +{ +} + +static void raw_flush(BlockDriverState *bs) +{ + bdrv_flush(bs->file); +} + +static BlockDriverAIOCB *raw_aio_flush(BlockDriverState *bs, + BlockDriverCompletionFunc *cb, void *opaque) +{ + return bdrv_aio_flush(bs->file, cb, opaque); +} + +static int64_t raw_getlength(BlockDriverState *bs) +{ + return bdrv_getlength(bs->file); +} + +static int raw_truncate(BlockDriverState *bs, int64_t offset) +{ + return bdrv_truncate(bs->file, offset); +} + +static int raw_probe(const uint8_t *buf, int buf_size, const char *filename) +{ + return 1; /* everything can be opened as raw image */ +} + +static int raw_is_inserted(BlockDriverState *bs) +{ + return bdrv_is_inserted(bs->file); +} + +static int raw_eject(BlockDriverState *bs, int eject_flag) +{ + return bdrv_eject(bs->file, eject_flag); +} + +static int raw_set_locked(BlockDriverState *bs, int locked) +{ + bdrv_set_locked(bs->file, locked); + return 0; +} + +static int raw_ioctl(BlockDriverState *bs, unsigned long int req, void *buf) +{ + return bdrv_ioctl(bs->file, req, buf); +} + +static BlockDriverAIOCB *raw_aio_ioctl(BlockDriverState *bs, + unsigned long int req, void *buf, + BlockDriverCompletionFunc *cb, void *opaque) +{ + return bdrv_aio_ioctl(bs->file, req, buf, cb, opaque); +} + +static int raw_create(const char *filename, QEMUOptionParameter *options) +{ + return bdrv_create_file(filename, options); +} + +static QEMUOptionParameter raw_create_options[] = { + { + .name = BLOCK_OPT_SIZE, + .type = OPT_SIZE, + .help = "Virtual disk size" + }, + { NULL } +}; + +static BlockDriver bdrv_raw = { + .format_name = "raw", + + /* It's really 0, but we need to make qemu_malloc() happy */ + .instance_size = 1, + + .bdrv_open = raw_open, + .bdrv_close = raw_close, + .bdrv_read = raw_read, + .bdrv_write = raw_write, + .bdrv_flush = raw_flush, + .bdrv_probe = raw_probe, + .bdrv_getlength = raw_getlength, + .bdrv_truncate = raw_truncate, + + .bdrv_aio_readv = raw_aio_readv, + .bdrv_aio_writev = raw_aio_writev, + .bdrv_aio_flush = raw_aio_flush, + + .bdrv_is_inserted = raw_is_inserted, + .bdrv_eject = raw_eject, + .bdrv_set_locked = raw_set_locked, + .bdrv_ioctl = raw_ioctl, + .bdrv_aio_ioctl = raw_aio_ioctl, + + .bdrv_create = raw_create, + .create_options = raw_create_options, +}; + +static void bdrv_raw_init(void) +{ + bdrv_register(&bdrv_raw); +} + +block_init(bdrv_raw_init); diff --git a/block/vdi.c b/block/vdi.c index c91961acb4..1d257b4838 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -376,21 +376,15 @@ static int vdi_probe(const uint8_t *buf, int buf_size, const char *filename) return result; } -static int vdi_open(BlockDriverState *bs, const char *filename, int flags) +static int vdi_open(BlockDriverState *bs, int flags) { BDRVVdiState *s = bs->opaque; VdiHeader header; size_t bmap_size; - int ret; logout("\n"); - ret = bdrv_file_open(&s->hd, filename, flags); - if (ret < 0) { - return ret; - } - - if (bdrv_read(s->hd, 0, (uint8_t *)&header, 1) < 0) { + if (bdrv_read(bs->file, 0, (uint8_t *)&header, 1) < 0) { goto fail; } @@ -442,7 +436,7 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags) bmap_size = header.blocks_in_image * sizeof(uint32_t); bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE; s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE); - if (bdrv_read(s->hd, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) { + if (bdrv_read(bs->file, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) { goto fail_free_bmap; } @@ -452,7 +446,6 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags) qemu_free(s->bmap); fail: - bdrv_delete(s->hd); return -1; } @@ -607,7 +600,7 @@ static void vdi_aio_read_cb(void *opaque, int ret) acb->hd_iov.iov_base = (void *)acb->buf; acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - acb->hd_aiocb = bdrv_aio_readv(s->hd, offset, &acb->hd_qiov, + acb->hd_aiocb = bdrv_aio_readv(bs->file, offset, &acb->hd_qiov, n_sectors, vdi_aio_read_cb, acb); if (acb->hd_aiocb == NULL) { goto done; @@ -670,7 +663,7 @@ static void vdi_aio_write_cb(void *opaque, int ret) acb->hd_iov.iov_base = acb->block_buffer; acb->hd_iov.iov_len = SECTOR_SIZE; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - acb->hd_aiocb = bdrv_aio_writev(s->hd, 0, &acb->hd_qiov, 1, + acb->hd_aiocb = bdrv_aio_writev(bs->file, 0, &acb->hd_qiov, 1, vdi_aio_write_cb, acb); if (acb->hd_aiocb == NULL) { goto done; @@ -699,7 +692,7 @@ static void vdi_aio_write_cb(void *opaque, int ret) qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); logout("will write %u block map sectors starting from entry %u\n", n_sectors, bmap_first); - acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov, + acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov, n_sectors, vdi_aio_write_cb, acb); if (acb->hd_aiocb == NULL) { goto done; @@ -748,7 +741,7 @@ static void vdi_aio_write_cb(void *opaque, int ret) acb->hd_iov.iov_base = (void *)block; acb->hd_iov.iov_len = s->block_size; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, + acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov, s->block_sectors, vdi_aio_write_cb, acb); if (acb->hd_aiocb == NULL) { @@ -761,7 +754,7 @@ static void vdi_aio_write_cb(void *opaque, int ret) acb->hd_iov.iov_base = (void *)acb->buf; acb->hd_iov.iov_len = n_sectors * SECTOR_SIZE; qemu_iovec_init_external(&acb->hd_qiov, &acb->hd_iov, 1); - acb->hd_aiocb = bdrv_aio_writev(s->hd, offset, &acb->hd_qiov, + acb->hd_aiocb = bdrv_aio_writev(bs->file, offset, &acb->hd_qiov, n_sectors, vdi_aio_write_cb, acb); if (acb->hd_aiocb == NULL) { goto done; @@ -891,16 +884,12 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options) static void vdi_close(BlockDriverState *bs) { - BDRVVdiState *s = bs->opaque; - logout("\n"); - bdrv_delete(s->hd); } static void vdi_flush(BlockDriverState *bs) { - BDRVVdiState *s = bs->opaque; logout("\n"); - bdrv_flush(s->hd); + bdrv_flush(bs->file); } diff --git a/block/vmdk.c b/block/vmdk.c index 6fdea1d305..e659908028 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -76,7 +76,6 @@ typedef struct BDRVVmdkState { unsigned int cluster_sectors; uint32_t parent_cid; - int is_parent; } BDRVVmdkState; typedef struct VmdkMetaData { @@ -87,14 +86,6 @@ typedef struct VmdkMetaData { int valid; } VmdkMetaData; -typedef struct ActiveBDRVState{ - BlockDriverState *hd; // active image handler - uint64_t cluster_offset; // current write offset -}ActiveBDRVState; - -static ActiveBDRVState activeBDRV; - - static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) { uint32_t magic; @@ -117,14 +108,13 @@ static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename) static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) { - BDRVVmdkState *s = bs->opaque; char desc[DESC_SIZE]; uint32_t cid; const char *p_name, *cid_str; size_t cid_str_size; /* the descriptor offset = 0x200 */ - if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) + if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE) return 0; if (parent) { @@ -145,12 +135,11 @@ static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent) static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) { - BDRVVmdkState *s = bs->opaque; char desc[DESC_SIZE], tmp_desc[DESC_SIZE]; char *p_name, *tmp_str; /* the descriptor offset = 0x200 */ - if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) + if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE) return -1; tmp_str = strstr(desc,"parentCID"); @@ -161,7 +150,7 @@ static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid) pstrcat(desc, sizeof(desc), tmp_desc); } - if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) + if (bdrv_pwrite(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE) return -1; return 0; } @@ -346,27 +335,17 @@ fail: return ret; } -static void vmdk_parent_close(BlockDriverState *bs) -{ - if (bs->backing_hd) - bdrv_close(bs->backing_hd); -} - -static int parent_open = 0; -static int vmdk_parent_open(BlockDriverState *bs, const char * filename) +static int vmdk_parent_open(BlockDriverState *bs) { - BDRVVmdkState *s = bs->opaque; char *p_name; char desc[DESC_SIZE]; - char parent_img_name[1024]; /* the descriptor offset = 0x200 */ - if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE) + if (bdrv_pread(bs->file, 0x200, desc, DESC_SIZE) != DESC_SIZE) return -1; if ((p_name = strstr(desc,"parentFileNameHint")) != NULL) { char *end_name; - struct stat file_buf; p_name += sizeof("parentFileNameHint") + 1; if ((end_name = strchr(p_name,'\"')) == NULL) @@ -375,51 +354,25 @@ static int vmdk_parent_open(BlockDriverState *bs, const char * filename) return -1; pstrcpy(bs->backing_file, end_name - p_name + 1, p_name); - if (stat(bs->backing_file, &file_buf) != 0) { - path_combine(parent_img_name, sizeof(parent_img_name), - filename, bs->backing_file); - } else { - pstrcpy(parent_img_name, sizeof(parent_img_name), - bs->backing_file); - } - - bs->backing_hd = bdrv_new(""); - if (!bs->backing_hd) { - failure: - bdrv_close(s->hd); - return -1; - } - parent_open = 1; - if (bdrv_open(bs->backing_hd, parent_img_name, 0, NULL) < 0) - goto failure; - parent_open = 0; } return 0; } -static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) +static int vmdk_open(BlockDriverState *bs, int flags) { BDRVVmdkState *s = bs->opaque; uint32_t magic; - int l1_size, i, ret; + int l1_size, i; - if (parent_open) { - /* Parent must be opened as RO, no RDWR. */ - flags = 0; - } - - ret = bdrv_file_open(&s->hd, filename, flags); - if (ret < 0) - return ret; - if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic)) + if (bdrv_pread(bs->file, 0, &magic, sizeof(magic)) != sizeof(magic)) goto fail; magic = be32_to_cpu(magic); if (magic == VMDK3_MAGIC) { VMDK3Header header; - if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header)) + if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)) != sizeof(header)) goto fail; s->cluster_sectors = le32_to_cpu(header.granularity); s->l2_size = 1 << 9; @@ -431,7 +384,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) } else if (magic == VMDK4_MAGIC) { VMDK4Header header; - if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header)) + if (bdrv_pread(bs->file, sizeof(magic), &header, sizeof(header)) != sizeof(header)) goto fail; bs->total_sectors = le64_to_cpu(header.capacity); s->cluster_sectors = le64_to_cpu(header.granularity); @@ -444,13 +397,8 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9; s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9; - if (parent_open) - s->is_parent = 1; - else - s->is_parent = 0; - // try to open parent images, if exist - if (vmdk_parent_open(bs, filename) != 0) + if (vmdk_parent_open(bs) != 0) goto fail; // write the CID once after the image creation s->parent_cid = vmdk_read_cid(bs,1); @@ -461,7 +409,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) /* read the L1 table */ l1_size = s->l1_size * sizeof(uint32_t); s->l1_table = qemu_malloc(l1_size); - if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size) + if (bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, l1_size) != l1_size) goto fail; for(i = 0; i < s->l1_size; i++) { le32_to_cpus(&s->l1_table[i]); @@ -469,7 +417,7 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) if (s->l1_backup_table_offset) { s->l1_backup_table = qemu_malloc(l1_size); - if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size) + if (bdrv_pread(bs->file, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size) goto fail; for(i = 0; i < s->l1_size; i++) { le32_to_cpus(&s->l1_backup_table[i]); @@ -482,7 +430,6 @@ static int vmdk_open(BlockDriverState *bs, const char *filename, int flags) qemu_free(s->l1_backup_table); qemu_free(s->l1_table); qemu_free(s->l2_cache); - bdrv_delete(s->hd); return -1; } @@ -492,30 +439,28 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset, uint64_t offset, int allocate) { - uint64_t parent_cluster_offset; BDRVVmdkState *s = bs->opaque; uint8_t whole_grain[s->cluster_sectors*512]; // 128 sectors * 512 bytes each = grain size 64KB // we will be here if it's first write on non-exist grain(cluster). // try to read from parent image, if exist if (bs->backing_hd) { - BDRVVmdkState *ps = bs->backing_hd->opaque; + int ret; if (!vmdk_is_cid_valid(bs)) return -1; - parent_cluster_offset = get_cluster_offset(bs->backing_hd, NULL, - offset, allocate); - - if (parent_cluster_offset) { - BDRVVmdkState *act_s = activeBDRV.hd->opaque; - - if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) != ps->cluster_sectors*512) - return -1; + ret = bdrv_read(bs->backing_hd, offset >> 9, whole_grain, + s->cluster_sectors); + if (ret < 0) { + return -1; + } - //Write grain only into the active image - if (bdrv_pwrite(act_s->hd, activeBDRV.cluster_offset << 9, whole_grain, sizeof(whole_grain)) != sizeof(whole_grain)) - return -1; + //Write grain only into the active image + ret = bdrv_write(bs->file, cluster_offset, whole_grain, + s->cluster_sectors); + if (ret < 0) { + return -1; } } return 0; @@ -526,13 +471,13 @@ static int vmdk_L2update(BlockDriverState *bs, VmdkMetaData *m_data) BDRVVmdkState *s = bs->opaque; /* update L2 table */ - if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), + if (bdrv_pwrite(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset)) return -1; /* update backup L2 table */ if (s->l1_backup_table_offset != 0) { m_data->l2_offset = s->l1_backup_table[m_data->l1_index]; - if (bdrv_pwrite(s->hd, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), + if (bdrv_pwrite(bs->file, ((int64_t)m_data->l2_offset * 512) + (m_data->l2_index * sizeof(m_data->offset)), &(m_data->offset), sizeof(m_data->offset)) != sizeof(m_data->offset)) return -1; } @@ -580,7 +525,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, } } l2_table = s->l2_cache + (min_index * s->l2_size); - if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) != + if (bdrv_pread(bs->file, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) != s->l2_size * sizeof(uint32_t)) return 0; @@ -593,18 +538,15 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, VmdkMetaData *m_data, if (!cluster_offset) { if (!allocate) return 0; + // Avoid the L2 tables update for the images that have snapshots. - if (!s->is_parent) { - cluster_offset = bdrv_getlength(s->hd); - bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9)); - - cluster_offset >>= 9; - tmp = cpu_to_le32(cluster_offset); - l2_table[l2_index] = tmp; - // Save the active image state - activeBDRV.cluster_offset = cluster_offset; - activeBDRV.hd = bs; - } + cluster_offset = bdrv_getlength(bs->file); + bdrv_truncate(bs->file, cluster_offset + (s->cluster_sectors << 9)); + + cluster_offset >>= 9; + tmp = cpu_to_le32(cluster_offset); + l2_table[l2_index] = tmp; + /* First of all we write grain itself, to avoid race condition * that may to corrupt the image. * This problem may occur because of insufficient space on host disk @@ -666,7 +608,7 @@ static int vmdk_read(BlockDriverState *bs, int64_t sector_num, memset(buf, 0, 512 * n); } } else { - if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) + if(bdrv_pread(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) return -1; } nb_sectors -= n; @@ -702,7 +644,7 @@ static int vmdk_write(BlockDriverState *bs, int64_t sector_num, if (!cluster_offset) return -1; - if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) + if (bdrv_pwrite(bs->file, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512) return -1; if (m_data.valid) { /* update L2 tables */ @@ -879,15 +821,11 @@ static void vmdk_close(BlockDriverState *bs) qemu_free(s->l1_table); qemu_free(s->l2_cache); - // try to close parent image, if exist - vmdk_parent_close(s->hd); - bdrv_delete(s->hd); } static void vmdk_flush(BlockDriverState *bs) { - BDRVVmdkState *s = bs->opaque; - bdrv_flush(s->hd); + bdrv_flush(bs->file); } @@ -914,7 +852,7 @@ static BlockDriver bdrv_vmdk = { .format_name = "vmdk", .instance_size = sizeof(BDRVVmdkState), .bdrv_probe = vmdk_probe, - .bdrv_open = vmdk_open, + .bdrv_open = vmdk_open, .bdrv_read = vmdk_read, .bdrv_write = vmdk_write, .bdrv_close = vmdk_close, diff --git a/block/vpc.c b/block/vpc.c index 950ad58b3b..f94e4698b7 100644 --- a/block/vpc.c +++ b/block/vpc.c @@ -150,20 +150,16 @@ static int vpc_probe(const uint8_t *buf, int buf_size, const char *filename) return 0; } -static int vpc_open(BlockDriverState *bs, const char *filename, int flags) +static int vpc_open(BlockDriverState *bs, int flags) { BDRVVPCState *s = bs->opaque; - int ret, i; + int i; struct vhd_footer* footer; struct vhd_dyndisk_header* dyndisk_header; uint8_t buf[HEADER_SIZE]; uint32_t checksum; - ret = bdrv_file_open(&s->hd, filename, flags); - if (ret < 0) - return ret; - - if (bdrv_pread(s->hd, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE) + if (bdrv_pread(bs->file, 0, s->footer_buf, HEADER_SIZE) != HEADER_SIZE) goto fail; footer = (struct vhd_footer*) s->footer_buf; @@ -174,7 +170,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags) footer->checksum = 0; if (vpc_checksum(s->footer_buf, HEADER_SIZE) != checksum) fprintf(stderr, "block-vpc: The header checksum of '%s' is " - "incorrect.\n", filename); + "incorrect.\n", bs->filename); // The visible size of a image in Virtual PC depends on the geometry // rather than on the size stored in the footer (the size in the footer @@ -182,7 +178,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags) bs->total_sectors = (int64_t) be16_to_cpu(footer->cyls) * footer->heads * footer->secs_per_cyl; - if (bdrv_pread(s->hd, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE) + if (bdrv_pread(bs->file, be64_to_cpu(footer->data_offset), buf, HEADER_SIZE) != HEADER_SIZE) goto fail; @@ -199,7 +195,7 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags) s->pagetable = qemu_malloc(s->max_table_entries * 4); s->bat_offset = be64_to_cpu(dyndisk_header->table_offset); - if (bdrv_pread(s->hd, s->bat_offset, s->pagetable, + if (bdrv_pread(bs->file, s->bat_offset, s->pagetable, s->max_table_entries * 4) != s->max_table_entries * 4) goto fail; @@ -228,7 +224,6 @@ static int vpc_open(BlockDriverState *bs, const char *filename, int flags) return 0; fail: - bdrv_delete(s->hd); return -1; } @@ -266,7 +261,7 @@ static inline int64_t get_sector_offset(BlockDriverState *bs, s->last_bitmap_offset = bitmap_offset; memset(bitmap, 0xff, s->bitmap_size); - bdrv_pwrite(s->hd, bitmap_offset, bitmap, s->bitmap_size); + bdrv_pwrite(bs->file, bitmap_offset, bitmap, s->bitmap_size); } // printf("sector: %" PRIx64 ", index: %x, offset: %x, bioff: %" PRIx64 ", bloff: %" PRIx64 "\n", @@ -316,7 +311,7 @@ static int rewrite_footer(BlockDriverState* bs) BDRVVPCState *s = bs->opaque; int64_t offset = s->free_data_block_offset; - ret = bdrv_pwrite(s->hd, offset, s->footer_buf, HEADER_SIZE); + ret = bdrv_pwrite(bs->file, offset, s->footer_buf, HEADER_SIZE); if (ret < 0) return ret; @@ -351,7 +346,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num) // Initialize the block's bitmap memset(bitmap, 0xff, s->bitmap_size); - bdrv_pwrite(s->hd, s->free_data_block_offset, bitmap, s->bitmap_size); + bdrv_pwrite(bs->file, s->free_data_block_offset, bitmap, s->bitmap_size); // Write new footer (the old one will be overwritten) s->free_data_block_offset += s->block_size + s->bitmap_size; @@ -362,7 +357,7 @@ static int64_t alloc_block(BlockDriverState* bs, int64_t sector_num) // Write BAT entry to disk bat_offset = s->bat_offset + (4 * index); bat_value = be32_to_cpu(s->pagetable[index]); - ret = bdrv_pwrite(s->hd, bat_offset, &bat_value, 4); + ret = bdrv_pwrite(bs->file, bat_offset, &bat_value, 4); if (ret < 0) goto fail; @@ -376,7 +371,6 @@ fail: static int vpc_read(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors) { - BDRVVPCState *s = bs->opaque; int ret; int64_t offset; @@ -386,7 +380,7 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num, if (offset == -1) { memset(buf, 0, 512); } else { - ret = bdrv_pread(s->hd, offset, buf, 512); + ret = bdrv_pread(bs->file, offset, buf, 512); if (ret != 512) return -1; } @@ -401,7 +395,6 @@ static int vpc_read(BlockDriverState *bs, int64_t sector_num, static int vpc_write(BlockDriverState *bs, int64_t sector_num, const uint8_t *buf, int nb_sectors) { - BDRVVPCState *s = bs->opaque; int64_t offset; int ret; @@ -414,7 +407,7 @@ static int vpc_write(BlockDriverState *bs, int64_t sector_num, return -1; } - ret = bdrv_pwrite(s->hd, offset, buf, 512); + ret = bdrv_pwrite(bs->file, offset, buf, 512); if (ret != 512) return -1; @@ -590,7 +583,6 @@ static void vpc_close(BlockDriverState *bs) #ifdef CACHE qemu_free(s->pageentry_u8); #endif - bdrv_delete(s->hd); } static QEMUOptionParameter vpc_create_options[] = { diff --git a/block/vvfat.c b/block/vvfat.c index 66259b48d5..ce16bbd8c4 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2827,7 +2827,7 @@ static void vvfat_close(BlockDriverState *bs) static BlockDriver bdrv_vvfat = { .format_name = "vvfat", .instance_size = sizeof(BDRVVVFATState), - .bdrv_open = vvfat_open, + .bdrv_file_open = vvfat_open, .bdrv_read = vvfat_read, .bdrv_write = vvfat_write, .bdrv_close = vvfat_close, diff --git a/block_int.h b/block_int.h index d4067ff726..1a7240c582 100644 --- a/block_int.h +++ b/block_int.h @@ -51,7 +51,8 @@ struct BlockDriver { int instance_size; int (*bdrv_probe)(const uint8_t *buf, int buf_size, const char *filename); int (*bdrv_probe_device)(const char *filename); - int (*bdrv_open)(BlockDriverState *bs, const char *filename, int flags); + int (*bdrv_open)(BlockDriverState *bs, int flags); + int (*bdrv_file_open)(BlockDriverState *bs, const char *filename, int flags); int (*bdrv_read)(BlockDriverState *bs, int64_t sector_num, uint8_t *buf, int nb_sectors); int (*bdrv_write)(BlockDriverState *bs, int64_t sector_num, @@ -155,6 +156,8 @@ struct BlockDriverState { int media_changed; BlockDriverState *backing_hd; + BlockDriverState *file; + /* async read/write emulation */ void *sync_aiocb; @@ -164,6 +167,7 @@ struct BlockDriverState { uint64_t wr_bytes; uint64_t rd_ops; uint64_t wr_ops; + uint64_t wr_highest_sector; /* Whether the disk can expand beyond total_sectors */ int growable; diff --git a/qemu-img-cmds.hx b/qemu-img-cmds.hx index f96876ae3b..c079019048 100644 --- a/qemu-img-cmds.hx +++ b/qemu-img-cmds.hx @@ -49,5 +49,11 @@ DEF("rebase", img_rebase, "rebase [-f fmt] [-u] -b backing_file [-F backing_fmt] filename") STEXI @item rebase [-f @var{fmt}] [-u] -b @var{backing_file} [-F @var{backing_fmt}] @var{filename} +ETEXI + +DEF("resize", img_resize, + "resize filename [+ | -]size") +STEXI +@item rebase @var{filename} [+ | -]@var{size} @end table ETEXI diff --git a/qemu-img.c b/qemu-img.c index 7203b8bc72..d3c30a74f3 100644 --- a/qemu-img.c +++ b/qemu-img.c @@ -732,6 +732,8 @@ static int img_convert(int argc, char **argv) /* signal EOF to align */ bdrv_write_compressed(out_bs, 0, NULL, 0); } else { + int has_zero_init = bdrv_has_zero_init(out_bs); + sector_num = 0; // total number of sectors converted so far for(;;) { nb_sectors = total_sectors - sector_num; @@ -755,7 +757,7 @@ static int img_convert(int argc, char **argv) if (n > bs_offset + bs_sectors - sector_num) n = bs_offset + bs_sectors - sector_num; - if (!drv->no_zero_init) { + if (has_zero_init) { /* If the output image is being created as a copy on write image, assume that sectors which are unallocated in the input image are present in both the output's and input's base images (no @@ -788,7 +790,7 @@ static int img_convert(int argc, char **argv) If the output is to a host device, we also write out sectors that are entirely 0, since whatever data was already there is garbage, not 0s. */ - if (drv->no_zero_init || out_baseimg || + if (!has_zero_init || out_baseimg || is_allocated_sectors(buf1, n, &n1)) { if (bdrv_write(out_bs, sector_num, buf1, n1) < 0) error("error while writing"); @@ -1134,7 +1136,7 @@ static int img_rebase(int argc, char **argv) if (!unsafe) { uint64_t num_sectors; uint64_t sector; - int n, n1; + int n; uint8_t * buf_old; uint8_t * buf_new; @@ -1153,8 +1155,8 @@ static int img_rebase(int argc, char **argv) } /* If the cluster is allocated, we don't need to take action */ - if (bdrv_is_allocated(bs, sector, n, &n1)) { - n = n1; + ret = bdrv_is_allocated(bs, sector, n, &n); + if (ret) { continue; } @@ -1223,6 +1225,98 @@ static int img_rebase(int argc, char **argv) return 0; } +static int img_resize(int argc, char **argv) +{ + int c, ret, relative; + const char *filename, *fmt, *size; + int64_t n, total_size; + BlockDriverState *bs; + QEMUOptionParameter *param; + QEMUOptionParameter resize_options[] = { + { + .name = BLOCK_OPT_SIZE, + .type = OPT_SIZE, + .help = "Virtual disk size" + }, + { NULL } + }; + + fmt = NULL; + for(;;) { + c = getopt(argc, argv, "f:h"); + if (c == -1) { + break; + } + switch(c) { + case 'h': + help(); + break; + case 'f': + fmt = optarg; + break; + } + } + if (optind + 1 >= argc) { + help(); + } + filename = argv[optind++]; + size = argv[optind++]; + + /* Choose grow, shrink, or absolute resize mode */ + switch (size[0]) { + case '+': + relative = 1; + size++; + break; + case '-': + relative = -1; + size++; + break; + default: + relative = 0; + break; + } + + /* Parse size */ + param = parse_option_parameters("", resize_options, NULL); + if (set_option_parameter(param, BLOCK_OPT_SIZE, size)) { + /* Error message already printed when size parsing fails */ + exit(1); + } + n = get_option_parameter(param, BLOCK_OPT_SIZE)->value.n; + free_option_parameters(param); + + bs = bdrv_new_open(filename, fmt, BDRV_O_FLAGS | BDRV_O_RDWR); + + if (relative) { + total_size = bdrv_getlength(bs) + n * relative; + } else { + total_size = n; + } + if (total_size <= 0) { + error("New image size must be positive"); + } + + ret = bdrv_truncate(bs, total_size); + switch (ret) { + case 0: + printf("Image resized.\n"); + break; + case -ENOTSUP: + error("This image format does not support resize"); + break; + case -EACCES: + error("Image is read-only"); + break; + default: + error("Error resizing image (%d)", -ret); + break; + } + + bdrv_delete(bs); + return 0; +} + static const img_cmd_t img_cmds[] = { #define DEF(option, callback, arg_string) \ { option, callback }, diff --git a/qemu-img.texi b/qemu-img.texi index ac978542c2..c1b1f2717e 100644 --- a/qemu-img.texi +++ b/qemu-img.texi @@ -106,6 +106,18 @@ they are displayed too. @item snapshot [-l | -a @var{snapshot} | -c @var{snapshot} | -d @var{snapshot} ] @var{filename} List, apply, create or delete snapshots in image @var{filename}. + +@item resize @var{filename} [+ | -]@var{size} + +Change the disk image as if it had been created with @var{size}. + +Before using this command to shrink a disk image, you MUST use file system and +partitioning tools inside the VM to reduce allocated file systems and partition +sizes accordingly. Failure to do so will result in data loss! + +After using this command to grow a disk image, you must use file system and +partitioning tools inside the VM to actually begin using the new space on the +device. @end table Supported image file formats: |