Add saving the maximum values of the different accounting data seen per domain and (for unprivileged domains) globally, and print those values via the xenstore-control quota command. Add a sub-command for resetting the global maximum values seen.
This should help for a decision how to set the related quotas. Signed-off-by: Juergen Gross <jgr...@suse.com> --- docs/misc/xenstore.txt | 5 +- tools/xenstore/xenstored_control.c | 22 ++++++- tools/xenstore/xenstored_domain.c | 100 +++++++++++++++++++++++------ tools/xenstore/xenstored_domain.h | 2 + 4 files changed, 108 insertions(+), 21 deletions(-) diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt index 8887e7df88..44a02f6724 100644 --- a/docs/misc/xenstore.txt +++ b/docs/misc/xenstore.txt @@ -423,7 +423,7 @@ CONTROL <command>|[<parameters>|] print|<string> print <string> to syslog (xenstore runs as daemon) or to console (xenstore runs as stubdom) - quota|[set <name> <val>|<domid>] + quota|[set <name> <val>|<domid>|max [-r]] without parameters: print the current quota settings with "set <name> <val>": set the quota <name> to new value <val> (The admin should make sure all the domain usage is @@ -432,6 +432,9 @@ CONTROL <command>|[<parameters>|] violating the new quota setting isn't increased further) with "<domid>": print quota related accounting data for the domain <domid> + with "max [-r]": show global per-domain maximum values of all + unprivileged domains, optionally reset the values by adding + "-r" quota-soft|[set <name> <val>] like the "quota" command, but for soft-quota. help <supported-commands> diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c index cbd62556c3..a2ba64a15c 100644 --- a/tools/xenstore/xenstored_control.c +++ b/tools/xenstore/xenstored_control.c @@ -306,6 +306,22 @@ static int quota_get(const void *ctx, struct connection *conn, return domain_get_quota(ctx, conn, atoi(vec[0])); } +static int quota_max(const void *ctx, struct connection *conn, + char **vec, int num) +{ + if (num > 1) + return EINVAL; + + if (num == 1) { + if (!strcmp(vec[0], "-r")) + domain_reset_global_acc(); + else + return EINVAL; + } + + return domain_max_global_acc(ctx, conn); +} + static int do_control_quota(const void *ctx, struct connection *conn, char **vec, int num) { @@ -315,6 +331,9 @@ static int do_control_quota(const void *ctx, struct connection *conn, if (!strcmp(vec[0], "set")) return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas); + if (!strcmp(vec[0], "max")) + return quota_max(ctx, conn, vec + 1, num - 1); + return quota_get(ctx, conn, vec, num); } @@ -978,7 +997,8 @@ static struct cmd_s cmds[] = { { "memreport", do_control_memreport, "[<file>]" }, #endif { "print", do_control_print, "<string>" }, - { "quota", do_control_quota, "[set <name> <val>|<domid>]" }, + { "quota", do_control_quota, + "[set <name> <val>|<domid>|max [-r]]" }, { "quota-soft", do_control_quota_s, "[set <name> <val>]" }, { "help", do_control_help, "" }, }; diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index 4d48e7a9f4..91695b6313 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -43,6 +43,8 @@ static evtchn_port_t virq_port; xenevtchn_handle *xce_handle = NULL; +static unsigned int acc_global_max[ACC_N]; + struct domain { /* The id of this domain */ @@ -70,7 +72,10 @@ struct domain bool introduced; /* Accounting data for this domain. */ - unsigned int acc[ACC_N]; + struct acc { + unsigned int val; + unsigned int max; + } acc[ACC_N]; /* Memory quota data for this domain. */ bool soft_quota_reported; @@ -199,9 +204,9 @@ static bool domain_can_read(struct connection *conn) if (domain_is_unprivileged(conn)) { if (domain->wrl_credit < 0) return false; - if (domain->acc[ACC_OUTST] >= quota_req_outstanding) + if (domain->acc[ACC_OUTST].val >= quota_req_outstanding) return false; - if (domain->acc[ACC_MEM] >= quota_memory_per_domain_hard && + if (domain->acc[ACC_MEM].val >= quota_memory_per_domain_hard && quota_memory_per_domain_hard) return false; } @@ -264,7 +269,7 @@ static int domain_tree_remove_sub(const void *ctx, struct connection *conn, ret = WALK_TREE_SKIP_CHILDREN; } - return domain->acc[ACC_NODES] ? ret : WALK_TREE_SUCCESS_STOP; + return domain->acc[ACC_NODES].val ? ret : WALK_TREE_SUCCESS_STOP; } static void domain_tree_remove(struct domain *domain) @@ -272,7 +277,7 @@ static void domain_tree_remove(struct domain *domain) int ret; struct walk_funcs walkfuncs = { .enter = domain_tree_remove_sub }; - if (domain->acc[ACC_NODES]) { + if (domain->acc[ACC_NODES].val) { ret = walk_node_tree(domain, NULL, "/", &walkfuncs, domain); if (ret == WALK_TREE_ERROR_STOP) syslog(LOG_ERR, @@ -426,14 +431,41 @@ int domain_get_quota(const void *ctx, struct connection *conn, return ENOMEM; #define ent(t, e) \ - resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \ + resp = talloc_asprintf_append(resp, "%-16s: %8u (max: %8u\n", #t, \ + d->acc[e].val, d->acc[e].max); \ + if (!resp) return ENOMEM + + ent(nodes, ACC_NODES); + ent(watches, ACC_WATCH); + ent(transactions, ACC_TRANS); + ent(outstanding, ACC_OUTST); + ent(memory, ACC_MEM); + +#undef ent + + send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1); + + return 0; +} + +int domain_max_global_acc(const void *ctx, struct connection *conn) +{ + char *resp; + + resp = talloc_asprintf(ctx, "Max. seen accounting values:\n"); + if (!resp) + return ENOMEM; + +#define ent(t, e) \ + resp = talloc_asprintf_append(resp, "%-16s: %8u\n", #t, \ + acc_global_max[e]); \ if (!resp) return ENOMEM - ent(nodes, d->acc[ACC_NODES]); - ent(watches, d->acc[ACC_WATCH]); - ent(transactions, d->acc[ACC_TRANS]); - ent(outstanding, d->acc[ACC_OUTST]); - ent(memory, d->acc[ACC_MEM]); + ent(nodes, ACC_NODES); + ent(watches, ACC_WATCH); + ent(transactions, ACC_TRANS); + ent(outstanding, ACC_OUTST); + ent(memory, ACC_MEM); #undef ent @@ -1051,10 +1083,12 @@ int domain_adjust_node_perms(struct node *node) static int domain_acc_add_chk(struct domain *d, enum accitem what, int add, unsigned int domid) { + unsigned int val; + assert(what < ARRAY_SIZE(d->acc)); - if ((add < 0 && -add > d->acc[what]) || - (d->acc[what] + add) > INT_MAX) { + if ((add < 0 && -add > d->acc[what].val) || + (d->acc[what].val + add) > INT_MAX) { /* * In a transaction when a node is being added/removed AND the * same node has been added/removed outside the transaction in @@ -1065,7 +1099,13 @@ static int domain_acc_add_chk(struct domain *d, enum accitem what, int add, return (add < 0) ? 0 : INT_MAX; } - return d->acc[what] + add; + val = d->acc[what].val + add; + if (val > d->acc[what].max) + d->acc[what].max = val; + if (val > acc_global_max[what] && domid_is_unprivileged(domid)) + acc_global_max[what] = val; + + return val; } static int domain_acc_add(struct connection *conn, unsigned int domid, @@ -1121,10 +1161,10 @@ static int domain_acc_add(struct connection *conn, unsigned int domid, } trace_acc("global change domid %u: what=%u %u add %d\n", domid, what, - d->acc[what], add); - d->acc[what] = domain_acc_add_chk(d, what, add, domid); + d->acc[what].val, add); + d->acc[what].val = domain_acc_add_chk(d, what, add, domid); - return d->acc[what]; + return d->acc[what].val; } void acc_drop(struct connection *conn) @@ -1157,6 +1197,28 @@ void acc_commit(struct connection *conn) conn->in = in; } +static int domain_reset_global_acc_sub(const void *k, void *v, void *arg) +{ + struct domain *d = v; + unsigned int i; + + for (i = 0; i < ACC_N; i++) + d->acc[i].max = d->acc[i].val; + + return 0; +} + +void domain_reset_global_acc(void) +{ + unsigned int i; + + for (i = 0; i < ACC_N; i++) + acc_global_max[i] = 0; + + /* Set current max values seen. */ + hashtable_iterate(domhash, domain_reset_global_acc_sub, NULL); +} + int domain_nbentry_inc(struct connection *conn, unsigned int domid) { return (domain_acc_add(conn, domid, ACC_NODES, 1, false) < 0) @@ -1657,7 +1719,7 @@ static int domain_check_acc_init_sub(const void *k, void *v, void *arg) * If everything is correct incrementing the value for each node will * result in dom->nodes being 0 at the end. */ - dom->nodes = -d->acc[ACC_NODES]; + dom->nodes = -d->acc[ACC_NODES].val; if (!hashtable_insert(domains, &dom->domid, dom)) { talloc_free(dom); @@ -1712,7 +1774,7 @@ static int domain_check_acc_cb(const void *k, void *v, void *arg) if (!d) return 0; - d->acc[ACC_NODES] += dom->nodes; + d->acc[ACC_NODES].val += dom->nodes; return 0; } diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h index e0562b0b4d..162e7dc0d0 100644 --- a/tools/xenstore/xenstored_domain.h +++ b/tools/xenstore/xenstored_domain.h @@ -116,6 +116,8 @@ int domain_get_quota(const void *ctx, struct connection *conn, int acc_fix_domains(struct list_head *head, bool update); void acc_drop(struct connection *conn); void acc_commit(struct connection *conn); +int domain_max_global_acc(const void *ctx, struct connection *conn); +void domain_reset_global_acc(void); /* Write rate limiting */ -- 2.35.3