#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;
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");
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)
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);
_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.
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
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
/*