diff --git a/src/backend/storage/file/copydir.c b/src/backend/storage/file/copydir.c
index a51ee81..d80d18a 100644
--- a/src/backend/storage/file/copydir.c
+++ b/src/backend/storage/file/copydir.c
@@ -192,7 +192,7 @@ copy_file(char *fromfile, char *tofile)
 		 * cache and hopefully get the kernel to start writing them out before
 		 * the fsync comes.
 		 */
-		pg_flush_data(dstfd, offset, nbytes);
+		pg_flush_data(dstfd, offset, nbytes, false);
 	}
 
 	if (CloseTransientFile(dstfd))
diff --git a/src/backend/storage/file/fd.c b/src/backend/storage/file/fd.c
index 3e02dce..f5da08c 100644
--- a/src/backend/storage/file/fd.c
+++ b/src/backend/storage/file/fd.c
@@ -395,8 +395,10 @@ pg_fdatasync(int fd)
  * flushed.
  */
 void
-pg_flush_data(int fd, off_t offset, off_t nbytes)
+pg_flush_data(int fd, off_t offset, off_t nbytes, bool isdir)
 {
+	(void) isdir;  	/* this can be unused on some archs */
+
 	/*
 	 * Right now file flushing is primarily used to avoid making later
 	 * fsync()/fdatasync() calls have a less impact. Thus don't trigger
@@ -451,8 +453,31 @@ pg_flush_data(int fd, off_t offset, off_t nbytes)
 		 * We map the file (mmap()), tell the kernel to sync back the contents
 		 * (msync()), and then remove the mapping again (munmap()).
 		 */
+
+		/* mmap() will not work with dirs */
+		if (isdir)
+			return;
+
+		/* mmap() need exact length when we want to map whole file */
+		if ((offset == 0) && (nbytes == 0))
+		{
+			int pagesize = sysconf(_SC_PAGESIZE);
+
+			nbytes = lseek(fd, 0, SEEK_END);
+			if (nbytes < 0)
+				ereport(WARNING,
+						(errcode_for_file_access(),
+						 errmsg("could not determine dirty data size: %m")));
+
+			/* aling to pagesize with underestimation */
+			nbytes = (nbytes/pagesize)*pagesize;
+
+			if(nbytes == 0)
+				return;
+		}
+
 		p = mmap(NULL, nbytes,
-				 PROT_READ | PROT_WRITE, MAP_SHARED,
+				 PROT_READ, MAP_SHARED,
 				 fd, offset);
 		if (p == MAP_FAILED)
 		{
@@ -1514,7 +1539,7 @@ FileWriteback(File file, off_t offset, int amount)
 	if (returnCode < 0)
 		return;
 
-	pg_flush_data(VfdCache[file].fd, offset, amount);
+	pg_flush_data(VfdCache[file].fd, offset, amount, false);
 }
 
 int
@@ -2920,7 +2945,7 @@ pre_sync_fname(const char *fname, bool isdir, int elevel)
 	 * pg_flush_data() ignores errors, which is ok because this is only a
 	 * hint.
 	 */
-	pg_flush_data(fd, 0, 0);
+	pg_flush_data(fd, 0, 0, isdir);
 
 	(void) CloseTransientFile(fd);
 }
diff --git a/src/include/storage/fd.h b/src/include/storage/fd.h
index be24369..60246f7 100644
--- a/src/include/storage/fd.h
+++ b/src/include/storage/fd.h
@@ -116,7 +116,7 @@ extern int	pg_fsync(int fd);
 extern int	pg_fsync_no_writethrough(int fd);
 extern int	pg_fsync_writethrough(int fd);
 extern int	pg_fdatasync(int fd);
-extern void pg_flush_data(int fd, off_t offset, off_t amount);
+extern void pg_flush_data(int fd, off_t offset, off_t amount, bool isdir);
 extern void fsync_fname(const char *fname, bool isdir);
 extern int	durable_rename(const char *oldfile, const char *newfile, int loglevel);
 extern int	durable_link_or_rename(const char *oldfile, const char *newfile, int loglevel);
