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
代码
以下代码创建两个可执行的, 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;
- }
参考:
1] The Definitive Guide to the Xen Hypervisor David Chisnall
2] http://www.cs.uic.edu/~spopuri/minios.html
3] http://wiki.xensource.com/xenwiki/XenStoreReference
4] http://wiki.xensource.com/xenwiki/XenBus
5] http://lists.xensource.com/archives/html/xen-devel/2005-12/msg00151.html
6] http://wiki.xensource.com/xenwiki/XenBus
7] http://knol.google.com/k/learning-xenstore