On Tue, Nov 11, 2008 at 01:34:29PM -0500, Ben Guthro wrote:
This version of the Xen-Events patch goes a step further
than the last version, and now emits the following domain events:
STARTED
STOPPED
ADDED
REMOVED
This is accomplished by monitoring /etc/xen, and taking advantage
of what seemed to be dormant code in the XM driver. By re-enabling
the "config cache", we can properly track domains when files come,
and go into this directory.
This isn't quite correct. The /etc/xen directory & thus xm_internal.c
driver is only used for Xen < 3.0.4, where there was no XenD management
of inactive domains. For Xen >= 3.0.4, we let XenD itself manage
all inactive domains, so /etc/xen should not be used. XenD keeps its
persistent configs in /var/lib/xen/xend/domains.
So for this inotify magic, we shouldn't be looking at /etc/xen, and
instead watch /var/lib/xen/xend/domains. THis is actually nice & easy
because the files in the directry are named according to the UUID,
so we don't even need to read the file contents in that scenario.
+static void
+xenInotifyEvent(int fd,
+ int events ATTRIBUTE_UNUSED,
+ void *data)
+{
+ char buf[1024];
+ char fname[1024];
+ struct inotify_event *e;
+ int got;
+ char *tmp, *name;
+ virConnectPtr conn = (virConnectPtr) data;
+ xenUnifiedPrivatePtr priv = NULL;
+ virDomainPtr dom = NULL;
+
+ DEBUG0("got inotify event");
+
+ if( conn && conn->privateData ) {
+ priv = conn->privateData;
+ } else {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("conn, or private data is
NULL"));
+ return;
+ }
+
+reread:
+ got = read(fd, buf, sizeof(buf));
+ if (got == -1) {
+ if (errno == EINTR)
+ goto reread;
+ return;
+ }
+
+ tmp = buf;
+ while (got) {
+ if (got < sizeof(struct inotify_event))
+ return; /* bad */
+
+ e = (struct inotify_event *)tmp;
+ tmp += sizeof(struct inotify_event);
+ got -= sizeof(struct inotify_event);
+
+ if (got < e->len)
+ return;
+
+ tmp += e->len;
+ got -= e->len;
+
+ name = (char *)&(e->name);
+
+ snprintf(fname, 1024, "%s/%s", xenXMGetConfigDir(), name);
+
+ if (e->mask & IN_DELETE) {
+ if (!(dom = xenInotifyConfigLookupCache(conn, fname))) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("looking up dom"));
+ continue;
+ }
+
+ xenUnifiedDomainEventDispatch(conn->privateData,
+ dom, VIR_DOMAIN_EVENT_REMOVED);
+
+ if (xenXMConfigCacheRefresh (conn) < 0) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Error refreshing config
cache"));
+ return;
+ }
+ } else if (e->mask & IN_MODIFY) {
+ /* if we track IN_CREATED we get 2 added events */
+ if (xenXMConfigCacheRefresh (conn) < 0) {
+ virXenInotifyError(NULL, VIR_ERR_INTERNAL_ERROR,
+ "%s", _("Error refreshing config
cache"));
+ return;
+ }
If we've activated inotify, then we should not call xenXMConfigCacheRefresh()
since that iterates over every file in the directory. Since we know the new
or old filenames, we can just populate / remove the individual file.
This will require re-factoring xenXMConfigCacheRefresh() slightly. It currently
has all its useful logic inside its while() loop. We should break the body of
xenXMConfigCacheRefresh() out into a separate method which just able to process
a single new file, eg
xenXMConfigCacheAddFile(virConnectPtr conn, const char *filename);
And also add a new
xenXMConfigCacheRemoveFile(virConnectPtr conn, const char *filename);
to just remove the old file from the cache.
When activating inotify we can call xenXMConfigCacheRefresh() once to get
the initial list of domains, and then disable various calls to it in all
the public APIs in xm_internal.h, and rely on the inotify code to keep it
up2date.
Daniel
--
|: Red Hat, Engineering, London -o-
http://people.redhat.com/berrange/ :|
|:
http://libvirt.org -o-
http://virt-manager.org -o-
http://ovirt.org :|
|:
http://autobuild.org -o-
http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505 -o- F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|