diff --git a/tools/xenstored/control.c b/tools/xenstored/control.c index 2611a6fade..ca59d30d05 100644 --- a/tools/xenstored/control.c +++ b/tools/xenstored/control.c @@ -101,7 +101,7 @@ static int do_control_log(const void *ctx, struct connection *conn, } static int quota_show_current(const void *ctx, struct connection *conn, - const struct quota *quotas) + unsigned int idx) { char *resp; unsigned int i; @@ -111,11 +111,12 @@ static int quota_show_current(const void *ctx, struct connection *conn, return ENOMEM; for (i = 0; i < ACC_N; i++) { - if (!quotas[i].name) + if (!quota_adm[i].name || quotas[i].val[idx] == Q_VAL_DISABLED) continue; resp = talloc_asprintf_append(resp, "%-17s: %8d %s\n", - quotas[i].name, quotas[i].val, - quotas[i].descr); + quota_adm[i].name, + quotas[i].val[idx], + quota_adm[i].descr); if (!resp) return ENOMEM; } @@ -126,7 +127,7 @@ static int quota_show_current(const void *ctx, struct connection *conn, } static int quota_set(const void *ctx, struct connection *conn, - const char **vec, int num, struct quota *quotas) + const char **vec, int num, unsigned int idx) { unsigned int i; int val; @@ -139,8 +140,9 @@ static int quota_set(const void *ctx, struct connection *conn, return EINVAL; for (i = 0; i < ACC_N; i++) { - if (quotas[i].name && !strcmp(vec[0], quotas[i].name)) { - quotas[i].val = val; + if (quota_adm[i].name && !strcmp(vec[0], quota_adm[i].name) && + quotas[i].val[idx] != Q_VAL_DISABLED) { + quotas[i].val[idx] = val; send_ack(conn, XS_CONTROL); return 0; } @@ -178,10 +180,10 @@ static int do_control_quota(const void *ctx, struct connection *conn, const char **vec, int num) { if (num == 0) - return quota_show_current(ctx, conn, hard_quotas); + return quota_show_current(ctx, conn, Q_IDX_HARD); if (!strcmp(vec[0], "set")) - return quota_set(ctx, conn, vec + 1, num - 1, hard_quotas); + return quota_set(ctx, conn, vec + 1, num - 1, Q_IDX_HARD); if (!strcmp(vec[0], "max")) return quota_max(ctx, conn, vec + 1, num - 1); @@ -193,10 +195,10 @@ static int do_control_quota_s(const void *ctx, struct connection *conn, const char **vec, int num) { if (num == 0) - return quota_show_current(ctx, conn, soft_quotas); + return quota_show_current(ctx, conn, Q_IDX_SOFT); if (!strcmp(vec[0], "set")) - return quota_set(ctx, conn, vec + 1, num - 1, soft_quotas); + return quota_set(ctx, conn, vec + 1, num - 1, Q_IDX_SOFT); return EINVAL; } diff --git a/tools/xenstored/core.c b/tools/xenstored/core.c index e86d947be4..dc63c97658 100644 --- a/tools/xenstored/core.c +++ b/tools/xenstored/core.c @@ -2614,10 +2614,9 @@ static void set_timeout(const char *arg) barf("unknown timeout \"%s\"\n", arg); } -static void set_quota(const char *arg, bool soft) +static void set_quota(const char *arg, unsigned int idx) { const char *eq = strchr(arg, '='); - struct quota *q = soft ? soft_quotas : hard_quotas; unsigned int val; unsigned int i; @@ -2626,8 +2625,9 @@ static void set_quota(const char *arg, bool soft) val = get_optval_uint(eq + 1); for (i = 0; i < ACC_N; i++) { - if (what_matches(arg, q[i].name)) { - q[i].val = val; + if (what_matches(arg, quota_adm[i].name) && + quotas[i].val[idx] != Q_VAL_DISABLED) { + quotas[i].val[idx] = val; return; } } @@ -2635,6 +2635,11 @@ static void set_quota(const char *arg, bool soft) barf("unknown quota \"%s\"\n", arg); } +static void set_one_quota(const char *arg, unsigned int idx, enum accitem what) +{ + quotas[what].val[idx] = get_optval_uint(arg); +} + /* Sorted by bit values of TRACE_* flags. Flag is (1u << index). */ const char *const trace_switches[] = { "obj", "io", "wrl", "acc", "tdb", @@ -2688,7 +2693,7 @@ int main(int argc, char *argv[]) options, NULL)) != -1) { switch (opt) { case 'E': - hard_quotas[ACC_NODES].val = get_optval_uint(optarg); + set_one_quota(optarg, Q_IDX_HARD, ACC_NODES); break; case 'F': pidfile = optarg; @@ -2700,10 +2705,10 @@ int main(int argc, char *argv[]) dofork = false; break; case 'S': - hard_quotas[ACC_NODESZ].val = get_optval_uint(optarg); + set_one_quota(optarg, Q_IDX_HARD, ACC_NODESZ); break; case 't': - hard_quotas[ACC_TRANS].val = get_optval_uint(optarg); + set_one_quota(optarg, Q_IDX_HARD, ACC_TRANS); break; case 'T': tracefile = optarg; @@ -2716,22 +2721,22 @@ int main(int argc, char *argv[]) keep_orphans = true; break; case 'W': - hard_quotas[ACC_WATCH].val = get_optval_uint(optarg); + set_one_quota(optarg, Q_IDX_HARD, ACC_WATCH); break; case 'A': - hard_quotas[ACC_NPERM].val = get_optval_uint(optarg); + set_one_quota(optarg, Q_IDX_HARD, ACC_NPERM); break; case 'M': - hard_quotas[ACC_PATHLEN].val = get_optval_uint(optarg); - hard_quotas[ACC_PATHLEN].val = + set_one_quota(optarg, Q_IDX_HARD, ACC_PATHLEN); + quotas[ACC_PATHLEN].val[Q_IDX_HARD] = min((unsigned int)XENSTORE_REL_PATH_MAX, - hard_quotas[ACC_PATHLEN].val); + quotas[ACC_PATHLEN].val[Q_IDX_HARD]); break; case 'Q': - set_quota(optarg, false); + set_quota(optarg, Q_IDX_HARD); break; case 'q': - set_quota(optarg, true); + set_quota(optarg, Q_IDX_SOFT); break; case 'w': set_timeout(optarg); diff --git a/tools/xenstored/domain.c b/tools/xenstored/domain.c index 21f6f13f83..4e696a81a8 100644 --- a/tools/xenstored/domain.c +++ b/tools/xenstored/domain.c @@ -51,60 +51,60 @@ static evtchn_port_t virq_port; xenevtchn_handle *xce_handle = NULL; -struct quota hard_quotas[ACC_N] = { +struct quotaadm quota_adm[ACC_N] = { [ACC_NODES] = { .name = "nodes", .descr = "Nodes per domain", - .val = 1000, }, [ACC_WATCH] = { .name = "watches", .descr = "Watches per domain", - .val = 128, }, [ACC_OUTST] = { .name = "outstanding", .descr = "Outstanding requests per domain", - .val = 20, }, [ACC_MEM] = { .name = "memory", - .descr = "Total Xenstore memory per domain (error level)", - .val = 2 * 1024 * 1024 + 512 * 1024, /* 2.5 MB */ + .descr = "Total Xenstore memory per domain", }, [ACC_TRANS] = { .name = "transactions", .descr = "Active transactions per domain", - .val = 10, }, [ACC_TRANSNODES] = { .name = "transaction-nodes", .descr = "Max. number of accessed nodes per transaction", - .val = 1024, }, [ACC_NPERM] = { .name = "node-permissions", .descr = "Max. number of permissions per node", - .val = 5, }, [ACC_PATHLEN] = { .name = "path-max", .descr = "Max. length of a node path", - .val = XENSTORE_REL_PATH_MAX, }, [ACC_NODESZ] = { .name = "node-size", .descr = "Max. size of a node", - .val = 2048, }, }; -struct quota soft_quotas[ACC_N] = { - [ACC_MEM] = { - .name = "memory", - .descr = "Total Xenstore memory per domain (warning level)", - .val = 2 * 1024 * 1024, /* 2.0 MB */ +struct quota quotas[ACC_N] = { + [ACC_NODES] = { .val = { 1000, Q_VAL_DISABLED }, }, + [ACC_WATCH] = { .val = { 128, Q_VAL_DISABLED }, }, + [ACC_OUTST] = { .val = { 20, Q_VAL_DISABLED }, }, + [ACC_MEM] = { + .val = { 2 * 1024 * 1024 + 512 * 1024, /* 2.5 MB */ + 2 * 1024 * 1024 /* 2.0 MB */ }, }, + [ACC_TRANS] = { .val = { 10, Q_VAL_DISABLED }, }, + [ACC_TRANSNODES] = { .val = { 1024, Q_VAL_DISABLED }, }, + [ACC_NPERM] = { .val = { 5, Q_VAL_DISABLED }, }, + [ACC_PATHLEN] = { + .val = { XENSTORE_REL_PATH_MAX, Q_VAL_DISABLED }, + }, + [ACC_NODESZ] = { .val = { 2048, Q_VAL_DISABLED }, }, }; typedef int32_t wrl_creditt; @@ -389,10 +389,15 @@ void wrl_apply_debit_trans_commit(struct connection *conn) wrl_apply_debit_actual(conn->domain); } +static unsigned int domain_get_soft_quota(struct domain *d, enum accitem what) +{ + return quotas[what].val[Q_IDX_SOFT]; +} + static bool domain_quota_val_exceeds(struct domain *d, enum accitem what, unsigned int val) { - unsigned int quota = hard_quotas[what].val; + unsigned int quota = quotas[what].val[Q_IDX_HARD]; if (!quota || !domid_is_unprivileged(d->domid)) return false; @@ -777,10 +782,10 @@ int domain_get_quota(const void *ctx, struct connection *conn, return ENOMEM; for (i = 0; i < ACC_N; i++) { - if (!hard_quotas[i].name) + if (!quota_adm[i].name) continue; resp = talloc_asprintf_append(resp, "%-17s: %8u (max %8u)\n", - hard_quotas[i].name, + quota_adm[i].name, d->acc[i].val, d->acc[i].max); if (!resp) return ENOMEM; @@ -801,11 +806,10 @@ int domain_max_global_acc(const void *ctx, struct connection *conn) return ENOMEM; for (i = 0; i < ACC_N; i++) { - if (!hard_quotas[i].name) + if (!quota_adm[i].name) continue; resp = talloc_asprintf_append(resp, "%-17s: %8u\n", - hard_quotas[i].name, - hard_quotas[i].max); + quota_adm[i].name, quotas[i].max); if (!resp) return ENOMEM; } @@ -1631,12 +1635,12 @@ static void domain_acc_valid_max(struct domain *d, enum accitem what, unsigned int val) { assert(what < ARRAY_SIZE(d->acc)); - assert(what < ARRAY_SIZE(hard_quotas)); + assert(what < ARRAY_SIZE(quotas)); if (val > d->acc[what].max) d->acc[what].max = val; - if (val > hard_quotas[what].max && domid_is_unprivileged(d->domid)) - hard_quotas[what].max = val; + if (val > quotas[what].max && domid_is_unprivileged(d->domid)) + quotas[what].max = val; } static int domain_acc_add_valid(struct domain *d, enum accitem what, int add) @@ -1773,7 +1777,7 @@ void domain_reset_global_acc(void) unsigned int i; for (i = 0; i < ACC_N; i++) - hard_quotas[i].max = 0; + quotas[i].max = 0; /* Set current max values seen. */ hashtable_iterate(domhash, domain_reset_global_acc_sub, NULL); @@ -1833,21 +1837,22 @@ static bool domain_chk_quota(struct connection *conn, unsigned int mem) } if (now - domain->mem_last_msg >= MEM_WARN_MINTIME_SEC) { + unsigned int soft_mem = domain_get_soft_quota(domain, ACC_MEM); + if (domain->hard_quota_reported) { domain->mem_last_msg = now; domain->hard_quota_reported = false; syslog(LOG_INFO, "Domain %u below hard memory quota again\n", domain->domid); } - if (mem >= soft_quotas[ACC_MEM].val && - soft_quotas[ACC_MEM].val && !domain->soft_quota_reported) { + if (mem >= soft_mem && soft_mem && + !domain->soft_quota_reported) { domain->mem_last_msg = now; domain->soft_quota_reported = true; syslog(LOG_WARNING, "Domain %u exceeds soft memory quota\n", domain->domid); } - if (mem < soft_quotas[ACC_MEM].val && - domain->soft_quota_reported) { + if (mem < soft_mem && domain->soft_quota_reported) { domain->mem_last_msg = now; domain->soft_quota_reported = false; syslog(LOG_INFO, "Domain %u below soft memory quota again\n", diff --git a/tools/xenstored/domain.h b/tools/xenstored/domain.h index 29b91fc783..3bedadb477 100644 --- a/tools/xenstored/domain.h +++ b/tools/xenstored/domain.h @@ -40,15 +40,18 @@ enum accitem { ACC_N, /* Number of elements per domain. */ }; -struct quota { +extern struct quotaadm { const char *name; const char *descr; - unsigned int val; - unsigned int max; -}; +} quota_adm[ACC_N]; -extern struct quota hard_quotas[ACC_N]; -extern struct quota soft_quotas[ACC_N]; +extern struct quota { + unsigned int val[2]; +#define Q_IDX_HARD 0 +#define Q_IDX_SOFT 1 +#define Q_VAL_DISABLED UINT_MAX + unsigned int max; +} quotas[ACC_N]; void handle_event(void);