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: { }