@@ -409,14 +409,8 @@ CONTROL <command>|[<parameters>|]
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
- logfile|<file-name>
- log to specified file
memreport|[<file-name>]
- print memory statistics to logfile (no <file-name>
+ print memory statistics to tracefile (no <file-name>
specified) or to specific file
print|<string>
print <string> to syslog (xenstore runs as daemon) or
@@ -432,6 +426,16 @@ CONTROL <command>|[<parameters>|]
the domain <domid>
quota-soft|[set <name> <val>]
like the "quota" command, but for soft-quota.
+ trace|[+|-<switch>]
+ without parameters: show possible trace switches
+ +<switch> activates trace entries for <switch>,
+ -<switch> deactivates trace entries for <switch>
+ trace|on
+ turn xenstore tracing on
+ trace|off
+ turn xenstore tracing off
+ tracefile|<file-name>
+ trace to specified file
help <supported-commands>
return list of supported commands for CONTROL
@@ -179,9 +179,31 @@ static int do_control_check(const void *ctx, struct connection *conn,
return 0;
}
-static int do_control_log(const void *ctx, struct connection *conn,
- char **vec, int num)
+static int do_control_trace(const void *ctx, struct connection *conn,
+ char **vec, int num)
{
+ int ret;
+
+ if (num == 0) {
+ char *resp = talloc_asprintf(ctx, "Trace 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;
@@ -189,8 +211,11 @@ static int do_control_log(const void *ctx, struct connection *conn,
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;
@@ -318,8 +343,8 @@ static int do_control_memreport(const void *ctx, struct connection *conn,
return 0;
}
#else
-static int do_control_logfile(const void *ctx, struct connection *conn,
- char **vec, int num)
+static int do_control_tracefile(const void *ctx, struct connection *conn,
+ char **vec, int num)
{
if (num != 1)
return EINVAL;
@@ -923,7 +948,7 @@ static int do_control_help(const void *, struct connection *, char **, int);
static struct cmd_s cmds[] = {
{ "check", do_control_check, "" },
- { "log", do_control_log, "on|off" },
+ { "trace", do_control_trace, "[on|off|[!]<switch>]" },
#ifndef NO_LIVE_UPDATE
/*
@@ -949,7 +974,7 @@ static struct cmd_s cmds[] = {
#ifdef __MINIOS__
{ "memreport", do_control_memreport, "" },
#else
- { "logfile", do_control_logfile, "<file>" },
+ { "tracefile", do_control_tracefile, "<file>" },
{ "memreport", do_control_memreport, "[<file>]" },
#endif
{ "print", do_control_print, "<string>" },
@@ -85,6 +85,7 @@ static int reopen_log_pipe[2];
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);
@@ -139,13 +140,13 @@ static void trace_io(const struct connection *conn,
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,
@@ -158,12 +159,14 @@ static void trace_io(const struct connection *conn,
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);
}
/**
@@ -2590,6 +2593,8 @@ static void usage(void)
" -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 (no \"!\" prepended) or deactivate\n"
+" 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"
@@ -2633,6 +2638,7 @@ static struct option options[] = {
{ "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' },
@@ -2707,6 +2713,33 @@ static void set_quota(const char *arg, bool soft)
barf("unknown quota \"%s\"\n", arg);
}
+/* Sorted by bit values of TRACE_* flags. Flag is (1u << index). */
+const char *trace_switches[] = {
+ "obj", "io", "wrl",
+ NULL
+};
+
+int set_trace_switch(const char *arg)
+{
+ bool remove = (arg[0] == '!');
+ unsigned int idx;
+
+ if (remove)
+ 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;
@@ -2755,6 +2788,9 @@ int main(int argc, char *argv[])
case 'T':
tracefile = optarg;
break;
+ case 1:
+ set_trace_switch(optarg);
+ break;
case 'I':
if (optarg && !strcmp(optarg, "off"))
tdb_flags = 0;
@@ -287,6 +287,12 @@ extern char **orig_argv;
extern char *tracefile;
extern int tracefd;
+extern unsigned int trace_flags;
+#define TRACE_OBJ 0x00000001
+#define TRACE_IO 0x00000002
+#define TRACE_WRL 0x00000004
+extern const char *trace_switches[];
+int set_trace_switch(const char *arg);
extern TDB_CONTEXT *tdb_ctx;
extern int dom0_domid;
@@ -1256,6 +1256,12 @@ static long wrl_ndomains;
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;
@@ -1361,12 +1367,9 @@ void wrl_credit_update(struct domain *domain, struct wrl_timestampt now)
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,
@@ -1398,10 +1401,9 @@ 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, ...) \
@@ -1419,9 +1421,8 @@ void wrl_apply_debit_actual(struct domain *domain)
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) {
@@ -475,6 +475,7 @@ int do_transaction_start(const void *ctx, struct connection *conn,
if (!trans)
return ENOMEM;
+ trace_create(trans, "transaction");
INIT_LIST_HEAD(&trans->accessed);
INIT_LIST_HEAD(&trans->changed_domains);
trans->conn = conn;
Make the xenstored internal trace configurable by adding classes which can be switched on and off independently from each other. Define the following classes: - obj: Creation and deletion of interesting "objects" (watch, transaction, connection) - io: incoming requests and outgoing responses - wrl: write limiting Per default "obj" and "io" are switched on. Entries written via trace() will always be printed (if tracing is on at all). Rename the misnamed xenstore-control commands "logfile" to "tracefile" and "log" to "trace". Add the capability to control the trace settings via the "trace" command and via a new "--trace-control" command line option. Add a missing trace_create() call for creating a transaction. Signed-off-by: Juergen Gross <jgross@suse.com> --- docs/misc/xenstore.txt | 18 +++++++---- tools/xenstore/xenstored_control.c | 41 +++++++++++++++++++----- tools/xenstore/xenstored_core.c | 44 +++++++++++++++++++++++--- tools/xenstore/xenstored_core.h | 6 ++++ tools/xenstore/xenstored_domain.c | 27 ++++++++-------- tools/xenstore/xenstored_transaction.c | 1 + 6 files changed, 105 insertions(+), 32 deletions(-)