[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen master] libxl: add infrastructure to track and query 'recent' domids



commit 2b02882ebbbc5225182824fb66b1fb80724bb22a
Author:     Paul Durrant <pdurrant@xxxxxxxxxx>
AuthorDate: Tue Jan 7 13:46:45 2020 +0000
Commit:     Paul Durrant <pdurrant@xxxxxxxxxx>
CommitDate: Mon Feb 24 17:17:35 2020 +0000

    libxl: add infrastructure to track and query 'recent' domids
    
    A domid is considered recent if the domain it represents was destroyed
    less than a specified number of seconds ago. For debugging and/or testing
    purposes the number can be set using the environment variable
    LIBXL_DOMID_REUSE_TIMEOUT. If the variable does not exist then a default
    value of 60s is used.
    
    Whenever a domain is destroyed, a time-stamped record will be written into
    a history file (/var/run/xen/domid-history). To avoid the history file
    growing too large, any records with time-stamps that indicate that the
    age of a domid has exceeded the re-use timeout will also be purged.
    
    A new utility function, libxl__is_recent_domid(), has been added. This
    function reads the same history file checking whether a specified domid
    has a record that does not exceed the re-use timeout. Since this utility
    function does not write to the file, no records are actually purged by it.
    
    NOTE: The history file is purged on boot to it is safe to use
          CLOCK_MONOTONIC as a time source.
    
    Signed-off-by: Paul Durrant <pdurrant@xxxxxxxxxx>
    Reviewed-by: Ian Jackson <ian.jackson@xxxxxxxxxxxxx>
---
 tools/helpers/xen-init-dom0.c |  30 ++++++
 tools/libxl/libxl.h           |   7 ++
 tools/libxl/libxl_domain.c    | 226 ++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_internal.c  |  10 ++
 tools/libxl/libxl_internal.h  |  14 +++
 5 files changed, 287 insertions(+)

diff --git a/tools/helpers/xen-init-dom0.c b/tools/helpers/xen-init-dom0.c
index a1e5729458..56f69ab66f 100644
--- a/tools/helpers/xen-init-dom0.c
+++ b/tools/helpers/xen-init-dom0.c
@@ -12,6 +12,32 @@
 #define DOMNAME_PATH   "/local/domain/0/name"
 #define DOMID_PATH     "/local/domain/0/domid"
 
+int clear_domid_history(void)
+{
+    int rc = 1;
+    xentoollog_logger_stdiostream *logger;
+    libxl_ctx *ctx;
+
+    logger = xtl_createlogger_stdiostream(stderr, XTL_ERROR, 0);
+    if (!logger)
+        return 1;
+
+    if (libxl_ctx_alloc(&ctx, LIBXL_VERSION, 0,
+                        (xentoollog_logger *)logger)) {
+        fprintf(stderr, "cannot init libxl context\n");
+        goto outlog;
+    }
+
+    if (!libxl_clear_domid_history(ctx))
+        rc = 0;
+
+    libxl_ctx_free(ctx);
+
+outlog:
+    xtl_logger_destroy((xentoollog_logger *)logger);
+    return rc;
+}
+
 int main(int argc, char **argv)
 {
     int rc;
@@ -70,6 +96,10 @@ int main(int argc, char **argv)
     if (rc)
         goto out;
 
+    rc = clear_domid_history();
+    if (rc)
+        goto out;
+
     /* Write xenstore entries. */
     if (!xs_write(xsh, XBT_NULL, DOMID_PATH, "0", strlen("0"))) {
         fprintf(stderr, "cannot set domid for Dom0\n");
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index fde8548847..80ae110a52 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -2679,6 +2679,13 @@ static inline int 
libxl_qemu_monitor_command_0x041200(libxl_ctx *ctx,
 
 #include <libxl_event.h>
 
+/*
+ * This function is for use only during host initialisation. If it is
+ * invoked on a host with running domains, or concurrent libxl
+ * processes then the system may malfuntion.
+ */
+int libxl_clear_domid_history(libxl_ctx *ctx);
+
 #endif /* LIBXL_H */
 
 /*
diff --git a/tools/libxl/libxl_domain.c b/tools/libxl/libxl_domain.c
index 973fc1434d..8937aeb260 100644
--- a/tools/libxl/libxl_domain.c
+++ b/tools/libxl/libxl_domain.c
@@ -1268,6 +1268,230 @@ static void dm_destroy_cb(libxl__egc *egc,
     libxl__devices_destroy(egc, &dis->drs);
 }
 
+static unsigned int libxl__get_domid_reuse_timeout(void)
+{
+    const char *env_timeout = getenv("LIBXL_DOMID_REUSE_TIMEOUT");
+
+    return env_timeout ? strtol(env_timeout, NULL, 0) :
+        LIBXL_DOMID_REUSE_TIMEOUT;
+}
+
+char *libxl__domid_history_path(libxl__gc *gc, const char *suffix)
+{
+    return GCSPRINTF("%s/domid-history%s", libxl__run_dir_path(),
+                     suffix ?: "");
+}
+
+int libxl_clear_domid_history(libxl_ctx *ctx)
+{
+    GC_INIT(ctx);
+    char *path;
+    int rc = ERROR_FAIL;
+
+    path = libxl__domid_history_path(gc, NULL);
+    if (!path)
+        goto out;
+
+    if (unlink(path) < 0 && errno != ENOENT) {
+        LOGE(ERROR, "failed to remove '%s'\n", path);
+        goto out;
+    }
+
+    rc = 0;
+
+out:
+    GC_FREE;
+    return rc;
+}
+
+struct libxl__domid_history {
+    long timeout;
+    char *path;
+    FILE *f;
+    struct timespec ts;
+};
+
+static void libxl__domid_history_dispose(
+    struct libxl__domid_history *ctxt)
+{
+    if (ctxt->f) {
+        fclose(ctxt->f);
+        ctxt->f = NULL;
+    }
+}
+
+static int libxl__open_domid_history(libxl__gc *gc,
+                                     struct libxl__domid_history *ctxt)
+{
+    ctxt->timeout = libxl__get_domid_reuse_timeout();
+    ctxt->path = libxl__domid_history_path(gc, NULL);
+
+    ctxt->f = fopen(ctxt->path, "r");
+    if (!ctxt->f && errno != ENOENT) {
+        LOGE(ERROR, "failed to open '%s'", ctxt->path);
+        return ERROR_FAIL;
+    }
+
+    if (clock_gettime(CLOCK_MONOTONIC, &ctxt->ts)) {
+        LOGE(ERROR, "failed to get time");
+        libxl__domid_history_dispose(ctxt);
+        return ERROR_FAIL;
+    }
+
+    return 0;
+}
+
+static int libxl__close_domid_history(libxl__gc *gc,
+                                      struct libxl__domid_history *ctxt)
+{
+    int r;
+
+    if (!ctxt->f) return 0;
+
+    r = fclose(ctxt->f);
+    ctxt->f = NULL;
+    if (r == EOF) {
+        LOGE(ERROR, "failed to close '%s'", ctxt->path);
+        return ERROR_FAIL;
+    }
+
+    return 0;
+}
+
+static int libxl__read_recent(libxl__gc *gc,
+                              struct libxl__domid_history *ctxt,
+                              unsigned long *sec, unsigned int *domid)
+{
+    if (!ctxt->f) {
+        *domid = INVALID_DOMID;
+        return 0;
+    }
+
+    for (;;) {
+        int r = fscanf(ctxt->f, "%lu %u", sec, domid);
+
+        if (r == EOF) {
+            if (ferror(ctxt->f)) {
+                LOGE(ERROR, "failed to read from '%s'", ctxt->path);
+                return ERROR_FAIL;
+            }
+
+            *domid = INVALID_DOMID;
+            break;
+        } else if (r == 2 && libxl_domid_valid_guest(*domid) &&
+                   ctxt->ts.tv_sec - *sec <= ctxt->timeout) {
+            break;
+        }
+    }
+
+    return 0;
+}
+
+static int libxl__mark_domid_recent(libxl__gc *gc, uint32_t domid)
+{
+    libxl__flock *lock;
+    struct libxl__domid_history ctxt;
+    char *new;
+    FILE *nf = NULL;
+    int r, rc;
+
+    lock = libxl__lock_domid_history(gc);
+    if (!lock) {
+        LOGED(ERROR, domid, "failed to acquire lock");
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+    rc = libxl__open_domid_history(gc, &ctxt);
+    if (rc) goto out;
+
+    new = libxl__domid_history_path(gc, ".new");
+    nf = fopen(new, "a");
+    if (!nf) {
+        LOGED(ERROR, domid, "failed to open '%s'", new);
+        goto out;
+    }
+
+    for (;;) {
+        unsigned long sec;
+        unsigned int val;
+
+        rc = libxl__read_recent(gc, &ctxt, &sec, &val);
+        if (rc) goto out;
+
+        if (val == INVALID_DOMID) /* EOF */
+            break;
+
+        r = fprintf(nf, "%lu %u\n", sec, val);
+        if (r < 0) {
+            LOGED(ERROR, domid, "failed to write to '%s'", new);
+            goto out;
+        }
+    }
+
+    r = fprintf(nf, "%lu %u\n", ctxt.ts.tv_sec, domid);
+    if (r < 0) {
+        LOGED(ERROR, domid, "failed to write to '%s'", new);
+        goto out;
+    }
+
+    r = fclose(nf);
+    nf = NULL;
+    if (r == EOF) {
+        LOGED(ERROR, domid, "failed to close '%s'", new);
+        goto out;
+    }
+
+    rc = libxl__close_domid_history(gc, &ctxt);
+    if (rc) goto out;
+
+    r = rename(new, ctxt.path);
+    if (r) {
+        LOGE(ERROR, "failed to rename '%s' -> '%s'", new, ctxt.path);
+        return ERROR_FAIL;
+    }
+
+out:
+    if (nf) fclose(nf);
+    libxl__domid_history_dispose(&ctxt);
+    if (lock) libxl__unlock_file(lock);
+
+    return rc;
+}
+
+int libxl__is_domid_recent(libxl__gc *gc, uint32_t domid, bool *recent)
+{
+    struct libxl__domid_history ctxt;
+    int rc;
+
+    rc = libxl__open_domid_history(gc, &ctxt);
+    if (rc) goto out;
+
+    *recent = false;
+    for (;;) {
+        unsigned long sec;
+        unsigned int val;
+
+        rc = libxl__read_recent(gc, &ctxt, &sec, &val);
+        if (rc) goto out;
+
+        if (val == INVALID_DOMID) /* EOF */
+            break;
+
+        if (val == domid && ctxt.ts.tv_sec - sec <= ctxt.timeout) {
+            *recent = true;
+            break;
+        }
+    }
+
+    rc = libxl__close_domid_history(gc, &ctxt);
+
+out:
+    libxl__domid_history_dispose(&ctxt);
+
+    return rc;
+}
+
 static void devices_destroy_cb(libxl__egc *egc,
                                libxl__devices_remove_state *drs,
                                int rc)
@@ -1331,6 +1555,8 @@ static void devices_destroy_cb(libxl__egc *egc,
         if (!ctx->xch) goto badchild;
 
         if (!dis->soft_reset) {
+            rc = libxl__mark_domid_recent(gc, domid);
+            if (rc) goto badchild;
             rc = xc_domain_destroy(ctx->xch, domid);
         } else {
             rc = xc_domain_pause(ctx->xch, domid);
diff --git a/tools/libxl/libxl_internal.c b/tools/libxl/libxl_internal.c
index a7da2921de..d93a75533f 100644
--- a/tools/libxl/libxl_internal.c
+++ b/tools/libxl/libxl_internal.c
@@ -504,6 +504,16 @@ libxl__flock *libxl__lock_domain_userdata(libxl__gc *gc, 
uint32_t domid)
     return lock;
 }
 
+libxl__flock *libxl__lock_domid_history(libxl__gc *gc)
+{
+    const char *lockfile;
+
+    lockfile = libxl__domid_history_path(gc, ".lock");
+    if (!lockfile) return NULL;
+
+    return libxl__lock_file(gc, lockfile);
+}
+
 int libxl__get_domain_configuration(libxl__gc *gc, uint32_t domid,
                                     libxl_domain_config *d_config)
 {
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index 4936446069..43e5885d1e 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -4263,6 +4263,8 @@ _hidden void libxl__remus_teardown(libxl__egc *egc,
 _hidden void libxl__remus_restore_setup(libxl__egc *egc,
                                         libxl__domain_create_state *dcs);
 
+_hidden char *libxl__domid_history_path(libxl__gc *gc,
+                                        const char *suffix);
 
 /*
  * Convenience macros.
@@ -4661,6 +4663,7 @@ libxl__flock *libxl__lock_file(libxl__gc *gc, const char 
*filename);
 void libxl__unlock_file(libxl__flock *lock);
 
 libxl__flock *libxl__lock_domain_userdata(libxl__gc *gc, uint32_t domid);
+libxl__flock *libxl__lock_domid_history(libxl__gc *gc);
 
 /*
  * Retrieve / store domain configuration from / to libxl private
@@ -4799,6 +4802,17 @@ _hidden int libxl__domain_pvcontrol(libxl__egc *egc,
                                     libxl__xswait_state *pvcontrol,
                                     domid_t domid, const char *cmd);
 
+/*
+ * Maximum number of seconds after desctruction then a domid remains
+ * 'recent'. Recent domids are not allowed to be re-used. This can be
+ * overidden, for debugging purposes, by the environment variable of the
+ * same name.
+ */
+#define LIBXL_DOMID_REUSE_TIMEOUT 60
+
+/* Check whether a domid is recent */
+int libxl__is_domid_recent(libxl__gc *gc, uint32_t domid, bool *recent);
+
 #endif
 
 /*
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.