diff --git a/src/bin/pg_upgrade/file.c b/src/bin/pg_upgrade/file.c
index b33f0b46e346fdde514ddda9509a1255182f3655..3e04c1a33e8ebce3155587dde6c50cf8d85f7d8b 100644
--- a/src/bin/pg_upgrade/file.c
+++ b/src/bin/pg_upgrade/file.c
@@ -18,8 +18,6 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
-#define BITS_PER_HEAPBLOCK_OLD 1
-
 
 #ifndef WIN32
 static int	copy_file(const char *fromfile, const char *tofile);
@@ -84,10 +82,11 @@ copy_file(const char *srcfile, const char *dstfile)
 		return -1;
 	}
 
-	if ((src_fd = open(srcfile, O_RDONLY, 0)) < 0)
+	if ((src_fd = open(srcfile, O_RDONLY | PG_BINARY, 0)) < 0)
 		return -1;
 
-	if ((dest_fd = open(dstfile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
+	if ((dest_fd = open(dstfile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
+						S_IRUSR | S_IWUSR)) < 0)
 	{
 		save_errno = errno;
 
@@ -153,31 +152,30 @@ copy_file(const char *srcfile, const char *dstfile)
  * version, we could refuse to copy visibility maps from the old cluster
  * to the new cluster; the next VACUUM would recreate them, but at the
  * price of scanning the entire table.  So, instead, we rewrite the old
- * visibility maps in the new format.  That way, the all-visible bit
- * remains set for the pages for which it was set previously.  The
- * all-frozen bit is never set by this conversion; we leave that to
- * VACUUM.
+ * visibility maps in the new format.  That way, the all-visible bits
+ * remain set for the pages for which they were set previously.  The
+ * all-frozen bits are never set by this conversion; we leave that to VACUUM.
  */
 const char *
 rewriteVisibilityMap(const char *fromfile, const char *tofile)
 {
-	int			src_fd = 0;
-	int			dst_fd = 0;
-	char		buffer[BLCKSZ];
-	ssize_t		bytesRead;
+	int			src_fd;
+	int			dst_fd;
+	char	   *buffer;
+	char	   *new_vmbuf;
 	ssize_t		totalBytesRead = 0;
 	ssize_t		src_filesize;
 	int			rewriteVmBytesPerPage;
 	BlockNumber new_blkno = 0;
 	struct stat statbuf;
 
-	/* Compute we need how many old page bytes to rewrite a new page */
+	/* Compute number of old-format bytes per new page */
 	rewriteVmBytesPerPage = (BLCKSZ - SizeOfPageHeaderData) / 2;
 
 	if ((fromfile == NULL) || (tofile == NULL))
 		return "Invalid old file or new file";
 
-	if ((src_fd = open(fromfile, O_RDONLY, 0)) < 0)
+	if ((src_fd = open(fromfile, O_RDONLY | PG_BINARY, 0)) < 0)
 		return getErrorText();
 
 	if (fstat(src_fd, &statbuf) != 0)
@@ -186,7 +184,8 @@ rewriteVisibilityMap(const char *fromfile, const char *tofile)
 		return getErrorText();
 	}
 
-	if ((dst_fd = open(tofile, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0)
+	if ((dst_fd = open(tofile, O_RDWR | O_CREAT | O_EXCL | PG_BINARY,
+					   S_IRUSR | S_IWUSR)) < 0)
 	{
 		close(src_fd);
 		return getErrorText();
@@ -195,14 +194,22 @@ rewriteVisibilityMap(const char *fromfile, const char *tofile)
 	/* Save old file size */
 	src_filesize = statbuf.st_size;
 
+	/*
+	 * Malloc the work buffers, rather than making them local arrays, to
+	 * ensure adequate alignment.
+	 */
+	buffer = (char *) pg_malloc(BLCKSZ);
+	new_vmbuf = (char *) pg_malloc(BLCKSZ);
+
 	/*
 	 * Turn each visibility map page into 2 pages one by one. Each new page
-	 * has the same page header as the old one.  If the last section of last
-	 * page is empty, we skip it, mostly to avoid turning one-page visibility
-	 * maps for small relations into two pages needlessly.
+	 * has the same page header as the old one.  If the last section of the
+	 * last page is empty, we skip it, mostly to avoid turning one-page
+	 * visibility maps for small relations into two pages needlessly.
 	 */
 	while (totalBytesRead < src_filesize)
 	{
+		ssize_t		bytesRead;
 		char	   *old_cur;
 		char	   *old_break;
 		char	   *old_blkend;
@@ -225,61 +232,59 @@ rewriteVisibilityMap(const char *fromfile, const char *tofile)
 		/*
 		 * These old_* variables point to old visibility map page. old_cur
 		 * points to current position on old page. old_blkend points to end of
-		 * old block. old_break points to old page break position for
-		 * rewriting a new page. After wrote a new page, old_break proceeds
-		 * rewriteVmBytesPerPage bytes.
+		 * old block.  old_break is the end+1 position on the old page for the
+		 * data that will be transferred to the current new page.
 		 */
 		old_cur = buffer + SizeOfPageHeaderData;
 		old_blkend = buffer + bytesRead;
 		old_break = old_cur + rewriteVmBytesPerPage;
 
-		while (old_blkend >= old_break)
+		while (old_break <= old_blkend)
 		{
-			char		new_vmbuf[BLCKSZ];
-			char	   *new_cur = new_vmbuf;
+			char	   *new_cur;
 			bool		empty = true;
 			bool		old_lastpart;
 
-			/* Copy page header in advance */
+			/* First, copy old page header to new page */
 			memcpy(new_vmbuf, &pageheader, SizeOfPageHeaderData);
 
-			/* Rewrite the last part of the old page? */
-			old_lastpart = old_lastblk && (old_blkend == old_break);
+			/* Rewriting the last part of the last old page? */
+			old_lastpart = old_lastblk && (old_break == old_blkend);
 
-			new_cur += SizeOfPageHeaderData;
+			new_cur = new_vmbuf + SizeOfPageHeaderData;
 
 			/* Process old page bytes one by one, and turn it into new page. */
-			while (old_break > old_cur)
+			while (old_cur < old_break)
 			{
+				uint8		byte = *(uint8 *) old_cur;
 				uint16		new_vmbits = 0;
 				int			i;
 
 				/* Generate new format bits while keeping old information */
 				for (i = 0; i < BITS_PER_BYTE; i++)
 				{
-					uint8		byte = *(uint8 *) old_cur;
-
-					if (byte & (1 << (BITS_PER_HEAPBLOCK_OLD * i)))
+					if (byte & (1 << i))
 					{
 						empty = false;
-						new_vmbits |= 1 << (BITS_PER_HEAPBLOCK * i);
+						new_vmbits |=
+							VISIBILITYMAP_ALL_VISIBLE << (BITS_PER_HEAPBLOCK * i);
 					}
 				}
 
-				/* Copy new visibility map bit to new format page */
-				memcpy(new_cur, &new_vmbits, BITS_PER_HEAPBLOCK);
+				/* Copy new visibility map bytes to new-format page */
+				new_cur[0] = (char) (new_vmbits & 0xFF);
+				new_cur[1] = (char) (new_vmbits >> 8);
 
-				old_cur += BITS_PER_HEAPBLOCK_OLD;
+				old_cur++;
 				new_cur += BITS_PER_HEAPBLOCK;
 			}
 
-			/* If the last part of the old page is empty, skip writing it */
+			/* If the last part of the last page is empty, skip writing it */
 			if (old_lastpart && empty)
 				break;
 
-			/* Set new checksum for a visibility map page (if enabled) */
-			if (old_cluster.controldata.data_checksum_version != 0 &&
-				new_cluster.controldata.data_checksum_version != 0)
+			/* Set new checksum for visibility map page, if enabled */
+			if (new_cluster.controldata.data_checksum_version != 0)
 				((PageHeader) new_vmbuf)->pd_checksum =
 					pg_checksum_page(new_vmbuf, new_blkno);
 
@@ -290,17 +295,19 @@ rewriteVisibilityMap(const char *fromfile, const char *tofile)
 				return getErrorText();
 			}
 
+			/* Advance for next new page */
 			old_break += rewriteVmBytesPerPage;
 			new_blkno++;
 		}
 	}
 
-	/* Close files */
+	/* Clean up */
+	pg_free(buffer);
+	pg_free(new_vmbuf);
 	close(dst_fd);
 	close(src_fd);
 
 	return NULL;
-
 }
 
 void