From 3016ede1dfd972badac65954d6e908f77e3c134b Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Mon, 19 Jul 2021 21:47:16 +0000
Subject: [PATCH 1/2] Support direct I/O on Solaris.

Extend the change done for macOS by commit 2dbe8905 to cover Solaris.
Note that this doesn't affect Illumos (it gained O_DIRECT).

Discussion: https://postgr.es/m/CA%2BhUKG%2BADiyyHe0cun2wfT%2BSVnFVqNYPxoO6J9zcZkVO7%2BNGig%40mail.gmail.com
---
 src/backend/storage/file/fd.c         | 19 +++++++++++++++----
 src/bin/pg_test_fsync/pg_test_fsync.c | 27 +++++++++++++++++++++------
 src/include/storage/fd.h              |  9 ++++++---
 3 files changed, 42 insertions(+), 13 deletions(-)

diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 5d5e8ae94e..78ac2caa8f 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -1057,11 +1057,13 @@ BasicOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode)
 	int			fd;
 
 tryAgain:
-#ifdef PG_O_DIRECT_USE_F_NOCACHE
+#if defined(PG_O_DIRECT_USE_F_NOCACHE) || \
+	defined(PG_O_DIRECT_USE_DIRECTIO_ON)
 
 	/*
 	 * The value we defined to stand in for O_DIRECT when simulating it with
-	 * F_NOCACHE had better not collide with any of the standard flags.
+	 * an extra system call had better not collide with any of the standard
+	 * flags.
 	 */
 	StaticAssertStmt((PG_O_DIRECT &
 					  (O_APPEND |
@@ -1089,10 +1091,19 @@ tryAgain:
 
 	if (fd >= 0)
 	{
-#ifdef PG_O_DIRECT_USE_F_NOCACHE
+#if defined(PG_O_DIRECT_USE_F_NOCACHE) || \
+	defined(PG_O_DIRECT_USE_DIRECTIO_ON)
 		if (fileFlags & PG_O_DIRECT)
 		{
-			if (fcntl(fd, F_NOCACHE, 1) < 0)
+			int			rc;
+
+#if defined(PG_O_DIRECT_USE_F_NOCACHE)
+			rc = fcntl(fd, F_NOCACHE, 1);
+#endif
+#if defined(PG_O_DIRECT_USE_DIRECTIO_ON)
+			rc = directio(fd, DIRECTIO_ON);
+#endif
+			if (rc < 0)
 			{
 				int			save_errno = errno;
 
diff --git a/src/bin/pg_test_fsync/pg_test_fsync.c b/src/bin/pg_test_fsync/pg_test_fsync.c
index fef31844fa..f5e3868c10 100644
--- a/src/bin/pg_test_fsync/pg_test_fsync.c
+++ b/src/bin/pg_test_fsync/pg_test_fsync.c
@@ -221,6 +221,8 @@ handle_args(int argc, char *argv[])
 	printf(_("O_DIRECT supported on this platform for open_datasync and open_sync.\n"));
 #elif defined(F_NOCACHE)
 	printf(_("F_NOCACHE supported on this platform for open_datasync and open_sync.\n"));
+#elif defined(DIRECTIO_ON)
+	printf(_("DIRECTIO_ON supported on this platform for open_datasync and open_sync.\n"));
 #else
 	printf(_("Direct I/O is not supported on this platform.\n"));
 #endif
@@ -271,14 +273,27 @@ open_direct(const char *path, int flags, mode_t mode)
 
 	fd = open(path, flags, mode);
 
-#if !defined(O_DIRECT) && defined(F_NOCACHE)
-	if (fd >= 0 && fcntl(fd, F_NOCACHE, 1) < 0)
+#if !defined(O_DIRECT) && \
+	(defined(F_NOCACHE) || \
+	 defined(DIRECTIO_ON))
+	if (fd >= 0)
 	{
-		int			save_errno = errno;
+		int			rc;
 
-		close(fd);
-		errno = save_errno;
-		return -1;
+#if defined(F_NOCACHE)
+		rc = fcntl(fd, F_NOCACHE, 1);
+#endif
+#if defined(DIRECTIO_ON)
+		rc = directio(fd, DIRECTIO_ON);
+#endif
+		if (rc < 0)
+		{
+			int			save_errno = errno;
+
+			close(fd);
+			errno = save_errno;
+			return -1;
+		}
 	}
 #endif
 
diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h
index 2d843eb992..b04988f818 100644
--- a/src/include/storage/fd.h
+++ b/src/include/storage/fd.h
@@ -82,15 +82,18 @@ extern int	max_safe_fds;
 /*
  * O_DIRECT is not standard, but almost every Unix has it.  We translate it
  * to the appropriate Windows flag in src/port/open.c.  We simulate it with
- * fcntl(F_NOCACHE) on macOS inside fd.c's open() wrapper.  We use the name
- * PG_O_DIRECT rather than defining O_DIRECT in that case (probably not a good
- * idea on a Unix).
+ * extra calls on macOS and Solaris inside fd.c's open() wrapper.  We use the
+ * name PG_O_DIRECT rather than defining O_DIRECT in that case (probably not a
+ * good idea on a Unix).
  */
 #if defined(O_DIRECT)
 #define		PG_O_DIRECT O_DIRECT
 #elif defined(F_NOCACHE)
 #define		PG_O_DIRECT 0x80000000
 #define		PG_O_DIRECT_USE_F_NOCACHE
+#elif defined(DIRECTIO_ON)
+#define		PG_O_DIRECT 0x80000000
+#define		PG_O_DIRECT_USE_DIRECTIO_ON
 #else
 #define		PG_O_DIRECT 0
 #endif
-- 
2.30.2

