error string in case of failure. -s can return "BUSY" in case
of an active transaction, a retry of -s can be done in that
case.
- log|on
- turn xenstore logging on
- log|off
- turn xenstore logging off
+ log|[on|off|+<switch>|-<switch>]
+ without parameters: show possible log switches
+ on: turn xenstore logging on
+ off: turn xenstore logging off
+ +<switch>: activates log entries for <switch>,
+ -<switch>: deactivates log entries for <switch>
logfile|<file-name>
log to specified file
memreport|[<file-name>]
static int do_control_log(const void *ctx, struct connection *conn,
char **vec, int num)
{
+ int ret;
+
+ if (num == 0) {
+ char *resp = talloc_asprintf(ctx, "Log switch settings:\n");
+ unsigned int idx;
+ bool on;
+
+ if (!resp)
+ return ENOMEM;
+ for (idx = 0; trace_switches[idx]; idx++) {
+ on = trace_flags & (1u << idx);
+ resp = talloc_asprintf_append(resp, "%-8s: %s\n",
+ trace_switches[idx],
+ on ? "on" : "off");
+ if (!resp)
+ return ENOMEM;
+ }
+
+ send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+ return 0;
+ }
+
if (num != 1)
return EINVAL;
reopen_log();
else if (!strcmp(vec[0], "off"))
close_log();
- else
- return EINVAL;
+ else {
+ ret = set_trace_switch(vec[0]);
+ if (ret)
+ return ret;
+ }
send_ack(conn, XS_CONTROL);
return 0;
static struct cmd_s cmds[] = {
{ "check", do_control_check, "" },
- { "log", do_control_log, "on|off" },
+ { "log", do_control_log, "[on|off|+<switch>|-<switch>]" },
#ifndef NO_LIVE_UPDATE
/*
static int reopen_log_pipe0_pollfd_idx = -1;
char *tracefile = NULL;
TDB_CONTEXT *tdb_ctx = NULL;
+unsigned int trace_flags = TRACE_OBJ | TRACE_IO;
static const char *sockmsg_string(enum xsd_sockmsg_type type);
time_t now;
struct tm *tm;
- if (tracefd < 0)
+ if (tracefd < 0 || !(trace_flags & TRACE_IO))
return;
now = time(NULL);
tm = localtime(&now);
- trace("%s %p %04d%02d%02d %02d:%02d:%02d %s (",
+ trace("io: %s %p %04d%02d%02d %02d:%02d:%02d %s (",
out ? "OUT" : "IN", conn,
tm->tm_year + 1900, tm->tm_mon + 1,
tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
void trace_create(const void *data, const char *type)
{
- trace("CREATE %s %p\n", type, data);
+ if (trace_flags & TRACE_OBJ)
+ trace("obj: CREATE %s %p\n", type, data);
}
void trace_destroy(const void *data, const char *type)
{
- trace("DESTROY %s %p\n", type, data);
+ if (trace_flags & TRACE_OBJ)
+ trace("obj: DESTROY %s %p\n", type, data);
}
/**
" -N, --no-fork to request that the daemon does not fork,\n"
" -P, --output-pid to request that the pid of the daemon is output,\n"
" -T, --trace-file <file> giving the file for logging, and\n"
+" --trace-control=+<switch> activate a specific <switch>\n"
+" --trace-control=-<switch> deactivate a specific <switch>\n"
" -E, --entry-nb <nb> limit the number of entries per domain,\n"
" -S, --entry-size <size> limit the size of entry per domain, and\n"
" -W, --watch-nb <nb> limit the number of watches per domain,\n"
{ "output-pid", 0, NULL, 'P' },
{ "entry-size", 1, NULL, 'S' },
{ "trace-file", 1, NULL, 'T' },
+ { "trace-control", 1, NULL, 1 },
{ "transaction", 1, NULL, 't' },
{ "perm-nb", 1, NULL, 'A' },
{ "path-max", 1, NULL, 'M' },
barf("unknown quota \"%s\"\n", arg);
}
+/* Sorted by bit values of TRACE_* flags. Flag is (1u << index). */
+const char *const trace_switches[] = {
+ "obj", "io", "wrl",
+ NULL
+};
+
+int set_trace_switch(const char *arg)
+{
+ bool remove = (arg[0] == '-');
+ unsigned int idx;
+
+ switch (arg[0]) {
+ case '-':
+ remove = true;
+ break;
+ case '+':
+ remove = false;
+ break;
+ default:
+ return EINVAL;
+ }
+
+ arg++;
+
+ for (idx = 0; trace_switches[idx]; idx++) {
+ if (!strcmp(arg, trace_switches[idx])) {
+ if (remove)
+ trace_flags &= ~(1u << idx);
+ else
+ trace_flags |= 1u << idx;
+ return 0;
+ }
+ }
+
+ return EINVAL;
+}
+
int main(int argc, char *argv[])
{
int opt;
case 'T':
tracefile = optarg;
break;
+ case 1:
+ if (set_trace_switch(optarg))
+ barf("Illegal trace switch \"%s\"\n", optarg);
+ break;
case 'I':
if (optarg && !strcmp(optarg, "off"))
tdb_flags = 0;
extern char *tracefile;
extern int tracefd;
+/* Trace flag values must be kept in sync with trace_switches[] contents. */
+extern unsigned int trace_flags;
+#define TRACE_OBJ 0x00000001
+#define TRACE_IO 0x00000002
+#define TRACE_WRL 0x00000004
+extern const char *const trace_switches[];
+int set_trace_switch(const char *arg);
+
extern TDB_CONTEXT *tdb_ctx;
extern int dom0_domid;
extern int dom0_event;
static wrl_creditt wrl_reserve; /* [-wrl_config_newdoms_dburst, +_gburst ] */
static time_t wrl_log_last_warning; /* 0: no previous warning */
+#define trace_wrl(...) \
+do { \
+ if (trace_flags & TRACE_WRL) \
+ trace("wrl: " __VA_ARGS__); \
+} while (0)
+
void wrl_gettime_now(struct wrl_timestampt *now_wt)
{
struct timespec now_ts;
domain->wrl_timestamp = now;
- trace("wrl: dom %4d %6ld msec %9ld credit %9ld reserve"
- " %9ld discard\n",
- domain->domid,
- msec,
- (long)domain->wrl_credit, (long)wrl_reserve,
- (long)surplus);
+ trace_wrl("dom %4d %6ld msec %9ld credit %9ld reserve %9ld discard\n",
+ domain->domid, msec, (long)domain->wrl_credit,
+ (long)wrl_reserve, (long)surplus);
}
void wrl_check_timeout(struct domain *domain,
if (*ptimeout==-1 || wakeup < *ptimeout)
*ptimeout = wakeup;
- trace("wrl: domain %u credit=%ld (reserve=%ld) SLEEPING for %d\n",
- domain->domid,
- (long)domain->wrl_credit, (long)wrl_reserve,
- wakeup);
+ trace_wrl("domain %u credit=%ld (reserve=%ld) SLEEPING for %d\n",
+ domain->domid, (long)domain->wrl_credit, (long)wrl_reserve,
+ wakeup);
}
#define WRL_LOG(now, ...) \
wrl_credit_update(domain, now);
domain->wrl_credit -= wrl_config_writecost;
- trace("wrl: domain %u credit=%ld (reserve=%ld)\n",
- domain->domid,
- (long)domain->wrl_credit, (long)wrl_reserve);
+ trace_wrl("domain %u credit=%ld (reserve=%ld)\n", domain->domid,
+ (long)domain->wrl_credit, (long)wrl_reserve);
if (domain->wrl_credit < 0) {
if (!domain->wrl_delay_logged) {
if (!trans)
return ENOMEM;
+ trace_create(trans, "transaction");
INIT_LIST_HEAD(&trans->accessed);
INIT_LIST_HEAD(&trans->changed_domains);
trans->conn = conn;