mirror of
https://github.com/xen-project/xen.git
synced 2026-10-29 10:40:03 +01:00
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@amazon.com>
Reviewed-by: Ian Jackson <ian.jackson@eu.citrix.com>
This commit is contained in:
1 parent
310c32faab
commit
2b02882ebb
5 files changed
+287
No files matched your search
@@ -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");
|
||||
|
||||
@@ -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 */
|
||||
|
||||
/*
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
/*
|
||||
|
||||