XenStore
是一个类似于数据库的文件系统, 包含了domain间的共享信息. 有domain配置和状态信息.XenStore
提供了一种发现设备信息的简便方法. 它作为数据库在 /var/lib/xenstore/tdb, 在用户空间的 daemon 称为
"xenstored".这个逻辑文件树有三个主要的路径:
/vm - /vm/uuid 存储配置信息,例如虚拟CPU数和内存分配数.
/local/domain - 包含了正在运行的domain信息, 由domid标识.
/tool - 存储多种工具信息.
应用程序向这个数据库的 key 写信息, 配置驱动; 驱动在key上设置watch并对改变做出回应.
详细介绍请参考: http://wiki.xensource.com/xenwiki/XenStoreReference
访问xenstore
在guest
kernel启动时xenstore经过start_info页而被访问到, 作为共享页的机器页帧号和event
channel使用.Dom0工具使用UNIX domain socket /var/run/xenstored/socket 或
/var/run/xenstoed/socket_ro; Dom0工具使用proce接口/proc/xen/xenbus,
内核代码使用xenbus API.
命令
Domain 标识
1)
通用唯一标识符(UUID)是标识domain的数字, 即使guest迁移也保持相同.
2) domain 标识(DOMID) 标识一个正在运行的实例, 当guest
迁移到另一台机器后DOMID改变.
什么是Xenbus
Xenbus是一个虚拟设备的mgmt bus. Xen PV "backend" 设备出现在xenbus上, 而且能被DomU使用PV
"fronted"设备驱动访问到. 这些虚拟后端设备的状态由xenbus管理. 这些状态被存储到xenstore,
并且一直被Dom0和DomU的xenbus驱动程序监测.XenStore 指供了一个domain如何将前端设备与后端提供的服务联系起来的方法,
(实际这部分是由XenBus承载的,
一种建立在XenStore顶层的协议). 后端与前端通信使用共享event channel 和 ring buffer通信.
所有规范的xen虚拟设备驱动在初始化时向XenBus注册自己. 这是通过传递xenbus_driver 结构体给
代码
以下代码创建两个可执行的, xenstore-read 和 xenstore-write 程序.
在一个Dom中运行xenstore-read - 从 /loca/doman/X/memory/target 读取Domx的memory/target值.依赖于你运行这个程序所在的Dom.
在一个Dom中运行xenstore-wirte - 写一个memory/target值到这个程序所运行的Dom.
- // Example taken from wiki.xensource.com/xenwiki/XenStoreReference and some code added
- //
- // Compiled using
- // gcc -g xenstore.c -DREAD=1 -lxenstore -o xenstore-read
- // gcc -g xenstore.c -DWRITE=1 -lxenstore -o xenstore-write
- //
- // To change permissions on /local/domain/0, use
- // xenstore-chod -r /local/domain/0 b - for r and w
- // xenstore-chod -r /local/domain/0 w - for w
- //
- #include <sys/types.h>
- #include <xs.h>
- #include <stdio.h>
- #include <string.h>
- #include <malloc.h>
- #include <sys/stat.h> // for lstat()
- #include <stdlib.h> // for exit()
- #define DOM0 0
- #define DOMU 1
- int
dom = 999;
- // This function checks if the app is in domU or dom0. The /proc/xen/capabilities
- // contains the string "control_d" if the app is in a dom0
- //
- // /sys/hypervisor/type can be checked too, to see if we are running on a xen
- // hyervisor
- check_dom()
- {
- FILE
*file = NULL;
- char
*filePath;
- struct
stat linkAttrs;
- char
buf[100] =
""
;
- filePath = "/proc/xen/capabilities"
;
- if
((lstat(filePath, &linkAttrs)) != 0) {
- perror("lstat"
);
- return
;
- }
- if
((file = fopen(
"/proc/xen/capabilities"
,
"r"
)) == NULL) {
- perror("fopen"
);
- return
;
- }
- if
(!fgets(buf,
sizeof
(buf), file)) {
- // we are in DomU, since the buffer is empty
- printf("/n Surely in DOMU, since capabilities is empty"
);
- dom = DOMU;
- return
;
- } else
{
- // we are probably in Dom0
- printf("/n Probably in DOM0, since capabilities has some data"
);
- dom = DOM0;
- }
- // the following is in case they change the capabilities to have some
- // data in a DomU
- if
((strstr(buf,
"control_d"
)) == NULL) {
- // we are in DomU
- printf("/n We are in DOMU"
);
- dom = DOMU;
- } else
{
- // we are in Dom0
- printf("/n We are in DOM0"
);
- dom = DOM0;
- }
- return
;
- }
- // xs_write is written outside a transaction. Else it does not work for me. Pass
- // a XBT_NULL as a 2nd param to xs_write().
- write_to_xenstore (struct
xs_handle *xs,
char
* path) {
- char
somedata[8] = {
"2200000"
};
- xs_transaction_t trans;
- bool
err;
- printf("/nWriting data %s of len %d to %s"
,
- somedata, strlen(somedata), path);
- // xs_write() -> xs_talkv()
- // -> xs_write_all() -> write() - sys_write()
- // -> xs_read_reply()
- err = xs_write(xs, XBT_NULL, path, &somedata[0],
- strlen(somedata));
- if
(!err) {
- printf("/n Could'nt write var in xenstore"
);
- }
- xs_daemon_close(xs);
- free(path);
- exit(0);
- }
- int
main(
int
argc,
char
*argv[]) {
- struct
xs_handle *xs;
// handle to xenstore
- xs_transaction_t trans;
- char
*path;
- int
fd;
- fd_set set;
- bool
err;
- struct
timeval tv = {.tv_sec = 0, .tv_usec = 0};
- char
**vec;
- unsigned int
num;
- char
*buf;
- char
**buf2;
- unsigned int
len, i;
- unsigned int
domid;
- // check if we are in Dom0 or DomU
- check_dom();
- // Connect to XenStore. From Dom0 we call xs_daemon_open,
- // and from DomU, we call xs_domain_open().
- // xs_daemon_open() -> get_handle(xs_daemon_socket()).
- // xs_daemon_socket()->xs_daemon_path() which returns
- // XENSTORED_PATH/socket. A get_handle() on the above path generates
- // a socket (PF_UNIX, SOCK_STREAM, 0) and connects to above socket.
- // For domU, connect to XenStore via xs_domain_open().
- // xs_domain_dev() returns path to /proc/xen/xenbus, and a
- // get_handle() on this returns a 'fd' to this file.
- if
(dom == DOMU) {
- xs = xs_domain_open(); // DomU
- if
(xs == NULL) error();
- buf = xs_read(xs, XBT_NULL, "domid"
, &len);
- if
(!buf) {
- printf("/n Could not read domid"
);
- return
;
- }
- domid = atoi(buf);
- printf("/n Retrieved Dom ID = %d/n"
, domid);
- } else
{
- xs = xs_daemon_open(); // Dom0
- if
(xs == NULL) error();
- trans = xs_transaction_start(xs);
- if
(trans == 0) {
- printf("/n Could not start xaction with XS"
);
return
;
- }
- // Get contents of a directory. Need to call free after use,
- // since the API mallocs memory
- buf2 = xs_directory(xs, trans, "/local/domain"
, &len);
- if
(!buf2) {
- printf("/n Could not read XS dir /local/domain"
);
return
;
- }
- xs_transaction_end(xs, trans, true
);
- if
(trans == 0) {
- printf("/n Could not end xaction with XS"
);
return
;
- }
- printf("/n Len of Dir /local/domain is %d"
, len);
- printf("/n Dir Contents: "
);
- for
(i=0; i<len;i++) { printf(
"%s "
, buf2[i]); }
- if
(len == 1) {
- // we have only 1 Dom running, i.e. Dom0
- domid = atoi(buf2[0]);
- } else
if
(len == 2) {
- domid = atoi(buf2[1]);
- }
- // Set domid to 0, since Dom0 is always id 0
- domid = 0;
- printf("/n Setting Dom ID = %d/n"
, domid);
- }
- // Get the local Domain path in xenstore
- path = xs_get_domain_path(xs, domid);
- if
(path == NULL) {
- printf("/n Dom Path in Xenstore not found"
);
- error(); return
;
- }
- // xs_directory has an implicit root at /local/domain/<domid> in DomU
- // and thus need to just pass "memory/target" if we are running this
- // from a DomU to read the directory's contents
- if
(dom == DOM0) {
- path = realloc(path, strlen(path) + strlen("/memory/target"
) + 1);
- if
(path == NULL) {
- error(); return
;
- }
- strcat(path, "/memory/target"
);
- } else
{
- strcpy(path, "memory/target"
);
- }
- printf("/nPath = %s"
, path);
- // If we are doing a write to the xenstore, branch off here and
- // then exit from the program. Else for read, cary on, and do a
- // select() to wait for a change in watched values
- #ifdef WRITE
- write_to_xenstore(xs, path);
- #endif
- // Create a watch on the path
- err = xs_watch(xs, path, "mytoken"
);
- if
(err == 0) {
- printf("/n Error in setting watch on mytoken in %s"
, path);
- error(); return
;
- }
- // Watches are notified via a File Descriptor. We can POLL on this.
- fd = xs_fileno(xs);
- while
(1) {
- FD_ZERO(&set);
- FD_SET(fd, &set);
- printf("!-"
);
- fflush(stdout);
- struct
timeval tv = {.tv_sec = 5, .tv_usec = 0};
- if
(select(fd+1, &set, NULL, NULL, &tv) > 0
- && FD_ISSET(fd, &set)) {
- printf("@"
);
- // This blocks is nothing is pending. Returns an array
- // containing path and token. Use Xs_WATCH_* to
- // access these elements. Call free after use.
- vec = xs_read_watch(xs, &num);
- if
(!vec) {
- printf("Error on watch firing"
);
- error(); return
;
- }
- // In our example code, the following will print out
- // /local/domain/0/memory/target|mytoken
- printf("/nvec contents: %s|%s/n"
, vec[XS_WATCH_PATH],
- vec[XS_WATCH_TOKEN]);
- // Prepare a transacation to do a read
- trans = xs_transaction_start(xs);
- if
(trans == 0) {
- printf("/n Could'nt start xaction xenstore"
);
- return
;
- }
- buf = xs_read(xs, trans, vec[XS_WATCH_PATH], &len);
- if
(!buf) {
- printf("/n Could'nt read watch var in vec"
);
- return
;
- }
- xs_transaction_end(xs, trans, true
);
- if
(trans == 0) {
- printf("/n Could not end xaction xenstore"
);
- return
;
- }
- if
(buf) {
- printf("/n buflen: %d, buf: %s"
, len, buf);
- }
- } // end of select
- } // end while(1)
- printf("/n"
);
- // cleanup
- close(fd);
- xs_daemon_close(xs);
- free(path);
- return
;
- }