From nobody Mon Mar 23 21:24:10 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) client-ip=192.237.175.120; envelope-from=xen-devel-bounces@lists.xenproject.org; helo=lists.xenproject.org; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass(p=quarantine dis=none) header.from=suse.com ARC-Seal: i=1; a=rsa-sha256; t=1774018945; cv=none; d=zohomail.com; s=zohoarc; b=LrpK3O+r5b2eu/8VeqkJUuFRIZTarqyP4KXgcC7JmC02e7tT6hZq5YExYFEixhzHh5VzM84aG8tUUPWwKoSelx52jqiGKmSs7jB7uyIS8OzJbPVkiXo/d4jdHyeOtAF0Vsc7Ebh2fA+F0sc0eqrikA925SyQKk3eZ4fAA3zOClg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1774018945; h=Content-Transfer-Encoding:Cc:Cc:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:Subject:To:To:Message-Id:Reply-To; bh=qdvDBarqGgiL43xd/vvQTmt16yx93JcWCKCmVqFw2vI=; b=lz34SEyYfOpYFKW3dOGIkZYC70YlP2eco9xI2q6Don6Gh4siHArzs+2YhpNOTLfrNTyPoT97iACsTbrKitACqpUyKA6Y1CDwnvsRDv4A5aNSi2CLkliS5MiuLdg48e3hIr1SfGpZBfpPVUGv+i4+RWE3E1glPsv1fYCimTR/yNc= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of lists.xenproject.org designates 192.237.175.120 as permitted sender) smtp.mailfrom=xen-devel-bounces@lists.xenproject.org; dmarc=pass header.from= (p=quarantine dis=none) Return-Path: Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) by mx.zohomail.com with SMTPS id 1774018945077972.7008148887862; Fri, 20 Mar 2026 08:02:25 -0700 (PDT) Received: from list by lists.xenproject.org with outflank-mailman.1258100.1552284 (Exim 4.92) (envelope-from ) id 1w3bMF-0002aC-B6; Fri, 20 Mar 2026 15:01:51 +0000 Received: by outflank-mailman (output) from mailman id 1258100.1552284; Fri, 20 Mar 2026 15:01:51 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1w3bMF-0002a1-7E; Fri, 20 Mar 2026 15:01:51 +0000 Received: by outflank-mailman (input) for mailman id 1258100; Fri, 20 Mar 2026 15:01:49 +0000 Received: from se1-gles-sth1-in.inumbo.com ([159.253.27.254] helo=se1-gles-sth1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1w3bMD-0001Ve-Ms for xen-devel@lists.xenproject.org; Fri, 20 Mar 2026 15:01:49 +0000 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.223.130]) by se1-gles-sth1.inumbo.com (Halon) with ESMTPS id b7b1befc-246d-11f1-b164-2bf370ae4941; Fri, 20 Mar 2026 16:01:47 +0100 (CET) Received: from imap1.dmz-prg2.suse.org (imap1.dmz-prg2.suse.org [IPv6:2a07:de40:b281:104:10:150:64:97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id DB28B4D283; Fri, 20 Mar 2026 15:01:43 +0000 (UTC) Received: from imap1.dmz-prg2.suse.org (localhost [127.0.0.1]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by imap1.dmz-prg2.suse.org (Postfix) with ESMTPS id B9BB94286A; Fri, 20 Mar 2026 15:01:43 +0000 (UTC) Received: from dovecot-director2.suse.de ([2a07:de40:b281:106:10:150:64:167]) by imap1.dmz-prg2.suse.org with ESMTPSA id 5qkuLFdhvWnIXAAAD6G6ig (envelope-from ); Fri, 20 Mar 2026 15:01:43 +0000 X-Outflank-Mailman: Message body and most headers restored to incoming version X-BeenThere: xen-devel@lists.xenproject.org List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xenproject.org Precedence: list Sender: "Xen-devel" X-Inumbo-ID: b7b1befc-246d-11f1-b164-2bf370ae4941 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1774018907; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qdvDBarqGgiL43xd/vvQTmt16yx93JcWCKCmVqFw2vI=; b=dfEGX3AKjjWqhGOj0IZESdUAapuHSM78emCH0i9bbYOosKxcDABJy6vmqAmPdVyVVW//om 9FdpZX334eXePmHeOphKrXxj2rslJ3ggkS72vmnHIuks0KdxiKgtKKayZcXgAN8dPorQJt J33UMI2hJOK5ZK9CBkXLcfZmrsg4R8A= Authentication-Results: smtp-out1.suse.de; dkim=pass header.d=suse.com header.s=susede1 header.b="Z93Mv/u9" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1774018903; h=from:from:reply-to:date:date:message-id:message-id:to:to:cc:cc: mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=qdvDBarqGgiL43xd/vvQTmt16yx93JcWCKCmVqFw2vI=; b=Z93Mv/u9y2dtiHFRupINtCViI4zqk8cCCVnj7+Ba7fEFY16xsbOGGozjdby8gjlpD0s7dW noK92+GdsOdrArxgvWWRr+6mhAJsMZHbebpQ/oxt/weuMafSEtsHJRd/KcXb1onEuaFrwp 9glmz26IfP6yP9rK56Klfk5CLerhL3s= From: Juergen Gross To: xen-devel@lists.xenproject.org Cc: Juergen Gross , Julien Grall , Anthony PERARD Subject: [PATCH v2 04/12] tools/xenstored: rework hard_quotas and soft_quotas arrays Date: Fri, 20 Mar 2026 16:01:12 +0100 Message-ID: <20260320150120.874878-5-jgross@suse.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260320150120.874878-1-jgross@suse.com> References: <20260320150120.874878-1-jgross@suse.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Spamd-Result: default: False [-3.01 / 50.00]; BAYES_HAM(-3.00)[100.00%]; NEURAL_HAM_LONG(-1.00)[-1.000]; MID_CONTAINS_FROM(1.00)[]; R_MISSING_CHARSET(0.50)[]; R_DKIM_ALLOW(-0.20)[suse.com:s=susede1]; NEURAL_HAM_SHORT(-0.20)[-1.000]; MIME_GOOD(-0.10)[text/plain]; MX_GOOD(-0.01)[]; ARC_NA(0.00)[]; FUZZY_RATELIMITED(0.00)[rspamd.com]; RCVD_COUNT_TWO(0.00)[2]; MIME_TRACE(0.00)[0:+]; RCVD_VIA_SMTP_AUTH(0.00)[]; SPAMHAUS_XBL(0.00)[2a07:de40:b281:104:10:150:64:97:from]; TO_DN_SOME(0.00)[]; RBL_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[2a07:de40:b281:104:10:150:64:97:from]; RECEIVED_SPAMHAUS_BLOCKED_OPENRESOLVER(0.00)[2a07:de40:b281:106:10:150:64:167:received]; FROM_HAS_DN(0.00)[]; TO_MATCH_ENVRCPT_ALL(0.00)[]; DBL_BLOCKED_OPENRESOLVER(0.00)[imap1.dmz-prg2.suse.org:helo,imap1.dmz-prg2.suse.org:rdns,suse.com:mid,suse.com:dkim,suse.com:email]; RCVD_TLS_ALL(0.00)[]; FROM_EQ_ENVFROM(0.00)[]; RCPT_COUNT_THREE(0.00)[4]; DKIM_SIGNED(0.00)[suse.com:s=susede1]; DKIM_TRACE(0.00)[suse.com:+] X-Rspamd-Action: no action X-Spam-Flag: NO X-Spam-Score: -3.01 X-Spam-Level: X-Rspamd-Server: rspamd1.dmz-prg2.suse.org X-Rspamd-Queue-Id: DB28B4D283 X-ZohoMail-DKIM: pass (identity @suse.com) (identity @suse.com) X-ZM-MESSAGEID: 1774018945672158500 Content-Type: text/plain; charset="utf-8" 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 Reviewed-by: Anthony PERARD --- 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 conne= ction *conn, } =20 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; =20 for (i =3D 0; i < ACC_N; i++) { - if (!quotas[i].name) + if (!quota_adm[i].name || quotas[i].val[idx] =3D=3D Q_VAL_DISABLED) continue; resp =3D 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 c= onnection *conn, } =20 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; =20 for (i =3D 0; i < ACC_N; i++) { - if (quotas[i].name && !strcmp(vec[0], quotas[i].name)) { - quotas[i].val =3D val; + if (quota_adm[i].name && !strcmp(vec[0], quota_adm[i].name) && + quotas[i].val[idx] !=3D Q_VAL_DISABLED) { + quotas[i].val[idx] =3D val; send_ack(conn, XS_CONTROL); return 0; } @@ -178,10 +180,10 @@ static int do_control_quota(const void *ctx, struct c= onnection *conn, const char **vec, int num) { if (num =3D=3D 0) - return quota_show_current(ctx, conn, hard_quotas); + return quota_show_current(ctx, conn, Q_IDX_HARD); =20 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); =20 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 =3D=3D 0) - return quota_show_current(ctx, conn, soft_quotas); + return quota_show_current(ctx, conn, Q_IDX_SOFT); =20 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); =20 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); } =20 -static void set_quota(const char *arg, bool soft) +static void set_quota(const char *arg, unsigned int idx) { const char *eq =3D strchr(arg, '=3D'); - struct quota *q =3D soft ? soft_quotas : hard_quotas; unsigned int val; unsigned int i; =20 @@ -2626,8 +2625,9 @@ static void set_quota(const char *arg, bool soft) val =3D get_optval_uint(eq + 1); =20 for (i =3D 0; i < ACC_N; i++) { - if (what_matches(arg, q[i].name)) { - q[i].val =3D val; + if (what_matches(arg, quota_adm[i].name) && + quotas[i].val[idx] !=3D Q_VAL_DISABLED) { + quotas[i].val[idx] =3D val; return; } } @@ -2635,6 +2635,11 @@ static void set_quota(const char *arg, bool soft) barf("unknown quota \"%s\"\n", arg); } =20 +static void set_one_quota(const char *arg, unsigned int idx, enum accitem = what) +{ + quotas[what].val[idx] =3D get_optval_uint(arg); +} + /* Sorted by bit values of TRACE_* flags. Flag is (1u << index). */ const char *const trace_switches[] =3D { "obj", "io", "wrl", "acc", "tdb", @@ -2688,7 +2693,7 @@ int main(int argc, char *argv[]) options, NULL)) !=3D -1) { switch (opt) { case 'E': - hard_quotas[ACC_NODES].val =3D get_optval_uint(optarg); + set_one_quota(optarg, Q_IDX_HARD, ACC_NODES); break; case 'F': pidfile =3D optarg; @@ -2700,10 +2705,10 @@ int main(int argc, char *argv[]) dofork =3D false; break; case 'S': - hard_quotas[ACC_NODESZ].val =3D get_optval_uint(optarg); + set_one_quota(optarg, Q_IDX_HARD, ACC_NODESZ); break; case 't': - hard_quotas[ACC_TRANS].val =3D get_optval_uint(optarg); + set_one_quota(optarg, Q_IDX_HARD, ACC_TRANS); break; case 'T': tracefile =3D optarg; @@ -2716,22 +2721,22 @@ int main(int argc, char *argv[]) keep_orphans =3D true; break; case 'W': - hard_quotas[ACC_WATCH].val =3D get_optval_uint(optarg); + set_one_quota(optarg, Q_IDX_HARD, ACC_WATCH); break; case 'A': - hard_quotas[ACC_NPERM].val =3D get_optval_uint(optarg); + set_one_quota(optarg, Q_IDX_HARD, ACC_NPERM); break; case 'M': - hard_quotas[ACC_PATHLEN].val =3D get_optval_uint(optarg); - hard_quotas[ACC_PATHLEN].val =3D + set_one_quota(optarg, Q_IDX_HARD, ACC_PATHLEN); + quotas[ACC_PATHLEN].val[Q_IDX_HARD] =3D 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; =20 xenevtchn_handle *xce_handle =3D NULL; =20 -struct quota hard_quotas[ACC_N] =3D { +struct quotaadm quota_adm[ACC_N] =3D { [ACC_NODES] =3D { .name =3D "nodes", .descr =3D "Nodes per domain", - .val =3D 1000, }, [ACC_WATCH] =3D { .name =3D "watches", .descr =3D "Watches per domain", - .val =3D 128, }, [ACC_OUTST] =3D { .name =3D "outstanding", .descr =3D "Outstanding requests per domain", - .val =3D 20, }, [ACC_MEM] =3D { .name =3D "memory", - .descr =3D "Total Xenstore memory per domain (error level)", - .val =3D 2 * 1024 * 1024 + 512 * 1024, /* 2.5 MB */ + .descr =3D "Total Xenstore memory per domain", }, [ACC_TRANS] =3D { .name =3D "transactions", .descr =3D "Active transactions per domain", - .val =3D 10, }, [ACC_TRANSNODES] =3D { .name =3D "transaction-nodes", .descr =3D "Max. number of accessed nodes per transaction", - .val =3D 1024, }, [ACC_NPERM] =3D { .name =3D "node-permissions", .descr =3D "Max. number of permissions per node", - .val =3D 5, }, [ACC_PATHLEN] =3D { .name =3D "path-max", .descr =3D "Max. length of a node path", - .val =3D XENSTORE_REL_PATH_MAX, }, [ACC_NODESZ] =3D { .name =3D "node-size", .descr =3D "Max. size of a node", - .val =3D 2048, }, }; =20 -struct quota soft_quotas[ACC_N] =3D { - [ACC_MEM] =3D { - .name =3D "memory", - .descr =3D "Total Xenstore memory per domain (warning level)", - .val =3D 2 * 1024 * 1024, /* 2.0 MB */ +struct quota quotas[ACC_N] =3D { + [ACC_NODES] =3D { .val =3D { 1000, Q_VAL_DISABLED }, }, + [ACC_WATCH] =3D { .val =3D { 128, Q_VAL_DISABLED }, }, + [ACC_OUTST] =3D { .val =3D { 20, Q_VAL_DISABLED }, }, + [ACC_MEM] =3D { + .val =3D { 2 * 1024 * 1024 + 512 * 1024, /* 2.5 MB */ + 2 * 1024 * 1024 /* 2.0 MB */ }, }, + [ACC_TRANS] =3D { .val =3D { 10, Q_VAL_DISABLED }, }, + [ACC_TRANSNODES] =3D { .val =3D { 1024, Q_VAL_DISABLED }, }, + [ACC_NPERM] =3D { .val =3D { 5, Q_VAL_DISABLED }, }, + [ACC_PATHLEN] =3D { + .val =3D { XENSTORE_REL_PATH_MAX, Q_VAL_DISABLED }, + }, + [ACC_NODESZ] =3D { .val =3D { 2048, Q_VAL_DISABLED }, }, }; =20 typedef int32_t wrl_creditt; @@ -389,10 +389,15 @@ void wrl_apply_debit_trans_commit(struct connection *= conn) wrl_apply_debit_actual(conn->domain); } =20 +static unsigned int domain_get_soft_quota(struct domain *d, enum accitem w= hat) +{ + 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 =3D hard_quotas[what].val; + unsigned int quota =3D quotas[what].val[Q_IDX_HARD]; =20 if (!quota || !domid_is_unprivileged(d->domid)) return false; @@ -777,10 +782,10 @@ int domain_get_quota(const void *ctx, struct connecti= on *conn, return ENOMEM; =20 for (i =3D 0; i < ACC_N; i++) { - if (!hard_quotas[i].name) + if (!quota_adm[i].name) continue; resp =3D 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 con= nection *conn) return ENOMEM; =20 for (i =3D 0; i < ACC_N; i++) { - if (!hard_quotas[i].name) + if (!quota_adm[i].name) continue; resp =3D 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)); =20 if (val > d->acc[what].max) d->acc[what].max =3D val; - if (val > hard_quotas[what].max && domid_is_unprivileged(d->domid)) - hard_quotas[what].max =3D val; + if (val > quotas[what].max && domid_is_unprivileged(d->domid)) + quotas[what].max =3D val; } =20 static int domain_acc_add_valid(struct domain *d, enum accitem what, int a= dd) @@ -1773,7 +1777,7 @@ void domain_reset_global_acc(void) unsigned int i; =20 for (i =3D 0; i < ACC_N; i++) - hard_quotas[i].max =3D 0; + quotas[i].max =3D 0; =20 /* 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 *con= n, unsigned int mem) } =20 if (now - domain->mem_last_msg >=3D MEM_WARN_MINTIME_SEC) { + unsigned int soft_mem =3D domain_get_soft_quota(domain, ACC_MEM); + if (domain->hard_quota_reported) { domain->mem_last_msg =3D now; domain->hard_quota_reported =3D false; syslog(LOG_INFO, "Domain %u below hard memory quota again\n", domain->domid); } - if (mem >=3D soft_quotas[ACC_MEM].val && - soft_quotas[ACC_MEM].val && !domain->soft_quota_reported) { + if (mem >=3D soft_mem && soft_mem && + !domain->soft_quota_reported) { domain->mem_last_msg =3D now; domain->soft_quota_reported =3D 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 =3D now; domain->soft_quota_reported =3D 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. */ }; =20 -struct quota { +extern struct quotaadm { const char *name; const char *descr; - unsigned int val; - unsigned int max; -}; +} quota_adm[ACC_N]; =20 -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]; =20 void handle_event(void); =20 --=20 2.53.0