From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from gate001.proxmox.com (gate001.proxmox.com [45.144.208.40]) by lore.proxmox.com (Postfix) with ESMTPS id 565981FF0C1 for ; Fri, 18 Sep 2026 16:42:23 +0200 (CEST) Received: from gate001.proxmox.com (localhost.localdomain [127.0.0.1]) by gate001.proxmox.com (Proxmox) with ESMTP id 7E0A4215C8; Fri, 18 Sep 2026 16:42:11 +0200 (CEST) From: Hannes Laimer To: pve-devel@lists.proxmox.com Subject: [PATCH pve-cluster 04/10] pmxcfs: memdb: add change notification hook Date: Fri, 18 Sep 2026 16:41:46 +0200 Message-ID: <20260918144152.575163-5-h.laimer@proxmox.com> X-Mailer: git-send-email 2.47.3 In-Reply-To: <20260918144152.575163-1-h.laimer@proxmox.com> References: <20260918144152.575163-1-h.laimer@proxmox.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Bm-Milter-Handled: 55990f41-d878-4baa-be0a-ee34c49e34d2 X-Bm-Transport-Timestamp: 1789742527230 X-SPAM-LEVEL: Spam detection results: 0 AWL 0.498 Adjusted score from AWL reputation of From: address DMARC_MISSING 0.1 Missing DMARC policy KAM_DMARC_STATUS 0.01 Test Rule for DKIM or SPF Failure with Strict Alignment (newer systems) RCVD_IN_DNSWL_MED -2.3 Sender listed at https://www.dnswl.org/, medium trust RCVD_IN_MSPIKE_H2 0.001 Average reputation (+2) SPF_HELO_NONE 0.001 SPF: HELO does not publish an SPF Record SPF_PASS -0.001 SPF: sender matches SPF record Message-ID-Hash: QFY72SJMR7ASEYNOUGBNOXSM3H635DZK X-Message-ID-Hash: QFY72SJMR7ASEYNOUGBNOXSM3H635DZK X-MailFrom: h.laimer@proxmox.com X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; emergency; member-moderation; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.10 Precedence: list List-Id: Proxmox VE development discussion List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Every mutation of the cluster file system, local or delivered from another node, passes through memdb, which makes it the one place where a change notification can be raised for all of them. Add a hook the daemon installs at startup and call it as the last step of a mutation, after the change is persisted and the guest list updated. An observer is then told only about changes that survived, and whatever it reads next, the guest list included, already reflects them. A node that takes the whole state from the cluster during a synchronization raises a resync in place of the mutations it never saw, since its state is replaced as a whole then. The hook stays a plain function pointer rather than a direct call into the notifier, since memdb is part of the static C library the database tools and the unit tests also link, which must not drag the socket server along. The event types come straight from the notifier's header, so the values cross the boundary without translation. Signed-off-by: Hannes Laimer --- src/pmxcfs/Makefile | 1 + src/pmxcfs/database.c | 2 ++ src/pmxcfs/memdb.c | 24 ++++++++++++++++++++++++ src/pmxcfs/memdb.h | 11 +++++++++++ 4 files changed, 38 insertions(+) diff --git a/src/pmxcfs/Makefile b/src/pmxcfs/Makefile index 547f258..90bc6a5 100644 --- a/src/pmxcfs/Makefile +++ b/src/pmxcfs/Makefile @@ -8,6 +8,7 @@ CFLAGS += -Wpedantic CFLAGS += -g -O2 CFLAGS += -I. CFLAGS += $(shell pkg-config --cflags $(DEPENDENCIES)) +CFLAGS += -I../rust/pmxcfs-ffi/include LDFLAGS += -Wl,-z,relro $(shell pkg-config --libs $(DEPENDENCIES)) diff --git a/src/pmxcfs/database.c b/src/pmxcfs/database.c index 4ee2389..486fe84 100644 --- a/src/pmxcfs/database.c +++ b/src/pmxcfs/database.c @@ -611,6 +611,8 @@ gboolean bdb_backend_commit_update( memdb_update_locks(memdb); + memdb_notify(PMXCFS_NOTIFY_RESYNC, memdb->root->version, NULL, NULL); + result = TRUE; ret: diff --git a/src/pmxcfs/memdb.c b/src/pmxcfs/memdb.c index 77d7652..a6a2a62 100644 --- a/src/pmxcfs/memdb.c +++ b/src/pmxcfs/memdb.c @@ -41,6 +41,18 @@ #define CFS_LOCK_TIMEOUT (60 * 2) +// Set once before any other thread runs, so no locking is needed here. +// The hook runs under memdb->mutex and must not call back into memdb. +static memdb_notify_fn notify_hook; + +void memdb_set_notify_hook(memdb_notify_fn hook) { notify_hook = hook; } + +void memdb_notify(enum pmxcfs_notify_type type, uint64_t seq, const char *path, const char *to) { + if (notify_hook) { + notify_hook(type, seq, path, to); + } +} + memdb_tree_entry_t *memdb_tree_entry_new(const char *name) { g_return_val_if_fail(name != NULL, NULL); @@ -621,6 +633,8 @@ int memdb_mkdir(memdb_t *memdb, const char *path, guint32 writer, guint32 mtime) } } + memdb_notify(PMXCFS_NOTIFY_MKDIR, memdb->root->version, path, NULL); + ret = 0; ret: @@ -824,6 +838,10 @@ static int memdb_pwrite( vmlist_register_vm(vmtype, vmid, nodename); } + memdb_notify( + old ? PMXCFS_NOTIFY_WRITE : PMXCFS_NOTIFY_CREATE, memdb->root->version, path, NULL + ); + ret = count; ret: @@ -929,6 +947,8 @@ int memdb_mtime(memdb_t *memdb, const char *path, guint32 writer, guint32 mtime) } } + memdb_notify(PMXCFS_NOTIFY_MTIME, memdb->root->version, path, NULL); + ret = 0; ret: @@ -1191,6 +1211,8 @@ int memdb_rename(memdb_t *memdb, const char *from, const char *to, guint32 write /* directories are alwayse empty (see unlink_tree_entry) */ } + memdb_notify(PMXCFS_NOTIFY_RENAME, memdb->root->version, from, to); + ret = 0; ret: @@ -1264,6 +1286,8 @@ int memdb_delete(memdb_t *memdb, const char *path, guint32 writer, guint32 mtime vmlist_delete_vm(vmid); } + memdb_notify(PMXCFS_NOTIFY_DELETE, memdb->root->version, path, NULL); + ret = 0; ret: diff --git a/src/pmxcfs/memdb.h b/src/pmxcfs/memdb.h index bca8967..f7dff5b 100644 --- a/src/pmxcfs/memdb.h +++ b/src/pmxcfs/memdb.h @@ -22,11 +22,14 @@ #define _PVE_MEMDB_H_ #include +#include #include #include #include +#include "pmxcfs-notify.h" + #define MEMDB_MAX_FILE_SIZE (1024 * 1024) // 1 MiB #define MEMDB_MAX_FSSIZE (128 * 1024 * 1024) // 128 MiB #define MEMDB_MAX_INODES (256 * 1024) // 256k @@ -83,6 +86,10 @@ typedef struct { db_backend_t *bdb; } memdb_t; +typedef void (*memdb_notify_fn)( + enum pmxcfs_notify_type type, uint64_t seq, const char *path, const char *to +); + memdb_t *memdb_open(const char *dbfilename); void memdb_close(memdb_t *memdb); @@ -138,6 +145,10 @@ memdb_tree_entry_t *memdb_getattr(memdb_t *memdb, const char *path); int memdb_rename(memdb_t *memdb, const char *from, const char *to, guint32 writer, guint32 mtime); +void memdb_set_notify_hook(memdb_notify_fn hook); + +void memdb_notify(enum pmxcfs_notify_type type, uint64_t seq, const char *path, const char *to); + void memdb_dump(memdb_t *memdb); gboolean -- 2.47.3