网站制作青岛公司哪些平台可以打小广告
旧的 QEMU 图像格式,支持备份文件、紧凑图像文件、加密和压缩。
backing_file
基础镜像的文件名(参见create子命令)
encryption
此选项已弃用,相当于encrypt.format=aes
encrypt.format
如果设置为aes,则图像将使用 128 位 AES-CBC 加密。加密密钥由参数给出encrypt.key-secret。现代密码学标准认为这种加密格式存在缺陷,存在许多针对qcow2图像格式的先前列举的设计问题。
系统模拟器不再支持使用此功能。仅命令行实用程序仍支持此功能,用于数据释放和与旧版 QEMU 的互操作性。
需要本机加密的用户应该使用qcow2格式代替encrypt.format=luks。
encrypt.key-secret
secret提供包含加密密钥的对象的 ID ( encrypt.format=aes)。
1、注册qcow块格式
static BlockDriver bdrv_qcow = {.format_name = "qcow",.instance_size = sizeof(BDRVQcowState),.bdrv_probe = qcow_probe,.bdrv_open = qcow_open,.bdrv_close = qcow_close,.bdrv_child_perm = bdrv_default_perms,.bdrv_reopen_prepare = qcow_reopen_prepare,.bdrv_co_create = qcow_co_create,.bdrv_co_create_opts = qcow_co_create_opts,.bdrv_has_zero_init = bdrv_has_zero_init_1,.is_format = true,.supports_backing = true,.bdrv_refresh_limits = qcow_refresh_limits,.bdrv_co_preadv = qcow_co_preadv,.bdrv_co_pwritev = qcow_co_pwritev,.bdrv_co_block_status = qcow_co_block_status,.bdrv_make_empty = qcow_make_empty,.bdrv_co_pwritev_compressed = qcow_co_pwritev_compressed,.bdrv_get_info = qcow_get_info,.create_opts = &qcow_create_opts,.strong_runtime_opts = qcow_strong_runtime_opts,
};static void bdrv_qcow_init(void)
{bdrv_register(&bdrv_qcow);
}block_init(bdrv_qcow_init);
2、打开qcow文件
static int qcow_open(BlockDriverState *bs, QDict *options, int flags, Error **errp)
{BDRVQcowState *s = bs->opaque;unsigned int len, i, shift;int ret;QCowHeader header;QCryptoBlockOpenOptions *crypto_opts = NULL;unsigned int cflags = 0;QDict *encryptopts = NULL;const char *encryptfmt;qdict_extract_subqdict(options, &encryptopts, "encrypt.");encryptfmt = qdict_get_try_str(encryptopts, "format");// 打开qcow文件bs->file = bdrv_open_child(NULL, options, "file", bs, &child_of_bds, BDRV_CHILD_IMAGE, false, errp);if (!bs->file) {ret = -EINVAL;goto fail;}// 读取并解析qcow头部ret = bdrv_pread(bs->file, 0, &header, sizeof(header));if (ret < 0) {goto fail;}header.magic = be32_to_cpu(header.magic);header.version = be32_to_cpu(header.version);header.backing_file_offset = be64_to_cpu(header.backing_file_offset);header.backing_file_size = be32_to_cpu(header.backing_file_size);header.mtime = be32_to_cpu(header.mtime);header.size = be64_to_cpu(header.size);header.crypt_method = be32_to_cpu(header.crypt_method);header.l1_table_offset = be64_to_cpu(header.l1_table_offset);// 验证有效性if (header.magic != QCOW_MAGIC) {error_setg(errp, "Image not in qcow format");ret = -EINVAL;goto fail;}if (header.version != QCOW_VERSION) {error_setg(errp, "qcow (v%d) does not support qcow version %" PRIu32, QCOW_VERSION, header.version);if (header.version == 2 || header.version == 3) {error_append_hint(errp, "Try the 'qcow2' driver instead.\n");}ret = -ENOTSUP;goto fail;}if (header.size <= 1) {error_setg(errp, "Image size is too small (must be at least 2 bytes)");ret = -EINVAL;goto fail;}if (header.cluster_bits < 9 || header.cluster_bits > 16) {error_setg(errp, "Cluster size must be between 512 and 64k");ret = -EINVAL;goto fail;}/* l2_bits specifies number of entries; storing a uint64_t in each entry,* so bytes = num_entries << 3. */if (header.l2_bits < 9 - 3 || header.l2_bits > 16 - 3) {error_setg(errp, "L2 table size must be between 512 and 64k");ret = -EINVAL;goto fail;}s->crypt_method_header = header.crypt_method;if (s->crypt_method_header) {if (bdrv_uses_whitelist() &&s->crypt_method_header == QCOW_CRYPT_AES) {error_setg(errp,"Use of AES-CBC encrypted qcow images is no longer supported in system emulators");error_append_hint(errp,You can use 'qemu-img convert' to convert your image to an alternative supported format, such ""as unencrypted qcow, or raw with the LUKS format instead.\n");ret = -ENOSYS;goto fail;}if (s->crypt_method_header == QCOW_CRYPT_AES) {if (encryptfmt && !g_str_equal(encryptfmt, "aes")) {error_setg(errp, "Header reported 'aes' encryption format but options specify '%s'", encryptfmt);ret = -EINVAL;goto fail;}qdict_put_str(encryptopts, "format", "qcow");crypto_opts = block_crypto_open_opts_init(encryptopts, errp);if (!crypto_opts) {ret = -EINVAL;goto fail;}if (flags & BDRV_O_NO_IO) {cflags |= QCRYPTO_BLOCK_OPEN_NO_IO;}s->crypto = qcrypto_block_open(crypto_opts, "encrypt.", NULL, NULL, cflags, 1, errp);if (!s->crypto) {ret = -EINVAL;goto fail;}} else {error_setg(errp, "invalid encryption method in qcow header");ret = -EINVAL;goto fail;}bs->encrypted = true;} else {if (encryptfmt) {error_setg(errp, "No encryption in image header, but options " "specified format '%s'", encryptfmt);ret = -EINVAL;goto fail;}}s->cluster_bits = header.cluster_bits;s->cluster_size = 1 << s->cluster_bits;s->l2_bits = header.l2_bits;s->l2_size = 1 << s->l2_bits;bs->total_sectors = header.size / 512;s->cluster_offset_mask = (1LL << (63 - s->cluster_bits)) - 1;/* read the level 1 table */shift = s->cluster_bits + s->l2_bits;if (header.size > UINT64_MAX - (1LL << shift)) {error_setg(errp, "Image too large");ret = -EINVAL;goto fail;} else {uint64_t l1_size = (header.size + (1LL << shift) - 1) >> shift;if (l1_size > INT_MAX / sizeof(uint64_t)) {error_setg(errp, "Image too large");ret = -EINVAL;goto fail;}s->l1_size = l1_size;}s->l1_table_offset = header.l1_table_offset;s->l1_table = g_try_new(uint64_t, s->l1_size);if (s->l1_table == NULL) {error_setg(errp, "Could not allocate memory for L1 table");ret = -ENOMEM;goto fail;}// 读取并解析1级缓存ret = bdrv_pread(bs->file, s->l1_table_offset, s->l1_table, s->l1_size * sizeof(uint64_t));if (ret < 0) {goto fail;}for(i = 0;i < s->l1_size; i++) {s->l1_table[i] = be64_to_cpu(s->l1_table[i]);}// 2级缓存/* alloc L2 cache (max. 64k * 16 * 8 = 8 MB) */s->l2_cache = qemu_try_blockalign(bs->file->bs, s->l2_size * L2_CACHE_SIZE * sizeof(uint64_t));if (s->l2_cache == NULL) {error_setg(errp, "Could not allocate L2 table cache");ret = -ENOMEM;goto fail;}s->cluster_cache = g_malloc(s->cluster_size);s->cluster_data = g_malloc(s->cluster_size);s->cluster_cache_offset = -1;/* read the backing file name */if (header.backing_file_offset != 0) {len = header.backing_file_size;if (len > 1023 || len >= sizeof(bs->backing_file)) {error_setg(errp, "Backing file name too long");ret = -EINVAL;goto fail;}ret = bdrv_pread(bs->file, header.backing_file_offset, bs->auto_backing_file, len);if (ret < 0) {goto fail;}bs->auto_backing_file[len] = '\0';pstrcpy(bs->backing_file, sizeof(bs->backing_file), bs->auto_backing_file);}// 使用 qcow 镜像时禁用迁移error_setg(&s->migration_blocker, "The qcow format used by node '%s' does not support live migration", bdrv_get_device_or_node_name(bs));ret = migrate_add_blocker(s->migration_blocker, errp);if (ret < 0) {error_free(s->migration_blocker);goto fail;}qobject_unref(encryptopts);qapi_free_QCryptoBlockOpenOptions(crypto_opts);qemu_co_mutex_init(&s->lock);return 0;
fail:g_free(s->l1_table);qemu_vfree(s->l2_cache);g_free(s->cluster_cache);g_free(s->cluster_data);qcrypto_block_free(s->crypto);qobject_unref(encryptopts);qapi_free_QCryptoBlockOpenOptions(crypto_opts);return ret;
}
3、读取qcow文件
static coroutine_fn int qcow_co_preadv(BlockDriverState *bs, uint64_t offset,uint64_t bytes, QEMUIOVector *qiov,int flags)
{BDRVQcowState *s = bs->opaque;int offset_in_cluster;int ret = 0, n;uint64_t cluster_offset;uint8_t *buf;void *orig_buf;assert(!flags);if (qiov->niov > 1) {buf = orig_buf = qemu_try_blockalign(bs, qiov->size);if (buf == NULL) {return -ENOMEM;}} else {orig_buf = NULL;buf = (uint8_t *)qiov->iov->iov_base;}qemu_co_mutex_lock(&s->lock);while (bytes != 0) {/* prepare next request */ret = get_cluster_offset(bs, offset, 0, 0, 0, 0, &cluster_offset);if (ret < 0) {break;}offset_in_cluster = offset & (s->cluster_size - 1);n = s->cluster_size - offset_in_cluster;if (n > bytes) {n = bytes;}if (!cluster_offset) {if (bs->backing) {/* read from the base image */qemu_co_mutex_unlock(&s->lock);/* qcow2 emits this on bs->file instead of bs->backing */BLKDBG_EVENT(bs->file, BLKDBG_READ_BACKING_AIO);ret = bdrv_co_pread(bs->backing, offset, n, buf, 0);qemu_co_mutex_lock(&s->lock);if (ret < 0) {break;}} else {/* Note: in this case, no need to wait */memset(buf, 0, n);}} else if (cluster_offset & QCOW_OFLAG_COMPRESSED) {/* add AIO support for compressed blocks ? */if (decompress_cluster(bs, cluster_offset) < 0) {ret = -EIO;break;}memcpy(buf, s->cluster_cache + offset_in_cluster, n);} else {if ((cluster_offset & 511) != 0) {ret = -EIO;break;}qemu_co_mutex_unlock(&s->lock);BLKDBG_EVENT(bs->file, BLKDBG_READ_AIO);ret = bdrv_co_pread(bs->file, cluster_offset + offset_in_cluster, n, buf, 0);qemu_co_mutex_lock(&s->lock);if (ret < 0) {break;}if (bs->encrypted) {assert(s->crypto);if (qcrypto_block_decrypt(s->crypto,offset, buf, n, NULL) < 0) {ret = -EIO;break;}}}ret = 0;bytes -= n;offset += n;buf += n;}qemu_co_mutex_unlock(&s->lock);if (qiov->niov > 1) {qemu_iovec_from_buf(qiov, 0, orig_buf, qiov->size);qemu_vfree(orig_buf);}return ret;
}