void commit_active_start(BlockDriverState *bs, BlockDriverState *base, int64_t speed, BlockdevOnError on_error, BlockCompletionFunc *cb, void *opaque, Error **errp) { int64_t length, base_length; int orig_base_flags; int ret; Error *local_err = NULL; orig_base_flags = bdrv_get_flags(base); if (bdrv_reopen(base, bs->open_flags, errp)) { return; } length = bdrv_getlength(bs); if (length < 0) { error_setg_errno(errp, -length, "Unable to determine length of %s", bs->filename); goto error_restore_flags; } base_length = bdrv_getlength(base); if (base_length < 0) { error_setg_errno(errp, -base_length, "Unable to determine length of %s", base->filename); goto error_restore_flags; } if (length > base_length) { ret = bdrv_truncate(base, length); if (ret < 0) { error_setg_errno(errp, -ret, "Top image %s is larger than base image %s, and " "resize of base image failed", bs->filename, base->filename); goto error_restore_flags; } } bdrv_ref(base); mirror_start_job(bs, base, NULL, speed, 0, 0, on_error, on_error, cb, opaque, &local_err, &commit_active_job_driver, false, base); if (local_err) { error_propagate(errp, local_err); goto error_restore_flags; } return; error_restore_flags: /* ignore error and errp for bdrv_reopen, because we want to propagate * the original error */ bdrv_reopen(base, orig_base_flags, NULL); return; }
static void test_sync_op_truncate(BdrvChild *c) { int ret; /* Normal success path */ ret = bdrv_truncate(c, 65536, PREALLOC_MODE_OFF, NULL); g_assert_cmpint(ret, ==, 0); /* Early error: Negative offset */ ret = bdrv_truncate(c, -2, PREALLOC_MODE_OFF, NULL); g_assert_cmpint(ret, ==, -EINVAL); /* Error: Read-only image */ c->bs->read_only = true; c->bs->open_flags &= ~BDRV_O_RDWR; ret = bdrv_truncate(c, 65536, PREALLOC_MODE_OFF, NULL); g_assert_cmpint(ret, ==, -EACCES); c->bs->read_only = false; c->bs->open_flags |= BDRV_O_RDWR; }
static int block_crypto_create_generic(QCryptoBlockFormat format, const char *filename, QemuOpts *opts, Error **errp) { int ret = -EINVAL; QCryptoBlockCreateOptions *create_opts = NULL; QCryptoBlock *crypto = NULL; struct BlockCryptoCreateData data = { .size = ROUND_UP(qemu_opt_get_size_del(opts, BLOCK_OPT_SIZE, 0), BDRV_SECTOR_SIZE), .opts = opts, .filename = filename, }; create_opts = block_crypto_create_opts_init(format, opts, errp); if (!create_opts) { return -1; } crypto = qcrypto_block_create(create_opts, block_crypto_init_func, block_crypto_write_func, &data, errp); if (!crypto) { ret = -EIO; goto cleanup; } ret = 0; cleanup: qcrypto_block_free(crypto); blk_unref(data.blk); qapi_free_QCryptoBlockCreateOptions(create_opts); return ret; } static int block_crypto_truncate(BlockDriverState *bs, int64_t offset, Error **errp) { BlockCrypto *crypto = bs->opaque; size_t payload_offset = qcrypto_block_get_payload_offset(crypto->block); offset += payload_offset; return bdrv_truncate(bs->file, offset, errp); }
static int truncate_f(int argc, char **argv) { int64_t offset; int ret; offset = cvtnum(argv[1]); if (offset < 0) { printf("non-numeric truncate argument -- %s\n", argv[1]); return 0; } ret = bdrv_truncate(bs, offset); if (ret < 0) { printf("truncate: %s\n", strerror(-ret)); return 0; } return 0; }
static int create_fixed_disk(BlockDriverState *bs, uint8_t *buf, int64_t total_size) { int ret; /* Add footer to total size */ total_size += HEADER_SIZE; ret = bdrv_truncate(bs, total_size); if (ret < 0) { return ret; } ret = bdrv_pwrite_sync(bs, total_size - HEADER_SIZE, buf, HEADER_SIZE); if (ret < 0) { return ret; } return ret; }
static uint32_t allocate_chunk (BlockDriverState * bs) { BDRVFvdState *s = bs->opaque; /* Check if there is sufficient storage space. */ if (s->used_storage + s->chunk_size > s->data_storage) { if (s->add_storage_cmd) { if (system (s->add_storage_cmd)) { fprintf (stderr, "Error in executing %s\n", s->add_storage_cmd); } } else { /* If the image is stored on a file system, the image file size * can be increased by bdrv_truncate. */ int64_t new_size = (s->data_offset + s->used_storage + s->storage_grow_unit) * 512; bdrv_truncate (s->fvd_data, new_size); } /* Check how much storage is available now. */ int64_t size = bdrv_getlength (s->fvd_data); if (size < 0) { fprintf (stderr, "Error in bdrv_getlength(%s)\n", bs->filename); return EMPTY_TABLE; } s->data_storage = size / 512 - s->data_offset; if (s->used_storage + s->chunk_size > s->data_storage) { fprintf (stderr, "Could not allocate more storage space.\n"); return EMPTY_TABLE; } QDEBUG ("Increased storage to %" PRId64 " bytes.\n", size); } uint32_t allocated_chunk_id = s->used_storage / s->chunk_size; s->used_storage += s->chunk_size; return allocated_chunk_id; }
static int raw_truncate(BlockDriverState *bs, int64_t offset) { return bdrv_truncate(bs->file, offset); }
/* Flush the entire log (as described by 'logs') to the VHDX image * file, and then set the log to 'empty' status once complete. * * The log entries should be validate prior to flushing */ static int vhdx_log_flush(BlockDriverState *bs, BDRVVHDXState *s, VHDXLogSequence *logs) { int ret = 0; int i; uint32_t cnt, sectors_read; uint64_t new_file_size; void *data = NULL; VHDXLogDescEntries *desc_entries = NULL; VHDXLogEntryHeader hdr_tmp = { 0 }; cnt = logs->count; data = qemu_blockalign(bs, VHDX_LOG_SECTOR_SIZE); ret = vhdx_user_visible_write(bs, s); if (ret < 0) { goto exit; } /* each iteration represents one log sequence, which may span multiple * sectors */ while (cnt--) { ret = vhdx_log_peek_hdr(bs, &logs->log, &hdr_tmp); if (ret < 0) { goto exit; } /* if the log shows a FlushedFileOffset larger than our current file * size, then that means the file has been truncated / corrupted, and * we must refused to open it / use it */ if (hdr_tmp.flushed_file_offset > bdrv_getlength(bs->file)) { ret = -EINVAL; goto exit; } ret = vhdx_log_read_desc(bs, s, &logs->log, &desc_entries); if (ret < 0) { goto exit; } for (i = 0; i < desc_entries->hdr.descriptor_count; i++) { if (!memcmp(&desc_entries->desc[i].signature, "desc", 4)) { /* data sector, so read a sector to flush */ ret = vhdx_log_read_sectors(bs, &logs->log, §ors_read, data, 1, false); if (ret < 0) { goto exit; } if (sectors_read != 1) { ret = -EINVAL; goto exit; } } ret = vhdx_log_flush_desc(bs, &desc_entries->desc[i], data); if (ret < 0) { goto exit; } } if (bdrv_getlength(bs->file) < desc_entries->hdr.last_file_offset) { new_file_size = desc_entries->hdr.last_file_offset; if (new_file_size % (1024*1024)) { /* round up to nearest 1MB boundary */ new_file_size = ((new_file_size >> 20) + 1) << 20; bdrv_truncate(bs->file, new_file_size); } }
static int cor_truncate(BlockDriverState *bs, int64_t offset, PreallocMode prealloc, Error **errp) { return bdrv_truncate(bs->file, offset, prealloc, errp); }
static void coroutine_fn commit_run(void *opaque) { CommitBlockJob *s = opaque; BlockDriverState *active = s->active; BlockDriverState *top = s->top; BlockDriverState *base = s->base; BlockDriverState *overlay_bs = NULL; int64_t sector_num, end; int ret = 0; int n = 0; void *buf; int bytes_written = 0; int64_t base_len; ret = s->common.len = bdrv_getlength(top); if (s->common.len < 0) { goto exit_restore_reopen; } ret = base_len = bdrv_getlength(base); if (base_len < 0) { goto exit_restore_reopen; } if (base_len < s->common.len) { ret = bdrv_truncate(base, s->common.len); if (ret) { goto exit_restore_reopen; } } overlay_bs = bdrv_find_overlay(active, top); end = s->common.len >> BDRV_SECTOR_BITS; buf = qemu_blockalign(top, COMMIT_BUFFER_SIZE); for (sector_num = 0; sector_num < end; sector_num += n) { uint64_t delay_ms = 0; bool copy; wait: /* Note that even when no rate limit is applied we need to yield * with no pending I/O here so that qemu_aio_flush() returns. */ block_job_sleep(&s->common, rt_clock, delay_ms); if (block_job_is_cancelled(&s->common)) { break; } /* Copy if allocated above the base */ ret = bdrv_co_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) { if (s->common.speed) { delay_ms = ratelimit_calculate_delay(&s->limit, n); if (delay_ms > 0) { goto wait; } } ret = commit_populate(top, base, sector_num, n, buf); bytes_written += n * BDRV_SECTOR_SIZE; } if (ret < 0) { if (s->on_error == BLOCK_ERR_STOP_ANY || s->on_error == BLOCK_ERR_REPORT || (s->on_error == BLOCK_ERR_STOP_ENOSPC && ret == -ENOSPC)) { goto exit_free_buf; } else { n = 0; continue; } } /* Publish progress */ s->common.offset += n * BDRV_SECTOR_SIZE; } ret = 0; if (!block_job_is_cancelled(&s->common) && sector_num == end) { /* success */ ret = bdrv_drop_intermediate(active, top, base); } exit_free_buf: qemu_vfree(buf); exit_restore_reopen: /* restore base open flags here if appropriate (e.g., change the base back * to r/o). These reopens do not need to be atomic, since we won't abort * even on failure here */ if (s->base_flags != bdrv_get_flags(base)) { bdrv_reopen(base, s->base_flags, NULL); } if (s->orig_overlay_flags != bdrv_get_flags(overlay_bs)) { bdrv_reopen(overlay_bs, s->orig_overlay_flags, NULL); } block_job_complete(&s->common, ret); }