diff --git a/docs/misc/xenstore.txt b/docs/misc/xenstore.txt index 4bc262fd5d..988ef89cba 100644 --- a/docs/misc/xenstore.txt +++ b/docs/misc/xenstore.txt @@ -410,6 +410,17 @@ CONTROL |[|] print| print to syslog (xenstore runs as daemon) or to console (xenstore runs as stubdom) + quota|[set |] + without parameters: print the current quota settings + with "set ": set the quota to new value + (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 "": print quota related accounting data for + the domain + quota-soft|[set ] + like the "quota" command, but for soft-quota. help return list of supported commands for CONTROL diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c index 61bcbc069d..264bb39d7b 100644 --- a/tools/xenstore/xenstored_control.c +++ b/tools/xenstore/xenstored_control.c @@ -196,6 +196,115 @@ static int do_control_log(void *ctx, struct connection *conn, return 0; } +struct quota { + const char *name; + int *quota; + const char *descr; +}; + +static const struct quota hard_quotas[] = { + { "nodes", "a_nb_entry_per_domain, "Nodes per domain" }, + { "watches", "a_nb_watch_per_domain, "Watches per domain" }, + { "transactions", "a_max_transaction, "Transactions per domain" }, + { "outstanding", "a_req_outstanding, + "Outstanding requests per domain" }, + { "transaction-nodes", "a_trans_nodes, + "Max. number of accessed nodes per transaction" }, + { "memory", "a_memory_per_domain_hard, + "Total Xenstore memory per domain (error level)" }, + { "node-size", "a_max_entry_size, "Max. size of a node" }, + { "path-max", "a_max_path_len, "Max. length of a node path" }, + { "permissions", "a_nb_perms_per_node, + "Max. number of permissions per node" }, + { NULL, NULL, NULL } +}; + +static const struct quota soft_quotas[] = { + { "memory", "a_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; +} + #ifdef __MINIOS__ static int do_control_memreport(void *ctx, struct connection *conn, char **vec, int num) @@ -847,6 +956,8 @@ static struct cmd_s cmds[] = { { "memreport", do_control_memreport, "[]" }, #endif { "print", do_control_print, "" }, + { "quota", do_control_quota, "[set |]" }, + { "quota-soft", do_control_quota_s, "[set ]" }, { "help", do_control_help, "" }, }; diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_domain.c index 4242380886..983b348ee5 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -31,6 +31,7 @@ #include "xenstored_domain.h" #include "xenstored_transaction.h" #include "xenstored_watch.h" +#include "xenstored_control.h" #include #include @@ -345,6 +346,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(const void *context, unsigned int domid) { struct domain *domain; diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_domain.h index d342e5e867..5b86a92e1b 100644 --- a/tools/xenstore/xenstored_domain.h +++ b/tools/xenstore/xenstored_domain.h @@ -88,6 +88,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,