From: Ian Jackson <ian.jackson@eu.citrix.com>
To: xen-devel@lists.xensource.com
Cc: Ian Jackson <Ian.Jackson@eu.citrix.com>,
Wei Liu <wei.liu2@citrix.com>,
Ian Campbell <Ian.Campbell@citrix.com>,
Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Subject: [PATCH 03/28] libxl: Provide libxl__dm_support_*
Date: Tue, 22 Dec 2015 18:44:38 +0000 [thread overview]
Message-ID: <1450809903-3393-4-git-send-email-ian.jackson@eu.citrix.com> (raw)
In-Reply-To: <1450809903-3393-1-git-send-email-ian.jackson@eu.citrix.com>
This allows code elsewhere in libxl to find out what options a device
model executable supports. This is done by searching the usage
message for fixed strings.
Because this involves calling fork, callers must use the async
machinery. To make this easier, and to avoid repeatedly invoking the
dm, we provide a cache within the libxl__ctx.
No call site yet.
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Signed-off-by: Ian Jackson <Ian.Jackson@eu.citrix.com>
---
v6: Completely rewritten.
Cache is now in ctx only, not in xenstore.
We use the proper libxl__ev_child machinery for fork.
---
tools/libxl/libxl.c | 4 +
tools/libxl/libxl_dm.c | 231 ++++++++++++++++++++++++++++++++++++++++++
tools/libxl/libxl_internal.h | 76 ++++++++++++++
3 files changed, 311 insertions(+)
diff --git a/tools/libxl/libxl.c b/tools/libxl/libxl.c
index 9207621..d96189d 100644
--- a/tools/libxl/libxl.c
+++ b/tools/libxl/libxl.c
@@ -87,6 +87,8 @@ int libxl_ctx_alloc(libxl_ctx **pctx, int version,
ctx->sigchld_selfpipe[1] = -1;
libxl__ev_fd_init(&ctx->sigchld_selfpipe_efd);
+ LIBXL_LIST_INIT(&ctx->dm_support_cache);
+
/* The mutex is special because we can't idempotently destroy it */
if (libxl__init_recursive_mutex(ctx, &ctx->lock) < 0) {
@@ -208,6 +210,8 @@ int libxl_ctx_free(libxl_ctx *ctx)
libxl__sigchld_notneeded(gc);
libxl__pipe_close(ctx->sigchld_selfpipe);
+ libxl__dm_support_cache_destroy(gc);
+
CTX_UNLOCK;
pthread_mutex_destroy(&ctx->lock);
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index 0aaefd9..675e859 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -2169,6 +2169,237 @@ out:
return ret;
}
+/*----- libxl__dm_support_* -----*/
+
+/* cache */
+
+static libxl__dm_support_cached *
+dm_support_cache_lookup(libxl__gc *gc, const char *dm)
+{
+ libxl__dm_support_cached *search;
+
+ LIBXL_LIST_FOREACH(search, &CTX->dm_support_cache, entry)
+ if (!strcmp(search->dm, dm))
+ return search;
+
+ return 0;
+}
+
+_hidden void libxl__dm_support_cache_destroy(libxl__gc *gc)
+{
+ libxl__dm_support_cached *iter, *next;
+
+ LIBXL_LIST_FOREACH_SAFE(iter, &CTX->dm_support_cache, entry, next) {
+ free(iter->dm);
+ free(iter);
+ }
+}
+
+_hidden bool libxl__dm_supported(libxl__gc *gc, const char *dm,
+ libxl__dm_support_check__index opt)
+{
+ libxl__dm_support_cached *cached = dm_support_cache_lookup(gc, dm);
+ assert(cached);
+ return !!(cached->bitmap & (1UL << opt));
+}
+
+/* `check', the long-running operation to check for support */
+
+static void dm_support_check_immed_cb(libxl__egc *egc, libxl__ev_time *ev,
+ const struct timeval *requested_abs,
+ int rc);
+static void dm_support_check_child_cb(libxl__egc *egc, libxl__ev_child*,
+ pid_t pid, int status);
+static void dm_support_check_done(libxl__egc *gc,
+ libxl__dm_support_check_state *ch,
+ int rc);
+
+_hidden void libxl__dm_support_check_init(libxl__dm_support_check_state *ch)
+{
+ FILLZERO(*ch);
+ libxl__ev_child_init(&ch->child);
+ libxl__ev_time_init(&ch->immediate);
+}
+
+static void dm_support_check_free(libxl__gc *gc,
+ libxl__dm_support_check_state *ch)
+{
+ if (ch->helpmsg) fclose(ch->helpmsg);
+ assert(!libxl__ev_child_inuse(&ch->child));
+ libxl__ev_time_deregister(gc, &ch->immediate);
+}
+
+_hidden int libxl__dm_support_check_start(libxl__dm_support_check_state *ch)
+{
+ int r, rc;
+
+ /* convenience aliases */
+ const char *const dm = ch->dm;
+ libxl__ao *const ao = ch->ao;
+ AO_GC;
+
+ libxl__dm_support_check_init(ch);
+
+ r = stat(ch->dm, &ch->stab);
+ if (r<0) {
+ LOGE(ERROR, "device model %s is not accessible", dm);
+ rc = ERROR_FAIL;
+ goto out;
+ }
+
+ libxl__dm_support_cached *cached = dm_support_cache_lookup(gc, dm);
+ if (cached &&
+ (ch->stab.st_mode == cached->stab.st_mode &&
+ ch->stab.st_dev == cached->stab.st_dev &&
+ ch->stab.st_ino == cached->stab.st_ino &&
+ ch->stab.st_mtime == cached->stab.st_mtime &&
+ ch->stab.st_ctime == cached->stab.st_ctime)) {
+
+ LOG(DEBUG, "returning cached support options for %s: %"PRIx32"",
+ dm, cached->bitmap);
+
+ rc = libxl__ev_time_register_rel(ao, &ch->immediate,
+ dm_support_check_immed_cb, 0);
+ if (rc) goto out;
+
+ /* we have queued a callback, our work in this function is done */
+ return 0;
+ }
+
+ ch->revalidate = cached;
+ if (cached) {
+ LOG(DEBUG, "revalidating cached support options for %s", dm);
+ }
+
+ ch->helpmsg = tmpfile();
+ if (!ch->helpmsg) {
+ LOGE(ERROR, "create tempfile for help message");
+ rc = ERROR_FAIL;
+ goto out;
+ }
+
+ pid_t pid = libxl__ev_child_fork(gc, &ch->child,
+ dm_support_check_child_cb);
+ if (pid < 0) {
+ LOGE(ERROR, "fork for %s -help", dm);
+ rc = pid;
+ goto out;
+ }
+
+ if (!pid) {
+ const char *const args[] = { dm, "--help", NULL };
+ int outfd = fileno(ch->helpmsg);
+ r = putenv("LC_ALL=C");
+ if (r) libxl__alloc_failed(CTX,__func__,1,0);
+ libxl__exec(gc, -1,outfd,-1, dm, (char**)args, NULL);
+ }
+ return 0;
+
+ out:
+ dm_support_check_free(gc,ch);
+ return rc;
+}
+
+static void dm_support_check_immed_cb(libxl__egc *egc, libxl__ev_time *ev,
+ const struct timeval *requested_abs,
+ int rc)
+{
+ libxl__dm_support_check_state *ch = CONTAINER_OF(ev, *ch, immediate);
+ dm_support_check_done(egc, ch, rc);
+}
+
+static void dm_support_check_lookfor(uint32_t *result_io,
+ const void *data, int datalen,
+ const char *str, int strlen,
+ int opt)
+{
+ if (memmem(data,datalen, str,strlen))
+ *result_io |= (1UL << opt);
+}
+
+void dm_support_check_child_cb(libxl__egc *egc, libxl__ev_child *child,
+ pid_t pid, int status)
+{
+ libxl__dm_support_check_state *ch = CONTAINER_OF(child, *ch, child);
+ STATE_AO_GC(ch->ao);
+ int rc;
+
+ /* convenience aliases */
+ const char *const dm = ch->dm;
+
+ if (status) {
+ libxl_report_child_exitstatus(CTX, XTL_ERROR,
+ GCSPRINTF("%s -HELP", dm),
+ pid, status);
+ rc = ERROR_FAIL;
+ goto out;
+ }
+
+ rewind(ch->helpmsg);
+
+ void *data;
+ int datalen;
+ rc = libxl_read_file_contents(CTX, "(temp file for dm help output)",
+ &data, &datalen);
+ if (rc) goto out;
+ libxl__ptr_add(gc, data);
+
+ if (!datalen) {
+ LOG(ERROR, "dm help output (from %s) was empty!", dm);
+ rc = ERROR_FAIL;
+ goto out;
+ }
+ ((char*)data)[datalen-1] = 0; /* a null-terminated string new */
+
+ uint32_t result = 0;
+
+#define DM_SUPPORT_CHECK_ENTRY(name, string) \
+ dm_support_check_lookfor(&result, \
+ data, datalen, \
+ string, sizeof(string)-1, \
+ libxl__dm_support_check__##name);
+ DM_SUPPORT_CHECK_LIST
+#undef DM_SUPPORT_CHECK_ENTRY
+
+ libxl__dm_support_cached *cached = ch->revalidate;
+ if (cached) {
+ if (cached->bitmap == result)
+ LOG(DEBUG, "confirmed cached support options for %s: %"PRIx32"",
+ dm, result);
+ else
+ LOG(DEBUG, "updating cached support options for %s:"
+ " %"PRIx32" -> %"PRIx32"", dm, cached->bitmap, result);
+ }
+ if (!cached) {
+ LOG(DEBUG, "multiple in-parallel checks for %s", dm);
+ cached = dm_support_cache_lookup(gc, dm);
+ /* if already there, take the one which finished last, willy-nilly */
+ }
+ if (!cached) {
+ LOG(DEBUG, "caching support options for %s: %"PRIx32"", dm, result);
+ cached = libxl__zalloc(NOGC, sizeof(*cached));
+ cached->dm = libxl__strdup(NOGC, dm);
+ LIBXL_LIST_INSERT_HEAD(&CTX->dm_support_cache, cached, entry);
+ }
+
+ cached->stab = ch->stab;
+ cached->bitmap = result;
+
+ rc = 0;
+
+ out:
+ dm_support_check_done(egc, ch, rc);
+}
+
+static void dm_support_check_done(libxl__egc *egc,
+ libxl__dm_support_check_state *ch,
+ int rc)
+{
+ STATE_AO_GC(ch->ao);
+ dm_support_check_free(gc, ch);
+ ch->callback(egc, ch, rc);
+}
+
/*
* Local variables:
* mode: C
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index e442996..f963ad6 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -181,6 +181,7 @@ typedef struct libxl__ao libxl__ao;
typedef struct libxl__aop_occurred libxl__aop_occurred;
typedef struct libxl__osevent_hook_nexus libxl__osevent_hook_nexus;
typedef struct libxl__osevent_hook_nexi libxl__osevent_hook_nexi;
+typedef struct libxl__dm_support_cached libxl__dm_support_cached;
_hidden void libxl__alloc_failed(libxl_ctx *, const char *func,
size_t nmemb, size_t size) __attribute__((noreturn));
@@ -398,6 +399,13 @@ struct libxl__poller {
bool fds_changed;
};
+struct libxl__dm_support_cached {
+ LIBXL_LIST_ENTRY(libxl__dm_support_cached) entry;
+ char *dm;
+ struct stat stab;
+ uint32_t bitmap;
+};
+
struct libxl__gc {
/* mini-GC */
int alloc_maxsize; /* -1 means this is the dummy non-gc gc */
@@ -471,6 +479,8 @@ struct libxl__ctx {
bool sigchld_user_registered;
LIBXL_LIST_ENTRY(libxl_ctx) sigchld_users_entry;
+ LIBXL_LIST_HEAD(, libxl__dm_support_cached) dm_support_cache;
+
libxl_version_info version_info;
};
@@ -3198,6 +3208,72 @@ _hidden void libxl__bootloader_init(libxl__bootloader_state *bl);
* If callback is passed rc==0, will have updated st->info appropriately */
_hidden void libxl__bootloader_run(libxl__egc*, libxl__bootloader_state *st);
+/*----- Device model support check -----*/
+
+/*
+ * This can be used to determine whether a particular qemu supports
+ * a particular option. (Strictly, whether a particular literal
+ * string appears in the help text.)
+ *
+ * Callers should:
+ * 1. Some time it is convenient:
+ * Set up a libxl__dm_support_check_state
+ * Invoke libxl__dm_support_check_start
+ * Await the callback and bomb if it fails
+ * 2. Any time after that, perhaps repeatedly
+ * Call libxl__dm_supported
+ */
+
+typedef struct libxl__dm_support_check_state libxl__dm_support_check_state;
+
+#define DM_SUPPORT_CHECK_LIST \
+ DM_SUPPORT_CHECK_ENTRY(emulator_id, "emulator_id") \
+ DM_SUPPORT_CHECK_ENTRY(xsrestrict, "xsrestrict")
+
+typedef enum {
+#define DM_SUPPORT_CHECK_ENTRY(name, string) \
+ libxl__dm_support_check__##name,
+DM_SUPPORT_CHECK_LIST
+#undef DM_SUPPORT_CHECK_ENTRY
+ libxl__dm_support_check__max
+} libxl__dm_support_check__index;
+
+typedef struct libxl__dm_support_check_state
+ libxl__dm_support_check_state;
+
+/* Cannot be called reentrantly */
+typedef void libxl__dm_support_check_callback(libxl__egc *egc,
+ libxl__dm_support_check_state *checking, int rc);
+
+_hidden void libxl__dm_support_cache_destroy(libxl__gc *gc);
+
+struct libxl__dm_support_check_state {
+ /* caller must fill these in, and they must all remain valid */
+ libxl__ao *ao;
+ const char *dm;
+ libxl__dm_support_check_callback *callback;
+ /* private */
+ FILE *helpmsg;
+ struct stat stab;
+ libxl__ev_child child;
+ libxl__ev_time immediate;
+ libxl__dm_support_cached *revalidate; /* points into dm_support_cache */
+};
+
+_hidden void libxl__dm_support_check_init(
+ libxl__dm_support_check_state *checking);
+
+_hidden int libxl__dm_support_check_start(
+ libxl__dm_support_check_state *checking);
+
+/*
+ * Eg
+ * libxl__dm_supported(gc, my_dm, libxl__dm_support_check__xsrestrict);
+ * (opt is from DM_SUPPORT_CHECK_LIST, above).
+ */
+_hidden bool libxl__dm_supported(libxl__gc *gc,
+ const char *dm, libxl__dm_support_check__index opt);
+
/*----- Domain destruction -----*/
/* Domain destruction has been split into two functions:
--
1.7.10.4
next prev parent reply other threads:[~2015-12-22 18:44 UTC|newest]
Thread overview: 61+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-22 18:44 [RFC PATCH v6 00/28] libxl: Deprivilege qemu Ian Jackson
2015-12-22 18:44 ` [PATCH 01/28] libxl: Move FILLZERO up in libxl_internal.h Ian Jackson
2016-01-07 17:08 ` Ian Campbell
2015-12-22 18:44 ` [PATCH 02/28] libxl: libxl_types_internal.idl: Add Emacs mode comment Ian Jackson
2016-01-07 17:09 ` Ian Campbell
2015-12-22 18:44 ` Ian Jackson [this message]
2016-01-07 17:13 ` [PATCH 03/28] libxl: Provide libxl__dm_support_* Ian Campbell
2016-01-08 12:13 ` Ian Jackson
2016-01-11 17:00 ` Jim Fehlig
2016-01-14 10:14 ` Ian Campbell
2016-01-14 18:31 ` Jim Fehlig
2016-01-15 9:56 ` Ian Campbell
2016-01-15 14:54 ` Jim Fehlig
2015-12-22 18:44 ` [PATCH 04/28] libxl: Invoke libxl__dm_support_* Ian Jackson
2015-12-22 18:44 ` [PATCH 05/28] libxl: libxl__spawn_stub_dm: Introduce `dmpath' Ian Jackson
2015-12-22 18:44 ` [PATCH 06/28] libxl: qemu_pci_*: Introduce DMPATH local macro, twice Ian Jackson
2015-12-22 18:44 ` [PATCH 07/28] libxl: libxl__device_model_xs_path: Add emulator_id parameter Ian Jackson
2015-12-22 18:44 ` [PATCH 08/28] libxl: libxl__destroy_domid: Bring dm destruction together Ian Jackson
2015-12-22 18:44 ` [PATCH 09/28] libxl: Move some error handling and cleanup into libxl__destroy_device_model Ian Jackson
2015-12-22 18:44 ` [PATCH 10/28] libxl: kill_device_model: Silently tolerate ENOENT on pid xs path Ian Jackson
2015-12-22 18:44 ` [PATCH 11/28] libxl: emuids: Pass correct emuid to internal functions Ian Jackson
2015-12-22 18:44 ` [PATCH 12/28] libxl: Use libxl__device_model_xs_path in libxl__spawn_qdisk_backend Ian Jackson
2015-12-22 18:44 ` [PATCH 13/28] libxl: emuids: Record which emuids we have started to create Ian Jackson
2015-12-22 18:44 ` [PATCH 14/28] libxl: emuids: Pass emuid to dm destruction Ian Jackson
2015-12-22 18:44 ` [PATCH 15/28] libxl: emuids: Pass emuid to device model argument construction Ian Jackson
2015-12-22 18:44 ` [PATCH 16/28] libxl: emuids: Provide libxl__dm_xs_path_rel Ian Jackson
2015-12-22 18:44 ` [PATCH 17/28] libxl: emuids: Do not open-code device-model/%u in libxl__destroy_qdisk_backend Ian Jackson
2015-12-22 18:44 ` [PATCH 18/28] libxl: emuids: Change pid path in xenstore Ian Jackson
2015-12-22 18:44 ` [PATCH 19/28] libxl: Improve libxl__destroy_device_model Ian Jackson
2015-12-22 18:44 ` [PATCH 20/28] libxl: domcreate_dm_support_checked: Introduce `goto out' Ian Jackson
2015-12-22 18:44 ` [PATCH 21/28] libxl: dm user: Reject attempts to set user!=root with qemu trad Ian Jackson
2016-01-07 17:20 ` Ian Campbell
2016-01-08 12:16 ` Ian Jackson
2016-01-08 12:23 ` Ian Campbell
2015-12-22 18:44 ` [PATCH 22/28] libxl: dm user: Document the default Ian Jackson
2016-01-07 17:20 ` Ian Campbell
2015-12-22 18:44 ` [PATCH 23/28] libxl: dm user: Move user choice earlier, and fill in config Ian Jackson
2015-12-22 18:44 ` [PATCH 24/28] libxl: dm spawn records rc in state struct rather than passing as argument Ian Jackson
2015-12-22 18:45 ` [PATCH 25/28] libxl: emuids: Perhaps change dm xs control path Ian Jackson
2016-01-07 17:26 ` Ian Campbell
2016-01-08 14:12 ` Ian Jackson
2016-01-08 14:36 ` Ian Campbell
2016-01-08 14:45 ` Ian Jackson
2016-01-08 14:49 ` Ian Campbell
2015-12-22 18:45 ` [PATCH 26/28] libxl: spawns two QEMUs for HVM guests Ian Jackson
2016-01-07 17:28 ` Ian Campbell
2016-01-08 14:35 ` Ian Jackson
2016-01-08 14:52 ` Ian Campbell
2015-12-22 18:45 ` [PATCH 27/28] libxl: Limit qemu physmap entries Ian Jackson
2016-01-07 17:28 ` Ian Campbell
2015-12-22 18:45 ` [PATCH 28/28] libxl: xsrestrict QEMU Ian Jackson
2016-01-07 17:36 ` Ian Campbell
2016-01-08 14:38 ` Ian Jackson
2016-04-10 19:52 ` Stefano Stabellini
2016-01-07 16:19 ` [RFC PATCH v6 00/28] libxl: Deprivilege qemu Wei Liu
2016-01-07 16:23 ` Stefano Stabellini
2016-01-07 16:36 ` Ian Jackson
2016-04-10 19:36 ` Stefano Stabellini
2016-04-11 10:35 ` Wei Liu
2016-04-14 17:27 ` Ian Jackson
2016-04-28 14:32 ` Ian Jackson
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=1450809903-3393-4-git-send-email-ian.jackson@eu.citrix.com \
--to=ian.jackson@eu.citrix.com \
--cc=Ian.Campbell@citrix.com \
--cc=stefano.stabellini@eu.citrix.com \
--cc=wei.liu2@citrix.com \
--cc=xen-devel@lists.xensource.com \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).