From: Paul Durrant <pdurrant@amazon.com>
To: <xen-devel@lists.xenproject.org>
Cc: Anthony PERARD <anthony.perard@citrix.com>,
Paul Durrant <pdurrant@amazon.com>,
Ian Jackson <ian.jackson@eu.citrix.com>, Wei Liu <wl@xen.org>
Subject: [Xen-devel] [PATCH v6 1/6] libxl: add infrastructure to track and query 'recent' domids
Date: Wed, 19 Feb 2020 09:37:49 +0000 [thread overview]
Message-ID: <20200219093754.2924-2-pdurrant@amazon.com> (raw)
In-Reply-To: <20200219093754.2924-1-pdurrant@amazon.com>
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@amazon.com>
---
Cc: Ian Jackson <ian.jackson@eu.citrix.com>
Cc: Wei Liu <wl@xen.org>
Cc: Anthony PERARD <anthony.perard@citrix.com>
v6:
_ Addressed further comments from Ian
v5:
- Re-work file manipulation some more
- Add more error checks
v4:
- Use new generalised libxl__flock
- Don't read and write the same file
- Use 'recent' rather than 'retired'
- Add code into xen-init-dom0 to delete an old history file at boot
v2:
- New in v2
---
tools/helpers/xen-init-dom0.c | 30 +++++
tools/libxl/libxl.h | 7 ++
tools/libxl/libxl_domain.c | 222 ++++++++++++++++++++++++++++++++++
tools/libxl/libxl_internal.c | 10 ++
tools/libxl/libxl_internal.h | 14 +++
5 files changed, 283 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..53f90cb555 100644
--- a/tools/libxl/libxl_domain.c
+++ b/tools/libxl/libxl_domain.c
@@ -1268,6 +1268,226 @@ 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;
+}
+
+static int libxl__read_recent(libxl__gc *gc, FILE *f, unsigned long *sec,
+ unsigned int *domid)
+{
+ if (!f) {
+ *domid = INVALID_DOMID;
+ return 0;
+ }
+
+ for (;;) {
+ int n = fscanf(f, "%lu %u", sec, domid);
+
+ if (n == EOF) {
+ if (ferror(f)) {
+ LOGE(ERROR, "failed");
+ return ERROR_FAIL;
+ }
+
+ *domid = INVALID_DOMID;
+ break;
+ } else if (n == 2 && libxl_domid_valid_guest(*domid)) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int libxl__write_recent(libxl__gc *gc, FILE *f, unsigned long sec,
+ unsigned int domid)
+{
+ int n = fprintf(f, "%lu %u\n", sec, domid);
+
+ if (n >= 0) return 0;
+
+ LOGE(ERROR, "failed");
+ return ERROR_FAIL;
+}
+
+static int libxl__open_domid_history(libxl__gc *gc, FILE **f)
+{
+ char *path = libxl__domid_history_path(gc, NULL);
+
+ *f = fopen(path, "r");
+ if (*f || errno == ENOENT) return 0;
+
+ LOGE(ERROR, "failed to open '%s'", path);
+ return ERROR_FAIL;
+}
+
+static int libxl__close_domid_history(libxl__gc *gc, FILE **f)
+{
+ int ret;
+
+ if (!*f) return 0;
+
+ ret = fclose(*f);
+ *f = NULL;
+ if (!ret) return 0;
+
+ LOGE(ERROR, "failed");
+ return ERROR_FAIL;
+}
+
+static int libxl__replace_domid_history(libxl__gc *gc, char *new)
+{
+ char *path = libxl__domid_history_path(gc, NULL);
+ int ret = rename(new, path);
+
+ if (!ret) return 0;
+
+ LOGE(ERROR, "failed to rename '%s' -> '%s'", new, path);
+ return ERROR_FAIL;
+}
+
+static int libxl__mark_domid_recent(libxl__gc *gc, uint32_t domid)
+{
+ long timeout = libxl__get_domid_reuse_timeout();
+ libxl__flock *lock;
+ char *new;
+ FILE *of = NULL, *nf = NULL;
+ struct timespec ts;
+ int ret, 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, &of);
+ 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;
+ }
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
+ LOGED(ERROR, domid, "failed to get time");
+ goto out;
+ }
+
+ for (;;) {
+ unsigned long sec;
+ unsigned int val;
+
+ rc = libxl__read_recent(gc, of, &sec, &val);
+ if (rc) goto out;
+
+ if (val == INVALID_DOMID) /* EOF */
+ break;
+
+ if (ts.tv_sec - sec > timeout)
+ continue; /* Ignore expired entries */
+
+ rc = libxl__write_recent(gc, nf, sec, val);
+ if (rc) goto out;
+ }
+
+ rc = libxl__write_recent(gc, nf, ts.tv_sec, domid);
+ if (rc) goto out;
+
+ ret = fclose(nf);
+ nf = NULL;
+ if (ret == EOF) {
+ LOGED(ERROR, domid, "failed to close '%s'", new);
+ goto out;
+ }
+
+ rc = libxl__close_domid_history(gc, &of);
+ if (rc) goto out;
+
+ rc = libxl__replace_domid_history(gc, new);
+
+out:
+ if (nf) fclose(nf);
+ if (of) fclose(of);
+ if (lock) libxl__unlock_file(lock);
+
+ return rc;
+}
+
+int libxl__is_domid_recent(libxl__gc *gc, uint32_t domid, bool *recent)
+{
+ long timeout = libxl__get_domid_reuse_timeout();
+ FILE *f;
+ struct timespec ts;
+ int rc;
+
+ rc = libxl__open_domid_history(gc, &f);
+ if (rc) goto out;
+
+ if (clock_gettime(CLOCK_MONOTONIC, &ts)) {
+ LOGED(ERROR, domid, "failed to get time");
+ goto out;
+ }
+
+ *recent = false;
+ for (;;) {
+ unsigned long sec;
+ unsigned int val;
+
+ rc = libxl__read_recent(gc, f, &sec, &val);
+ if (rc) goto out;
+
+ if (val == INVALID_DOMID) /* EOF */
+ break;
+
+ if (val == domid && ts.tv_sec - sec <= timeout) {
+ *recent = true;
+ break;
+ }
+ }
+
+ rc = libxl__close_domid_history(gc, &f);
+
+out:
+ if (f) fclose(f);
+ return rc;
+}
+
static void devices_destroy_cb(libxl__egc *egc,
libxl__devices_remove_state *drs,
int rc)
@@ -1331,6 +1551,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 211236dc99..bbd4c6cba9 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
/*
--
2.20.1
_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel
next prev parent reply other threads:[~2020-02-19 9:38 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-02-19 9:37 [Xen-devel] [PATCH v6 0/6] xl/libxl: domid allocation/preservation changes Paul Durrant
2020-02-19 9:37 ` Paul Durrant [this message]
2020-02-20 16:19 ` [Xen-devel] [PATCH v6 1/6] libxl: add infrastructure to track and query 'recent' domids Ian Jackson
2020-02-20 16:36 ` Durrant, Paul
2020-02-20 16:45 ` Ian Jackson
2020-02-20 16:54 ` Durrant, Paul
2020-02-20 17:19 ` Ian Jackson
2020-02-19 9:37 ` [Xen-devel] [PATCH v6 2/6] libxl: modify libxl__logv() to only log valid domid values Paul Durrant
2020-02-20 16:20 ` Ian Jackson
2020-02-19 9:37 ` [Xen-devel] [PATCH v6 3/6] public/xen.h: add a definition for a 'valid domid' mask Paul Durrant
2020-02-20 16:22 ` Ian Jackson
2020-02-19 9:37 ` [Xen-devel] [PATCH v6 4/6] libxl: allow creation of domains with a specified or random domid Paul Durrant
2020-02-20 16:25 ` Ian Jackson
2020-02-19 9:37 ` [Xen-devel] [PATCH v6 5/6] xl.conf: introduce 'domid_policy' Paul Durrant
2020-02-19 9:37 ` [Xen-devel] [PATCH v6 6/6] xl: allow domid to be preserved on save/restore or migrate Paul Durrant
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200219093754.2924-2-pdurrant@amazon.com \
--to=pdurrant@amazon.com \
--cc=anthony.perard@citrix.com \
--cc=ian.jackson@eu.citrix.com \
--cc=wl@xen.org \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.