diff --git a/src/backend/utils/mmgr/dsa.c b/src/backend/utils/mmgr/dsa.c
index ce9ede4c196..b7a089bc288 100644
--- a/src/backend/utils/mmgr/dsa.c
+++ b/src/backend/utils/mmgr/dsa.c
@@ -2131,6 +2131,7 @@ static dsa_segment_map *
 make_new_segment(dsa_area *area, size_t requested_pages)
 {
        dsa_segment_index new_index;
+       size_t          metadata_fixed_bytes;
        size_t          metadata_bytes;
        size_t          total_size;
        size_t          total_pages;
@@ -2180,9 +2181,11 @@ make_new_segment(dsa_area *area, size_t requested_pages)
                                         area->control->total_segment_size);

        total_pages = total_size / FPM_PAGE_SIZE;
-       metadata_bytes =
+       metadata_fixed_bytes =
                MAXALIGN(sizeof(dsa_segment_header)) +
-               MAXALIGN(sizeof(FreePageManager)) +
+               MAXALIGN(sizeof(FreePageManager));
+       metadata_bytes =
+               metadata_fixed_bytes +
                sizeof(dsa_pointer) * total_pages;

        /* Add padding up to next page boundary. */
@@ -2196,19 +2199,36 @@ make_new_segment(dsa_area *area, size_t requested_pages)
        /* See if that is enough... */
        if (requested_pages > usable_pages)
        {
+               size_t pagemap_entries;
+
                /*
                 * We'll make an odd-sized segment, working forward from the requested
                 * number of pages.
                 */
                usable_pages = requested_pages;
-               metadata_bytes =
-                       MAXALIGN(sizeof(dsa_segment_header)) +
-                       MAXALIGN(sizeof(FreePageManager)) +
-                       usable_pages * sizeof(dsa_pointer);
-
-               /* Add padding up to next page boundary. */
-               if (metadata_bytes % FPM_PAGE_SIZE != 0)
-                       metadata_bytes += FPM_PAGE_SIZE - (metadata_bytes % FPM_PAGE_SIZE);
+               pagemap_entries = usable_pages;
+
+               for (;;)
+               {
+                       size_t actual_pages;
+                       size_t metadata_pages;
+
+                       metadata_bytes =
+                               metadata_fixed_bytes +
+                               pagemap_entries * sizeof(dsa_pointer);
+
+                       /* Add padding up to next page boundary. */
+                       if (metadata_bytes % FPM_PAGE_SIZE != 0)
+                               metadata_bytes += FPM_PAGE_SIZE - (metadata_bytes % FPM_PAGE_SIZE);
+
+                       metadata_pages = metadata_bytes / FPM_PAGE_SIZE;
+                       actual_pages = metadata_pages + usable_pages;
+                       if (pagemap_entries >= actual_pages)
+                               break;
+
+                       pagemap_entries = actual_pages;
+               }
+
                total_size = metadata_bytes + usable_pages * FPM_PAGE_SIZE;

                /* Is that too large for dsa_pointer's addressing scheme? */
