On 11/26/18 10:13 PM, David Steele wrote:
> Hackers,
> 
> I propose we remove the deprecated exclusive backup mode of
> pg_start_backup()/pg_stop_backup() for Postgres 12.
> 
> The exclusive backup mode has a serious known issue.  If Postgres
> terminates ungracefully during a backup (due to hardware, kernel,
> Postgres issues, etc.) then Postgres may refuse to restart.
> 
> The reason is that the backup_label file will usually reference a
> checkpoint LSN that is older than the WAL available in pg_wal.  Postgres
> does emit a helpful error message while PANIC'ing but that's cold
> comfort to an admin who must manually intervene to get their cluster
> operational again.
> 
> The deprecated exclusive mode promises to make a difficult problem
> simple but doesn't live up to that promise. That's why it was replaced
> externally in 9.6 and why pg_basebackup has not used exclusive backups
> since it was introduced in 9.2.
> 
> Non-exclusive backups have been available since 9.6 and several
> third-party solutions support this mode, in addition to pg_basebackup.
> 
> The recently introduced recovery changes will break current automated
> solutions so this seems like a good opportunity to make improvements on
> the backup side as well.
> 
> I'll submit a patch for the 2019-01 commitfest.

Attached is the patch.

I was a bit surprised by how much code went away.  There was a lot of
code dedicated to making sure that backup_label got renamed on shutdown,
that there was not an exclusive backup running, etc.

There were no tests for exclusive backup so the test changes were minimal.

I did have to replace one "hot backup" in
010_logical_decoding_timelines.pl.  I'm not sure why the backup was
being done this way, or why the standby needs a copy of pg_replslot
(which is not copied by pg_basebackup).  It might be worth looking at
but it seemed out of scope for this patch.

Regards,
-- 
-David
da...@pgmasters.net
diff --git a/doc/src/sgml/backup.sgml b/doc/src/sgml/backup.sgml
index a73fd4d044..6f45f2e177 100644
--- a/doc/src/sgml/backup.sgml
+++ b/doc/src/sgml/backup.sgml
@@ -819,15 +819,8 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 
&& cp pg_wal/0
     sequence, and that the success of a step is verified before
     proceeding to the next step.
    </para>
-   <para>
-    Low level base backups can be made in a non-exclusive or an exclusive
-    way. The non-exclusive method is recommended and the exclusive one is
-    deprecated and will eventually be removed.
-   </para>
-   <sect3 id="backup-lowlevel-base-backup-nonexclusive">
-    <title>Making a non-exclusive low level backup</title>
     <para>
-     A non-exclusive low level backup is one that allows other
+     A low level backup allows other
      concurrent backups to be running (both those started using
      the same backup API and those started using
      <xref linkend="app-pgbasebackup"/>).
@@ -845,7 +838,7 @@ test ! -f /mnt/server/archivedir/00000001000000A900000065 
&amp;&amp; cp pg_wal/0
      rights to run pg_start_backup (superuser, or a user who has been granted
      EXECUTE on the function) and issue the command:
 <programlisting>
-SELECT pg_start_backup('label', false, false);
+SELECT pg_start_backup('label', false);
 </programlisting>
      where <literal>label</literal> is any string you want to use to uniquely
      identify this backup operation. The connection
@@ -866,10 +859,6 @@ SELECT pg_start_backup('label', false, false);
      issue an immediate checkpoint using as much I/O as available.
     </para>
 
-    <para>
-     The third parameter being <literal>false</literal> tells
-     <function>pg_start_backup</function> to initiate a non-exclusive base 
backup.
-    </para>
    </listitem>
    <listitem>
     <para>
@@ -887,7 +876,7 @@ SELECT pg_start_backup('label', false, false);
     <para>
      In the same connection as before, issue the command:
 <programlisting>
-SELECT * FROM pg_stop_backup(false, true);
+SELECT * FROM pg_stop_backup(true);
 </programlisting>
      This terminates backup mode. On a primary, it also performs an automatic
      switch to the next WAL segment.  On a standby, it is not possible to
@@ -945,116 +934,6 @@ SELECT * FROM pg_stop_backup(false, true);
    </listitem>
   </orderedlist>
     </para>
-   </sect3>
-   <sect3 id="backup-lowlevel-base-backup-exclusive">
-    <title>Making an exclusive low level backup</title>
-    <para>
-     The process for an exclusive backup is mostly the same as for a
-     non-exclusive one, but it differs in a few key steps. This type of backup
-     can only be taken on a primary and does not allow concurrent backups.
-     Prior to <productname>PostgreSQL</productname> 9.6, this
-     was the only low-level method available, but it is now recommended that
-     all users upgrade their scripts to use non-exclusive backups if possible.
-    </para>
-    <para>
-  <orderedlist>
-   <listitem>
-    <para>
-     Ensure that WAL archiving is enabled and working.
-    </para>
-   </listitem>
-   <listitem>
-    <para>
-     Connect to the server (it does not matter which database) as a user with
-     rights to run pg_start_backup (superuser, or a user who has been granted
-     EXECUTE on the function) and issue the command:
-<programlisting>
-SELECT pg_start_backup('label');
-</programlisting>
-     where <literal>label</literal> is any string you want to use to uniquely
-     identify this backup operation.
-     <function>pg_start_backup</function> creates a <firstterm>backup 
label</firstterm> file,
-     called <filename>backup_label</filename>, in the cluster directory with
-     information about your backup, including the start time and label string.
-     The function also creates a <firstterm>tablespace map</firstterm> file,
-     called <filename>tablespace_map</filename>, in the cluster directory with
-     information about tablespace symbolic links in 
<filename>pg_tblspc/</filename> if
-     one or more such link is present.  Both files are critical to the
-     integrity of the backup, should you need to restore from it.
-    </para>
-
-    <para>
-     By default, <function>pg_start_backup</function> can take a long time to 
finish.
-     This is because it performs a checkpoint, and the I/O
-     required for the checkpoint will be spread out over a significant
-     period of time, by default half your inter-checkpoint interval
-     (see the configuration parameter
-     <xref linkend="guc-checkpoint-completion-target"/>).  This is
-     usually what you want, because it minimizes the impact on query
-     processing.  If you want to start the backup as soon as
-     possible, use:
-<programlisting>
-SELECT pg_start_backup('label', true);
-</programlisting>
-     This forces the checkpoint to be done as quickly as possible.
-    </para>
-   </listitem>
-   <listitem>
-    <para>
-     Perform the backup, using any convenient file-system-backup tool
-     such as <application>tar</application> or <application>cpio</application> 
(not
-     <application>pg_dump</application> or
-     <application>pg_dumpall</application>).  It is neither
-     necessary nor desirable to stop normal operation of the database
-     while you do this. See
-     <xref linkend="backup-lowlevel-base-backup-data"/> for things to
-     consider during this backup.
-    </para>
-    <para>
-      Note that if the server crashes during the backup it may not be
-      possible to restart until the <literal>backup_label</literal> file has 
been
-      manually deleted from the <envar>PGDATA</envar> directory.
-    </para>
-   </listitem>
-   <listitem>
-    <para>
-     Again connect to the database as a user with rights to run
-     pg_stop_backup (superuser, or a user who has been granted EXECUTE on
-     the function), and issue the command:
-<programlisting>
-SELECT pg_stop_backup();
-</programlisting>
-     This function terminates backup mode and
-     performs an automatic switch to the next WAL segment. The reason for the
-     switch is to arrange for the last WAL segment written during the backup
-     interval to be ready to archive.
-    </para>
-   </listitem>
-   <listitem>
-    <para>
-     Once the WAL segment files active during the backup are archived, you are
-     done.  The file identified by <function>pg_stop_backup</function>'s 
result is
-     the last segment that is required to form a complete set of backup files.
-     If <varname>archive_mode</varname> is enabled,
-     <function>pg_stop_backup</function> does not return until the last 
segment has
-     been archived.
-     Archiving of these files happens automatically since you have
-     already configured <varname>archive_command</varname>. In most cases this
-     happens quickly, but you are advised to monitor your archive
-     system to ensure there are no delays.
-     If the archive process has fallen behind
-     because of failures of the archive command, it will keep retrying
-     until the archive succeeds and the backup is complete.
-     If you wish to place a time limit on the execution of
-     <function>pg_stop_backup</function>, set an appropriate
-     <varname>statement_timeout</varname> value, but make note that if
-     <function>pg_stop_backup</function> terminates because of this your backup
-     may not be valid.
-    </para>
-   </listitem>
-  </orderedlist>
-    </para>
-   </sect3>
    <sect3 id="backup-lowlevel-base-backup-data">
    <title>Backing up the data directory</title>
    <para>
diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index b3336ea9be..ae7722bb12 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -18945,38 +18945,17 @@ SELECT set_config('log_statement_stats', 'off', 
false);
       </row>
       <row>
        <entry>
-        <literal><function>pg_start_backup(<parameter>label</parameter> 
<type>text</type> <optional>, <parameter>fast</parameter> <type>boolean</type> 
<optional>, <parameter>exclusive</parameter> <type>boolean</type> 
</optional></optional>)</function></literal>
+        <literal><function>pg_start_backup(<parameter>label</parameter> 
<type>text</type> <optional>, <parameter>fast</parameter> <type>boolean</type> 
</optional>)</function></literal>
         </entry>
        <entry><type>pg_lsn</type></entry>
        <entry>Prepare for performing on-line backup (restricted to superusers 
by default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
-        <literal><function>pg_stop_backup()</function></literal>
-        </entry>
-       <entry><type>pg_lsn</type></entry>
-       <entry>Finish performing exclusive on-line backup (restricted to 
superusers by default, but other users can be granted EXECUTE to run the 
function)</entry>
-      </row>
-      <row>
-       <entry>
-        <literal><function>pg_stop_backup(<parameter>exclusive</parameter> 
<type>boolean</type> <optional>, <parameter>wait_for_archive</parameter> 
<type>boolean</type> </optional>)</function></literal>
+        <literal><function>pg_stop_backup(<optional> 
<parameter>wait_for_archive</parameter> <type>boolean</type> 
</optional>)</function></literal>
         </entry>
        <entry><type>setof record</type></entry>
-       <entry>Finish performing exclusive or non-exclusive on-line backup 
(restricted to superusers by default, but other users can be granted EXECUTE to 
run the function)</entry>
-      </row>
-      <row>
-       <entry>
-        <literal><function>pg_is_in_backup()</function></literal>
-        </entry>
-       <entry><type>bool</type></entry>
-       <entry>True if an on-line exclusive backup is still in progress.</entry>
-      </row>
-      <row>
-       <entry>
-        <literal><function>pg_backup_start_time()</function></literal>
-        </entry>
-       <entry><type>timestamp with time zone</type></entry>
-       <entry>Get start time of an on-line exclusive backup in 
progress.</entry>
+       <entry>Finish performing on-line backup (restricted to superusers by 
default, but other users can be granted EXECUTE to run the function)</entry>
       </row>
       <row>
        <entry>
@@ -19013,16 +18992,9 @@ SELECT set_config('log_statement_stats', 'off', false);
    <para>
     <function>pg_start_backup</function> accepts an arbitrary user-defined 
label for
     the backup.  (Typically this would be the name under which the backup dump
-    file will be stored.) When used in exclusive mode, the function writes a
-    backup label file (<filename>backup_label</filename>) and, if there are 
any links
-    in the <filename>pg_tblspc/</filename> directory, a tablespace map file
-    (<filename>tablespace_map</filename>) into the database cluster's data 
directory,
-    performs a checkpoint, and then returns the backup's starting write-ahead
-    log location as text.  The user can ignore this result value, but it is
-    provided in case it is useful. When used in non-exclusive mode, the
-    contents of these files are instead returned by the
-    <function>pg_stop_backup</function> function, and should be written to the 
backup
-    by the caller.
+    file will be stored.) It returns the backup's starting write-ahead
+    log location as a <type>pg_lsn</type> which can be ignored by the user, 
but is
+    provided in case it is useful.
 
 <programlisting>
 postgres=# select pg_start_backup('label_goes_here');
@@ -19038,12 +19010,10 @@ postgres=# select pg_start_backup('label_goes_here');
    </para>
 
    <para>
-    In an exclusive backup, <function>pg_stop_backup</function> removes the 
label file
-    and, if it exists, the <filename>tablespace_map</filename> file created by
-    <function>pg_start_backup</function>. In a non-exclusive backup, the 
contents of
-    the <filename>backup_label</filename> and 
<filename>tablespace_map</filename> are returned
-    in the result of the function, and should be written to files in the
-    backup (and not in the data directory).  There is an optional second
+    The contents of the <filename>backup_label</filename> and
+    <filename>tablespace_map</filename> are returned in the result of
+    <function>pg_stop_backup</function>, and should be written to files in the
+    backup (and not in the data directory).  There is an optional
     parameter of type <type>boolean</type>.  If false, the 
<function>pg_stop_backup</function>
     will return immediately after the backup is completed without waiting for
     WAL to be archived.  This behavior is only useful for backup
diff --git a/src/backend/access/transam/xlog.c 
b/src/backend/access/transam/xlog.c
index c80b14ed97..5807616289 100644
--- a/src/backend/access/transam/xlog.c
+++ b/src/backend/access/transam/xlog.c
@@ -493,29 +493,6 @@ typedef union WALInsertLockPadded
        char            pad[PG_CACHE_LINE_SIZE];
 } WALInsertLockPadded;
 
-/*
- * State of an exclusive backup, necessary to control concurrent activities
- * across sessions when working on exclusive backups.
- *
- * EXCLUSIVE_BACKUP_NONE means that there is no exclusive backup actually
- * running, to be more precise pg_start_backup() is not being executed for
- * an exclusive backup and there is no exclusive backup in progress.
- * EXCLUSIVE_BACKUP_STARTING means that pg_start_backup() is starting an
- * exclusive backup.
- * EXCLUSIVE_BACKUP_IN_PROGRESS means that pg_start_backup() has finished
- * running and an exclusive backup is in progress. pg_stop_backup() is
- * needed to finish it.
- * EXCLUSIVE_BACKUP_STOPPING means that pg_stop_backup() is stopping an
- * exclusive backup.
- */
-typedef enum ExclusiveBackupState
-{
-       EXCLUSIVE_BACKUP_NONE = 0,
-       EXCLUSIVE_BACKUP_STARTING,
-       EXCLUSIVE_BACKUP_IN_PROGRESS,
-       EXCLUSIVE_BACKUP_STOPPING
-} ExclusiveBackupState;
-
 /*
  * Session status of running backup, used for sanity checks in SQL-callable
  * functions to start and stop backups.
@@ -563,15 +540,12 @@ typedef struct XLogCtlInsert
        bool            fullPageWrites;
 
        /*
-        * exclusiveBackupState indicates the state of an exclusive backup (see
-        * comments of ExclusiveBackupState for more details). 
nonExclusiveBackups
-        * is a counter indicating the number of streaming base backups 
currently
-        * in progress. forcePageWrites is set to true when either of these is
-        * non-zero. lastBackupStart is the latest checkpoint redo location used
-        * as a starting point for an online backup.
+        * runningBackups is a counter indicating the number of backups 
currently in
+        * progress. forcePageWrites is set to true when either of these is
+        * non-zero. lastBackupStart is the latest checkpoint redo location 
used as
+        * a starting point for an online backup.
         */
-       ExclusiveBackupState exclusiveBackupState;
-       int                     nonExclusiveBackups;
+       int                     runningBackups;
        XLogRecPtr      lastBackupStart;
 
        /*
@@ -916,7 +890,6 @@ static void xlog_outrec(StringInfo buf, XLogReaderState 
*record);
 #endif
 static void xlog_outdesc(StringInfo buf, XLogReaderState *record);
 static void pg_start_backup_callback(int code, Datum arg);
-static void pg_stop_backup_callback(int code, Datum arg);
 static bool read_backup_label(XLogRecPtr *checkPointLoc,
                                  bool *backupEndRequired, bool 
*backupFromStandby);
 static bool read_tablespace_map(List **tablespaces);
@@ -9208,7 +9181,7 @@ CreateRestartPoint(int flags)
                 * Ensure minRecoveryPoint is past the checkpoint record.  
Normally,
                 * this will have happened already while writing out dirty 
buffers,
                 * but not necessarily - e.g. because no buffers were dirtied.  
We do
-                * this because a non-exclusive base backup uses 
minRecoveryPoint to
+                * this because a backup performed in recovery uses 
minRecoveryPoint to
                 * determine which WAL files must be included in the backup, 
and the
                 * file (or files) containing the checkpoint record must be 
included,
                 * at a minimum. Note that for an ordinary restart of recovery 
there's
@@ -10165,36 +10138,25 @@ XLogFileNameP(TimeLineID tli, XLogSegNo segno)
 /*
  * do_pg_start_backup is the workhorse of the user-visible pg_start_backup()
  * function. It creates the necessary starting checkpoint and constructs the
- * backup label file.
- *
- * There are two kind of backups: exclusive and non-exclusive. An exclusive
- * backup is started with pg_start_backup(), and there can be only one active
- * at a time. The backup and tablespace map files of an exclusive backup are
- * written to $PGDATA/backup_label and $PGDATA/tablespace_map, and they are
- * removed by pg_stop_backup().
- *
- * A non-exclusive backup is used for the streaming base backups (see
- * src/backend/replication/basebackup.c). The difference to exclusive backups
- * is that the backup label and tablespace map files are not written to disk.
- * Instead, their would-be contents are returned in *labelfile and 
*tblspcmapfile,
- * and the caller is responsible for including them in the backup archive as
- * 'backup_label' and 'tablespace_map'. There can be many non-exclusive backups
- * active at the same time, and they don't conflict with an exclusive backup
- * either.
+ * backup label and tablespace map.
+ *
+ * The backup label and tablespace map contents are returned in *labelfile and
+ * *tblspcmapfile, and the caller is responsible for including them in the
+ * backup archive as 'backup_label' and 'tablespace_map'. There can be many
+ * backups active at the same time.
  *
  * tblspcmapfile is required mainly for tar format in windows as native windows
  * utilities are not able to create symlinks while extracting files from tar.
  * However for consistency, the same is used for all platforms.
  *
- * needtblspcmapfile is true for the cases (exclusive backup and for
- * non-exclusive backup only when tar format is used for taking backup)
- * when backup needs to generate tablespace_map file, it is used to
- * embed escape character before newline character in tablespace path.
+ * needtblspcmapfile is true for the cases (only when tar format is used for
+ * taking backup) when backup needs to generate tablespace_map file, it is used
+ * to embed escape character before newline character in tablespace path.
  *
  * Returns the minimum WAL location that must be present to restore from this
  * backup, and the corresponding timeline ID in *starttli_p.
  *
- * Every successfully started non-exclusive backup must be stopped by calling
+ * Every successfully started backup must be stopped by calling
  * do_pg_stop_backup() or do_pg_abort_backup().
  *
  * It is the responsibility of the caller of this function to verify the
@@ -10206,7 +10168,6 @@ do_pg_start_backup(const char *backupidstr, bool fast, 
TimeLineID *starttli_p,
                                   StringInfo tblspcmapfile, bool infotbssize,
                                   bool needtblspcmapfile)
 {
-       bool            exclusive = (labelfile == NULL);
        bool            backup_started_in_recovery = false;
        XLogRecPtr      checkpointloc;
        XLogRecPtr      startpoint;
@@ -10215,20 +10176,9 @@ do_pg_start_backup(const char *backupidstr, bool fast, 
TimeLineID *starttli_p,
        char            strfbuf[128];
        char            xlogfilename[MAXFNAMELEN];
        XLogSegNo       _logSegNo;
-       struct stat stat_buf;
-       FILE       *fp;
 
        backup_started_in_recovery = RecoveryInProgress();
 
-       /*
-        * Currently only non-exclusive backup can be taken during recovery.
-        */
-       if (backup_started_in_recovery && exclusive)
-               ereport(ERROR,
-                               
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("recovery is in progress"),
-                                errhint("WAL control functions cannot be 
executed during recovery.")));
-
        /*
         * During recovery, we don't need to check WAL level. Because, if WAL
         * level is not sufficient, it's impossible to get here during recovery.
@@ -10267,30 +10217,12 @@ do_pg_start_backup(const char *backupidstr, bool 
fast, TimeLineID *starttli_p,
         * XLogInsertRecord().
         */
        WALInsertLockAcquireExclusive();
-       if (exclusive)
-       {
-               /*
-                * At first, mark that we're now starting an exclusive backup, 
to
-                * ensure that there are no other sessions currently running
-                * pg_start_backup() or pg_stop_backup().
-                */
-               if (XLogCtl->Insert.exclusiveBackupState != 
EXCLUSIVE_BACKUP_NONE)
-               {
-                       WALInsertLockRelease();
-                       ereport(ERROR,
-                                       
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                        errmsg("a backup is already in 
progress"),
-                                        errhint("Run pg_stop_backup() and try 
again.")));
-               }
-               XLogCtl->Insert.exclusiveBackupState = 
EXCLUSIVE_BACKUP_STARTING;
-       }
-       else
-               XLogCtl->Insert.nonExclusiveBackups++;
+       XLogCtl->Insert.runningBackups++;
        XLogCtl->Insert.forcePageWrites = true;
        WALInsertLockRelease();
 
        /* Ensure we release forcePageWrites if fail below */
-       PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 
BoolGetDatum(exclusive));
+       PG_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0);
        {
                bool            gotUniqueStartpoint = false;
                DIR                *tblspcdir;
@@ -10417,11 +10349,8 @@ do_pg_start_backup(const char *backupidstr, bool fast, 
TimeLineID *starttli_p,
                XLogFileName(xlogfilename, starttli, _logSegNo, 
wal_segment_size);
 
                /*
-                * Construct tablespace_map file
+                * Construct tablespace_map
                 */
-               if (exclusive)
-                       tblspcmapfile = makeStringInfo();
-
                datadirpathlen = strlen(DataDir);
 
                /* Collect information about all tablespaces */
@@ -10511,11 +10440,8 @@ do_pg_start_backup(const char *backupidstr, bool fast, 
TimeLineID *starttli_p,
                FreeDir(tblspcdir);
 
                /*
-                * Construct backup label file
+                * Construct backup_label
                 */
-               if (exclusive)
-                       labelfile = makeStringInfo();
-
                /* Use the log timezone here, not the session timezone */
                stamp_time = (pg_time_t) time(NULL);
                pg_strftime(strfbuf, sizeof(strfbuf),
@@ -10525,122 +10451,19 @@ do_pg_start_backup(const char *backupidstr, bool 
fast, TimeLineID *starttli_p,
                                                 (uint32) (startpoint >> 32), 
(uint32) startpoint, xlogfilename);
                appendStringInfo(labelfile, "CHECKPOINT LOCATION: %X/%X\n",
                                                 (uint32) (checkpointloc >> 
32), (uint32) checkpointloc);
-               appendStringInfo(labelfile, "BACKUP METHOD: %s\n",
-                                                exclusive ? "pg_start_backup" 
: "streamed");
+               appendStringInfo(labelfile, "BACKUP METHOD: streamed\n");
                appendStringInfo(labelfile, "BACKUP FROM: %s\n",
                                                 backup_started_in_recovery ? 
"standby" : "master");
                appendStringInfo(labelfile, "START TIME: %s\n", strfbuf);
                appendStringInfo(labelfile, "LABEL: %s\n", backupidstr);
                appendStringInfo(labelfile, "START TIMELINE: %u\n", starttli);
-
-               /*
-                * Okay, write the file, or return its contents to caller.
-                */
-               if (exclusive)
-               {
-                       /*
-                        * Check for existing backup label --- implies a backup 
is already
-                        * running.  (XXX given that we checked 
exclusiveBackupState
-                        * above, maybe it would be OK to just unlink any such 
label
-                        * file?)
-                        */
-                       if (stat(BACKUP_LABEL_FILE, &stat_buf) != 0)
-                       {
-                               if (errno != ENOENT)
-                                       ereport(ERROR,
-                                                       
(errcode_for_file_access(),
-                                                        errmsg("could not stat 
file \"%s\": %m",
-                                                                       
BACKUP_LABEL_FILE)));
-                       }
-                       else
-                               ereport(ERROR,
-                                               
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                                errmsg("a backup is already in 
progress"),
-                                                errhint("If you're sure there 
is no backup in progress, remove file \"%s\" and try again.",
-                                                                
BACKUP_LABEL_FILE)));
-
-                       fp = AllocateFile(BACKUP_LABEL_FILE, "w");
-
-                       if (!fp)
-                               ereport(ERROR,
-                                               (errcode_for_file_access(),
-                                                errmsg("could not create file 
\"%s\": %m",
-                                                               
BACKUP_LABEL_FILE)));
-                       if (fwrite(labelfile->data, labelfile->len, 1, fp) != 1 
||
-                               fflush(fp) != 0 ||
-                               pg_fsync(fileno(fp)) != 0 ||
-                               ferror(fp) ||
-                               FreeFile(fp))
-                               ereport(ERROR,
-                                               (errcode_for_file_access(),
-                                                errmsg("could not write file 
\"%s\": %m",
-                                                               
BACKUP_LABEL_FILE)));
-                       /* Allocated locally for exclusive backups, so free 
separately */
-                       pfree(labelfile->data);
-                       pfree(labelfile);
-
-                       /* Write backup tablespace_map file. */
-                       if (tblspcmapfile->len > 0)
-                       {
-                               if (stat(TABLESPACE_MAP, &stat_buf) != 0)
-                               {
-                                       if (errno != ENOENT)
-                                               ereport(ERROR,
-                                                               
(errcode_for_file_access(),
-                                                                errmsg("could 
not stat file \"%s\": %m",
-                                                                               
TABLESPACE_MAP)));
-                               }
-                               else
-                                       ereport(ERROR,
-                                                       
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                                        errmsg("a backup is 
already in progress"),
-                                                        errhint("If you're 
sure there is no backup in progress, remove file \"%s\" and try again.",
-                                                                        
TABLESPACE_MAP)));
-
-                               fp = AllocateFile(TABLESPACE_MAP, "w");
-
-                               if (!fp)
-                                       ereport(ERROR,
-                                                       
(errcode_for_file_access(),
-                                                        errmsg("could not 
create file \"%s\": %m",
-                                                                       
TABLESPACE_MAP)));
-                               if (fwrite(tblspcmapfile->data, 
tblspcmapfile->len, 1, fp) != 1 ||
-                                       fflush(fp) != 0 ||
-                                       pg_fsync(fileno(fp)) != 0 ||
-                                       ferror(fp) ||
-                                       FreeFile(fp))
-                                       ereport(ERROR,
-                                                       
(errcode_for_file_access(),
-                                                        errmsg("could not 
write file \"%s\": %m",
-                                                                       
TABLESPACE_MAP)));
-                       }
-
-                       /* Allocated locally for exclusive backups, so free 
separately */
-                       pfree(tblspcmapfile->data);
-                       pfree(tblspcmapfile);
-               }
        }
-       PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 
BoolGetDatum(exclusive));
+       PG_END_ENSURE_ERROR_CLEANUP(pg_start_backup_callback, (Datum) 0);
 
        /*
-        * Mark that start phase has correctly finished for an exclusive backup.
-        * Session-level locks are updated as well to reflect that state.
-        *
-        * Note that CHECK_FOR_INTERRUPTS() must not occur while updating backup
-        * counters and session-level lock. Otherwise they can be updated
-        * inconsistently, and which might cause do_pg_abort_backup() to fail.
+        * Mark that the start phase has correctly finished for the backup.
         */
-       if (exclusive)
-       {
-               WALInsertLockAcquireExclusive();
-               XLogCtl->Insert.exclusiveBackupState = 
EXCLUSIVE_BACKUP_IN_PROGRESS;
-
-               /* Set session-level lock */
-               sessionBackupState = SESSION_BACKUP_EXCLUSIVE;
-               WALInsertLockRelease();
-       }
-       else
-               sessionBackupState = SESSION_BACKUP_NON_EXCLUSIVE;
+       sessionBackupState = SESSION_BACKUP_RUNNING;
 
        /*
         * We're done.  As a convenience, return the starting WAL location.
@@ -10654,43 +10477,15 @@ do_pg_start_backup(const char *backupidstr, bool 
fast, TimeLineID *starttli_p,
 static void
 pg_start_backup_callback(int code, Datum arg)
 {
-       bool            exclusive = DatumGetBool(arg);
-
        /* Update backup counters and forcePageWrites on failure */
        WALInsertLockAcquireExclusive();
-       if (exclusive)
-       {
-               Assert(XLogCtl->Insert.exclusiveBackupState == 
EXCLUSIVE_BACKUP_STARTING);
-               XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
-       }
-       else
-       {
-               Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
-               XLogCtl->Insert.nonExclusiveBackups--;
-       }
 
-       if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
-               XLogCtl->Insert.nonExclusiveBackups == 0)
-       {
-               XLogCtl->Insert.forcePageWrites = false;
-       }
-       WALInsertLockRelease();
-}
+       Assert(XLogCtl->Insert.runningBackups > 0);
+       XLogCtl->Insert.runningBackups--;
 
-/*
- * Error cleanup callback for pg_stop_backup
- */
-static void
-pg_stop_backup_callback(int code, Datum arg)
-{
-       bool            exclusive = DatumGetBool(arg);
-
-       /* Update backup status on failure */
-       WALInsertLockAcquireExclusive();
-       if (exclusive)
+       if (XLogCtl->Insert.runningBackups == 0)
        {
-               Assert(XLogCtl->Insert.exclusiveBackupState == 
EXCLUSIVE_BACKUP_STOPPING);
-               XLogCtl->Insert.exclusiveBackupState = 
EXCLUSIVE_BACKUP_IN_PROGRESS;
+               XLogCtl->Insert.forcePageWrites = false;
        }
        WALInsertLockRelease();
 }
@@ -10708,9 +10503,6 @@ get_backup_status(void)
  * do_pg_stop_backup is the workhorse of the user-visible pg_stop_backup()
  * function.
  *
- * If labelfile is NULL, this stops an exclusive backup. Otherwise this stops
- * the non-exclusive backup specified by 'labelfile'.
- *
  * Returns the last WAL location that must be present to restore from this
  * backup, and the corresponding timeline ID in *stoptli_p.
  *
@@ -10720,7 +10512,6 @@ get_backup_status(void)
 XLogRecPtr
 do_pg_stop_backup(char *labelfile, bool waitforarchive, TimeLineID *stoptli_p)
 {
-       bool            exclusive = (labelfile == NULL);
        bool            backup_started_in_recovery = false;
        XLogRecPtr      startpoint;
        XLogRecPtr      stoppoint;
@@ -10734,7 +10525,6 @@ do_pg_stop_backup(char *labelfile, bool waitforarchive, 
TimeLineID *stoptli_p)
        char            histfilename[MAXFNAMELEN];
        char            backupfrom[20];
        XLogSegNo       _logSegNo;
-       FILE       *lfp;
        FILE       *fp;
        char            ch;
        int                     seconds_before_warning;
@@ -10747,15 +10537,6 @@ do_pg_stop_backup(char *labelfile, bool 
waitforarchive, TimeLineID *stoptli_p)
 
        backup_started_in_recovery = RecoveryInProgress();
 
-       /*
-        * Currently only non-exclusive backup can be taken during recovery.
-        */
-       if (backup_started_in_recovery && exclusive)
-               ereport(ERROR,
-                               
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("recovery is in progress"),
-                                errhint("WAL control functions cannot be 
executed during recovery.")));
-
        /*
         * During recovery, we don't need to check WAL level. Because, if WAL
         * level is not sufficient, it's impossible to get here during recovery.
@@ -10766,106 +10547,23 @@ do_pg_stop_backup(char *labelfile, bool 
waitforarchive, TimeLineID *stoptli_p)
                                 errmsg("WAL level not sufficient for making an 
online backup"),
                                 errhint("wal_level must be set to \"replica\" 
or \"logical\" at server start.")));
 
-       if (exclusive)
-       {
-               /*
-                * At first, mark that we're now stopping an exclusive backup, 
to
-                * ensure that there are no other sessions currently running
-                * pg_start_backup() or pg_stop_backup().
-                */
-               WALInsertLockAcquireExclusive();
-               if (XLogCtl->Insert.exclusiveBackupState != 
EXCLUSIVE_BACKUP_IN_PROGRESS)
-               {
-                       WALInsertLockRelease();
-                       ereport(ERROR,
-                                       
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                        errmsg("exclusive backup not in 
progress")));
-               }
-               XLogCtl->Insert.exclusiveBackupState = 
EXCLUSIVE_BACKUP_STOPPING;
-               WALInsertLockRelease();
-
-               /*
-                * Remove backup_label. In case of failure, the state for an 
exclusive
-                * backup is switched back to in-progress.
-                */
-               PG_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) 
BoolGetDatum(exclusive));
-               {
-                       /*
-                        * Read the existing label file into memory.
-                        */
-                       struct stat statbuf;
-                       int                     r;
-
-                       if (stat(BACKUP_LABEL_FILE, &statbuf))
-                       {
-                               /* should not happen per the upper checks */
-                               if (errno != ENOENT)
-                                       ereport(ERROR,
-                                                       
(errcode_for_file_access(),
-                                                        errmsg("could not stat 
file \"%s\": %m",
-                                                                       
BACKUP_LABEL_FILE)));
-                               ereport(ERROR,
-                                               
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                                errmsg("a backup is not in 
progress")));
-                       }
-
-                       lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
-                       if (!lfp)
-                       {
-                               ereport(ERROR,
-                                               (errcode_for_file_access(),
-                                                errmsg("could not read file 
\"%s\": %m",
-                                                               
BACKUP_LABEL_FILE)));
-                       }
-                       labelfile = palloc(statbuf.st_size + 1);
-                       r = fread(labelfile, statbuf.st_size, 1, lfp);
-                       labelfile[statbuf.st_size] = '\0';
-
-                       /*
-                        * Close and remove the backup label file
-                        */
-                       if (r != 1 || ferror(lfp) || FreeFile(lfp))
-                               ereport(ERROR,
-                                               (errcode_for_file_access(),
-                                                errmsg("could not read file 
\"%s\": %m",
-                                                               
BACKUP_LABEL_FILE)));
-                       durable_unlink(BACKUP_LABEL_FILE, ERROR);
-
-                       /*
-                        * Remove tablespace_map file if present, it is created 
only if
-                        * there are tablespaces.
-                        */
-                       durable_unlink(TABLESPACE_MAP, DEBUG1);
-               }
-               PG_END_ENSURE_ERROR_CLEANUP(pg_stop_backup_callback, (Datum) 
BoolGetDatum(exclusive));
-       }
-
        /*
-        * OK to update backup counters, forcePageWrites and session-level lock.
+        * OK to update backup counters and forcePageWrites.
         *
         * Note that CHECK_FOR_INTERRUPTS() must not occur while updating them.
         * Otherwise they can be updated inconsistently, and which might cause
         * do_pg_abort_backup() to fail.
         */
        WALInsertLockAcquireExclusive();
-       if (exclusive)
-       {
-               XLogCtl->Insert.exclusiveBackupState = EXCLUSIVE_BACKUP_NONE;
-       }
-       else
-       {
-               /*
-                * The user-visible pg_start/stop_backup() functions that 
operate on
-                * exclusive backups can be called at any time, but for 
non-exclusive
-                * backups, it is expected that each do_pg_start_backup() call 
is
-                * matched by exactly one do_pg_stop_backup() call.
-                */
-               Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
-               XLogCtl->Insert.nonExclusiveBackups--;
-       }
 
-       if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
-               XLogCtl->Insert.nonExclusiveBackups == 0)
+       /*
+        * It is expected that each do_pg_start_backup() call is matched by 
exactly
+        * one do_pg_stop_backup() call.
+        */
+       Assert(XLogCtl->Insert.runningBackups > 0);
+       XLogCtl->Insert.runningBackups--;
+
+       if (XLogCtl->Insert.runningBackups == 0)
        {
                XLogCtl->Insert.forcePageWrites = false;
        }
@@ -11117,28 +10815,21 @@ do_pg_stop_backup(char *labelfile, bool 
waitforarchive, TimeLineID *stoptli_p)
  * This does just the most basic steps of do_pg_stop_backup(), by taking the
  * system out of backup mode, thus making it a lot more safe to call from
  * an error handler.
- *
- * NB: This is only for aborting a non-exclusive backup that doesn't write
- * backup_label. A backup started with pg_start_backup() needs to be finished
- * with pg_stop_backup().
  */
 void
 do_pg_abort_backup(void)
 {
        /*
-        * Quick exit if session is not keeping around a non-exclusive backup
-        * already started.
+        * Quick exit if session does not have a running backup.
         */
        if (sessionBackupState == SESSION_BACKUP_NONE)
                return;
 
        WALInsertLockAcquireExclusive();
-       Assert(XLogCtl->Insert.nonExclusiveBackups > 0);
-       Assert(sessionBackupState == SESSION_BACKUP_NON_EXCLUSIVE);
-       XLogCtl->Insert.nonExclusiveBackups--;
+       Assert(XLogCtl->Insert.runningBackups > 0);
+       XLogCtl->Insert.runningBackups--;
 
-       if (XLogCtl->Insert.exclusiveBackupState == EXCLUSIVE_BACKUP_NONE &&
-               XLogCtl->Insert.nonExclusiveBackups == 0)
+       if (XLogCtl->Insert.runningBackups == 0)
        {
                XLogCtl->Insert.forcePageWrites = false;
        }
@@ -11441,87 +11132,6 @@ rm_redo_error_callback(void *arg)
        pfree(buf.data);
 }
 
-/*
- * BackupInProgress: check if online backup mode is active
- *
- * This is done by checking for existence of the "backup_label" file.
- */
-bool
-BackupInProgress(void)
-{
-       struct stat stat_buf;
-
-       return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0);
-}
-
-/*
- * CancelBackup: rename the "backup_label" and "tablespace_map"
- *                              files to cancel backup mode
- *
- * If the "backup_label" file exists, it will be renamed to "backup_label.old".
- * Similarly, if the "tablespace_map" file exists, it will be renamed to
- * "tablespace_map.old".
- *
- * Note that this will render an online backup in progress
- * useless. To correctly finish an online backup, pg_stop_backup must be
- * called.
- */
-void
-CancelBackup(void)
-{
-       struct stat stat_buf;
-
-       /* if the backup_label file is not there, return */
-       if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0)
-               return;
-
-       /* remove leftover file from previously canceled backup if it exists */
-       unlink(BACKUP_LABEL_OLD);
-
-       if (durable_rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD, DEBUG1) != 0)
-       {
-               ereport(WARNING,
-                               (errcode_for_file_access(),
-                                errmsg("online backup mode was not canceled"),
-                                errdetail("File \"%s\" could not be renamed to 
\"%s\": %m.",
-                                                  BACKUP_LABEL_FILE, 
BACKUP_LABEL_OLD)));
-               return;
-       }
-
-       /* if the tablespace_map file is not there, return */
-       if (stat(TABLESPACE_MAP, &stat_buf) < 0)
-       {
-               ereport(LOG,
-                               (errmsg("online backup mode canceled"),
-                                errdetail("File \"%s\" was renamed to \"%s\".",
-                                                  BACKUP_LABEL_FILE, 
BACKUP_LABEL_OLD)));
-               return;
-       }
-
-       /* remove leftover file from previously canceled backup if it exists */
-       unlink(TABLESPACE_MAP_OLD);
-
-       if (durable_rename(TABLESPACE_MAP, TABLESPACE_MAP_OLD, DEBUG1) == 0)
-       {
-               ereport(LOG,
-                               (errmsg("online backup mode canceled"),
-                                errdetail("Files \"%s\" and \"%s\" were 
renamed to "
-                                                  "\"%s\" and \"%s\", 
respectively.",
-                                                  BACKUP_LABEL_FILE, 
TABLESPACE_MAP,
-                                                  BACKUP_LABEL_OLD, 
TABLESPACE_MAP_OLD)));
-       }
-       else
-       {
-               ereport(WARNING,
-                               (errcode_for_file_access(),
-                                errmsg("online backup mode canceled"),
-                                errdetail("File \"%s\" was renamed to \"%s\", 
but "
-                                                  "file \"%s\" could not be 
renamed to \"%s\": %m.",
-                                                  BACKUP_LABEL_FILE, 
BACKUP_LABEL_OLD,
-                                                  TABLESPACE_MAP, 
TABLESPACE_MAP_OLD)));
-       }
-}
-
 /*
  * Read the XLOG page containing RecPtr into readBuf (if not read already).
  * Returns number of bytes read, if the page is read successfully, or -1
diff --git a/src/backend/access/transam/xlogfuncs.c 
b/src/backend/access/transam/xlogfuncs.c
index f139eeff9f..469d5e41c1 100644
--- a/src/backend/access/transam/xlogfuncs.c
+++ b/src/backend/access/transam/xlogfuncs.c
@@ -40,17 +40,16 @@
 
 
 /*
- * Store label file and tablespace map during non-exclusive backups.
+ * Store label file and tablespace map during backups.
  */
 static StringInfo label_file;
 static StringInfo tblspc_map_file;
 
 /*
- * Called when the backend exits with a running non-exclusive base backup,
- * to clean up state.
+ * Called when the backend exits with a running base backup to clean up state.
  */
 static void
-nonexclusive_base_backup_cleanup(int code, Datum arg)
+base_backup_cleanup(int code, Datum arg)
 {
        do_pg_abort_backup();
        ereport(WARNING,
@@ -74,101 +73,40 @@ pg_start_backup(PG_FUNCTION_ARGS)
 {
        text       *backupid = PG_GETARG_TEXT_PP(0);
        bool            fast = PG_GETARG_BOOL(1);
-       bool            exclusive = PG_GETARG_BOOL(2);
        char       *backupidstr;
        XLogRecPtr      startpoint;
        SessionBackupState status = get_backup_status();
+       MemoryContext oldcontext;
 
        backupidstr = text_to_cstring(backupid);
 
-       if (status == SESSION_BACKUP_NON_EXCLUSIVE)
+       if (status == SESSION_BACKUP_RUNNING)
                ereport(ERROR,
                                
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                                 errmsg("a backup is already in progress in 
this session")));
 
-       if (exclusive)
-       {
-               startpoint = do_pg_start_backup(backupidstr, fast, NULL, NULL,
-                                                                               
NULL, NULL, false, true);
-       }
-       else
-       {
-               MemoryContext oldcontext;
-
-               /*
-                * Label file and tablespace map file need to be long-lived, 
since
-                * they are read in pg_stop_backup.
-                */
-               oldcontext = MemoryContextSwitchTo(TopMemoryContext);
-               label_file = makeStringInfo();
-               tblspc_map_file = makeStringInfo();
-               MemoryContextSwitchTo(oldcontext);
+       /*
+        * Label file and tablespace map file need to be long-lived, since
+        * they are read in pg_stop_backup.
+        */
+       oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+       label_file = makeStringInfo();
+       tblspc_map_file = makeStringInfo();
+       MemoryContextSwitchTo(oldcontext);
 
-               startpoint = do_pg_start_backup(backupidstr, fast, NULL, 
label_file,
-                                                                               
NULL, tblspc_map_file, false, true);
+       startpoint = do_pg_start_backup(backupidstr, fast, NULL, label_file,
+                                                                       NULL, 
tblspc_map_file, false, true);
 
-               before_shmem_exit(nonexclusive_base_backup_cleanup, (Datum) 0);
-       }
+       before_shmem_exit(base_backup_cleanup, (Datum) 0);
 
        PG_RETURN_LSN(startpoint);
 }
 
-/*
- * pg_stop_backup: finish taking an on-line backup dump
- *
- * We write an end-of-backup WAL record, and remove the backup label file
- * created by pg_start_backup, creating a backup history file in pg_wal
- * instead (whence it will immediately be archived). The backup history file
- * contains the same info found in the label file, plus the backup-end time
- * and WAL location. Before 9.0, the backup-end time was read from the backup
- * history file at the beginning of archive recovery, but we now use the WAL
- * record for that and the file is for informational and debug purposes only.
- *
- * Note: different from CancelBackup which just cancels online backup mode.
- *
- * Note: this version is only called to stop an exclusive backup. The function
- *              pg_stop_backup_v2 (overloaded as pg_stop_backup in SQL) is 
called to
- *              stop non-exclusive backups.
- *
- * Permission checking for this function is managed through the normal
- * GRANT system.
- */
-Datum
-pg_stop_backup(PG_FUNCTION_ARGS)
-{
-       XLogRecPtr      stoppoint;
-       SessionBackupState status = get_backup_status();
-
-       if (status == SESSION_BACKUP_NON_EXCLUSIVE)
-               ereport(ERROR,
-                               
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("non-exclusive backup in progress"),
-                                errhint("Did you mean to use 
pg_stop_backup('f')?")));
-
-       /*
-        * Exclusive backups were typically started in a different connection, 
so
-        * don't try to verify that status of backup is set to
-        * SESSION_BACKUP_EXCLUSIVE in this function. Actual verification that 
an
-        * exclusive backup is in fact running is handled inside
-        * do_pg_stop_backup.
-        */
-       stoppoint = do_pg_stop_backup(NULL, true, NULL);
-
-       PG_RETURN_LSN(stoppoint);
-}
-
 
 /*
- * pg_stop_backup_v2: finish taking exclusive or nonexclusive on-line backup.
+ * pg_stop_backup: finish taking an on-line backup.
  *
- * Works the same as pg_stop_backup, except for non-exclusive backups it 
returns
- * the backup label and tablespace map files as text fields in as part of the
- * resultset.
- *
- * The first parameter (variable 'exclusive') allows the user to tell us if
- * this is an exclusive or a non-exclusive backup.
- *
- * The second parameter (variable 'waitforarchive'), which is optional,
+ * The first parameter (variable 'waitforarchive'), which is optional,
  * allows the user to choose if they want to wait for the WAL to be archived
  * or if we should just return as soon as the WAL record is written.
  *
@@ -176,7 +114,7 @@ pg_stop_backup(PG_FUNCTION_ARGS)
  * GRANT system.
  */
 Datum
-pg_stop_backup_v2(PG_FUNCTION_ARGS)
+pg_stop_backup(PG_FUNCTION_ARGS)
 {
        ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
        TupleDesc       tupdesc;
@@ -186,8 +124,7 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
        Datum           values[3];
        bool            nulls[3];
 
-       bool            exclusive = PG_GETARG_BOOL(0);
-       bool            waitforarchive = PG_GETARG_BOOL(1);
+       bool            waitforarchive = PG_GETARG_BOOL(0);
        XLogRecPtr      stoppoint;
        SessionBackupState status = get_backup_status();
 
@@ -219,52 +156,30 @@ pg_stop_backup_v2(PG_FUNCTION_ARGS)
        MemSet(values, 0, sizeof(values));
        MemSet(nulls, 0, sizeof(nulls));
 
-       if (exclusive)
-       {
-               if (status == SESSION_BACKUP_NON_EXCLUSIVE)
-                       ereport(ERROR,
-                                       
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                        errmsg("non-exclusive backup in 
progress"),
-                                        errhint("Did you mean to use 
pg_stop_backup('f')?")));
-
-               /*
-                * Stop the exclusive backup, and since we're in an exclusive 
backup
-                * return NULL for both backup_label and tablespace_map.
-                */
-               stoppoint = do_pg_stop_backup(NULL, waitforarchive, NULL);
-
-               nulls[1] = true;
-               nulls[2] = true;
-       }
-       else
-       {
-               if (status != SESSION_BACKUP_NON_EXCLUSIVE)
-                       ereport(ERROR,
-                                       
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                        errmsg("non-exclusive backup is not in 
progress"),
-                                        errhint("Did you mean to use 
pg_stop_backup('t')?")));
-
-               /*
-                * Stop the non-exclusive backup. Return a copy of the backup 
label
-                * and tablespace map so they can be written to disk by the 
caller.
-                */
-               stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, 
NULL);
-               cancel_before_shmem_exit(nonexclusive_base_backup_cleanup, 
(Datum) 0);
-
-               values[1] = CStringGetTextDatum(label_file->data);
-               values[2] = CStringGetTextDatum(tblspc_map_file->data);
-
-               /* Free structures allocated in TopMemoryContext */
-               pfree(label_file->data);
-               pfree(label_file);
-               label_file = NULL;
-               pfree(tblspc_map_file->data);
-               pfree(tblspc_map_file);
-               tblspc_map_file = NULL;
-       }
+       if (status != SESSION_BACKUP_RUNNING)
+               ereport(ERROR,
+                               
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+                                errmsg("backup is not in progress"),
+                                errhint("Did you call pg_start_backup()?")));
+
+       /*
+        * Stop the backup. Return a copy of the backup label and tablespace 
map so
+        * they can be written to disk by the caller.
+        */
+       stoppoint = do_pg_stop_backup(label_file->data, waitforarchive, NULL);
+       cancel_before_shmem_exit(base_backup_cleanup, (Datum) 0);
 
-       /* Stoppoint is included on both exclusive and nonexclusive backups */
        values[0] = LSNGetDatum(stoppoint);
+       values[1] = CStringGetTextDatum(label_file->data);
+       values[2] = CStringGetTextDatum(tblspc_map_file->data);
+
+       /* Free structures allocated in TopMemoryContext */
+       pfree(label_file->data);
+       pfree(label_file);
+       label_file = NULL;
+       pfree(tblspc_map_file->data);
+       pfree(tblspc_map_file);
+       tblspc_map_file = NULL;
 
        tuplestore_putvalues(tupstore, tupdesc, values, nulls);
        tuplestore_donestoring(typstore);
@@ -626,81 +541,6 @@ pg_wal_lsn_diff(PG_FUNCTION_ARGS)
        PG_RETURN_NUMERIC(result);
 }
 
-/*
- * Returns bool with current on-line backup mode, a global state.
- */
-Datum
-pg_is_in_backup(PG_FUNCTION_ARGS)
-{
-       PG_RETURN_BOOL(BackupInProgress());
-}
-
-/*
- * Returns start time of an online exclusive backup.
- *
- * When there's no exclusive backup in progress, the function
- * returns NULL.
- */
-Datum
-pg_backup_start_time(PG_FUNCTION_ARGS)
-{
-       Datum           xtime;
-       FILE       *lfp;
-       char            fline[MAXPGPATH];
-       char            backup_start_time[30];
-
-       /*
-        * See if label file is present
-        */
-       lfp = AllocateFile(BACKUP_LABEL_FILE, "r");
-       if (lfp == NULL)
-       {
-               if (errno != ENOENT)
-                       ereport(ERROR,
-                                       (errcode_for_file_access(),
-                                        errmsg("could not read file \"%s\": 
%m",
-                                                       BACKUP_LABEL_FILE)));
-               PG_RETURN_NULL();
-       }
-
-       /*
-        * Parse the file to find the START TIME line.
-        */
-       backup_start_time[0] = '\0';
-       while (fgets(fline, sizeof(fline), lfp) != NULL)
-       {
-               if (sscanf(fline, "START TIME: %25[^\n]\n", backup_start_time) 
== 1)
-                       break;
-       }
-
-       /* Check for a read error. */
-       if (ferror(lfp))
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not read file \"%s\": %m", 
BACKUP_LABEL_FILE)));
-
-       /* Close the backup label file. */
-       if (FreeFile(lfp))
-               ereport(ERROR,
-                               (errcode_for_file_access(),
-                                errmsg("could not close file \"%s\": %m", 
BACKUP_LABEL_FILE)));
-
-       if (strlen(backup_start_time) == 0)
-               ereport(ERROR,
-                               
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
-                                errmsg("invalid data in file \"%s\"", 
BACKUP_LABEL_FILE)));
-
-       /*
-        * Convert the time string read from file to TimestampTz form.
-        */
-       xtime = DirectFunctionCall3(timestamptz_in,
-                                                               
CStringGetDatum(backup_start_time),
-                                                               
ObjectIdGetDatum(InvalidOid),
-                                                               
Int32GetDatum(-1));
-
-       PG_RETURN_DATUM(xtime);
-}
-
 /*
  * Promotes a standby server.
  *
diff --git a/src/backend/catalog/system_views.sql 
b/src/backend/catalog/system_views.sql
index 8630542bb3..bf30693f23 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -1018,14 +1018,14 @@ COMMENT ON FUNCTION ts_debug(text) IS
 --
 
 CREATE OR REPLACE FUNCTION
-  pg_start_backup(label text, fast boolean DEFAULT false, exclusive boolean 
DEFAULT true)
+  pg_start_backup(label text, fast boolean DEFAULT false)
   RETURNS pg_lsn STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'
   PARALLEL RESTRICTED;
 
 CREATE OR REPLACE FUNCTION pg_stop_backup (
-        exclusive boolean, wait_for_archive boolean DEFAULT true,
-        OUT lsn pg_lsn, OUT labelfile text, OUT spcmapfile text)
-  RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup_v2'
+  wait_for_archive boolean DEFAULT true, OUT lsn pg_lsn, OUT labelfile text,
+  OUT spcmapfile text)
+  RETURNS SETOF record STRICT VOLATILE LANGUAGE internal as 'pg_stop_backup'
   PARALLEL RESTRICTED;
 
 CREATE OR REPLACE FUNCTION
@@ -1133,9 +1133,8 @@ AS 'jsonb_insert';
 -- can later change who can access these functions, or leave them as only
 -- available to superuser / cluster owner, if they choose.
 --
-REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean, boolean) FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup() FROM public;
-REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_start_backup(text, boolean) FROM public;
+REVOKE EXECUTE ON FUNCTION pg_stop_backup(boolean) FROM public;
 REVOKE EXECUTE ON FUNCTION pg_create_restore_point(text) FROM public;
 REVOKE EXECUTE ON FUNCTION pg_switch_wal() FROM public;
 REVOKE EXECUTE ON FUNCTION pg_wal_replay_pause() FROM public;
diff --git a/src/backend/postmaster/postmaster.c 
b/src/backend/postmaster/postmaster.c
index a33a131182..3a8653ab4d 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -300,8 +300,7 @@ static bool FatalError = false; /* T if recovering from 
backend crash */
  * and we switch to PM_RUN state.
  *
  * Normal child backends can only be launched when we are in PM_RUN or
- * PM_HOT_STANDBY state.  (We also allow launch of normal
- * child backends in PM_WAIT_BACKUP state, but only for superusers.)
+ * PM_HOT_STANDBY state.
  * In other states we handle connection requests by launching "dead_end"
  * child processes, which will simply send the client an error message and
  * quit.  (We track these in the BackendList so that we can know when they
@@ -327,7 +326,6 @@ typedef enum
        PM_RECOVERY,                            /* in archive recovery mode */
        PM_HOT_STANDBY,                         /* in hot standby mode */
        PM_RUN,                                         /* normal "database is 
alive" state */
-       PM_WAIT_BACKUP,                         /* waiting for online backup 
mode to end */
        PM_WAIT_READONLY,                       /* waiting for read only 
backends to exit */
        PM_WAIT_BACKENDS,                       /* waiting for live backends to 
exit */
        PM_SHUTDOWN,                            /* waiting for checkpointer to 
do shutdown
@@ -2241,9 +2239,6 @@ retry1:
                                        (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
                                         errmsg("sorry, too many clients 
already")));
                        break;
-               case CAC_WAITBACKUP:
-                       /* OK for now, will check in InitPostgres */
-                       break;
                case CAC_OK:
                        break;
        }
@@ -2352,18 +2347,10 @@ canAcceptConnections(void)
        /*
         * Can't start backends when in startup/shutdown/inconsistent recovery
         * state.
-        *
-        * In state PM_WAIT_BACKUP only superusers can connect (this must be
-        * allowed so that a superuser can end online backup mode); we return
-        * CAC_WAITBACKUP code to indicate that this must be checked later. Note
-        * that neither CAC_OK nor CAC_WAITBACKUP can safely be returned until 
we
-        * have checked for too many children.
         */
        if (pmState != PM_RUN)
        {
-               if (pmState == PM_WAIT_BACKUP)
-                       result = CAC_WAITBACKUP;        /* allow superusers 
only */
-               else if (Shutdown > NoShutdown)
+               if (Shutdown > NoShutdown)
                        return CAC_SHUTDOWN;    /* shutdown is pending */
                else if (!FatalError &&
                                 (pmState == PM_STARTUP ||
@@ -2704,7 +2691,7 @@ pmdie(SIGNAL_ARGS)
                                 * and walreceiver processes.
                                 */
                                pmState = (pmState == PM_RUN) ?
-                                       PM_WAIT_BACKUP : PM_WAIT_READONLY;
+                                       PM_WAIT_BACKENDS : PM_WAIT_READONLY;
                        }
 
                        /*
@@ -2754,7 +2741,6 @@ pmdie(SIGNAL_ARGS)
                                pmState = PM_WAIT_BACKENDS;
                        }
                        else if (pmState == PM_RUN ||
-                                        pmState == PM_WAIT_BACKUP ||
                                         pmState == PM_WAIT_READONLY ||
                                         pmState == PM_WAIT_BACKENDS ||
                                         pmState == PM_HOT_STANDBY)
@@ -3571,7 +3557,6 @@ HandleChildCrash(int pid, int exitstatus, const char 
*procname)
        if (pmState == PM_RECOVERY ||
                pmState == PM_HOT_STANDBY ||
                pmState == PM_RUN ||
-               pmState == PM_WAIT_BACKUP ||
                pmState == PM_WAIT_READONLY ||
                pmState == PM_SHUTDOWN)
                pmState = PM_WAIT_BACKENDS;
@@ -3663,15 +3648,6 @@ LogChildExit(int lev, const char *procname, int pid, int 
exitstatus)
 static void
 PostmasterStateMachine(void)
 {
-       if (pmState == PM_WAIT_BACKUP)
-       {
-               /*
-                * PM_WAIT_BACKUP state ends when online backup mode is not 
active.
-                */
-               if (!BackupInProgress())
-                       pmState = PM_WAIT_BACKENDS;
-       }
-
        if (pmState == PM_WAIT_READONLY)
        {
                /*
@@ -3841,18 +3817,6 @@ PostmasterStateMachine(void)
                }
                else
                {
-                       /*
-                        * Terminate exclusive backup mode to avoid recovery 
after a clean
-                        * fast shutdown.  Since an exclusive backup can only 
be taken
-                        * during normal running (and not, for example, while 
running
-                        * under Hot Standby) it only makes sense to do this if 
we reached
-                        * normal running. If we're still in recovery, the 
backup file is
-                        * one we're recovering *from*, and we must keep it 
around so that
-                        * recovery restarts from the right place.
-                        */
-                       if (ReachedNormalRunning)
-                               CancelBackup();
-
                        /* Normal exit from the postmaster is here */
                        ExitPostmaster(0);
                }
@@ -4054,8 +4018,7 @@ BackendStartup(Port *port)
 
        /* Pass down canAcceptConnections state */
        port->canAcceptConnections = canAcceptConnections();
-       bn->dead_end = (port->canAcceptConnections != CAC_OK &&
-                                       port->canAcceptConnections != 
CAC_WAITBACKUP);
+       bn->dead_end = port->canAcceptConnections != CAC_OK;
 
        /*
         * Unless it's a dead_end child, assign it a child slot number
@@ -5182,7 +5145,7 @@ sigusr1_handler(SIGNAL_ARGS)
        }
 
        if (CheckPostmasterSignal(PMSIGNAL_ADVANCE_STATE_MACHINE) &&
-               (pmState == PM_WAIT_BACKUP || pmState == PM_WAIT_BACKENDS))
+               pmState == PM_WAIT_BACKENDS)
        {
                /* Advance postmaster's state machine */
                PostmasterStateMachine();
@@ -5775,7 +5738,6 @@ bgworker_should_start_now(BgWorkerStartTime start_time)
                case PM_SHUTDOWN:
                case PM_WAIT_BACKENDS:
                case PM_WAIT_READONLY:
-               case PM_WAIT_BACKUP:
                        break;
 
                case PM_RUN:
diff --git a/src/backend/replication/basebackup.c 
b/src/backend/replication/basebackup.c
index 78ed6cf797..448556d7c3 100644
--- a/src/backend/replication/basebackup.c
+++ b/src/backend/replication/basebackup.c
@@ -172,10 +172,8 @@ static const char *excludeFiles[] =
        RELCACHE_INIT_FILENAME,
 
        /*
-        * If there's a backup_label or tablespace_map file, it belongs to a
-        * backup started by the user with pg_start_backup().  It is *not* 
correct
-        * for this backup.  Our backup_label/tablespace_map is injected into 
the
-        * tar separately.
+        * backup_label and tablespace_map should not exist in in a running 
cluster
+        * capable of doing an online backup, but exclude then just in case.
         */
        BACKUP_LABEL_FILE,
        TABLESPACE_MAP,
diff --git a/src/backend/utils/init/postinit.c 
b/src/backend/utils/init/postinit.c
index b636b1e262..d868c21fdc 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -788,7 +788,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char 
*username,
         */
        if ((!am_superuser || am_walsender) &&
                MyProcPort != NULL &&
-               MyProcPort->canAcceptConnections == CAC_WAITBACKUP)
+               MyProcPort->canAcceptConnections == CAC_SHUTDOWN)
        {
                if (am_walsender)
                        ereport(FATAL,
diff --git a/src/bin/pg_basebackup/t/010_pg_basebackup.pl 
b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
index 3e1c3863c4..04eea9bfeb 100644
--- a/src/bin/pg_basebackup/t/010_pg_basebackup.pl
+++ b/src/bin/pg_basebackup/t/010_pg_basebackup.pl
@@ -158,6 +158,10 @@ isnt(slurp_file("$tempdir/backup/backup_label"),
        'DONOTCOPY', 'existing backup_label not copied');
 rmtree("$tempdir/backup");
 
+# Now delete the bogus backup_label file since it will interfere with startup
+unlink("$pgdata/backup_label")
+  or BAIL_OUT("unable to unlink $pgdata/backup_label");
+
 $node->command_ok(
        [
                'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
diff --git a/src/bin/pg_rewind/filemap.c b/src/bin/pg_rewind/filemap.c
index 222b56f58a..084ea06597 100644
--- a/src/bin/pg_rewind/filemap.c
+++ b/src/bin/pg_rewind/filemap.c
@@ -94,9 +94,9 @@ static const char *excludeFiles[] =
        "pg_internal.init",                     /* defined as 
RELCACHE_INIT_FILENAME */
 
        /*
-        * If there's a backup_label or tablespace_map file, it belongs to a
-        * backup started by the user with pg_start_backup().  It is *not* 
correct
-        * for this backup.  Our backup_label is written later on separately.
+        * If there is a backup_label or tablespace_map file, it indicates that
+        * a recovery failed and this cluster probably can't be rewound, but
+        * exclude them anyway if they are found.
         */
        "backup_label",                         /* defined as BACKUP_LABEL_FILE 
*/
        "tablespace_map",                       /* defined as TABLESPACE_MAP */
diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h
index f3a7ba4d42..7d0f45ff99 100644
--- a/src/include/access/xlog.h
+++ b/src/include/access/xlog.h
@@ -338,8 +338,7 @@ extern void assign_checkpoint_completion_target(double 
newval, void *extra);
 typedef enum SessionBackupState
 {
        SESSION_BACKUP_NONE,
-       SESSION_BACKUP_EXCLUSIVE,
-       SESSION_BACKUP_NON_EXCLUSIVE
+       SESSION_BACKUP_RUNNING,
 } SessionBackupState;
 
 extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast,
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index f79fcfe029..4a4c49cf99 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -5814,25 +5814,15 @@
   proargtypes => 'int4', prosrc => 'pg_terminate_backend' },
 { oid => '2172', descr => 'prepare for taking an online backup',
   proname => 'pg_start_backup', provolatile => 'v', proparallel => 'r',
-  prorettype => 'pg_lsn', proargtypes => 'text bool bool',
+  prorettype => 'pg_lsn', proargtypes => 'text bool',
   prosrc => 'pg_start_backup' },
-{ oid => '2173', descr => 'finish taking an online backup',
-  proname => 'pg_stop_backup', provolatile => 'v', proparallel => 'r',
-  prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_stop_backup' },
 { oid => '2739', descr => 'finish taking an online backup',
   proname => 'pg_stop_backup', prorows => '1', proretset => 't',
   provolatile => 'v', proparallel => 'r', prorettype => 'record',
-  proargtypes => 'bool bool', proallargtypes => '{bool,bool,pg_lsn,text,text}',
-  proargmodes => '{i,i,o,o,o}',
-  proargnames => '{exclusive,wait_for_archive,lsn,labelfile,spcmapfile}',
-  prosrc => 'pg_stop_backup_v2' },
-{ oid => '3813', descr => 'true if server is in online backup',
-  proname => 'pg_is_in_backup', provolatile => 'v', prorettype => 'bool',
-  proargtypes => '', prosrc => 'pg_is_in_backup' },
-{ oid => '3814', descr => 'start time of an online backup',
-  proname => 'pg_backup_start_time', provolatile => 's',
-  prorettype => 'timestamptz', proargtypes => '',
-  prosrc => 'pg_backup_start_time' },
+  proargtypes => 'bool', proallargtypes => '{bool,pg_lsn,text,text}',
+  proargmodes => '{i,o,o,o}',
+  proargnames => '{wait_for_archive,lsn,labelfile,spcmapfile}',
+  prosrc => 'pg_stop_backup' },
 { oid => '3436', descr => 'promote standby server',
   proname => 'pg_promote', provolatile => 'v', prorettype => 'bool',
   proargtypes => 'bool int4', proargnames => '{wait,wait_seconds}',
diff --git a/src/include/libpq/libpq-be.h b/src/include/libpq/libpq-be.h
index b2c59df54e..3d7b831599 100644
--- a/src/include/libpq/libpq-be.h
+++ b/src/include/libpq/libpq-be.h
@@ -70,8 +70,7 @@ typedef struct
 
 typedef enum CAC_state
 {
-       CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY,
-       CAC_WAITBACKUP
+       CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY
 } CAC_state;
 
 
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index d6b32c070c..687056ba55 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -447,8 +447,4 @@ extern void process_session_preload_libraries(void);
 extern void pg_bindtextdomain(const char *domain);
 extern bool has_rolreplication(Oid roleid);
 
-/* in access/transam/xlog.c */
-extern bool BackupInProgress(void);
-extern void CancelBackup(void);
-
 #endif                                                 /* MISCADMIN_H */
diff --git a/src/test/perl/PostgresNode.pm b/src/test/perl/PostgresNode.pm
index 8a2c6fc122..4c27a7d362 100644
--- a/src/test/perl/PostgresNode.pm
+++ b/src/test/perl/PostgresNode.pm
@@ -546,25 +546,6 @@ sub backup
        return;
 }
 
-=item $node->backup_fs_hot(backup_name)
-
-Create a backup with a filesystem level copy in subdirectory B<backup_name> of
-B<< $node->backup_dir >>, including WAL.
-
-Archiving must be enabled, as B<pg_start_backup()> and B<pg_stop_backup()> are
-used. This is not checked or enforced.
-
-The backup name is passed as the backup label to B<pg_start_backup()>.
-
-=cut
-
-sub backup_fs_hot
-{
-       my ($self, $backup_name) = @_;
-       $self->_backup_fs($backup_name, 1);
-       return;
-}
-
 =item $node->backup_fs_cold(backup_name)
 
 Create a backup with a filesystem level copy in subdirectory B<backup_name> of
@@ -578,53 +559,18 @@ Use B<backup> or B<backup_fs_hot> if you want to back up 
a running server.
 sub backup_fs_cold
 {
        my ($self, $backup_name) = @_;
-       $self->_backup_fs($backup_name, 0);
-       return;
-}
-
-
-# Common sub of backup_fs_hot and backup_fs_cold
-sub _backup_fs
-{
-       my ($self, $backup_name, $hot) = @_;
-       my $backup_path = $self->backup_dir . '/' . $backup_name;
-       my $port        = $self->port;
-       my $name        = $self->name;
-
-       print "# Taking filesystem backup $backup_name from node \"$name\"\n";
-
-       if ($hot)
-       {
-               my $stdout = $self->safe_psql('postgres',
-                       "SELECT * FROM pg_start_backup('$backup_name');");
-               print "# pg_start_backup: $stdout\n";
-       }
 
        RecursiveCopy::copypath(
                $self->data_dir,
-               $backup_path,
+               $self->backup_dir . '/' . $backup_name,
                filterfn => sub {
                        my $src = shift;
                        return ($src ne 'log' and $src ne 'postmaster.pid');
                });
 
-       if ($hot)
-       {
-
-               # We ignore pg_stop_backup's return value. We also assume 
archiving
-               # is enabled; otherwise the caller will have to copy the 
remaining
-               # segments.
-               my $stdout =
-                 $self->safe_psql('postgres', 'SELECT * FROM 
pg_stop_backup();');
-               print "# pg_stop_backup: $stdout\n";
-       }
-
-       print "# Backup finished\n";
        return;
 }
 
-
-
 =pod
 
 =item $node->init_from_backup(root_node, backup_name)
diff --git a/src/test/recovery/t/010_logical_decoding_timelines.pl 
b/src/test/recovery/t/010_logical_decoding_timelines.pl
index e582b20005..32dfda454c 100644
--- a/src/test/recovery/t/010_logical_decoding_timelines.pl
+++ b/src/test/recovery/t/010_logical_decoding_timelines.pl
@@ -66,7 +66,9 @@ $node_master->safe_psql('dropme',
 $node_master->safe_psql('postgres', 'CHECKPOINT;');
 
 my $backup_name = 'b1';
-$node_master->backup_fs_hot($backup_name);
+$node_master->stop();
+$node_master->backup_fs_cold($backup_name);
+$node_master->start();
 
 $node_master->safe_psql('postgres',
        q[SELECT pg_create_physical_replication_slot('phys_slot');]);

Reply via email to