From 25282054756d9f2743cb6e4702b7de25828455ed Mon Sep 17 00:00:00 2001
From: Rahila Syed <rahilasyed.90@gmail.com>
Date: Tue, 14 Jan 2025 11:30:36 +0530
Subject: [PATCH] Prevent the error on creating a dsm segment from an interrupt
 handler.

If DSA or DSM segment is attached to or created while
a transaction's resource owner is being released, it
will throw an error. Check whether the resource owner is
being released before adding the segment to that
resource owner.
---
 src/backend/storage/ipc/dsm.c         | 25 +++++++++++++++++--------
 src/backend/utils/mmgr/dsa.c          | 10 ++++++++--
 src/backend/utils/resowner/resowner.c |  9 +++++++++
 src/include/utils/resowner.h          |  1 +
 4 files changed, 35 insertions(+), 10 deletions(-)

diff --git a/src/backend/storage/ipc/dsm.c b/src/backend/storage/ipc/dsm.c
index f92a52a00e..a62ecdd003 100644
--- a/src/backend/storage/ipc/dsm.c
+++ b/src/backend/storage/ipc/dsm.c
@@ -934,9 +934,16 @@ void
 dsm_unpin_mapping(dsm_segment *seg)
 {
 	Assert(seg->resowner == NULL);
-	ResourceOwnerEnlarge(CurrentResourceOwner);
-	seg->resowner = CurrentResourceOwner;
-	ResourceOwnerRememberDSM(seg->resowner, seg);
+
+	if (CurrentResourceOwner && !IsResourceOwnerReleasing(CurrentResourceOwner))
+	{
+		ResourceOwnerEnlarge(CurrentResourceOwner);
+		seg->resowner = CurrentResourceOwner;
+		ResourceOwnerRememberDSM(seg->resowner, seg);
+	}
+	else
+		/* Could not unpin */
+		seg->resowner = NULL;
 }
 
 /*
@@ -1202,9 +1209,6 @@ dsm_create_descriptor(void)
 {
 	dsm_segment *seg;
 
-	if (CurrentResourceOwner)
-		ResourceOwnerEnlarge(CurrentResourceOwner);
-
 	seg = MemoryContextAlloc(TopMemoryContext, sizeof(dsm_segment));
 	dlist_push_head(&dsm_segment_list, &seg->node);
 
@@ -1214,9 +1218,14 @@ dsm_create_descriptor(void)
 	seg->mapped_address = NULL;
 	seg->mapped_size = 0;
 
-	seg->resowner = CurrentResourceOwner;
-	if (CurrentResourceOwner)
+	if (CurrentResourceOwner && !IsResourceOwnerReleasing(CurrentResourceOwner))
+	{
+		ResourceOwnerEnlarge(CurrentResourceOwner);
+		seg->resowner = CurrentResourceOwner;
 		ResourceOwnerRememberDSM(CurrentResourceOwner, seg);
+	}
+	else
+		seg->resowner = NULL;
 
 	slist_init(&seg->on_detach);
 
diff --git a/src/backend/utils/mmgr/dsa.c b/src/backend/utils/mmgr/dsa.c
index 17d4f7a7a0..7b2c5a4015 100644
--- a/src/backend/utils/mmgr/dsa.c
+++ b/src/backend/utils/mmgr/dsa.c
@@ -1282,7 +1282,10 @@ create_internal(void *place, size_t size,
 	 */
 	area = palloc(sizeof(dsa_area));
 	area->control = control;
-	area->resowner = CurrentResourceOwner;
+	if (CurrentResourceOwner && !IsResourceOwnerReleasing(CurrentResourceOwner))
+		area->resowner = CurrentResourceOwner;
+	else
+		area->resowner = NULL;
 	memset(area->segment_maps, 0, sizeof(dsa_segment_map) * DSA_MAX_SEGMENTS);
 	area->high_segment_index = 0;
 	area->freed_segment_counter = 0;
@@ -1338,7 +1341,10 @@ attach_internal(void *place, dsm_segment *segment, dsa_handle handle)
 	/* Build the backend-local area object. */
 	area = palloc(sizeof(dsa_area));
 	area->control = control;
-	area->resowner = CurrentResourceOwner;
+	if (CurrentResourceOwner && !IsResourceOwnerReleasing(CurrentResourceOwner))
+		area->resowner = CurrentResourceOwner;
+	else
+		area->resowner = NULL;
 	memset(&area->segment_maps[0], 0,
 		   sizeof(dsa_segment_map) * DSA_MAX_SEGMENTS);
 	area->high_segment_index = 0;
diff --git a/src/backend/utils/resowner/resowner.c b/src/backend/utils/resowner/resowner.c
index ac5ca4a765..60752e455d 100644
--- a/src/backend/utils/resowner/resowner.c
+++ b/src/backend/utils/resowner/resowner.c
@@ -1082,3 +1082,12 @@ ResourceOwnerForgetLock(ResourceOwner owner, LOCALLOCK *locallock)
 	elog(ERROR, "lock reference %p is not owned by resource owner %s",
 		 locallock, owner->name);
 }
+
+/*
+ * Returns true if resource owner is being released
+ */
+bool
+IsResourceOwnerReleasing(ResourceOwner owner)
+{
+	return(owner->releasing);
+}
diff --git a/src/include/utils/resowner.h b/src/include/utils/resowner.h
index e8d452ca7e..dea97b9c0d 100644
--- a/src/include/utils/resowner.h
+++ b/src/include/utils/resowner.h
@@ -163,5 +163,6 @@ extern void ReleaseAuxProcessResources(bool isCommit);
 struct LOCALLOCK;
 extern void ResourceOwnerRememberLock(ResourceOwner owner, struct LOCALLOCK *locallock);
 extern void ResourceOwnerForgetLock(ResourceOwner owner, struct LOCALLOCK *locallock);
+extern bool IsResourceOwnerReleasing(ResourceOwner owner);
 
 #endif							/* RESOWNER_H */
-- 
2.34.1

