searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享
原创

Qemu的块设备复制实现

2024-04-29 01:41:27
81
0

    Qemu的块设备复制可通过以下qmp调用发起:

{"execute":"drive-mirror","arguments":{"device": <device>,"target":<target>,"speed":<speed>, "granularity", granularity,"buf-size":<buf-size>,"sync":<sync>,"format":<format>}}

    此处sync参数指示需要进行复制的数据,支持三种:full/top/none,分别为全盘复制,镜像链中最顶层镜像所含扇区的复制,新写入IO的复制。granularity参数为脏数据比较的粒度(默认64k)。buf-size为用于存放复制到目标端的数据缓冲区的大小(默认16M)。

    Qemu在qmp_drive_mirror方法(qemu/blockdev.c)中处理此指令。处理分为3个阶段:

    1、准备阶段

    (1)根据传入的device参数获取对应块设备后端的驱动, 并对其它参数进行解析处理;

    (2)在目标路径(文件或块设备)创建新的指定格式(如raw格式)的块设备文件;

    (3)创建目标块设备后端驱动;

    (4)调用blockdev_mirror_common方法(qemu/blockdev.c)进入下一步处理。blockdev_mirror_common方法仅做了些简单的参数校验,随后调用mirror_start方法(qemu/block/mirror.c)进入下一步处理。mirror_start方法同样未做过多处理,调用mirror_start_job方法进入下一步处理。

    2、任务起始阶段

    (1)mirror_start_job方法创建了一个新的虚拟驱动用于复制I/O请求;

    (2)将新的虚拟驱动设置为镜像链的顶端,即源后端设备驱动的上一级,该虚拟驱动bdrv_mirror_top的读写操作仍调用源后端设备的读写操作;

    (3)创建任务(此处并非开始任务,仅对任务进行初始化),并将任务与相关源端、目标端后端设备驱动关联,并创建用于标识数据差异的bitmap;

    (4)调用job_start方法(qemu/job.c)创建协程开始执行任务。

    3、 任务同步阶段

    创建的协程将调用job驱动的.run方法(对于mirror_job_driver为mirror_run方法),实现任务的主体流程。mirror_run方法实现分为两部分,首先还是部分参数的初始化(包括创建了in_flight_bitmap用于记录在途操作的数据),然后进入循环,循环中控制任务的执行频率、更新任务的进度状态以及调用任务同步阶段的核心实现mirror_iteration方法。mirror_iteration方法实现如下:

    (1)从源bitmap里的第一个脏位开始,查找连续的脏位(或达到缓冲区大小);

    (2)将这些脏位标入in_flight_bitmap,同时将源bitmap的对应脏位复位;

    (3)对脏位对应的数据,调用mirror_do_read方法从源端到目的端进行复制。mirror_do_read方法调用blk_aio_preadv方法从源端读取数据,回调mirror_read_complete方法执行读取数据后的处理;mirror_read_complete方法调用blk_aio_pwritev方法将数据写入目标端,回调mirror_write_complete方法执行写入数据后的处理;mirror_write_complete方法最后调用mirror_iteration_done方法结束此次循环的任务;mirror_iteration_done方法最后所做的工作是将in_flight_bitmap的脏位清除。

    从代码实现来看,此任务对源端读写性能的影响有以下两点:

    1、对源端设备进行写操作时会调用bdrv_set_dirty方法进行脏数据标记,而在数据同步过程中同样会调用bdrv_reset_dirty_bitmap_locked等方法对bitmap进行操作,此处涉及锁的竞争,但锁的粒度很小,对性能不会产生明显影响;

    2、blockcopy任务在数据同步过程中需要从源端设备读取脏数据,此项读操作会对源端读写性能产生一定的影响。

0条评论
作者已关闭评论
CD
15文章数
0粉丝数
CD
15 文章 | 0 粉丝
原创

Qemu的块设备复制实现

2024-04-29 01:41:27
81
0

    Qemu的块设备复制可通过以下qmp调用发起:

{"execute":"drive-mirror","arguments":{"device": <device>,"target":<target>,"speed":<speed>, "granularity", granularity,"buf-size":<buf-size>,"sync":<sync>,"format":<format>}}

    此处sync参数指示需要进行复制的数据,支持三种:full/top/none,分别为全盘复制,镜像链中最顶层镜像所含扇区的复制,新写入IO的复制。granularity参数为脏数据比较的粒度(默认64k)。buf-size为用于存放复制到目标端的数据缓冲区的大小(默认16M)。

    Qemu在qmp_drive_mirror方法(qemu/blockdev.c)中处理此指令。处理分为3个阶段:

    1、准备阶段

    (1)根据传入的device参数获取对应块设备后端的驱动, 并对其它参数进行解析处理;

    (2)在目标路径(文件或块设备)创建新的指定格式(如raw格式)的块设备文件;

    (3)创建目标块设备后端驱动;

    (4)调用blockdev_mirror_common方法(qemu/blockdev.c)进入下一步处理。blockdev_mirror_common方法仅做了些简单的参数校验,随后调用mirror_start方法(qemu/block/mirror.c)进入下一步处理。mirror_start方法同样未做过多处理,调用mirror_start_job方法进入下一步处理。

    2、任务起始阶段

    (1)mirror_start_job方法创建了一个新的虚拟驱动用于复制I/O请求;

    (2)将新的虚拟驱动设置为镜像链的顶端,即源后端设备驱动的上一级,该虚拟驱动bdrv_mirror_top的读写操作仍调用源后端设备的读写操作;

    (3)创建任务(此处并非开始任务,仅对任务进行初始化),并将任务与相关源端、目标端后端设备驱动关联,并创建用于标识数据差异的bitmap;

    (4)调用job_start方法(qemu/job.c)创建协程开始执行任务。

    3、 任务同步阶段

    创建的协程将调用job驱动的.run方法(对于mirror_job_driver为mirror_run方法),实现任务的主体流程。mirror_run方法实现分为两部分,首先还是部分参数的初始化(包括创建了in_flight_bitmap用于记录在途操作的数据),然后进入循环,循环中控制任务的执行频率、更新任务的进度状态以及调用任务同步阶段的核心实现mirror_iteration方法。mirror_iteration方法实现如下:

    (1)从源bitmap里的第一个脏位开始,查找连续的脏位(或达到缓冲区大小);

    (2)将这些脏位标入in_flight_bitmap,同时将源bitmap的对应脏位复位;

    (3)对脏位对应的数据,调用mirror_do_read方法从源端到目的端进行复制。mirror_do_read方法调用blk_aio_preadv方法从源端读取数据,回调mirror_read_complete方法执行读取数据后的处理;mirror_read_complete方法调用blk_aio_pwritev方法将数据写入目标端,回调mirror_write_complete方法执行写入数据后的处理;mirror_write_complete方法最后调用mirror_iteration_done方法结束此次循环的任务;mirror_iteration_done方法最后所做的工作是将in_flight_bitmap的脏位清除。

    从代码实现来看,此任务对源端读写性能的影响有以下两点:

    1、对源端设备进行写操作时会调用bdrv_set_dirty方法进行脏数据标记,而在数据同步过程中同样会调用bdrv_reset_dirty_bitmap_locked等方法对bitmap进行操作,此处涉及锁的竞争,但锁的粒度很小,对性能不会产生明显影响;

    2、blockcopy任务在数据同步过程中需要从源端设备读取脏数据,此项读操作会对源端读写性能产生一定的影响。

文章来自个人专栏
文章 | 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0