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


Reply via email to