I have attached v3 which rebases v2 on top of master.
v1 still applies cleanly.
Regards,
Lucas
From 9ac7b993a71c1459eb707b596adf9f9a4e722651 Mon Sep 17 00:00:00 2001
From: Lucas DRAESCHER <[email protected]>
Date: Tue, 17 Mar 2026 17:26:11 +0100
Subject: [PATCH v3] Release io_uring resources on shmem exit
io_uring_queue_init() allocates resources for each io_uring
instance, but pgaio_uring_shmem_init() never registers a
cleanup callback to free them.
Add a shmem_cleanup callback to IoMethodOps registered in
AioShmemInit().
Implement the shmem_cleanup for method_io_uring.c as
pgaio_uring_shmem_cleanup() which calls
io_uring_queue_exit().
---
src/backend/storage/aio/aio_init.c | 18 ++++++++++++++++++
src/backend/storage/aio/method_io_uring.c | 18 ++++++++++++++++++
src/include/storage/aio_internal.h | 6 ++++++
3 files changed, 42 insertions(+)
diff --git a/src/backend/storage/aio/aio_init.c b/src/backend/storage/aio/aio_init.c
index da30d792a88..0f3572d4dba 100644
--- a/src/backend/storage/aio/aio_init.c
+++ b/src/backend/storage/aio/aio_init.c
@@ -172,6 +172,20 @@ AioShmemRequest(void *arg)
pgaio_method_ops->shmem_callbacks.request_fn(pgaio_method_ops->shmem_callbacks.opaque_arg);
}
+/*
+ * Wrapper around pgaio_method_ops->shmem_cleanup to satisfy the
+ * on_shmem_exit() callback signature.
+ */
+static void
+pgaio_shmem_cleanup(int code, Datum arg)
+{
+ /*
+ * No null check needed here; AioShmemInit only registers this callback
+ * when shmem_cleanup is non-null.
+ */
+ pgaio_method_ops->shmem_cleanup();
+}
+
/*
* Initialize AIO shared memory during postmaster startup.
*/
@@ -225,6 +239,10 @@ AioShmemInit(void *arg)
if (pgaio_method_ops->shmem_callbacks.init_fn)
pgaio_method_ops->shmem_callbacks.init_fn(pgaio_method_ops->shmem_callbacks.opaque_arg);
+
+ /* Register callback to release any resources allocated above. */
+ if (pgaio_method_ops->shmem_cleanup)
+ on_shmem_exit(pgaio_shmem_cleanup, 0);
}
static void
diff --git a/src/backend/storage/aio/method_io_uring.c b/src/backend/storage/aio/method_io_uring.c
index c0f9fc9c303..09f36102920 100644
--- a/src/backend/storage/aio/method_io_uring.c
+++ b/src/backend/storage/aio/method_io_uring.c
@@ -51,6 +51,7 @@
/* Entry points for IoMethodOps. */
static void pgaio_uring_shmem_request(void *arg);
static void pgaio_uring_shmem_init(void *arg);
+static void pgaio_uring_shmem_cleanup(void);
static void pgaio_uring_init_backend(void);
static int pgaio_uring_submit(uint16 num_staged_ios, PgAioHandle **staged_ios);
static void pgaio_uring_wait_one(PgAioHandle *ioh, uint64 ref_generation);
@@ -72,6 +73,7 @@ const IoMethodOps pgaio_uring_ops = {
.shmem_callbacks.request_fn = pgaio_uring_shmem_request,
.shmem_callbacks.init_fn = pgaio_uring_shmem_init,
+ .shmem_cleanup = pgaio_uring_shmem_cleanup,
.init_backend = pgaio_uring_init_backend,
.submit = pgaio_uring_submit,
@@ -403,6 +405,22 @@ pgaio_uring_shmem_init(void *arg)
}
}
+static void
+pgaio_uring_shmem_cleanup(void)
+{
+ if (pgaio_uring_contexts != NULL)
+ {
+ int TotalProcs = pgaio_uring_procs();
+
+ elog(DEBUG1, "cleaning up %d io_uring processes", TotalProcs);
+
+ for (int i = 0; i < TotalProcs; i++)
+ io_uring_queue_exit(&pgaio_uring_contexts[i].io_uring_ring);
+
+ pgaio_uring_contexts = NULL;
+ }
+}
+
static void
pgaio_uring_init_backend(void)
{
diff --git a/src/include/storage/aio_internal.h b/src/include/storage/aio_internal.h
index 9ca4087aa7f..96a3f86ea97 100644
--- a/src/include/storage/aio_internal.h
+++ b/src/include/storage/aio_internal.h
@@ -272,6 +272,12 @@ typedef struct IoMethodOps
/* global initialization */
ShmemCallbacks shmem_callbacks;
+ /*
+ * Clean up shared memory resources before shutdown. Called during shmem
+ * exit. Optional.
+ */
+ void (*shmem_cleanup) (void);
+
/*
* Per-backend initialization. Optional.
*/
--
2.53.0