Chinaunix首页 | 论坛 | 博客
  • 博客访问: 222288
  • 博文数量: 76
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 513
  • 用 户 组: 普通用户
  • 注册时间: 2013-08-23 00:06
个人简介

展示自己、证明自己

文章分类

全部博文(76)

文章存档

2018年(1)

2014年(55)

2013年(20)

我的朋友

分类: C/C++

2014-07-28 18:03:21

转载请注明出处:http://blog.chinaunix.net/blog/post/id/4379289.html
qemu-kvm0.12.1.2
原生态读写分为同步读写和异步读写

同步读写

前提

1)注释raw-posix.c bdrv_raw结构体中的bdrv_aio_readvbdrv_aio_writevbdrv_aio_flush变量,其目的是为了防止对文件读写时走aio分支。

2)建立原始文件,qemu-img create os.img 10G, 再安装启动虚拟机


io流走向

vm-guset-os ---> hw(ide/virtio) ---> block.c --->raw-posix.c--->img镜像文件

具体流程

  1. 在虚拟机系统中进行复制、新建文件等操作

  2. 虚拟机系统中该卷所在的磁盘驱动捕获读写操作,并记录操作所在的文件和内容,向qemu程序发送中断

  3. qemu子线程(ap_main_loop)捕获到该操作,并退出(vm-exit), 然后进行端口IO读写(kvm_handle_io)

  4. 使用vm-exit的端口参数和qemu初始化的地址进行对比操作,找到合适的驱动(ide or virtio)将虚拟机系统的读写操作解析

  5. 调用block.c文件中bdrv_aio_writev函数,选择原始写函数。详见文章末尾附录1(block函数初始化过程)

  1. 调用raw-posix.c中的原始读写函数将内容写入文件中。


gdb调试结果

Breakpoint 1, raw_write (bs=0xc8b3b0, sector_num=5485936, buf=0x7ffff001e200 "\002", nb_sectors=8)

at block/raw-posix.c:515

515 ret = raw_pwrite(bs, sector_num * 512, buf, nb_sectors * 512);

(gdb) bt

#0 raw_write (bs=0xc8b3b0, sector_num=5485936, buf=0x7ffff001e200 "\002", nb_sectors=8) at block/raw-posix.c:515

#1 0x0000000000499e6d in bdrv_write (bs=0xc8b3b0, sector_num=5485936, buf=0x7ffff001e200 "\002", nb_sectors=8)

at block.c:685

#2 0x000000000049c6ef in bdrv_aio_rw_vector (bs=0xc8b3b0, sector_num=5485936, qiov=0x7ffff00009a8,

nb_sectors=8, cb=0x58c0bd , opaque=0x7ffff0000950, is_write=1) at block.c:1858

#3 0x000000000049c7dd in bdrv_aio_writev_em (bs=0xc8b3b0, sector_num=5485936, qiov=0x7ffff00009a8,

nb_sectors=8, cb=0x58c0bd , opaque=0x7ffff0000950) at block.c:1879

#4 0x000000000049bcf5 in bdrv_aio_writev (bs=0xc8b3b0, sector_num=5485936, qiov=0x7ffff00009a8, nb_sectors=8,

cb=0x58c0bd , opaque=0x7ffff0000950) at block.c:1578

#5 0x000000000058c31c in dma_bdrv_cb (opaque=0x7ffff0000950, ret=0) at /root/qemu-kvm12/dma-helpers.c:120

#6 0x000000000058c4a4 in dma_bdrv_io (bs=0xc8b3b0, sg=0x1212568, sector_num=5485936,

cb=0x44023c , opaque=0x1212f70, is_write=1) at /root/qemu-kvm12/dma-helpers.c:167

#7 0x000000000058c55b in dma_bdrv_write (bs=0xc8b3b0, sg=0x1212568, sector=5485936,

cb=0x44023c , opaque=0x1212f70) at /root/qemu-kvm12/dma-helpers.c:187

#8 0x00000000004403d9 in ide_write_dma_cb (opaque=0x1212f70, ret=0) at /root/qemu-kvm12/hw/ide/core.c:743

#9 0x0000000000445765 in bmdma_cmd_writeb (opaque=0x1212f70, addr=49152, val=1)

at /root/qemu-kvm12/hw/ide/pci.c:51

#10 0x00000000004ca131 in ioport_write (index=0, address=49152, data=1) at ioport.c:80

#11 0x00000000004ca4c5 in cpu_outb (addr=49152, val=1 '\001') at ioport.c:198

#12 0x0000000000429327 in kvm_handle_io (port=49152, data=0x7ffff7ff7000, direction=1, size=1, count=1)

at /root/qemu-kvm12/kvm-all.c:535

#13 0x000000000042b79b in kvm_run (env=0xc8e2a0) at /root/qemu-kvm12/qemu-kvm.c:964

#14 0x000000000042cabd in kvm_cpu_exec (env=0xc8e2a0) at /root/qemu-kvm12/qemu-kvm.c:1646

#15 0x000000000042d28d in kvm_main_loop_cpu (env=0xc8e2a0) at /root/qemu-kvm12/qemu-kvm.c:1888

#16 0x000000000042d3ee in ap_main_loop (_env=0xc8e2a0) at /root/qemu-kvm12/qemu-kvm.c:1938

#17 0x0000003337c079d1 in start_thread () from /lib64/libpthread.so.0

#18 0x00000033378e8b6d in clone () from /lib64/libc.so.6


异步读写
读写函数和读写操作异步进行。

前面步骤与原始读写步骤一样,在最后读写是调用raw_aio_readvraw_aio_writev函数
调用读写函数

raw_aio_writev为例,

->bdrv_raw

->raw_aio_writev

->raw_aio_submit

->paio_submit

->qemu_paio_submit

->spawn_thread

->thread_create(&thread_id, &attr, aio_thread, NULL);

实际读写操作

aio_thread

->handle_aiocb_rw

->handle_aiocb_rw_linear(aiocb, buf);

->len = pwrite(aiocb->aio_fildes,

(const char *)buf + offset,

aiocb->aio_nbytes - offset,

aiocb->aio_offset + offset);


附录1(block函数初始化过程)

1) 调用bdrv_register,将各个bdrv结构体函数加载到firts_drv链表中。

2) 如果结构体中不存在变量bdrv_aio_readv,则将bdrv_aio_readv_em函数赋值给bdrv->bdrv_aio_readv(写函数类似)

3) 如果结构体中不存在变量bdrv_read,则将bdrv_read_em函数赋值给bdrv->bdrv_read(写函数类似)

./block/raw-posix.c:1345: bdrv_register(&bdrv_raw);

./block/raw-posix.c:1346: bdrv_register(&bdrv_host_device);

注册函数的实现

void bdrv_register(BlockDriver *bdrv)

{

if (!bdrv->bdrv_aio_readv) {  //判断bdrv_aio是否存在

/* add AIO emulation layer */

bdrv->bdrv_aio_readv = bdrv_aio_readv_em;

bdrv->bdrv_aio_writev = bdrv_aio_writev_em;

} else if (!bdrv->bdrv_read) { //判断bdrv是否存在

/* add synchronous IO emulation layer */

bdrv->bdrv_read = bdrv_read_em;

bdrv->bdrv_write = bdrv_write_em;

} // 如果两个函数均在块结构体中没有重定义,则读写函数将陷入死循环中

if (!bdrv->bdrv_aio_flush)

bdrv->bdrv_aio_flush = bdrv_aio_flush_em;

bdrv->next = first_drv;

first_drv = bdrv;

}

块读写过程,判bdrv_aio_readvbdrv_read结构体变量是否被重定义,如果bdrv_aio_readv没有重定义,则接着调用bdrv_read。同理如果bdrv_read没有重定义,则接着调用bdrv_aio_readv,这就不难理解上面的调用过程了。

bdrv_aio_readv_em为例:接着调用bdrv_aio_rw_vector函数

static BlockDriverAIOCB *bdrv_aio_readv_em(BlockDriverState *bs, int64_t sector_num, QEMUIOVector *qiov,
                         int nb_sectors, BlockDriverCompletionFunc *cb, void *opaque)

{

return bdrv_aio_rw_vector(bs, sector_num, qiov, nb_sectors, cb, opaque, 0);

}

static BlockDriverAIOCB *bdrv_aio_rw_vector(BlockDriverState *bs,int64_t sector_num,QEMUIOVector *qiov,

                 int nb_sectors,BlockDriverCompletionFunc *cb,void *opaque,int is_write)

{

if (is_write) {

qemu_iovec_to_buffer(acb->qiov, acb->bounce);

acb->ret = bdrv_write(bs, sector_num, acb->bounce, nb_sectors);

} else {

acb->ret = bdrv_read(bs, sector_num, acb->bounce, nb_sectors);

}

}

int bdrv_read(BlockDriverState *bs, int64_t sector_num,uint8_t *buf, int nb_sectors)

{

return drv->bdrv_read(bs, sector_num, buf, nb_sectors);

}

bdrv_read_em为例,

static int bdrv_read_em(BlockDriverState *bs, int64_t sector_num,uint8_t *buf, int nb_sectors)

{

acb = bdrv_aio_readv(bs, sector_num, &qiov, nb_sectors,bdrv_rw_em_cb, &async_ret);

}

BlockDriverAIOCB *bdrv_aio_readv(BlockDriverState *bs, int64_t sector_num,QEMUIOVector *qiov, int nb_sectors,

            BlockDriverCompletionFunc *cb, void *opaque)

{

ret = drv->bdrv_aio_readv(bs, sector_num, qiov, nb_sectors,cb, opaque);

}



以后需阅读并编写的:

1)端口IO处理过程

2virtio,ide驱动原理

3qemu各个线程的响应

4qemu-1.3 块设备的读写(使用协程(coroutine)进行函数调用管理bdrv_co_do_rw,然后调用对应读写函数)



阅读(1354) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~