All of lore.kernel.org
 help / color / mirror / Atom feed
From: Juergen Gross <jgross@suse.com>
To: xen-devel@lists.xenproject.org
Cc: Juergen Gross <jgross@suse.com>, Julien Grall <julien@xen.org>,
	Anthony PERARD <anthony.perard@vates.tech>
Subject: [PATCH 03/11] tools/xenstored: rework hard_quotas and soft_quotas arrays
Date: Thu,  5 Mar 2026 14:52:00 +0100	[thread overview]
Message-ID: <20260305135208.2208663-4-jgross@suse.com> (raw)
In-Reply-To: <20260305135208.2208663-1-jgross@suse.com>

Instead of having one array for hard quotas and one for soft quotas,
split them differently: have one array with the quota names and
descriptions, and one with the quota values (soft and hard) and the
maximum value so far.

This is in preparation of supporting per-domain quotas, as the layout
of the second array elements will be reused in the domain data.

While at it add an accessor for getting a soft quota value, as this
will be needed for per-domain quotas, too.

Signed-off-by: Juergen Gross <jgross@suse.com>
---
 tools/xenstored/control.c | 24 ++++++++-------
 tools/xenstored/core.c    | 33 +++++++++++---------
 tools/xenstored/domain.c  | 65 +++++++++++++++++++++------------------
 tools/xenstored/domain.h  | 15 +++++----
 4 files changed, 76 insertions(+), 61 deletions(-)

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 5a4bf3e302..8a06b35808 100644
--- a/tools/xenstored/core.c
+++ b/tools/xenstored/core.c
@@ -2613,10 +2613,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;
 
@@ -2625,8 +2624,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;
 		}
 	}
@@ -2634,6 +2634,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",
@@ -2687,7 +2692,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;
@@ -2699,10 +2704,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;
@@ -2715,22 +2720,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 1df9265ad5..acdcaa769e 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_check_quota_val(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;
@@ -765,10 +770,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;
@@ -789,11 +794,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;
 	}
@@ -1600,12 +1604,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)
@@ -1742,7 +1746,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);
@@ -1802,21 +1806,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 b229f6f4e0..a6db358fdc 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);
 
-- 
2.53.0



  parent reply	other threads:[~2026-03-05 13:52 UTC|newest]

Thread overview: 43+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-03-05 13:51 [PATCH 00/11] tools: add support for per-domain xenstore quota Juergen Gross
2026-03-05 13:51 ` [PATCH 01/11] tools/libs/store: add get- and set-quota related functions Juergen Gross
2026-03-13 14:23   ` Anthony PERARD
2026-03-16  7:51     ` Jürgen Groß
2026-03-19 13:31       ` Anthony PERARD
2026-03-05 13:51 ` [PATCH 02/11] tools/xenstored: add central quota check functions Juergen Gross
2026-03-13 15:01   ` Anthony PERARD
2026-03-16  7:53     ` Jürgen Groß
2026-03-13 21:22   ` Jason Andryuk
2026-03-16  8:18     ` Jürgen Groß
2026-03-05 13:52 ` Juergen Gross [this message]
2026-03-13 16:09   ` [PATCH 03/11] tools/xenstored: rework hard_quotas and soft_quotas arrays Anthony PERARD
2026-03-05 13:52 ` [PATCH 04/11] tools/xenstored: add GLOBAL_QUOTA_DATA record for live update Juergen Gross
2026-03-13 17:08   ` Anthony PERARD
2026-03-16  8:15     ` Jürgen Groß
2026-03-18 12:16       ` Juergen Gross
2026-03-19 16:15         ` Anthony PERARD
2026-03-19 16:31           ` Jürgen Groß
2026-03-19 15:59       ` Anthony PERARD
2026-03-05 13:52 ` [PATCH 05/11] tools/xenstored: split acc[] array in struct domain Juergen Gross
2026-03-13 17:15   ` Anthony PERARD
2026-03-05 13:52 ` [PATCH 06/11] tools/xenstored: add infrastructure for per-domain quotas Juergen Gross
2026-03-13 17:32   ` Anthony PERARD
2026-03-16  8:17     ` Jürgen Groß
2026-03-05 13:52 ` [PATCH 07/11] tools/xenstored: implement the GET/SET_QUOTA commands Juergen Gross
2026-03-16 15:08   ` Anthony PERARD
2026-03-16 15:27     ` Juergen Gross
2026-03-19 16:47       ` Anthony PERARD
2026-03-20  6:36         ` Jürgen Groß
2026-03-05 13:52 ` [PATCH 08/11] tools/libxl: add functions for retrieving and setting xenstore quota Juergen Gross
2026-03-10 13:58   ` Nick Rosbrook
2026-03-19  9:11   ` Anthony PERARD
2026-03-19 11:00     ` Jürgen Groß
2026-03-05 13:52 ` [PATCH 09/11] tools/libxl: add support for xenstore quota in domain_config Juergen Gross
2026-03-10 13:57   ` Nick Rosbrook
2026-03-19  9:26   ` Anthony PERARD
2026-03-19 11:01     ` Jürgen Groß
2026-03-05 13:52 ` [PATCH 10/11] tools/xl: add xl commands for xenstore quota operations Juergen Gross
2026-03-19 12:37   ` Anthony PERARD
2026-03-19 13:06     ` Jürgen Groß
2026-03-05 13:52 ` [PATCH 11/11] tools/xl: add support for xenstore quota setting via domain config Juergen Gross
2026-03-19 13:06   ` Anthony PERARD
2026-03-19 13:11     ` Jürgen Groß

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260305135208.2208663-4-jgross@suse.com \
    --to=jgross@suse.com \
    --cc=anthony.perard@vates.tech \
    --cc=julien@xen.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.