qemu侧 块设备调试记录(一)
前言
qemu 编译版本 7.0.0
gdb --args ./build/qemu-system-x86_64 \
-m 2G -smp 2 \
--enable-kvm \
-boot order=c \
-name plr1 \
-drive file=/home/ostest/linux-test/run-test/ubuntu1.img,index=0,media=disk,format=qcow2 \
-drive file=/home/ostest/new/disk.raw,index=1,media=disk,format=raw \
-nic none\
-vnc :1
调试程序
位于 disk.raw
上
#define _GNU_SOURCE
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <unistd.h>
int main(void)
{
char hello_str[] = "Hello World!";
void *write_buffer;
void *read_buffer;
int fd;
int ret = 0;
fd = open("direct_write.log", O_RDWR | O_CREAT | O_DIRECT, 0644);
if (fd < 0) {
perror("Failed to open file\n");
return fd;
}
/* allocate a 1024 bytes buffer memalign分配指定地址对齐的资源接口 */
write_buffer = memalign(512, 512 * 2); // align by 512
if (!write_buffer) {
perror("Failed to alloc write buffer\n");
ret = -ENOMEM;
goto bad_write_buffer;
}
memcpy(write_buffer, hello_str, sizeof(hello_str));
ret = write(fd, write_buffer, 512 * 2);
if (ret < 0) {
perror("Failed to write file\n");
goto bad_write;
}
// 文件同步
if (fsync(fd) < 0) {
perror("fysnc:");
goto bad_write;
}
lseek(fd, 0, SEEK_SET); // read previous write data
read_buffer = memalign(512, 512 * 2);
if (!read_buffer) {
perror("Failed to alloc read buffer\n");
ret = -ENOMEM;
goto bad_read_buffer;
}
ret = read(fd, read_buffer, 512 * 2);
if (ret < 0) {
perror("Failed to read file\n");
goto bad_read;
}
printf("read from file : %s\n", (char *)read_buffer);
bad_read:
free(read_buffer);
bad_read_buffer:
bad_write:
free(write_buffer);
bad_write_buffer:
close(fd);
return ret;
}
qemu monitor 查看
参考 QEMU(4) q35
可以在命令后面添加 -monitor stdio
(qemu) info qtree
bus: main-system-bus
type System
dev: hpet, id ""
gpio-in "" 2
gpio-out "" 1
gpio-out "sysbus-irq" 32
mmio 00000000fed00000/0000000000000400
dev: kvm-ioapic, id ""
gpio-in "" 24
gsi_base = 0 (0x0)
mmio 00000000fec00000/0000000000001000
dev: i440FX-pcihost, id ""
pci-hole64-size = 2147483648 (2 GiB)
bypass-iommu = false
bus: pci.0
type PCI
dev: PIIX4_PM, id "
class Bridge, addr 00:01.3, pci id 8086:7113 (sub 1af4:1100)
bus: i2c
type i2c-bus
dev: smbus-eeprom, id ""
address = 87 (0x57)
dev: piix3-ide, id ""
addr = 01.1
class IDE controller, addr 00:01.1, pci id 8086:7010 (sub 1af4:1100)
bar 4: i/o at 0xc000 [0xc00f]
bus: ide.1
type IDE
dev: ide-cd, id ""
drive = "ide1-cd0"
bus: ide.0
type IDE
dev: ide-hd, id ""
drive = "ide0-hd1"
backend_defaults = "auto"
logical_block_size = 512 (512 B)
physical_block_size = 512 (512 B)
discard_granularity = 512 (512 B)
write-cache = "auto"
share-rw = false
serial = "QM00002"
model = ""
unit = 1 (0x1)
dev: ide-hd, id ""
drive = "ide0-hd0"
unit = 0 (0x0)
dev: VGA, id ""
dev: PIIX3, id ""
class ISA bridge, addr 00:01.0, pci id 8086:7000 (sub 1af4:1100)
bus: isa.0
type ISA
dev: port92, id ""
gpio-out "a20" 1
dev: vmmouse, id ""
dev: vmport, id ""
dev: i8042, id ""
dev: isa-fdc, id ""
bus: floppy-bus.0
type floppy-bus
dev: floppy, id ""
unit = 0 (0x0)
drive = "floppy0"
dev: isa-parallel, id ""
chardev = "parallel0"
dev: isa-serial, id ""
dev: i8257, id ""
dev: i8257, id ""
dev: isa-pcspk, id ""
dev: kvm-pit, id ""
dev: mc146818rtc, id ""
dev: kvm-i8259, id ""
dev: kvm-i8259, id ""
dev: i440FX, id ""
class Host bridge, addr 00:00.0, pci id 8086:1237 (sub 1af4:1100)
dev: fw_cfg_io, id ""
dev: kvmclock, id ""
dev: kvmvapic, id ""
其他信息
(qemu) info block
ide0-hd0 (#block163): /home/ostest/new/ubuntu3.img (qcow2)
Attached to: /machine/unattached/device[24]
Cache mode: writeback
ide0-hd1 (#block307): /home/ostest/new/disk3.raw (raw)
Attached to: /machine/unattached/device[25]
Cache mode: writeback
ide1-cd0: [not inserted]
Attached to: /machine/unattached/device[26]
Removable device: not locked, tray closed
floppy0: [not inserted]
Attached to: /machine/unattached/device[18]
Removable device: not locked, tray closed
sd0: [not inserted]
Removable device: not locked, tray closed
(qemu) info chardev
parallel0: filename=vc
compat_monitor0: filename=stdio
serial0: filename=vc
info irq -- show the interrupts statistics (if available)
查看大致函数调用
知道 qemu 是通过协程 异步处理io 处理函数 handle_aiocb_rw
, 先通过断点这个查看函数栈,再往前进行分析
#0 handle_aiocb_rw (opaque=0x7fff51fcc4e0) at ../block/file-posix.c:1549
#1 0x00005555560fabbb in worker_thread (opaque=0x555556b16000) at ../util/thread-pool.c:104
#2 0x00005555560d297d in qemu_thread_start (args=0x555556c447f0)
at ../util/qemu-thread-posix.c:556
// 通过qemu 源码搜索,发现
static int coroutine_fn raw_co_prw(...) {
return raw_thread_pool_submit(bs, handle_aiocb_rw, &acb);
}
#0 raw_co_prw
(bs=0x555556c3df60, offset=10019602432, bytes=65536, qiov=0x7fff51fcc8e0, type=1)
at ../block/file-posix.c:2124
#1 0x0000555555f444c9 in raw_co_preadv
(bs=0x555556c3df60, offset=10019602432, bytes=65536, qiov=0x7fff51fcc8e0, flags=0)
at ../block/file-posix.c:2173
#2 0x0000555555ed29d0 in bdrv_driver_preadv
(bs=0x555556c3df60, offset=10019602432, bytes=65536, qiov=0x7fff51fcc8e0, qiov_offset=0, flags=0) at ../block/io.c:1220
#3 0x0000555555ed3b55 in bdrv_aligned_preadv
(child=0x555556bfd790, req=0x7fff51fcc720, offset=10019602432, bytes=65536, align=1, qiov=0x7fff51fcc8e0, qiov_offset=0, flags=0) at ../block/io.c:1608
#4 0x0000555555ed45aa in bdrv_co_preadv_part
(child=0x555556bfd790, offset=10019602432, bytes=65536, qiov=0x7fff51fcc8e0, qiov_offset=0, flags=0) at ../block/io.c:1881
#5 0x0000555555ed43a1 in bdrv_co_preadv
(child=0x555556bfd790, offset=10019602432, bytes=65536, qiov=0x7fff51fcc8e0, flags=0)
at ../block/io.c:1830
#6 0x0000555555e9556d in bdrv_preadv
(child=0x555556bfd790, offset=10019602432, bytes=65536, qiov=0x7fff51fcc8e0, flags=0)
at block/block-gen.c:348
#7 0x0000555555ed26c2 in bdrv_pread
(child=0x555556bfd790, offset=10019602432, buf=0x7ffff4a36000, bytes=65536)
at ../block/io.c:1125
#8 0x0000555555eeb4c8 in qcow2_cache_do_get
(bs=0x555556c368a0, c=0x555556c438f0, offset=10019602432, table=0x7fff51fcca48, read_from_disk=true) at ../block/qcow2-cache.c:382
#9 0x0000555555eeb5b0 in qcow2_cache_get
--Type <RET> for more, q to quit, c to continue without paging--
(bs=0x555556c368a0, c=0x555556c438f0, offset=10019602432, table=0x7fff51fcca48)
at ../block/qcow2-cache.c:406
#10 0x0000555555eecc0e in l2_load
(bs=0x555556c368a0, offset=22488797184, l2_offset=10019602432, l2_slice=0x7fff51fcca48)
at ../block/qcow2-cluster.c:215
#11 0x0000555555eee0ad in get_cluster_table
(bs=0x555556c368a0, offset=22488797184, new_l2_slice=0x7fff51fccad0, new_l2_index=0x7fff51fccac4) at ../block/qcow2-cluster.c:802
#12 0x0000555555eefeab in handle_copied
(bs=0x555556c368a0, guest_offset=22488797184, host_offset=0x7fff51fccb90, bytes=0x7fff51fccb98, m=0x7fff51fccc30) at ../block/qcow2-cluster.c:1519
#13 0x0000555555ef08db in qcow2_alloc_host_offset
(bs=0x555556c368a0, offset=22488797184, bytes=0x7fff51fccc14, host_offset=0x7fff51fccc28, m=0x7fff51fccc30) at ../block/qcow2-cluster.c:1854
#14 0x0000555555f055d5 in qcow2_co_pwritev_part
(bs=0x555556c368a0, offset=22488797184, bytes=4096, qiov=0x7fff586bfb80, qiov_offset=0, flags=0) at ../block/qcow2.c:2629
#15 0x0000555555ed2ca9 in bdrv_driver_pwritev
(bs=0x555556c368a0, offset=22488797184, bytes=4096, qiov=0x7fff586bfb80, qiov_offset=0, flags=0) at ../block/io.c:1281
#16 0x0000555555ed53d6 in bdrv_aligned_pwritev
(child=0x555556c10490, req=0x7fff51fcce00, offset=22488797184, bytes=4096, align=1, qiov=0x7fff586bfb80, qiov_offset=0, flags=0) at ../block/io.c:2157
#17 0x0000555555ed5ce5 in bdrv_co_pwritev_part
(child=0x555556c10490, offset=22488797184, bytes=4096, qiov=0x7fff586bfb80, qiov_offset=0, flags=0) at ../block/io.c:2349
#18 0x0000555555ec2357 in blk_co_do_pwritev_part
(blk=0x555556c36550, offset=22488797184, bytes=4096, qiov=0x7fff586bfb80, qiov_offset=0, fl--Type <RET> for more, q to quit, c to continue without paging--
ags=0) at ../block/block-backend.c:1365
#19 0x0000555555ec294c in blk_aio_write_entry (opaque=0x7fff580f40b0)
at ../block/block-backend.c:1556
#20 0x00005555560e859a in coroutine_trampoline (i0=1477213776, i1=32767)
at ../util/coroutine-ucontext.c:173
// 再搜索blk_aio_write_entry
BlockAIOCB *blk_aio_pwritev(BlockBackend *blk, int64_t offset,
QEMUIOVector *qiov, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque)
{
IO_CODE();
assert((uint64_t)qiov->size <= INT64_MAX);
return blk_aio_prwv(blk, offset, qiov->size, qiov,
blk_aio_write_entry, flags, cb, opaque);
}
BlockAIOCB *blk_aio_pwrite_zeroes(BlockBackend *blk, int64_t offset,
int64_t bytes, BdrvRequestFlags flags,
BlockCompletionFunc *cb, void *opaque)
{
IO_CODE();
return blk_aio_prwv(blk, offset, bytes, NULL, blk_aio_write_entry,
flags | BDRV_REQ_ZERO_WRITE, cb, opaque);
}
#0 blk_aio_pwritev
(blk=0x555556c36550, offset=22488797184, qiov=0x7fff586bfb80, flags=0, cb=0x5555559f5fdf <dma_blk_cb>, opaque=0x7fff586bfb20) at ../block/block-backend.c:1640
#1 0x00005555559f6a68 in dma_blk_write_io_func
(offset=22488797184, iov=0x7fff586bfb80, cb=0x5555559f5fdf <dma_blk_cb>, cb_opaque=0x7fff586bfb20, opaque=0x555556c36550) at ../softmmu/dma-helpers.c:379
#2 0x00005555559f64d9 in dma_blk_cb (opaque=0x7fff586bfb20, ret=0)
at ../softmmu/dma-helpers.c:238
#3 0x00005555559f6768 in dma_blk_io
(ctx=0x555556a06020, sg=0x5555576aa310, offset=22488797184, align=512, io_func=0x5555559f6824 <dma_blk_write_io_func>, io_func_opaque=0x555556c36550, cb=0x555555b0fb78 <ide_dma_cb>, opaque=0x5555576a9fe8, dir=DMA_DIRECTION_TO_DEVICE) at ../softmmu/dma-helpers.c:317
#4 0x00005555559f6ac9 in dma_blk_write
(blk=0x555556c36550, sg=0x5555576aa310, offset=22488797184, align=512, cb=
0x555555b0fb78 <ide_dma_cb>, opaque=0x5555576a9fe8) at ../softmmu/dma-helpers.c:386
#5 0x0000555555b0ff4a in ide_dma_cb (opaque=0x5555576a9fe8, ret=0) at ../hw/ide/core.c:986
#6 0x0000555555b18c2b in bmdma_cmd_writeb (bm=0x5555576ab140, val=1) at ../hw/ide/pci.c:355
#7 0x0000555555b194bf in bmdma_write (opaque=0x5555576ab140, addr=0, val=1, size=1)
at ../hw/ide/piix.c:76
piix_bmdma_ops 注册
#0 bmdma_setup_bar (d=0x5555576a9560) at ../hw/ide/piix.c:93
#1 0x0000555555b19903 in pci_piix_ide_realize (dev=0x5555576a9560, errp=0x7fffffffdae8)
at ../hw/ide/piix.c:164
#2 0x0000555555ba0783 in pci_qdev_realize (qdev=0x5555576a9560, errp=0x7fffffffdb60) at ../hw/pci/pci.c:2192
#3 0x0000555555e5ed7e in device_set_realized (obj=0x5555576a9560, value=true, errp=0x7fffffffdc70)
at ../hw/core/qdev.c:531
#4 0x0000555555e6789d in property_set_bool (obj=0x5555576a9560, v=
0x5555576abcb0, name=0x55555625f251 "realized", opaque=0x555556a08870, errp=0x7fffffffdc70)
at ../qom/object.c:2273
#5 0x0000555555e65808 in object_property_set (obj=0x5555576a9560, name=0x55555625f251 "realized", v=
0x5555576abcb0, errp=0x7fffffffdc70) at ../qom/object.c:1408
#6 0x0000555555e69d6e in object_property_set_qobject
(obj=0x5555576a9560, name=0x55555625f251 "realized", value=0x5555576a9510, errp=0x55555694b720 <error_fatal>) at ../qom/qom-qobject.c:28
#7 0x0000555555e65b83 in object_property_set_bool
(obj=0x5555576a9560, name=0x55555625f251 "realized", value=true, errp=0x55555694b720 <error_fatal>)
at ../qom/object.c:1477
#8 0x0000555555e5e612 in qdev_realize
(dev=0x5555576a9560, bus=0x555556dafee0, errp=0x55555694b720 <error_fatal>) at ../hw/core/qdev.c:333
#9 0x0000555555e5e643 in qdev_realize_and_unref
(dev=0x5555576a9560, bus=0x555556dafee0, errp=0x55555694b720 <error_fatal>) at ../hw/core/qdev.c:340
#10 0x0000555555ba0a72 in pci_realize_and_unref
(dev=0x5555576a9560, bus=0x555556dafee0, errp=0x55555694b720 <error_fatal>) at ../hw/pci/pci.c:2259
#11 0x0000555555ba0ac2 in pci_create_simple_multifunction
(bus=0x555556dafee0, devfn=9, multifunction=false, name=0x55555621c151 "piix3-ide")
at ../hw/pci/pci.c:2267
#12 0x0000555555ba0afa in pci_create_simple (bus=0x555556dafee0, devfn=9, name=0x55555621c151 "piix3-ide")
at ../hw/pci/pci.c:2273
#13 0x0000555555c852f0 in pc_init1
(machine=0x555556bd50c0, host_type=0x55555621c1a4 "i440FX-pcihost", pci_type=0x55555621c19d "i440FX")
at ../hw/i386/pc_piix.c:247
#14 0x0000555555c8592c in pc_init_v7_0 (machine=0x555556bd50c0) at ../hw/i386/pc_piix.c:427
#15 0x0000555555accf0c in machine_run_board_init (machine=0x555556bd50c0) at ../hw/core/machine.c:1189
bmdma_write
#0 bmdma_write (opaque=0x5555576ab140, addr=2, val=0, size=1) at ../hw/ide/piix.c:66
#1 0x0000555555d22607 in memory_region_write_accessor
(mr=0x5555576ab2b0, addr=2, value=0x7fff675fd688, size=1, shift=0, mask=255, attrs=...)
at ../softmmu/memory.c:518
(gdb) p *bm
$2 = {dma = {ops = 0x5555566dfbc0 <bmdma_ops>, qiov = {iov = 0x0, niov = 0, {{nalloc = 0, local_iov = {
iov_base = 0x0, iov_len = 0}}, {__pad = '\000' <repeats 11 times>, size = 0}}}, aiocb = 0x0},
hit Breakpoint 4, bmdma_cmd_writeb() at ../hw/ide/pci.c:341
// 从这些看不是需要debug的地方
(gdb) p bm->dma_cb
$5 = (BlockCompletionFunc *) 0x555555b158f4 <ide_atapi_cmd_read_dma_cb>
hit Breakpoint 5, ide_dma_cb()
p s->blk->name
$12 = 0x555556c44850 "ide0-hd0"
(gdb) n
948 if (prep_size < n * 512) {
(gdb) p prep_size
$18 = 512
(gdb) p n
$19 = 1
(gdb) p s->bus->dma->ops->prepare_buf
$20 = (DMAInt32Func *) 0x555555b184d9 <bmdma_prepare_buf>
dma_blk_write
Thread 6 "qemu-system-x86" hit Breakpoint 7, dma_blk_write (blk=0xfe7c075bd59d6200, sg=0x200000,
offset=93825027187640, align=0, cb=0x6, opaque=0x7fff675fd4b0) at ../softmmu/dma-helpers.c:389
389 {
(gdb) n
390 return dma_blk_io(blk_get_aio_context(blk), sg, offset, align,
(gdb) p *blk
$24 = {name = 0x555556c64bd0 "ide0-hd1", refcnt = 2, root = 0x555556bf5870, ctx = 0x555556a06020,
legacy_dinfo = 0x555556c46570,
dev = 0x5555577e0c60, dev_ops = 0x5555566de5c0 <ide_hd_block_ops>, dev_opaque = 0x5555576aa3b8,
(gdb) s
blk_get_aio_context (blk=) at ../block/block-backend.c:2164
(gdb) n
2168 if (bs) {
(gdb) p bs->filename
$31 = "/home/ostest/new/disk.raw", '\000' <repeats 4070 times>
(gdb) p *bs
$33 = {open_flags = 139266, encrypted = false, sg = false, probed = false, force_share = false,
implicit = false, drv = 0x5555568f40a0 <bdrv_raw>,walking_aio_notifiers = false,
(gdb) p *(bs->file)
$35 = {bs = 0x555556c5e550, name = 0x555556c64d50 "file", klass = 0x5555567f60c0 <child_of_bds>, role = 20,
// 指向是不一样的
(gdb) p bs
$36 = (BlockDriverState *) 0x555556c57200
(gdb) s
dma_blk_io ()at ../softmmu/dma-helpers.c:288
p *dbs
$43 = {common = {aiocb_info = 0x5555566cddc0 <dma_aiocb_info>, bs = 0x0, cb = 0x555555b0fb8b <ide_dma_cb>,
opaque = 0x5555576aa3b8, refcnt = 1}, ctx = 0x555556a06020, acb = 0x0, sg = 0x5555576aa6e0, align = 512,
offset = 536870912, dir = DMA_DIRECTION_TO_DEVICE, sg_cur_index = 0, sg_cur_byte = 0, iov = {
iov = 0x7fff6017a500, niov = 0, {{nalloc = 1, local_iov = {iov_base = 0x0, iov_len = 0}}, {__pad = "", size = 0}}}, bh = 0x0,
io_func = <dma_blk_write_io_func>, io_func_opaque = 0x555556c466d0}
dma_blk_write_io_func
函数调用关系
static void ide_dma_cb(void *opaque, int ret)
{
IDEState *s = opaque;
s->bus->dma->aiocb = dma_blk_write(s->blk, &s->sg, offset,
BDRV_SECTOR_SIZE, ide_dma_cb, s);
}
BlockAIOCB *dma_blk_write(BlockBackend *blk,
QEMUSGList *sg, uint64_t offset, uint32_t align,
void (*cb)(void *opaque, int ret), void *opaque)
{
// opaque -> IDEState
return dma_blk_io(blk_get_aio_context(blk), sg, offset, align,
dma_blk_write_io_func, blk, cb, opaque,
DMA_DIRECTION_TO_DEVICE);
}
BlockAIOCB *dma_blk_io(AioContext *ctx,
QEMUSGList *sg, uint64_t offset, uint32_t align,
DMAIOFunc *io_func, void *io_func_opaque,
BlockCompletionFunc *cb,
void *opaque, DMADirection dir)
{
// io_func_opaque->blk; opaque->IDEState
DMAAIOCB *dbs = qemu_aio_get(&dma_aiocb_info, NULL, cb, opaque);
dbs->acb = NULL;
dbs->sg = sg;
dbs->ctx = ctx;
dbs->offset = offset;
dbs->align = align;
dbs->sg_cur_index = 0;
dbs->sg_cur_byte = 0;
dbs->dir = dir;
dbs->io_func = io_func;
dbs->io_func_opaque = io_func_opaque;
dbs->bh = NULL;
qemu_iovec_init(&dbs->iov, sg->nsg);
dma_blk_cb(dbs, 0);
// 即调用dma_blk_write_io_func
dbs->acb = dbs->io_func(dbs->offset, &dbs->iov,
dma_blk_cb, dbs, dbs->io_func_opaque);
return &dbs->common;
}
static
BlockAIOCB *dma_blk_write_io_func(int64_t offset, QEMUIOVector *iov,
BlockCompletionFunc *cb, void *cb_opaque,
void *opaque)
{
// cb_opaque->DMAAIOCB
BlockBackend *blk = opaque;
return blk_aio_pwritev(blk, offset, iov, 0, cb, cb_opaque);
}
gdb 调试过程
Thread 6 "qemu-system-x86" hit Breakpoint 2, dma_blk_write_io_func ()
at ../softmmu/dma-helpers.c:269
(gdb) p blk->name
$2 = 0x555556d03cb0 "ide0-hd1"
(gdb) s
blk_aio_pwritev (blk=0x555556ce33a0, offset=138412032, qiov=0x7fff580052b0, flags=0,
cb=0x5555558b7f0a <dma_blk_cb>, opaque=0x7fff58005250
) at ../block/block-backend.c:1638
1638 {
(gdb) n
1640 assert((uint64_t)qiov->size <= INT64_MAX);
(gdb) n
1641 return blk_aio_prwv(blk, offset, qiov->size, qiov,
(gdb) p *qiov
$3 = {iov = 0x7fff58049bf0, niov = 1, {{nalloc = 1, local_iov = {iov_base = 0x0, iov_len = 1024}}, {, size = 1024}}}
(gdb) p *(qiov->iov)
$4 = {iov_base = 0x7fff7868f200, iov_len = 1024}
(gdb) p *(qiov->iov->iov_base)
Attempt to dereference a generic pointer.
(gdb) p (char *)(qiov->iov->iov_base)
// 此时是已经获取到数据的,猜测是在dma_blk_cb函数里
$5 = 0x7fff7868f200 "Hello World!"
(gdb) s
blk_aio_prwv (blk=0x555556ce33a0, offset=138412032, bytes=1024, iobuf=0x7fff580052b0,
co_entry= <blk_aio_write_entry>, flags=0, cb= <dma_blk_cb>,
opaque=0x7fff58005250
) at ../block/block-backend.c:1509