diff options
Diffstat (limited to 'block')
-rw-r--r-- | block/backup.c | 6 | ||||
-rw-r--r-- | block/blkverify.c | 4 | ||||
-rw-r--r-- | block/commit.c | 6 | ||||
-rw-r--r-- | block/cow.c | 93 | ||||
-rw-r--r-- | block/iscsi.c | 16 | ||||
-rw-r--r-- | block/mirror.c | 6 | ||||
-rw-r--r-- | block/qapi.c | 50 | ||||
-rw-r--r-- | block/qcow.c | 15 | ||||
-rw-r--r-- | block/qcow2.c | 26 | ||||
-rw-r--r-- | block/qed.c | 41 | ||||
-rw-r--r-- | block/raw-posix.c | 24 | ||||
-rw-r--r-- | block/raw-win32.c | 36 | ||||
-rw-r--r-- | block/raw_bsd.c | 10 | ||||
-rw-r--r-- | block/sheepdog.c | 20 | ||||
-rw-r--r-- | block/snapshot.c | 2 | ||||
-rw-r--r-- | block/stream.c | 12 | ||||
-rw-r--r-- | block/vdi.c | 17 | ||||
-rw-r--r-- | block/vmdk.c | 33 | ||||
-rw-r--r-- | block/vvfat.c | 21 |
19 files changed, 300 insertions, 138 deletions
diff --git a/block/backup.c b/block/backup.c index 23c7264488..04c4b5c263 100644 --- a/block/backup.c +++ b/block/backup.c @@ -289,14 +289,14 @@ static void coroutine_fn backup_run(void *opaque) * backing file. */ for (i = 0; i < BACKUP_SECTORS_PER_CLUSTER;) { - /* bdrv_co_is_allocated() only returns true/false based + /* bdrv_is_allocated() only returns true/false based * on the first set of sectors it comes across that * are are all in the same state. * For that reason we must verify each sector in the * backup cluster length. We end up copying more than * needed but at some point that is always the case. */ alloced = - bdrv_co_is_allocated(bs, + bdrv_is_allocated(bs, start * BACKUP_SECTORS_PER_CLUSTER + i, BACKUP_SECTORS_PER_CLUSTER - i, &n); i += n; @@ -338,7 +338,7 @@ static void coroutine_fn backup_run(void *opaque) hbitmap_free(job->bitmap); bdrv_iostatus_disable(target); - bdrv_delete(target); + bdrv_unref(target); block_job_completed(&job->common, ret); } diff --git a/block/blkverify.c b/block/blkverify.c index 1d58cc3932..c4e961eeb1 100644 --- a/block/blkverify.c +++ b/block/blkverify.c @@ -155,7 +155,7 @@ static int blkverify_open(BlockDriverState *bs, QDict *options, int flags) s->test_file = bdrv_new(""); ret = bdrv_open(s->test_file, filename, NULL, flags, NULL); if (ret < 0) { - bdrv_delete(s->test_file); + bdrv_unref(s->test_file); s->test_file = NULL; goto fail; } @@ -169,7 +169,7 @@ static void blkverify_close(BlockDriverState *bs) { BDRVBlkverifyState *s = bs->opaque; - bdrv_delete(s->test_file); + bdrv_unref(s->test_file); s->test_file = NULL; } diff --git a/block/commit.c b/block/commit.c index 51a1ab3678..ac4b7ccbc9 100644 --- a/block/commit.c +++ b/block/commit.c @@ -108,9 +108,9 @@ wait: break; } /* Copy if allocated above the base */ - ret = bdrv_co_is_allocated_above(top, base, sector_num, - COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE, - &n); + ret = bdrv_is_allocated_above(top, base, sector_num, + COMMIT_BUFFER_SIZE / BDRV_SECTOR_SIZE, + &n); copy = (ret == 1); trace_commit_one_iteration(s, sector_num, n, ret); if (copy) { diff --git a/block/cow.c b/block/cow.c index 1cc2e89c7c..764b93fae0 100644 --- a/block/cow.c +++ b/block/cow.c @@ -106,7 +106,7 @@ static int cow_open(BlockDriverState *bs, QDict *options, int flags) * XXX(hch): right now these functions are extremely inefficient. * We should just read the whole bitmap we'll need in one go instead. */ -static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum) +static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum, bool *first) { uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8; uint8_t bitmap; @@ -117,27 +117,52 @@ static inline int cow_set_bit(BlockDriverState *bs, int64_t bitnum) return ret; } + if (bitmap & (1 << (bitnum % 8))) { + return 0; + } + + if (*first) { + ret = bdrv_flush(bs->file); + if (ret < 0) { + return ret; + } + *first = false; + } + bitmap |= (1 << (bitnum % 8)); - ret = bdrv_pwrite_sync(bs->file, offset, &bitmap, sizeof(bitmap)); + ret = bdrv_pwrite(bs->file, offset, &bitmap, sizeof(bitmap)); if (ret < 0) { return ret; } return 0; } -static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum) +#define BITS_PER_BITMAP_SECTOR (512 * 8) + +/* Cannot use bitmap.c on big-endian machines. */ +static int cow_test_bit(int64_t bitnum, const uint8_t *bitmap) { - uint64_t offset = sizeof(struct cow_header_v2) + bitnum / 8; - uint8_t bitmap; - int ret; + return (bitmap[bitnum / 8] & (1 << (bitnum & 7))) != 0; +} - ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap)); - if (ret < 0) { - return ret; +static int cow_find_streak(const uint8_t *bitmap, int value, int start, int nb_sectors) +{ + int streak_value = value ? 0xFF : 0; + int last = MIN(start + nb_sectors, BITS_PER_BITMAP_SECTOR); + int bitnum = start; + while (bitnum < last) { + if ((bitnum & 7) == 0 && bitmap[bitnum / 8] == streak_value) { + bitnum += 8; + continue; + } + if (cow_test_bit(bitnum, bitmap) == value) { + bitnum++; + continue; + } + break; } - - return !!(bitmap & (1 << (bitnum % 8))); + return MIN(bitnum, last) - start; } /* Return true if first block has been changed (ie. current version is @@ -146,24 +171,33 @@ static inline int is_bit_set(BlockDriverState *bs, int64_t bitnum) static int coroutine_fn cow_co_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *num_same) { + int64_t bitnum = sector_num + sizeof(struct cow_header_v2) * 8; + uint64_t offset = (bitnum / 8) & -BDRV_SECTOR_SIZE; + uint8_t bitmap[BDRV_SECTOR_SIZE]; + int ret; int changed; - if (nb_sectors == 0) { - *num_same = nb_sectors; - return 0; + ret = bdrv_pread(bs->file, offset, &bitmap, sizeof(bitmap)); + if (ret < 0) { + return ret; } - changed = is_bit_set(bs, sector_num); - if (changed < 0) { - return 0; /* XXX: how to return I/O errors? */ - } + bitnum &= BITS_PER_BITMAP_SECTOR - 1; + changed = cow_test_bit(bitnum, bitmap); + *num_same = cow_find_streak(bitmap, changed, bitnum, nb_sectors); + return changed; +} - for (*num_same = 1; *num_same < nb_sectors; (*num_same)++) { - if (is_bit_set(bs, sector_num + *num_same) != changed) - break; +static int64_t coroutine_fn cow_co_get_block_status(BlockDriverState *bs, + int64_t sector_num, int nb_sectors, int *num_same) +{ + BDRVCowState *s = bs->opaque; + int ret = cow_co_is_allocated(bs, sector_num, nb_sectors, num_same); + int64_t offset = s->cow_sectors_offset + (sector_num << BDRV_SECTOR_BITS); + if (ret < 0) { + return ret; } - - return changed; + return (ret ? BDRV_BLOCK_DATA : 0) | offset | BDRV_BLOCK_OFFSET_VALID; } static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num, @@ -171,9 +205,10 @@ static int cow_update_bitmap(BlockDriverState *bs, int64_t sector_num, { int error = 0; int i; + bool first = true; for (i = 0; i < nb_sectors; i++) { - error = cow_set_bit(bs, sector_num + i); + error = cow_set_bit(bs, sector_num + i, &first); if (error) { break; } @@ -189,7 +224,11 @@ static int coroutine_fn cow_read(BlockDriverState *bs, int64_t sector_num, int ret, n; while (nb_sectors > 0) { - if (bdrv_co_is_allocated(bs, sector_num, nb_sectors, &n)) { + ret = cow_co_is_allocated(bs, sector_num, nb_sectors, &n); + if (ret < 0) { + return ret; + } + if (ret) { ret = bdrv_pread(bs->file, s->cow_sectors_offset + sector_num * 512, buf, n * 512); @@ -314,7 +353,7 @@ static int cow_create(const char *filename, QEMUOptionParameter *options) } exit: - bdrv_delete(cow_bs); + bdrv_unref(cow_bs); return ret; } @@ -344,7 +383,7 @@ static BlockDriver bdrv_cow = { .bdrv_read = cow_co_read, .bdrv_write = cow_co_write, - .bdrv_co_is_allocated = cow_co_is_allocated, + .bdrv_co_get_block_status = cow_co_get_block_status, .create_options = cow_create_options, }; diff --git a/block/iscsi.c b/block/iscsi.c index 2bbee1f6e5..813abd8fef 100644 --- a/block/iscsi.c +++ b/block/iscsi.c @@ -1241,11 +1241,11 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options) { int ret = 0; int64_t total_size = 0; - BlockDriverState bs; + BlockDriverState *bs; IscsiLun *iscsilun = NULL; QDict *bs_options; - memset(&bs, 0, sizeof(BlockDriverState)); + bs = bdrv_new(""); /* Read out options */ while (options && options->name) { @@ -1255,12 +1255,12 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options) options++; } - bs.opaque = g_malloc0(sizeof(struct IscsiLun)); - iscsilun = bs.opaque; + bs->opaque = g_malloc0(sizeof(struct IscsiLun)); + iscsilun = bs->opaque; bs_options = qdict_new(); qdict_put(bs_options, "filename", qstring_from_str(filename)); - ret = iscsi_open(&bs, bs_options, 0); + ret = iscsi_open(bs, bs_options, 0); QDECREF(bs_options); if (ret != 0) { @@ -1274,7 +1274,7 @@ static int iscsi_create(const char *filename, QEMUOptionParameter *options) ret = -ENODEV; goto out; } - if (bs.total_sectors < total_size) { + if (bs->total_sectors < total_size) { ret = -ENOSPC; goto out; } @@ -1284,7 +1284,9 @@ out: if (iscsilun->iscsi != NULL) { iscsi_destroy_context(iscsilun->iscsi); } - g_free(bs.opaque); + g_free(bs->opaque); + bs->opaque = NULL; + bdrv_unref(bs); return ret; } diff --git a/block/mirror.c b/block/mirror.c index 86de4582b4..f61a7799de 100644 --- a/block/mirror.c +++ b/block/mirror.c @@ -338,8 +338,8 @@ static void coroutine_fn mirror_run(void *opaque) base = s->mode == MIRROR_SYNC_MODE_FULL ? NULL : bs->backing_hd; for (sector_num = 0; sector_num < end; ) { int64_t next = (sector_num | (sectors_per_chunk - 1)) + 1; - ret = bdrv_co_is_allocated_above(bs, base, - sector_num, next - sector_num, &n); + ret = bdrv_is_allocated_above(bs, base, + sector_num, next - sector_num, &n); if (ret < 0) { goto immediate_exit; @@ -480,7 +480,7 @@ immediate_exit: bdrv_swap(s->target, s->common.bs); } bdrv_close(s->target); - bdrv_delete(s->target); + bdrv_unref(s->target); block_job_completed(&s->common, ret); } diff --git a/block/qapi.c b/block/qapi.c index a4bc4113b7..782051c65d 100644 --- a/block/qapi.c +++ b/block/qapi.c @@ -223,18 +223,44 @@ void bdrv_query_info(BlockDriverState *bs, info->inserted->backing_file_depth = bdrv_get_backing_file_depth(bs); if (bs->io_limits_enabled) { - info->inserted->bps = - bs->io_limits.bps[BLOCK_IO_LIMIT_TOTAL]; - info->inserted->bps_rd = - bs->io_limits.bps[BLOCK_IO_LIMIT_READ]; - info->inserted->bps_wr = - bs->io_limits.bps[BLOCK_IO_LIMIT_WRITE]; - info->inserted->iops = - bs->io_limits.iops[BLOCK_IO_LIMIT_TOTAL]; - info->inserted->iops_rd = - bs->io_limits.iops[BLOCK_IO_LIMIT_READ]; - info->inserted->iops_wr = - bs->io_limits.iops[BLOCK_IO_LIMIT_WRITE]; + ThrottleConfig cfg; + throttle_get_config(&bs->throttle_state, &cfg); + info->inserted->bps = cfg.buckets[THROTTLE_BPS_TOTAL].avg; + info->inserted->bps_rd = cfg.buckets[THROTTLE_BPS_READ].avg; + info->inserted->bps_wr = cfg.buckets[THROTTLE_BPS_WRITE].avg; + + info->inserted->iops = cfg.buckets[THROTTLE_OPS_TOTAL].avg; + info->inserted->iops_rd = cfg.buckets[THROTTLE_OPS_READ].avg; + info->inserted->iops_wr = cfg.buckets[THROTTLE_OPS_WRITE].avg; + + info->inserted->has_bps_max = + cfg.buckets[THROTTLE_BPS_TOTAL].max; + info->inserted->bps_max = + cfg.buckets[THROTTLE_BPS_TOTAL].max; + info->inserted->has_bps_rd_max = + cfg.buckets[THROTTLE_BPS_READ].max; + info->inserted->bps_rd_max = + cfg.buckets[THROTTLE_BPS_READ].max; + info->inserted->has_bps_wr_max = + cfg.buckets[THROTTLE_BPS_WRITE].max; + info->inserted->bps_wr_max = + cfg.buckets[THROTTLE_BPS_WRITE].max; + + info->inserted->has_iops_max = + cfg.buckets[THROTTLE_OPS_TOTAL].max; + info->inserted->iops_max = + cfg.buckets[THROTTLE_OPS_TOTAL].max; + info->inserted->has_iops_rd_max = + cfg.buckets[THROTTLE_OPS_READ].max; + info->inserted->iops_rd_max = + cfg.buckets[THROTTLE_OPS_READ].max; + info->inserted->has_iops_wr_max = + cfg.buckets[THROTTLE_OPS_WRITE].max; + info->inserted->iops_wr_max = + cfg.buckets[THROTTLE_OPS_WRITE].max; + + info->inserted->has_iops_size = cfg.op_size; + info->inserted->iops_size = cfg.op_size; } bs0 = bs; diff --git a/block/qcow.c b/block/qcow.c index 5239bd68f1..93a993bb44 100644 --- a/block/qcow.c +++ b/block/qcow.c @@ -395,7 +395,7 @@ static uint64_t get_cluster_offset(BlockDriverState *bs, return cluster_offset; } -static int coroutine_fn qcow_co_is_allocated(BlockDriverState *bs, +static int64_t coroutine_fn qcow_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { BDRVQcowState *s = bs->opaque; @@ -410,7 +410,14 @@ static int coroutine_fn qcow_co_is_allocated(BlockDriverState *bs, if (n > nb_sectors) n = nb_sectors; *pnum = n; - return (cluster_offset != 0); + if (!cluster_offset) { + return 0; + } + if ((cluster_offset & QCOW_OFLAG_COMPRESSED) || s->crypt_method) { + return BDRV_BLOCK_DATA; + } + cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS); + return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | cluster_offset; } static int decompress_buffer(uint8_t *out_buf, int out_buf_size, @@ -751,7 +758,7 @@ static int qcow_create(const char *filename, QEMUOptionParameter *options) g_free(tmp); ret = 0; exit: - bdrv_delete(qcow_bs); + bdrv_unref(qcow_bs); return ret; } @@ -896,7 +903,7 @@ static BlockDriver bdrv_qcow = { .bdrv_co_readv = qcow_co_readv, .bdrv_co_writev = qcow_co_writev, - .bdrv_co_is_allocated = qcow_co_is_allocated, + .bdrv_co_get_block_status = qcow_co_get_block_status, .bdrv_set_key = qcow_set_key, .bdrv_make_empty = qcow_make_empty, diff --git a/block/qcow2.c b/block/qcow2.c index 4bc679a155..578792f0a3 100644 --- a/block/qcow2.c +++ b/block/qcow2.c @@ -688,24 +688,34 @@ static int qcow2_reopen_prepare(BDRVReopenState *state, return 0; } -static int coroutine_fn qcow2_co_is_allocated(BlockDriverState *bs, +static int64_t coroutine_fn qcow2_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { BDRVQcowState *s = bs->opaque; uint64_t cluster_offset; - int ret; + int index_in_cluster, ret; + int64_t status = 0; *pnum = nb_sectors; - /* FIXME We can get errors here, but the bdrv_co_is_allocated interface - * can't pass them on today */ qemu_co_mutex_lock(&s->lock); ret = qcow2_get_cluster_offset(bs, sector_num << 9, pnum, &cluster_offset); qemu_co_mutex_unlock(&s->lock); if (ret < 0) { - *pnum = 0; + return ret; } - return (cluster_offset != 0) || (ret == QCOW2_CLUSTER_ZERO); + if (cluster_offset != 0 && ret != QCOW2_CLUSTER_COMPRESSED && + !s->crypt_method) { + index_in_cluster = sector_num & (s->cluster_sectors - 1); + cluster_offset |= (index_in_cluster << BDRV_SECTOR_BITS); + status |= BDRV_BLOCK_OFFSET_VALID | cluster_offset; + } + if (ret == QCOW2_CLUSTER_ZERO) { + status |= BDRV_BLOCK_ZERO; + } else if (ret != QCOW2_CLUSTER_UNALLOCATED) { + status |= BDRV_BLOCK_DATA; + } + return status; } /* handle reading after the end of the backing file */ @@ -1452,7 +1462,7 @@ static int qcow2_create2(const char *filename, int64_t total_size, ret = 0; out: - bdrv_delete(bs); + bdrv_unref(bs); return ret; } @@ -1868,7 +1878,7 @@ static BlockDriver bdrv_qcow2 = { .bdrv_reopen_prepare = qcow2_reopen_prepare, .bdrv_create = qcow2_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_co_is_allocated = qcow2_co_is_allocated, + .bdrv_co_get_block_status = qcow2_co_get_block_status, .bdrv_set_key = qcow2_set_key, .bdrv_make_empty = qcow2_make_empty, diff --git a/block/qed.c b/block/qed.c index cc904c4834..49b3a37ed5 100644 --- a/block/qed.c +++ b/block/qed.c @@ -599,7 +599,7 @@ static int qed_create(const char *filename, uint32_t cluster_size, ret = 0; /* success */ out: g_free(l1_table); - bdrv_delete(bs); + bdrv_unref(bs); return ret; } @@ -652,45 +652,66 @@ static int bdrv_qed_create(const char *filename, QEMUOptionParameter *options) } typedef struct { + BlockDriverState *bs; Coroutine *co; - int is_allocated; + uint64_t pos; + int64_t status; int *pnum; } QEDIsAllocatedCB; static void qed_is_allocated_cb(void *opaque, int ret, uint64_t offset, size_t len) { QEDIsAllocatedCB *cb = opaque; + BDRVQEDState *s = cb->bs->opaque; *cb->pnum = len / BDRV_SECTOR_SIZE; - cb->is_allocated = (ret == QED_CLUSTER_FOUND || ret == QED_CLUSTER_ZERO); + switch (ret) { + case QED_CLUSTER_FOUND: + offset |= qed_offset_into_cluster(s, cb->pos); + cb->status = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset; + break; + case QED_CLUSTER_ZERO: + cb->status = BDRV_BLOCK_ZERO; + break; + case QED_CLUSTER_L2: + case QED_CLUSTER_L1: + cb->status = 0; + break; + default: + assert(ret < 0); + cb->status = ret; + break; + } + if (cb->co) { qemu_coroutine_enter(cb->co, NULL); } } -static int coroutine_fn bdrv_qed_co_is_allocated(BlockDriverState *bs, +static int64_t coroutine_fn bdrv_qed_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { BDRVQEDState *s = bs->opaque; - uint64_t pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE; size_t len = (size_t)nb_sectors * BDRV_SECTOR_SIZE; QEDIsAllocatedCB cb = { - .is_allocated = -1, + .bs = bs, + .pos = (uint64_t)sector_num * BDRV_SECTOR_SIZE, + .status = BDRV_BLOCK_OFFSET_MASK, .pnum = pnum, }; QEDRequest request = { .l2_table = NULL }; - qed_find_cluster(s, &request, pos, len, qed_is_allocated_cb, &cb); + qed_find_cluster(s, &request, cb.pos, len, qed_is_allocated_cb, &cb); /* Now sleep if the callback wasn't invoked immediately */ - while (cb.is_allocated == -1) { + while (cb.status == BDRV_BLOCK_OFFSET_MASK) { cb.co = qemu_coroutine_self(); qemu_coroutine_yield(); } qed_unref_l2_cache_entry(request.l2_table); - return cb.is_allocated; + return cb.status; } static int bdrv_qed_make_empty(BlockDriverState *bs) @@ -1575,7 +1596,7 @@ static BlockDriver bdrv_qed = { .bdrv_reopen_prepare = bdrv_qed_reopen_prepare, .bdrv_create = bdrv_qed_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_co_is_allocated = bdrv_qed_co_is_allocated, + .bdrv_co_get_block_status = bdrv_qed_co_get_block_status, .bdrv_make_empty = bdrv_qed_make_empty, .bdrv_aio_readv = bdrv_qed_aio_readv, .bdrv_aio_writev = bdrv_qed_aio_writev, diff --git a/block/raw-posix.c b/block/raw-posix.c index ba721d3f5b..1b41ea3356 100644 --- a/block/raw-posix.c +++ b/block/raw-posix.c @@ -1084,12 +1084,12 @@ static int raw_create(const char *filename, QEMUOptionParameter *options) * 'nb_sectors' is the max value 'pnum' should be set to. If nb_sectors goes * beyond the end of the disk image it will be clamped. */ -static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, +static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { off_t start, data, hole; - int ret; + int64_t ret; ret = fd_open(bs); if (ret < 0) { @@ -1097,6 +1097,7 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, } start = sector_num * BDRV_SECTOR_SIZE; + ret = BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | start; #ifdef CONFIG_FIEMAP @@ -1114,7 +1115,7 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, if (ioctl(s->fd, FS_IOC_FIEMAP, &f) == -1) { /* Assume everything is allocated. */ *pnum = nb_sectors; - return 1; + return ret; } if (f.fm.fm_mapped_extents == 0) { @@ -1127,6 +1128,9 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, } else { data = f.fe.fe_logical; hole = f.fe.fe_logical + f.fe.fe_length; + if (f.fe.fe_flags & FIEMAP_EXTENT_UNWRITTEN) { + ret |= BDRV_BLOCK_ZERO; + } } #elif defined SEEK_HOLE && defined SEEK_DATA @@ -1141,7 +1145,7 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, /* Most likely EINVAL. Assume everything is allocated. */ *pnum = nb_sectors; - return 1; + return ret; } if (hole > start) { @@ -1154,19 +1158,21 @@ static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, } } #else - *pnum = nb_sectors; - return 1; + data = 0; + hole = start + nb_sectors * BDRV_SECTOR_SIZE; #endif if (data <= start) { /* On a data extent, compute sectors to the end of the extent. */ *pnum = MIN(nb_sectors, (hole - start) / BDRV_SECTOR_SIZE); - return 1; } else { /* On a hole, compute sectors to the beginning of the next extent. */ *pnum = MIN(nb_sectors, (data - start) / BDRV_SECTOR_SIZE); - return 0; + ret &= ~BDRV_BLOCK_DATA; + ret |= BDRV_BLOCK_ZERO; } + + return ret; } static coroutine_fn BlockDriverAIOCB *raw_aio_discard(BlockDriverState *bs, @@ -1200,7 +1206,7 @@ static BlockDriver bdrv_file = { .bdrv_close = raw_close, .bdrv_create = raw_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_co_is_allocated = raw_co_is_allocated, + .bdrv_co_get_block_status = raw_co_get_block_status, .bdrv_aio_readv = raw_aio_readv, .bdrv_aio_writev = raw_aio_writev, diff --git a/block/raw-win32.c b/block/raw-win32.c index 9b5b2af4e8..d2d2d9f4d4 100644 --- a/block/raw-win32.c +++ b/block/raw-win32.c @@ -535,13 +535,29 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags) { BDRVRawState *s = bs->opaque; int access_flags, create_flags; + int ret = 0; DWORD overlapped; char device_name[64]; - const char *filename = qdict_get_str(options, "filename"); + + Error *local_err = NULL; + const char *filename; + + QemuOpts *opts = qemu_opts_create_nofail(&raw_runtime_opts); + qemu_opts_absorb_qdict(opts, options, &local_err); + if (error_is_set(&local_err)) { + qerror_report_err(local_err); + error_free(local_err); + ret = -EINVAL; + goto done; + } + + filename = qemu_opt_get(opts, "filename"); if (strstart(filename, "/dev/cdrom", NULL)) { - if (find_cdrom(device_name, sizeof(device_name)) < 0) - return -ENOENT; + if (find_cdrom(device_name, sizeof(device_name)) < 0) { + ret = -ENOENT; + goto done; + } filename = device_name; } else { /* transform drive letters into device name */ @@ -564,11 +580,17 @@ static int hdev_open(BlockDriverState *bs, QDict *options, int flags) if (s->hfile == INVALID_HANDLE_VALUE) { int err = GetLastError(); - if (err == ERROR_ACCESS_DENIED) - return -EACCES; - return -1; + if (err == ERROR_ACCESS_DENIED) { + ret = -EACCES; + } else { + ret = -1; + } + goto done; } - return 0; + +done: + qemu_opts_del(opts); + return ret; } static BlockDriver bdrv_host_device = { diff --git a/block/raw_bsd.c b/block/raw_bsd.c index ab2b0fd7d2..a9060caec4 100644 --- a/block/raw_bsd.c +++ b/block/raw_bsd.c @@ -58,11 +58,11 @@ static int coroutine_fn raw_co_writev(BlockDriverState *bs, int64_t sector_num, return bdrv_co_writev(bs->file, sector_num, nb_sectors, qiov); } -static int coroutine_fn raw_co_is_allocated(BlockDriverState *bs, - int64_t sector_num, int nb_sectors, - int *pnum) +static int64_t coroutine_fn raw_co_get_block_status(BlockDriverState *bs, + int64_t sector_num, + int nb_sectors, int *pnum) { - return bdrv_co_is_allocated(bs->file, sector_num, nb_sectors, pnum); + return bdrv_get_block_status(bs->file, sector_num, nb_sectors, pnum); } static int coroutine_fn raw_co_write_zeroes(BlockDriverState *bs, @@ -164,7 +164,7 @@ static BlockDriver bdrv_raw = { .bdrv_co_writev = &raw_co_writev, .bdrv_co_write_zeroes = &raw_co_write_zeroes, .bdrv_co_discard = &raw_co_discard, - .bdrv_co_is_allocated = &raw_co_is_allocated, + .bdrv_co_get_block_status = &raw_co_get_block_status, .bdrv_truncate = &raw_truncate, .bdrv_getlength = &raw_getlength, .bdrv_get_info = &raw_get_info, diff --git a/block/sheepdog.c b/block/sheepdog.c index 1ad4d070e7..f9988d35ba 100644 --- a/block/sheepdog.c +++ b/block/sheepdog.c @@ -1430,7 +1430,7 @@ static int sd_prealloc(const char *filename) } out: if (bs) { - bdrv_delete(bs); + bdrv_unref(bs); } g_free(buf); @@ -1509,13 +1509,13 @@ static int sd_create(const char *filename, QEMUOptionParameter *options) if (!is_snapshot(&s->inode)) { error_report("cannot clone from a non snapshot vdi"); - bdrv_delete(bs); + bdrv_unref(bs); ret = -EINVAL; goto out; } base_vid = s->inode.vdi_id; - bdrv_delete(bs); + bdrv_unref(bs); } ret = do_sd_create(s, vdi, vdi_size, base_vid, &vid, 0); @@ -2270,9 +2270,9 @@ static coroutine_fn int sd_co_discard(BlockDriverState *bs, int64_t sector_num, return acb->ret; } -static coroutine_fn int -sd_co_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, - int *pnum) +static coroutine_fn int64_t +sd_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, + int *pnum) { BDRVSheepdogState *s = bs->opaque; SheepdogInode *inode = &s->inode; @@ -2280,7 +2280,7 @@ sd_co_is_allocated(BlockDriverState *bs, int64_t sector_num, int nb_sectors, end = DIV_ROUND_UP((sector_num + nb_sectors) * BDRV_SECTOR_SIZE, SD_DATA_OBJ_SIZE); unsigned long idx; - int ret = 1; + int64_t ret = BDRV_BLOCK_DATA; for (idx = start; idx < end; idx++) { if (inode->data_vdi_id[idx] == 0) { @@ -2338,7 +2338,7 @@ static BlockDriver bdrv_sheepdog = { .bdrv_co_writev = sd_co_writev, .bdrv_co_flush_to_disk = sd_co_flush_to_disk, .bdrv_co_discard = sd_co_discard, - .bdrv_co_is_allocated = sd_co_is_allocated, + .bdrv_co_get_block_status = sd_co_get_block_status, .bdrv_snapshot_create = sd_snapshot_create, .bdrv_snapshot_goto = sd_snapshot_goto, @@ -2366,7 +2366,7 @@ static BlockDriver bdrv_sheepdog_tcp = { .bdrv_co_writev = sd_co_writev, .bdrv_co_flush_to_disk = sd_co_flush_to_disk, .bdrv_co_discard = sd_co_discard, - .bdrv_co_is_allocated = sd_co_is_allocated, + .bdrv_co_get_block_status = sd_co_get_block_status, .bdrv_snapshot_create = sd_snapshot_create, .bdrv_snapshot_goto = sd_snapshot_goto, @@ -2394,7 +2394,7 @@ static BlockDriver bdrv_sheepdog_unix = { .bdrv_co_writev = sd_co_writev, .bdrv_co_flush_to_disk = sd_co_flush_to_disk, .bdrv_co_discard = sd_co_discard, - .bdrv_co_is_allocated = sd_co_is_allocated, + .bdrv_co_get_block_status = sd_co_get_block_status, .bdrv_snapshot_create = sd_snapshot_create, .bdrv_snapshot_goto = sd_snapshot_goto, diff --git a/block/snapshot.c b/block/snapshot.c index 6c6d9deea1..8f61cc0745 100644 --- a/block/snapshot.c +++ b/block/snapshot.c @@ -99,7 +99,7 @@ int bdrv_snapshot_goto(BlockDriverState *bs, ret = bdrv_snapshot_goto(bs->file, snapshot_id); open_ret = drv->bdrv_open(bs, NULL, bs->open_flags); if (open_ret < 0) { - bdrv_delete(bs->file); + bdrv_unref(bs->file); bs->drv = NULL; return open_ret; } diff --git a/block/stream.c b/block/stream.c index 99821252b1..078ce4aa6a 100644 --- a/block/stream.c +++ b/block/stream.c @@ -73,7 +73,7 @@ static void close_unused_images(BlockDriverState *top, BlockDriverState *base, unused = intermediate; intermediate = intermediate->backing_hd; unused->backing_hd = NULL; - bdrv_delete(unused); + bdrv_unref(unused); } } @@ -119,16 +119,16 @@ wait: break; } - ret = bdrv_co_is_allocated(bs, sector_num, - STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n); + ret = bdrv_is_allocated(bs, sector_num, + STREAM_BUFFER_SIZE / BDRV_SECTOR_SIZE, &n); if (ret == 1) { /* Allocated in the top, no need to copy. */ copy = false; - } else { + } else if (ret >= 0) { /* Copy if allocated in the intermediate images. Limit to the * known-unallocated area [sector_num, sector_num+n). */ - ret = bdrv_co_is_allocated_above(bs->backing_hd, base, - sector_num, n, &n); + ret = bdrv_is_allocated_above(bs->backing_hd, base, + sector_num, n, &n); /* Finish early if end of backing file has been reached */ if (ret == 0 && n == 0) { diff --git a/block/vdi.c b/block/vdi.c index 8a915257e8..1bf7dc575a 100644 --- a/block/vdi.c +++ b/block/vdi.c @@ -470,7 +470,7 @@ static int vdi_reopen_prepare(BDRVReopenState *state, return 0; } -static int coroutine_fn vdi_co_is_allocated(BlockDriverState *bs, +static int64_t coroutine_fn vdi_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { /* TODO: Check for too large sector_num (in bdrv_is_allocated or here). */ @@ -479,12 +479,23 @@ static int coroutine_fn vdi_co_is_allocated(BlockDriverState *bs, size_t sector_in_block = sector_num % s->block_sectors; int n_sectors = s->block_sectors - sector_in_block; uint32_t bmap_entry = le32_to_cpu(s->bmap[bmap_index]); + uint64_t offset; + int result; + logout("%p, %" PRId64 ", %d, %p\n", bs, sector_num, nb_sectors, pnum); if (n_sectors > nb_sectors) { n_sectors = nb_sectors; } *pnum = n_sectors; - return VDI_IS_ALLOCATED(bmap_entry); + result = VDI_IS_ALLOCATED(bmap_entry); + if (!result) { + return 0; + } + + offset = s->header.offset_data + + (uint64_t)bmap_entry * s->block_size + + sector_in_block * SECTOR_SIZE; + return BDRV_BLOCK_DATA | BDRV_BLOCK_OFFSET_VALID | offset; } static int vdi_co_read(BlockDriverState *bs, @@ -780,7 +791,7 @@ static BlockDriver bdrv_vdi = { .bdrv_reopen_prepare = vdi_reopen_prepare, .bdrv_create = vdi_create, .bdrv_has_zero_init = bdrv_has_zero_init_1, - .bdrv_co_is_allocated = vdi_co_is_allocated, + .bdrv_co_get_block_status = vdi_co_get_block_status, .bdrv_make_empty = vdi_make_empty, .bdrv_read = vdi_co_read, diff --git a/block/vmdk.c b/block/vmdk.c index 63b489d29e..fb5b5297ce 100644 --- a/block/vmdk.c +++ b/block/vmdk.c @@ -216,7 +216,7 @@ static void vmdk_free_extents(BlockDriverState *bs) g_free(e->l2_cache); g_free(e->l1_backup_table); if (e->file != bs->file) { - bdrv_delete(e->file); + bdrv_unref(e->file); } } g_free(s->extents); @@ -746,7 +746,7 @@ static int vmdk_parse_extents(const char *desc, BlockDriverState *bs, /* SPARSE extent and VMFSSPARSE extent are both "COWD" sparse file*/ ret = vmdk_open_sparse(bs, extent_file, bs->open_flags); if (ret) { - bdrv_delete(extent_file); + bdrv_unref(extent_file); return ret; } } else { @@ -1042,7 +1042,7 @@ static VmdkExtent *find_extent(BDRVVmdkState *s, return NULL; } -static int coroutine_fn vmdk_co_is_allocated(BlockDriverState *bs, +static int64_t coroutine_fn vmdk_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int *pnum) { BDRVVmdkState *s = bs->opaque; @@ -1059,7 +1059,24 @@ static int coroutine_fn vmdk_co_is_allocated(BlockDriverState *bs, sector_num * 512, 0, &offset); qemu_co_mutex_unlock(&s->lock); - ret = (ret == VMDK_OK || ret == VMDK_ZEROED); + switch (ret) { + case VMDK_ERROR: + ret = -EIO; + break; + case VMDK_UNALLOC: + ret = 0; + break; + case VMDK_ZEROED: + ret = BDRV_BLOCK_ZERO; + break; + case VMDK_OK: + ret = BDRV_BLOCK_DATA; + if (extent->file == bs->file) { + ret |= BDRV_BLOCK_OFFSET_VALID | offset; + } + + break; + } index_in_cluster = sector_num % extent->cluster_sectors; n = extent->cluster_sectors - index_in_cluster; @@ -1636,15 +1653,15 @@ static int vmdk_create(const char *filename, QEMUOptionParameter *options) BlockDriverState *bs = bdrv_new(""); ret = bdrv_open(bs, backing_file, NULL, 0, NULL); if (ret != 0) { - bdrv_delete(bs); + bdrv_unref(bs); return ret; } if (strcmp(bs->drv->format_name, "vmdk")) { - bdrv_delete(bs); + bdrv_unref(bs); return -EINVAL; } parent_cid = vmdk_read_cid(bs, 0); - bdrv_delete(bs); + bdrv_unref(bs); snprintf(parent_desc_line, sizeof(parent_desc_line), "parentFileNameHint=\"%s\"", backing_file); } @@ -1837,7 +1854,7 @@ static BlockDriver bdrv_vmdk = { .bdrv_close = vmdk_close, .bdrv_create = vmdk_create, .bdrv_co_flush_to_disk = vmdk_co_flush, - .bdrv_co_is_allocated = vmdk_co_is_allocated, + .bdrv_co_get_block_status = vmdk_co_get_block_status, .bdrv_get_allocated_file_size = vmdk_get_allocated_file_size, .bdrv_has_zero_init = vmdk_has_zero_init, diff --git a/block/vvfat.c b/block/vvfat.c index cd3b8edd9f..0129195e29 100644 --- a/block/vvfat.c +++ b/block/vvfat.c @@ -2874,16 +2874,17 @@ static coroutine_fn int vvfat_co_write(BlockDriverState *bs, int64_t sector_num, return ret; } -static int coroutine_fn vvfat_co_is_allocated(BlockDriverState *bs, +static int64_t coroutine_fn vvfat_co_get_block_status(BlockDriverState *bs, int64_t sector_num, int nb_sectors, int* n) { BDRVVVFATState* s = bs->opaque; *n = s->sector_count - sector_num; - if (*n > nb_sectors) - *n = nb_sectors; - else if (*n < 0) - return 0; - return 1; + if (*n > nb_sectors) { + *n = nb_sectors; + } else if (*n < 0) { + return 0; + } + return BDRV_BLOCK_DATA; } static int write_target_commit(BlockDriverState *bs, int64_t sector_num, @@ -2894,7 +2895,7 @@ static int write_target_commit(BlockDriverState *bs, int64_t sector_num, static void write_target_close(BlockDriverState *bs) { BDRVVVFATState* s = *((BDRVVVFATState**) bs->opaque); - bdrv_delete(s->qcow); + bdrv_unref(s->qcow); g_free(s->qcow_filename); } @@ -2935,7 +2936,7 @@ static int enable_write_target(BDRVVVFATState *s) ret = bdrv_open(s->qcow, s->qcow_filename, NULL, BDRV_O_RDWR | BDRV_O_CACHE_WB | BDRV_O_NO_FLUSH, bdrv_qcow); if (ret < 0) { - bdrv_delete(s->qcow); + bdrv_unref(s->qcow); goto err; } @@ -2943,7 +2944,7 @@ static int enable_write_target(BDRVVVFATState *s) unlink(s->qcow_filename); #endif - s->bs->backing_hd = calloc(sizeof(BlockDriverState), 1); + s->bs->backing_hd = bdrv_new(""); s->bs->backing_hd->drv = &vvfat_write_target; s->bs->backing_hd->opaque = g_malloc(sizeof(void*)); *(void**)s->bs->backing_hd->opaque = s; @@ -2984,7 +2985,7 @@ static BlockDriver bdrv_vvfat = { .bdrv_read = vvfat_co_read, .bdrv_write = vvfat_co_write, - .bdrv_co_is_allocated = vvfat_co_is_allocated, + .bdrv_co_get_block_status = vvfat_co_get_block_status, }; static void bdrv_vvfat_init(void) |