XenBus

14 篇文章 0 订阅
7 篇文章 0 订阅

【转】XenBus的结构


Xenbus是Xenstore的一个接口, 它也是在Xenstore之上写的设备驱动的连接协议. Xenbus是一个虚拟设备的mgmt bus. Xen PV "backend" 设备出现在xenbus上, 而且能被DomU使用PV "fronted"设备驱动访问到. 这些虚拟后端设备的状态由xenbus管理. 这些状态被存储到xenstore, 并且一直被Dom0和DomU的xenbus驱动程序监测.XenStore 指供了一个domain如何将前端设备与后端提供的服务联系起来的方法, (实际这部分是由XenBus承载的, 一种建立在XenStore顶层的协议).

xenbus <--> xenstore

xenbus和xenstore通信的代码主要在pvops/drivers/xen/xenbus/目录下的xenbus_xs.c xenbus_comms.c

 

xenbus驱动在初始化时,会调用xs_init函数,xs_init调用xs_init_comms先初始化xenbus和xenstore通信的两个ring。最后通过kthread_run调用xenwatch_thread,xenbus_thread两个内核线程。通过ps可以看到[xenwatch] [xenbus]。

 

 

[xenwatch]线程会调用wait_event_interruptible来监控watches_events链表,所有需要watch的xenstore node都在这个watches_events里面。对应的wait_queue是watch_events_waitq。OK, 下面遍历开始,对watch_events里每一个list_head的结构,通过list_entry找到包含他的xs_stored_msg,调用xs_stored_msg.u.watch.handle->callback函数。

 

[xenbus]线程循环调用process_msg,前面我们知道,xenbus和xenstore通过两个ring通信,如果ring上有xenstore返回给xenbus的rsp,这时break出循环开始处理rsp。首先kmalloc一块xs_stored_msg的内存,先读取msg的head,然后msg的body。如何msg是一个watch event,把event挂到watch_events中,然后wake_upwatch_events_waitq(这玩意儿像个sem),如果是xenstore的reply,就挂到xs_state.reply_list中,并wake_upreply_waitq。

 

xenbus_xs.c中,xs_talkv是xenbus和xenstore通信的核心函数,xs_talkv调用xb_write把请求发到xenstore,调用read_reply接受xenstore的rsp。

 

xenbus_directory, xenbus_read,xenbus_write, xenbus_exists, xenbus_rm, xenbus_mkdir等一系列xenbus_xxxx函数都是基于上述方法

 

xenbus_comms.c中,主要都是底层的通信实现

 

 

xenbus <--> frontend, backend

xenbus与前后端设备打交道也是其重要功能之一。无论前端还是后端设备,在xenbus看来都是一个xenbus_device结构。

 

 

xenbus_client.c

xenbus_grant_ring:前(后)端给后(前)端设备某个ring的access

 

__xenbus_switch_state:改变前(后)端设备的state

 

xenbus_alloc_evtchn:为前(后)端和后(前)端设备通信建立event channel。其中本地domain是DOMID_SELF,remote_domain是dev->otherend_id,最后调HYPERVISOR_event_channel_op

 

xenbus_bind_evtchn:为本地event channel绑定一个remote port。我们知道event channel一般有两个port,传进来bind_interdomain.remote_dom = dev->otherend_id,和bind_interdomain.remote_port。通过调用HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain),得到本地的port为bind_interdomain.local_port

 

xenbus_map_ring_valloc:授权dev->otherend_id的domain来访问一个page。该page是通过xen_alloc_vm_area(PAGE_SIZE)生成出来的。

xenbus_map_ring:授权dev->otherend_id的domain来访问vaddr所在的内存

 

 

xenbus_probe.c

 

xenbus_read_otherend_details:前(后)端调用xenbus_gather收集后(前)端信息。xenbus_gather最终调用xenbus_read,通过xenstore读出。

 

xenbus_otherend_changed:调用xenbus_read_driver_state,读取另一端设备状态

 

xenbus_dev_probe:传入的struct device结构__dev为本地端设备,通过to_xenbus_device,to_xenbus_driver得到struct xenbus_device *dev, struct xenbus_driver *drv结构。接着调用talk_to_otherend得到另一端设备信息,最后调用drv->probe。其实核心还是drv->probe,用来发现dev设备是不是在xenbus上(??这个我不太确定)

 

xenbus_dev_remove:核心也是调用drv->remove函数,其中drv是传入的_dev对应的xenbus_driver。之后把dev对应的xenbus state置为XenbusStateClosed

 

xenbus_dev_shutdown:调用xenbus_switch_state,修改dev的xenbus状态

 

get_device, put_device:dev对应的引用计数

 

xenbus_probe_node:基于nodename,new一片内存并生成一个xenbus_device结构体。最后调用device_register注册该设备。

 

xenbus_probe_device_type:探测bus下设备的类型

 

xenbus_init

xenbus_init是xenbus的初始化函数(废话,看名字就知道啦)。首先判断下是不是xen_initial_domain,如果在dom0里执行,要做一系列初始化的工作,包括

 

申请一个page的空间,用于和xenstore通信,并且把地址写到start_info那个共享page中

 

调用HYPERVISOR_event_channel_op,创建一个event channel,并把event channel其中一个port写到start_info里面。这样xenstore就可以去bind这个port

 

如果在domU里执行,继续判断是否是hvm,无论是否hvm,最终都为了获取到xenbus和xenstore通信的三个数据结构:共享ring的页空间,event channel的port,并基于该空间生成xenstore_domain_interface结构。

 

最后调用xs_init,初始化和xenstore通信的工作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值