From nobody Mon Feb 9 11:06:32 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=1674035746; cv=none; d=zohomail.com; s=zohoarc; b=FaUtcB4M753RJqEHoiXW7Q9/CgwFBfnEA7vWu4m2c09A4p7LA5wBSuIbCuCijQDrFn8QQG59mdgBI5y6AQ6gHhPWUSIhWDo7rP5Tx6OXZYhYrZ7pi2GF3mviDGhGQ3EG2f5MII71Zh176H/BP+MUemj0Cvk0X3Q2J3x16deszIk= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1674035746; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To; bh=UVU2p+c8txVUI24FAKxzeXD4L5boxXW/hUAgXWxAShI=; b=MwvP5gVW9j/0+k7RYxJlGNhacXU9klBtJfOSXyAv8MgpRCN3PJGfx9b3eTq1cGUNzB83Nj9fICy8ZxKjLehwzeGYE4MfcahFu7zejqysxo2kkPuNMe73AbtAZoVF5e4uA1K4WiCr+C4HOrqrZpq3BG8FUrkX0iBlAalVwaAUjhw= 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 167403574600590.70231780348513; Wed, 18 Jan 2023 01:55:46 -0800 (PST) Received: from list by lists.xenproject.org with outflank-mailman.480369.744778 (Exim 4.92) (envelope-from ) id 1pI5A5-00079l-Nk; Wed, 18 Jan 2023 09:55:17 +0000 Received: by outflank-mailman (output) from mailman id 480369.744778; Wed, 18 Jan 2023 09:55:17 +0000 Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pI5A5-00075w-BQ; Wed, 18 Jan 2023 09:55:17 +0000 Received: by outflank-mailman (input) for mailman id 480369; Wed, 18 Jan 2023 09:55:15 +0000 Received: from se1-gles-flk1-in.inumbo.com ([94.247.172.50] helo=se1-gles-flk1.inumbo.com) by lists.xenproject.org with esmtp (Exim 4.92) (envelope-from ) id 1pI562-0001BV-VN for xen-devel@lists.xenproject.org; Wed, 18 Jan 2023 09:51:07 +0000 Received: from smtp-out1.suse.de (smtp-out1.suse.de [195.135.220.28]) by se1-gles-flk1.inumbo.com (Halon) with ESMTPS id 6b087800-9715-11ed-b8d1-410ff93cb8f0; Wed, 18 Jan 2023 10:49:36 +0100 (CET) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by smtp-out1.suse.de (Postfix) with ESMTPS id 412E6340AE; Wed, 18 Jan 2023 09:51:04 +0000 (UTC) Received: from imap2.suse-dmz.suse.de (imap2.suse-dmz.suse.de [192.168.254.74]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (P-521) server-digest SHA512) (No client certificate requested) by imap2.suse-dmz.suse.de (Postfix) with ESMTPS id 15668139D2; Wed, 18 Jan 2023 09:51:04 +0000 (UTC) Received: from dovecot-director2.suse.de ([192.168.254.65]) by imap2.suse-dmz.suse.de with ESMTPSA id aY17AwjBx2OrQwAAMHmgww (envelope-from ); Wed, 18 Jan 2023 09:51:04 +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: 6b087800-9715-11ed-b8d1-410ff93cb8f0 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=suse.com; s=susede1; t=1674035464; 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=UVU2p+c8txVUI24FAKxzeXD4L5boxXW/hUAgXWxAShI=; b=gsVyF3gQ1Dumq+OU6saj7iIiCskw7e94KAt7KuJDi9Hgf4dTCHSOr26C04/hVZrlwEGMxh fdbr3ECHco+17JKZGlOhmOijCHyJWnT3YxvSHd+rRHDtg40cpbf8iPlOPFBZMMpd/vIeYW 9+Q07yVCRA7LW8gRgYkILBkVys2c+ik= From: Juergen Gross To: xen-devel@lists.xenproject.org Cc: Juergen Gross , Wei Liu , Julien Grall , Anthony PERARD Subject: [PATCH v4 08/17] tools/xenstore: change per-domain node accounting interface Date: Wed, 18 Jan 2023 10:50:07 +0100 Message-Id: <20230118095016.13091-9-jgross@suse.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20230118095016.13091-1-jgross@suse.com> References: <20230118095016.13091-1-jgross@suse.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-ZohoMail-DKIM: pass (identity @suse.com) X-ZM-MESSAGEID: 1674035747140100007 Content-Type: text/plain; charset="utf-8" Rework the interface and the internals of the per-domain node accounting: - rename the functions to domain_nbentry_*() in order to better match the related counter name - switch from node pointer to domid as interface, as all nodes have the owner filled in - use a common internal function for adding a value to the counter For the transaction case add a helper function to get the list head of the per-transaction changed domains, enabling to eliminate the transaction_entry_*() functions. Signed-off-by: Juergen Gross Reviewed-by: Julien Grall --- V3: - add get_node_owner() (Julien Grall) - rename domain_nbentry_add() parameter (Julien Grall) - avoid negative entry count (Julien Grall) V4: - make get_node_owner() an inline function --- tools/xenstore/xenstored_core.c | 28 +++--- tools/xenstore/xenstored_core.h | 6 ++ tools/xenstore/xenstored_domain.c | 126 ++++++++++++------------- tools/xenstore/xenstored_domain.h | 10 +- tools/xenstore/xenstored_transaction.c | 15 +-- tools/xenstore/xenstored_transaction.h | 7 +- 6 files changed, 87 insertions(+), 105 deletions(-) diff --git a/tools/xenstore/xenstored_core.c b/tools/xenstore/xenstored_cor= e.c index c82fb6e3d5..4582ee39e1 100644 --- a/tools/xenstore/xenstored_core.c +++ b/tools/xenstore/xenstored_core.c @@ -738,13 +738,13 @@ struct node *read_node(struct connection *conn, const= void *ctx, =20 /* Permissions are struct xs_permissions. */ node->perms.p =3D hdr->perms; - node->acc.domid =3D node->perms.p[0].id; + node->acc.domid =3D get_node_owner(node); node->acc.memory =3D data.dsize; if (domain_adjust_node_perms(node)) goto error; =20 /* If owner is gone reset currently accounted memory size. */ - if (node->acc.domid !=3D node->perms.p[0].id) + if (node->acc.domid !=3D get_node_owner(node)) node->acc.memory =3D 0; =20 /* Data is binary blob (usually ascii, no nul). */ @@ -1445,7 +1445,7 @@ static void destroy_node_rm(struct connection *conn, = struct node *node) static int destroy_node(struct connection *conn, struct node *node) { destroy_node_rm(conn, node); - domain_entry_dec(conn, node); + domain_nbentry_dec(conn, get_node_owner(node)); =20 /* * It is not possible to easily revert the changes in a transaction. @@ -1484,7 +1484,7 @@ static struct node *create_node(struct connection *co= nn, const void *ctx, for (i =3D node; i; i =3D i->parent) { /* i->parent is set for each new node, so check quota. */ if (i->parent && - domain_entry(conn) >=3D quota_nb_entry_per_domain) { + domain_nbentry(conn) >=3D quota_nb_entry_per_domain) { ret =3D ENOSPC; goto err; } @@ -1495,7 +1495,7 @@ static struct node *create_node(struct connection *co= nn, const void *ctx, =20 /* Account for new node */ if (i->parent) { - if (domain_entry_inc(conn, i)) { + if (domain_nbentry_inc(conn, get_node_owner(i))) { destroy_node_rm(conn, i); return NULL; } @@ -1648,7 +1648,7 @@ static int delnode_sub(const void *ctx, struct connec= tion *conn, watch_exact =3D strcmp(root, node->name); fire_watches(conn, ctx, node->name, node, watch_exact, NULL); =20 - domain_entry_dec(conn, node); + domain_nbentry_dec(conn, get_node_owner(node)); =20 return WALK_TREE_RM_CHILDENTRY; } @@ -1784,29 +1784,29 @@ static int do_set_perms(const void *ctx, struct con= nection *conn, =20 /* Unprivileged domains may not change the owner. */ if (domain_is_unprivileged(conn) && - perms.p[0].id !=3D node->perms.p[0].id) + perms.p[0].id !=3D get_node_owner(node)) return EPERM; =20 old_perms =3D node->perms; - domain_entry_dec(conn, node); + domain_nbentry_dec(conn, get_node_owner(node)); node->perms =3D perms; - if (domain_entry_inc(conn, node)) { + if (domain_nbentry_inc(conn, get_node_owner(node))) { node->perms =3D old_perms; /* * This should never fail because we had a reference on the * domain before and Xenstored is single-threaded. */ - domain_entry_inc(conn, node); + domain_nbentry_inc(conn, get_node_owner(node)); return ENOMEM; } =20 if (write_node(conn, node, false)) { int saved_errno =3D errno; =20 - domain_entry_dec(conn, node); + domain_nbentry_dec(conn, get_node_owner(node)); node->perms =3D old_perms; /* No failure possible as above. */ - domain_entry_inc(conn, node); + domain_nbentry_inc(conn, get_node_owner(node)); =20 errno =3D saved_errno; return errno; @@ -2378,7 +2378,7 @@ void setup_structure(bool live_update) manual_node("/tool/xenstored", NULL); manual_node("@releaseDomain", NULL); manual_node("@introduceDomain", NULL); - domain_entry_fix(dom0_domid, 5, true); + domain_nbentry_fix(dom0_domid, 5, true); } =20 check_store(); @@ -3386,7 +3386,7 @@ void read_state_node(const void *ctx, const void *sta= te) if (write_node_raw(NULL, &key, node, true)) barf("write node error restoring node"); =20 - if (domain_entry_inc(&conn, node)) + if (domain_nbentry_inc(&conn, get_node_owner(node))) barf("node accounting error restoring node"); =20 talloc_free(node); diff --git a/tools/xenstore/xenstored_core.h b/tools/xenstore/xenstored_cor= e.h index 89055cbb21..62d8ee96bd 100644 --- a/tools/xenstore/xenstored_core.h +++ b/tools/xenstore/xenstored_core.h @@ -232,6 +232,12 @@ char *canonicalize(struct connection *conn, const void= *ctx, const char *node); unsigned int perm_for_conn(struct connection *conn, const struct node_perms *perms); =20 +/* Get owner of a node. */ +static inline unsigned int get_node_owner(const struct node *node) +{ + return node->perms.p[0].id; +} + /* Write a node to the tdb data base. */ int write_node_raw(struct connection *conn, TDB_DATA *key, struct node *no= de, bool no_quota_check); diff --git a/tools/xenstore/xenstored_domain.c b/tools/xenstore/xenstored_d= omain.c index 1d765ceffa..703ddeec4e 100644 --- a/tools/xenstore/xenstored_domain.c +++ b/tools/xenstore/xenstored_domain.c @@ -249,7 +249,7 @@ static int domain_tree_remove_sub(const void *ctx, stru= ct connection *conn, domain->nbentry--; node->perms.p[0].id =3D priv_domid; node->acc.memory =3D 0; - domain_entry_inc(NULL, node); + domain_nbentry_inc(NULL, priv_domid); if (write_node_raw(NULL, &key, node, true)) { /* That's unfortunate. We only can try to continue. */ syslog(LOG_ERR, @@ -561,7 +561,7 @@ int acc_fix_domains(struct list_head *head, bool update) int cnt; =20 list_for_each_entry(cd, head, list) { - cnt =3D domain_entry_fix(cd->domid, cd->nbentry, update); + cnt =3D domain_nbentry_fix(cd->domid, cd->nbentry, update); if (!update) { if (cnt >=3D quota_nb_entry_per_domain) return ENOSPC; @@ -606,8 +606,8 @@ static struct changed_domain *acc_get_changed_domain(co= nst void *ctx, return cd; } =20 -int acc_add_dom_nbentry(const void *ctx, struct list_head *head, int val, - unsigned int domid) +static int acc_add_dom_nbentry(const void *ctx, struct list_head *head, in= t val, + unsigned int domid) { struct changed_domain *cd; =20 @@ -991,30 +991,6 @@ void domain_deinit(void) xenevtchn_unbind(xce_handle, virq_port); } =20 -int domain_entry_inc(struct connection *conn, struct node *node) -{ - struct domain *d; - unsigned int domid; - - if (!node->perms.p) - return 0; - - domid =3D node->perms.p[0].id; - - if (conn && conn->transaction) { - transaction_entry_inc(conn->transaction, domid); - } else { - d =3D (conn && domid =3D=3D conn->id && conn->domain) ? conn->domain - : find_or_alloc_existing_domain(domid); - if (d) - d->nbentry++; - else - return ENOMEM; - } - - return 0; -} - /* * Check whether a domain was created before or after a specific generation * count (used for testing whether a node permission is older than a domai= n). @@ -1082,62 +1058,76 @@ int domain_adjust_node_perms(struct node *node) return 0; } =20 -void domain_entry_dec(struct connection *conn, struct node *node) +static int domain_nbentry_add(struct connection *conn, unsigned int domid, + int add, bool no_dom_alloc) { struct domain *d; - unsigned int domid; - - if (!node->perms.p) - return; + struct list_head *head; + int ret; =20 - domid =3D node->perms.p ? node->perms.p[0].id : conn->id; + if (conn && domid =3D=3D conn->id && conn->domain) + d =3D conn->domain; + else if (no_dom_alloc) { + d =3D find_domain_struct(domid); + if (!d) { + errno =3D ENOENT; + corrupt(conn, "Missing domain %u\n", domid); + return -1; + } + } else { + d =3D find_or_alloc_existing_domain(domid); + if (!d) { + errno =3D ENOMEM; + return -1; + } + } =20 if (conn && conn->transaction) { - transaction_entry_dec(conn->transaction, domid); - } else { - d =3D (conn && domid =3D=3D conn->id && conn->domain) ? conn->domain - : find_domain_struct(domid); - if (d) { - d->nbentry--; - } else { - errno =3D ENOENT; - corrupt(conn, - "Node \"%s\" owned by non-existing domain %u\n", - node->name, domid); + head =3D transaction_get_changed_domains(conn->transaction); + ret =3D acc_add_dom_nbentry(conn->transaction, head, add, domid); + if (errno) { + fail_transaction(conn->transaction); + return -1; } + /* + * In a transaction when a node is being added/removed AND the + * same node has been added/removed outside the transaction in + * parallel, the resulting number of nodes will be wrong. This + * is no problem, as the transaction will fail due to the + * resulting conflict. + * In the node remove case the resulting number can be even + * negative, which should be avoided. + */ + return max(d->nbentry + ret, 0); } + + d->nbentry +=3D add; + + return d->nbentry; } =20 -int domain_entry_fix(unsigned int domid, int num, bool update) +int domain_nbentry_inc(struct connection *conn, unsigned int domid) { - struct domain *d; - int cnt; + return (domain_nbentry_add(conn, domid, 1, false) < 0) ? errno : 0; +} =20 - if (update) { - d =3D find_domain_struct(domid); - assert(d); - } else { - /* - * We are called first with update =3D=3D false in order to catch - * any error. So do a possible allocation and check for error - * only in this case, as in the case of update =3D=3D true nothing - * can go wrong anymore as the allocation already happened. - */ - d =3D find_or_alloc_existing_domain(domid); - if (!d) - return -1; - } +int domain_nbentry_dec(struct connection *conn, unsigned int domid) +{ + return (domain_nbentry_add(conn, domid, -1, true) < 0) ? errno : 0; +} =20 - cnt =3D d->nbentry + num; - assert(cnt >=3D 0); +int domain_nbentry_fix(unsigned int domid, int num, bool update) +{ + int ret; =20 - if (update) - d->nbentry =3D cnt; + ret =3D domain_nbentry_add(NULL, domid, update ? num : 0, update); + if (ret < 0 || update) + return ret; =20 - return domid_is_unprivileged(domid) ? cnt : 0; + return domid_is_unprivileged(domid) ? ret + num : 0; } =20 -int domain_entry(struct connection *conn) +int domain_nbentry(struct connection *conn) { return (domain_is_unprivileged(conn)) ? conn->domain->nbentry diff --git a/tools/xenstore/xenstored_domain.h b/tools/xenstore/xenstored_d= omain.h index 9e20d2b17d..1e402f2609 100644 --- a/tools/xenstore/xenstored_domain.h +++ b/tools/xenstore/xenstored_domain.h @@ -66,10 +66,10 @@ int domain_adjust_node_perms(struct node *node); int domain_alloc_permrefs(struct node_perms *perms); =20 /* Quota manipulation */ -int domain_entry_inc(struct connection *conn, struct node *); -void domain_entry_dec(struct connection *conn, struct node *); -int domain_entry_fix(unsigned int domid, int num, bool update); -int domain_entry(struct connection *conn); +int domain_nbentry_inc(struct connection *conn, unsigned int domid); +int domain_nbentry_dec(struct connection *conn, unsigned int domid); +int domain_nbentry_fix(unsigned int domid, int num, bool update); +int domain_nbentry(struct connection *conn); int domain_memory_add(unsigned int domid, int mem, bool no_quota_check); =20 /* @@ -99,8 +99,6 @@ void domain_outstanding_domid_dec(unsigned int domid); int domain_get_quota(const void *ctx, struct connection *conn, unsigned int domid); int acc_fix_domains(struct list_head *head, bool update); -int acc_add_dom_nbentry(const void *ctx, struct list_head *head, int val, - unsigned int domid); =20 /* Write rate limiting */ =20 diff --git a/tools/xenstore/xenstored_transaction.c b/tools/xenstore/xensto= red_transaction.c index c009c67989..82e5e66c18 100644 --- a/tools/xenstore/xenstored_transaction.c +++ b/tools/xenstore/xenstored_transaction.c @@ -548,20 +548,9 @@ int do_transaction_end(const void *ctx, struct connect= ion *conn, return 0; } =20 -void transaction_entry_inc(struct transaction *trans, unsigned int domid) +struct list_head *transaction_get_changed_domains(struct transaction *tran= s) { - if (!acc_add_dom_nbentry(trans, &trans->changed_domains, 1, domid)) { - /* Let the transaction fail. */ - trans->fail =3D true; - } -} - -void transaction_entry_dec(struct transaction *trans, unsigned int domid) -{ - if (!acc_add_dom_nbentry(trans, &trans->changed_domains, -1, domid)) { - /* Let the transaction fail. */ - trans->fail =3D true; - } + return &trans->changed_domains; } =20 void fail_transaction(struct transaction *trans) diff --git a/tools/xenstore/xenstored_transaction.h b/tools/xenstore/xensto= red_transaction.h index 3417303f94..b6f8cb7d0a 100644 --- a/tools/xenstore/xenstored_transaction.h +++ b/tools/xenstore/xenstored_transaction.h @@ -36,10 +36,6 @@ int do_transaction_end(const void *ctx, struct connectio= n *conn, =20 struct transaction *transaction_lookup(struct connection *conn, uint32_t i= d); =20 -/* inc/dec entry number local to trans while changing a node */ -void transaction_entry_inc(struct transaction *trans, unsigned int domid); -void transaction_entry_dec(struct transaction *trans, unsigned int domid); - /* This node was accessed. */ int __must_check access_node(struct connection *conn, struct node *node, enum node_access_type type, TDB_DATA *key); @@ -54,6 +50,9 @@ void transaction_prepend(struct connection *conn, const c= har *name, /* Mark the transaction as failed. This will prevent it to be committed. */ void fail_transaction(struct transaction *trans); =20 +/* Get the list head of the changed domains. */ +struct list_head *transaction_get_changed_domains(struct transaction *tran= s); + void conn_delete_all_transactions(struct connection *conn); int check_transactions(struct hashtable *hash); =20 --=20 2.35.3