]> xenbits.xensource.com Git - xen.git/commitdiff
tools/xenstore: add control command for setting and showing quota
authorJuergen Gross <jgross@suse.com>
Tue, 13 Sep 2022 05:35:10 +0000 (07:35 +0200)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 1 Nov 2022 15:25:15 +0000 (15:25 +0000)
Add a xenstore-control command "quota" to:
- show current quota settings
- change quota settings
- show current quota related values of a domain

Note that in the case the new quota is lower than existing one,
Xenstored may continue to handle requests from a domain exceeding the
new limit (depends on which one has been broken) and the amount of
resource used will not change. However the domain will not be able to
create more resource (associated to the quota) until it is back to below
the limit.

This is part of XSA-326.

Signed-off-by: Juergen Gross <jgross@suse.com>
Reviewed-by: Julien Grall <jgrall@amazon.com>
(cherry picked from commit 9c484bef83496b683b0087e3bd2a560da4aa37af)

docs/misc/xenstore.txt
tools/xenstore/xenstored_control.c
tools/xenstore/xenstored_domain.c
tools/xenstore/xenstored_domain.h

index 32969eb3fecd72f753ae75a416efc86ec65ca781..0dbac442d79dcdffbc7331bfa4ab302b97c76923 100644 (file)
@@ -346,6 +346,17 @@ 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>]
+               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
+               below the quota. If it is not, then Xenstored may continue to
+               handle requests from the domain as long as the resource
+               violating the new quota setting isn't increased further)
+               with "<domid>": print quota related accounting data for
+               the domain <domid>
+       quota-soft|[set <name> <val>]
+               like the "quota" command, but for soft-quota.
        help                    <supported-commands>
                return list of supported commands for CONTROL
 
index 715e0d2a9e0302ad94e4c8add77f359080c98aba..454fe9d5ab18c9ceb5c6764e28b9ed3768eba755 100644 (file)
@@ -19,6 +19,7 @@
 #include <errno.h>
 #include <stdarg.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 
 #include "utils.h"
@@ -77,6 +78,114 @@ static int do_control_logfile(void *ctx, struct connection *conn,
        return 0;
 }
 
+struct quota {
+       const char *name;
+       int *quota;
+       const char *descr;
+};
+
+static const struct quota hard_quotas[] = {
+       { "nodes", &quota_nb_entry_per_domain, "Nodes per domain" },
+       { "watches", &quota_nb_watch_per_domain, "Watches per domain" },
+       { "transactions", &quota_max_transaction, "Transactions per domain" },
+       { "outstanding", &quota_req_outstanding,
+               "Outstanding requests per domain" },
+       { "transaction-nodes", &quota_trans_nodes,
+               "Max. number of accessed nodes per transaction" },
+       { "memory", &quota_memory_per_domain_hard,
+               "Total Xenstore memory per domain (error level)" },
+       { "node-size", &quota_max_entry_size, "Max. size of a node" },
+       { "permissions", &quota_nb_perms_per_node,
+               "Max. number of permissions per node" },
+       { NULL, NULL, NULL }
+};
+
+static const struct quota soft_quotas[] = {
+       { "memory", &quota_memory_per_domain_soft,
+               "Total Xenstore memory per domain (warning level)" },
+       { NULL, NULL, NULL }
+};
+
+static int quota_show_current(const void *ctx, struct connection *conn,
+                             const struct quota *quotas)
+{
+       char *resp;
+       unsigned int i;
+
+       resp = talloc_strdup(ctx, "Quota settings:\n");
+       if (!resp)
+               return ENOMEM;
+
+       for (i = 0; quotas[i].quota; i++) {
+               resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n",
+                                             quotas[i].name, *quotas[i].quota,
+                                             quotas[i].descr);
+               if (!resp)
+                       return ENOMEM;
+       }
+
+       send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+       return 0;
+}
+
+static int quota_set(const void *ctx, struct connection *conn,
+                    char **vec, int num, const struct quota *quotas)
+{
+       unsigned int i;
+       int val;
+
+       if (num != 2)
+               return EINVAL;
+
+       val = atoi(vec[1]);
+       if (val < 1)
+               return EINVAL;
+
+       for (i = 0; quotas[i].quota; i++) {
+               if (!strcmp(vec[0], quotas[i].name)) {
+                       *quotas[i].quota = val;
+                       send_ack(conn, XS_CONTROL);
+                       return 0;
+               }
+       }
+
+       return EINVAL;
+}
+
+static int quota_get(const void *ctx, struct connection *conn,
+                    char **vec, int num)
+{
+       if (num != 1)
+               return EINVAL;
+
+       return domain_get_quota(ctx, conn, atoi(vec[0]));
+}
+
+static int do_control_quota(void *ctx, struct connection *conn,
+                           char **vec, int num)
+{
+       if (num == 0)
+               return quota_show_current(ctx, conn, hard_quotas);
+
+       if (!strcmp(vec[0], "set"))
+               return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas);
+
+       return quota_get(ctx, conn, vec, num);
+}
+
+static int do_control_quota_s(void *ctx, struct connection *conn,
+                             char **vec, int num)
+{
+       if (num == 0)
+               return quota_show_current(ctx, conn, soft_quotas);
+
+       if (!strcmp(vec[0], "set"))
+               return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas);
+
+       return EINVAL;
+}
+
 static int do_control_memreport(void *ctx, struct connection *conn,
                                char **vec, int num)
 {
@@ -136,6 +245,8 @@ static struct cmd_s cmds[] = {
        { "logfile", do_control_logfile, "<file>" },
        { "memreport", do_control_memreport, "[<file>]" },
        { "print", do_control_print, "<string>" },
+       { "quota", do_control_quota, "[set <name> <val>|<domid>]" },
+       { "quota-soft", do_control_quota_s, "[set <name> <val>]" },
        { "help", do_control_help, "" },
 };
 
index 2b23452e0c3dd6f330d3077bbad81c60f3bf22b2..4b2da302c2f0cee4c6b566cc4d87e6392188b8bb 100644 (file)
@@ -31,6 +31,7 @@
 #include "xenstored_domain.h"
 #include "xenstored_transaction.h"
 #include "xenstored_watch.h"
+#include "xenstored_control.h"
 
 #include <xenevtchn.h>
 #include <xenctrl.h>
@@ -352,6 +353,38 @@ static struct domain *find_domain_struct(unsigned int domid)
        return NULL;
 }
 
+int domain_get_quota(const void *ctx, struct connection *conn,
+                    unsigned int domid)
+{
+       struct domain *d = find_domain_struct(domid);
+       char *resp;
+       int ta;
+
+       if (!d)
+               return ENOENT;
+
+       ta = d->conn ? d->conn->transaction_started : 0;
+       resp = talloc_asprintf(ctx, "Domain %u:\n", domid);
+       if (!resp)
+               return ENOMEM;
+
+#define ent(t, e) \
+       resp = talloc_asprintf_append(resp, "%-16s: %8d\n", #t, e); \
+       if (!resp) return ENOMEM
+
+       ent(nodes, d->nbentry);
+       ent(watches, d->nbwatch);
+       ent(transactions, ta);
+       ent(outstanding, d->nboutstanding);
+       ent(memory, d->memory);
+
+#undef ent
+
+       send_reply(conn, XS_CONTROL, resp, strlen(resp) + 1);
+
+       return 0;
+}
+
 static struct domain *alloc_domain(void *context, unsigned int domid)
 {
        struct domain *domain;
index 3a8c6bab48ba183c64919f58f44081898b4a2286..e013a9991ca8e8d843e27676ebbfb226b19c5fd8 100644 (file)
@@ -90,6 +90,8 @@ int domain_watch(struct connection *conn);
 void domain_outstanding_inc(struct connection *conn);
 void domain_outstanding_dec(struct connection *conn);
 void domain_outstanding_domid_dec(unsigned int domid);
+int domain_get_quota(const void *ctx, struct connection *conn,
+                    unsigned int domid);
 
 /* Special node permission handling. */
 int set_perms_special(struct connection *conn, const char *name,