Chinaunix首页 | 论坛 | 博客
  • 博客访问: 38741
  • 博文数量: 4
  • 博客积分: 434
  • 博客等级: 一等列兵
  • 技术积分: 47
  • 用 户 组: 普通用户
  • 注册时间: 2010-11-04 21:17
文章分类

全部博文(4)

文章存档

2012年(3)

2010年(1)

分类: 虚拟化

2012-03-02 10:29:12

    前端时间看了篇论文,突然有了这样一个想法,对于执行I/O-intensive任务的VMs,我们是否可以推迟其发送时间通知的时间和减少事件通知的次数,以此来减少上下文切换次数,从而减少开销。因此就以磁盘驱动为例浏览了下代码。
   
在磁盘的前端驱动中处理的I/O请求队列为通用块设备层发送下来的(I/O处理流程见下图),并交由前端驱动中的do_blk_request函数进行处理。
        \drivers\xen\blkfront\vbd.c   202行
        rq = blk_init_queue( do_blkif_request, &blkif_io_lock); 
这里就是绑定块设备驱动层处理I/O的函数do_blkif_request()
在do_blkif_request()函数中,
        while ((req = elv_next_request(rq)) != NULL) {          //依次获取request队列中的req
info = req->rq_disk->private_data;
if (!blk_fs_request(req)) {
end_request(req, 0);
continue;
}

if (RING_FULL(&info->ring))
goto wait;

blkdev_dequeue_request(req);                          //将req从队列中删除
if (blkif_queue_request(req)) {                            //将req相关信息填充到I/O环中
blk_requeue_request(rq, req);                    //对request队列进行排队处理(大致是传递给I/O调度层, 没详细看)
wait:
/* Avoid pointless unplugs. */
blk_stop_queue(rq);
break;
}

queued++;
}
        flush_requests(info);                                                
将request队列填充到I/O环后,接下来就是要告知后端驱动我这里有请求了,请尽快处理。在flush_request()函数中,直接调用
        notify_remote_via_irq(info->irq)------>notify_remote_via_evtchn(evtchn)---------
        ------>VOID(HYPERVISOR_event_channel_op(EVTCHNOP_send, &send))
这个时候已经到了超级调用这里了,在Xen中,事件通道是使用hypercall2(int, event_channel_op, cmd, arg),这个时候,我们在/xen/arch/x86/x86_32/entry.S中看到,对应的中断处理函数为do_event_channel_op,这个函数的定义在
/xen/common/event_channel.c中,
        long do_event_channel_op(int cmd, XEN_GUEST_HANDLE(void) arg)
        {
            long rc;

            switch ( cmd )
            {
                case EVTCHNOP_alloc_unbound: { }
                case EVTCHNOP_bind_interdomain: {
                    struct evtchn_bind_interdomain bind_interdomain;
                    if ( copy_from_guest(&bind_interdomain, arg, 1) != 0 )
                            return -EFAULT;
                    rc = evtchn_bind_interdomain(&bind_interdomain);
                    if ( (rc == 0) && (copy_to_guest(arg, &bind_interdomain, 1) != 0) )
                        rc = -EFAULT; /* Cleaning up here would be a mess! */
                    break;
                }
                case EVTCHNOP_bind_virq: { }
                case EVTCHNOP_bind_ipi: { }
                case EVTCHNOP_bind_pirq: { }
                case EVTCHNOP_close: { }
                case EVTCHNOP_send: { }
                case EVTCHNOP_status: { }
                case EVTCHNOP_bind_vcpu: { }
                case EVTCHNOP_unmask: { }
                case EVTCHNOP_reset: {}
                default:
             }

            return rc;
        }
由于前后端驱动分属于domU和domain-0,因此事件通道类型为域间通信,即EVTCHNOP_bind_interdomain,接下来调用evtchn_bind_interdomain(&bind_interdomain, arg, 1)---->evtchn_set_pending(ld->vcpu[lchn->notify_vcpu_id], lport)
------->vcpu_ublock( v )这个时候已经进入schedule层次了--------->vcpu_wake(v)唤醒对应的vcpu。
流程图见下图:
阅读(4026) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~