一、缺陷信息
内核信息:
4.19.90-89.11.v2401.ky10.x86_64
缺陷归属组件:
qemu-kvm
缺陷归属的版本:
qemu-8.2.0-13.oe2403.x86_64
缺陷简述:
使用基于openEuler24.03环境构建容器,在该容器中运行NestOS构建程序,使用libguestfs启动qemu失败,具体执行参数如下。
【环境信息】
软件信息
【问题复现步骤】
[nestos-assembler]$ /usr/bin/qemu-kvm
-global virtio-blk-pci.scsi=off
-no-user-config
-nodefaults
-display none
-machine accel=kvm:tcg,graphics=off,hpet=off
-cpu max,la57=off
-smp 64
-m 1280
-no-reboot
-rtc driftfix=slew
-global kvm-pit.lost_tick_policy=discard
-kernel /var/tmp/.guestfs-0/appliance.d/kernel
-initrd /var/tmp/.guestfs-0/appliance.d/initrd
-object rng-random,filename=/dev/urandom,id=rng0
-device virtio-rng-pci,rng=rng0
-device virtio-scsi-pci,id=scsi
-drive file.file.filename=/tmp/libguestfsBK7Kt5/overlay1.qcow2,file.driver=qcow2,file.backing.file.locking=off,cache=unsafe,id=hd0,if=none
-device scsi-hd,drive=hd0
-drive file=/var/tmp/.guestfs-0/appliance.d/root,snapshot=on,id=appliance,cache=unsafe,if=none,format=raw
-device scsi-hd,drive=appliance
-device virtio-serial-pci
-serial stdio
-device virtserialport,chardev=channel0,name=org.libguestfs.channel.0
-append "panic=1 console=ttyS0 edd=off udevtimeout=6000 udev.event-timeout=6000 no_timer_check printk.time=1 cgroup_disable=memory usbcore.nousb cryptomgr.notests tsc=reliable 8250.nr_uarts=1 root=UUID=4312b3e9-f40c-41db-9542-510655647e53 selinux=0 guestfs_verbose=1 TERM=xterm"
【实际结果】,请描述出问题的结果和影响
qemu-kvm: ../blockdev.c:629: blockdev_init: Assertion `(bdrv_flags & BDRV_O_CACHE_MASK) == 0' failed.
Aborted (core dumped)
【其他相关附件信息】
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
进一步分析,是guestfish初始化qemu-kvm时,添加磁盘中存在cache=unsafe参数,触发该断言。经排查,oe22.03-sp4版本的1.40.2和oe24.03版本的1.49.5版本的guestfish均在添加磁盘时添加cache=unsafe参数,且该参数为代码中硬编码添加。但oe22.03sp4版本qemu可正常工作,oe24.03版本出现此问题。初步认为需qemu组件进行修改适配。
代码分析:
assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0);
在断言错误的代码上,BDRV_O_CACHE_MASK宏定义是固定的:
#define BDRV_O_CACHE_MASK (BDRV_O_NOCACHE | BDRV_O_NO_FLUSH)
在上游社区原始版本的qemu-8.2.0中,bdrv_flags可能的赋值只有BDRV_O_COPY_ON_READ和BDRV_O_SNAPSHOT标志,完全不会与 BDRV_O_CACHE_MASK 冲突。
在qemu-6.2.0中添加了一段代码:
if (!file || !*file) {
cache = qdict_get_try_str(bs_opts, BDRV_OPT_CACHE_NO_FLUSH);
if (cache && !strcmp(cache, "on")) {
bdrv_flags |= BDRV_O_NO_FLUSH;
}
cache = qdict_get_try_str(bs_opts, BDRV_OPT_CACHE_DIRECT);
if (cache && !strcmp(cache, "on")) {
bdrv_flags |= BDRV_O_NOCACHE;
}
qdict_del(bs_opts, BDRV_OPT_CACHE_NO_FLUSH);
qdict_del(bs_opts, BDRV_OPT_CACHE_DIRECT);
}
这段代码来自block-enable-cache-mode-of-empty-cdrom.patch,目的是在cdrom文件为空的情况下启用缓存模式。但是这部分代码中给 bdrv_flags 添加的参数,与后面 assert((bdrv_flags & BDRV_O_CACHE_MASK) == 0) 的操作出现巨大冲突,导致在该测试用例的场景下,qemu会因断言失败而启动失败。
并且,在对代码的分析中,BDRV_OPT_CACHE_NO_FLUSH 和 BDRV_OPT_CACHE_DIRECT 宏定义一般是在bdrv_parse_cache_mode函数中,通过对 QemuOpts 对象的选项进行判断,来进行赋值的:
int bdrv_parse_cache_mode(const char *mode, int *flags, bool *writethrough)
{
*flags &= ~BDRV_O_CACHE_MASK;
if (!strcmp(mode, "off") || !strcmp(mode, "none")) {
*writethrough = false;
*flags |= BDRV_O_NOCACHE;
} else if (!strcmp(mode, "directsync")) {
*writethrough = true;
*flags |= BDRV_O_NOCACHE;
} else if (!strcmp(mode, "writeback")) {
*writethrough = false;
} else if (!strcmp(mode, "unsafe")) {
*writethrough = false;
*flags |= BDRV_O_NO_FLUSH;
} else if (!strcmp(mode, "writethrough")) {
*writethrough = true;
} else {
return -1;
}
return 0;
}
----------------------------------------------------
在 blockdev.c 的 drive_new 函数中:
value = qemu_opt_get(all_opts, "cache");
if (value) {
int flags = 0;
bool writethrough;
if (bdrv_parse_cache_mode(value, &flags, &writethrough) != 0) {
error_setg(errp, "invalid cache option");
return NULL;
}
/* Specific options take precedence */
if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_WB)) {
qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_WB,
!writethrough, &error_abort);
}
if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_DIRECT)) {
qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_DIRECT,
!!(flags & BDRV_O_NOCACHE), &error_abort);
}
if (!qemu_opt_get(all_opts, BDRV_OPT_CACHE_NO_FLUSH)) {
qemu_opt_set_bool(all_opts, BDRV_OPT_CACHE_NO_FLUSH,
!!(flags & BDRV_O_NO_FLUSH), &error_abort);
}
qemu_opt_unset(all_opts, "cache");
}
从这方面看,对 bdrv_flags 进行宏赋值是没有必要的,qemu 原本的设计中主要是通过对 QemuOpts 对象赋值 BDRV_OPT_CACHE_NO_FLUSH 和 BDRV_OPT_CACHE_DIRECT 宏。并且当前添加的 bdrv_flags 赋值会触发assert failed问题,建议回退代码,取消对 bdrv_flags 的赋值。
并且在上述代码问题下,在使用问题描述中的qemu命令行参数时,如果修改cache=none 或是 cache=directsync 都会触发给 bdrv_flags 赋值,造成qemu Assertion `(bdrv_flags & BDRV_O_CACHE_MASK) == 0' failed.
登录 后才可以发表评论