From: Tom Lane <tgl@sss.pgh.pa.us>
To: Álvaro Herrera <alvherre@kurilemu.de>
Cc: Andrew Dunstan <andrew@dunslane.net>
Cc: PostgreSQL Hackers <pgsql-hackers@lists.postgresql.org>
Subject: Re: fix pg_mkdir_p to tolerate concurrent directory creation
Date: Fri, 19 Jun 2026 11:07:58 -0400
Message-ID: <1528024.1781881678@sss.pgh.pa.us> (raw)
In-Reply-To: <ajVLauHFakqDsXsY@alvherre.pgsql>
References: <ajVLauHFakqDsXsY@alvherre.pgsql>
Actually ... given this change, why don't we drop the initial stat()
call? Just try mkdir(), and move on if it succeeds. If not, but
there's already a directory there, we're good. That eliminates the
race condition without duplicating code.
regards, tom lane
Attachments:v3-0001-Make-pg_mkdir_p-tolerant-of-a-concurrent-director.patch (text/x-diff, 1.7K) downloaddiff --git a/src/port/pgmkdirp.c b/src/port/pgmkdirp.cindex 7d7cea4dd0e..3e6b06fce79 100644--- a/src/port/pgmkdirp.c+++ b/src/port/pgmkdirp.c@@ -56,7 +56,6 @@
int
pg_mkdir_p(char *path, int omode)
{
- struct stat sb;
mode_t numask,
oumask;
int last,
@@ -119,24 +118,46 @@ pg_mkdir_p(char *path, int omode)
if (last)
(void) umask(oumask);
- /* check for pre-existing directory */- if (stat(path, &sb) == 0)+ if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)
{
- if (!S_ISDIR(sb.st_mode))+ /*+ * If we got EEXIST because there's already a directory there,+ * don't complain.+ */+#ifndef WIN32+ int save_errno = errno;+ struct stat sb;++ if (save_errno != EEXIST ||+ stat(path, &sb) != 0 ||+ !S_ISDIR(sb.st_mode))
{
- if (last)- errno = EEXIST;- else- errno = ENOTDIR;+ /* Don't let stat replace mkdir's errno */+ errno = save_errno;
retval = -1;
break;
}
+#else /* WIN32 */+ /*+ * On Windows, stat() opens a handle and can transiently fail on a+ * directory another process is concurrently creating. Probe with+ * a path-based attribute query instead: it requests only+ * FILE_READ_ATTRIBUTES and is exempt from share-mode denial, so+ * it reliably sees a concurrently-created directory. We assume+ * GetFileAttributes() won't change errno.+ */+ DWORD attr = GetFileAttributes(path);++ if (errno != EEXIST ||+ attr == INVALID_FILE_ATTRIBUTES ||+ !(attr & FILE_ATTRIBUTE_DIRECTORY))+ {+ retval = -1;+ break;+ }+#endif /* WIN32 */
}
- else if (mkdir(path, last ? omode : S_IRWXU | S_IRWXG | S_IRWXO) < 0)- {- retval = -1;- break;- }+
if (!last)
*p = '/';
}
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: pgsql-hackers@postgresql.org
Cc: tgl@sss.pgh.pa.us, alvherre@kurilemu.de, andrew@dunslane.net, pgsql-hackers@lists.postgresql.org
Subject: Re: fix pg_mkdir_p to tolerate concurrent directory creation
In-Reply-To: <1528024.1781881678@sss.pgh.pa.us>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by DDX for PostgreSQL; see mirroring instructions
for how to clone and mirror all data and code used for this inbox