git: 54d8d0fe12a4 - main - xinstall: use dynamic bufsize as in cat(1) / cp(1).

From: Dag-Erling Smørgrav <des_at_FreeBSD.org>
Date: Wed, 03 Aug 2022 21:02:06 UTC
The branch main has been updated by des:

URL: https://cgit.FreeBSD.org/src/commit/?id=54d8d0fe12a4996427923048ab4261819774fbd4

commit 54d8d0fe12a4996427923048ab4261819774fbd4
Author:     Dag-Erling Smørgrav <des@FreeBSD.org>
AuthorDate: 2022-08-03 21:00:14 +0000
Commit:     Dag-Erling Smørgrav <des@FreeBSD.org>
CommitDate: 2022-08-03 21:01:13 +0000

    xinstall: use dynamic bufsize as in cat(1) / cp(1).
    
    Sponsored by:   Klara, Inc.
---
 usr.bin/xinstall/xinstall.c | 58 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 53 insertions(+), 5 deletions(-)

diff --git a/usr.bin/xinstall/xinstall.c b/usr.bin/xinstall/xinstall.c
index a236838c8fd1..b0e52453ca29 100644
--- a/usr.bin/xinstall/xinstall.c
+++ b/usr.bin/xinstall/xinstall.c
@@ -79,6 +79,21 @@ __FBSDID("$FreeBSD$");
 
 #include "mtree.h"
 
+/*
+ * Memory strategy threshold, in pages: if physmem is larger then this, use a
+ * large buffer.
+ */
+#define PHYSPAGES_THRESHOLD (32*1024)
+
+/* Maximum buffer size in bytes - do not allow it to grow larger than this. */
+#define BUFSIZE_MAX (2*1024*1024)
+
+/*
+ * Small (default) buffer size in bytes. It's inefficient for this to be
+ * smaller than MAXPHYS.
+ */
+#define BUFSIZE_SMALL (MAXPHYS)
+
 /*
  * We need to build xinstall during the bootstrap stage when building on a
  * non-FreeBSD system. Linux does not have the st_flags and st_birthtime
@@ -1139,15 +1154,32 @@ compare(int from_fd, const char *from_name __unused, size_t from_len,
 		}
 	out:
 		if (!done_compare) {
-			char buf1[MAXBSIZE];
-			char buf2[MAXBSIZE];
+			static char *buf, *buf1, *buf2;
+			static size_t bufsize;
 			int n1, n2;
 
+			if (buf == NULL) {
+				/*
+				 * Note that buf and bufsize are static. If
+				 * malloc() fails, it will fail at the start
+				 * and not copy only some files.
+				 */
+				if (sysconf(_SC_PHYS_PAGES) >
+				    PHYSPAGES_THRESHOLD)
+					bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
+				else
+					bufsize = BUFSIZE_SMALL;
+				buf = malloc(bufsize * 2);
+				if (buf == NULL)
+					err(1, "Not enough memory");
+				buf1 = buf;
+				buf2 = buf + bufsize;
+			}
 			rv = 0;
 			lseek(from_fd, 0, SEEK_SET);
 			lseek(to_fd, 0, SEEK_SET);
 			while (rv == 0) {
-				n1 = read(from_fd, buf1, sizeof(buf1));
+				n1 = read(from_fd, buf1, bufsize);
 				if (n1 == 0)
 					break;		/* EOF */
 				else if (n1 > 0) {
@@ -1264,10 +1296,11 @@ static char *
 copy(int from_fd, const char *from_name, int to_fd, const char *to_name,
     off_t size)
 {
+	static char *buf = NULL;
+	static size_t bufsize;
 	int nr, nw;
 	int serrno;
 	char *p;
-	char buf[MAXBSIZE];
 	int done_copy;
 	DIGEST_CTX ctx;
 
@@ -1301,7 +1334,22 @@ copy(int from_fd, const char *from_name, int to_fd, const char *to_name,
 		done_copy = 1;
 	}
 	if (!done_copy) {
-		while ((nr = read(from_fd, buf, sizeof(buf))) > 0) {
+		if (buf == NULL) {
+			/*
+			 * Note that buf and bufsize are static. If
+			 * malloc() fails, it will fail at the start
+			 * and not copy only some files.
+			 */
+			if (sysconf(_SC_PHYS_PAGES) >
+			    PHYSPAGES_THRESHOLD)
+				bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
+			else
+				bufsize = BUFSIZE_SMALL;
+			buf = malloc(bufsize);
+			if (buf == NULL)
+				err(1, "Not enough memory");
+		}
+		while ((nr = read(from_fd, buf, bufsize)) > 0) {
 			if ((nw = write(to_fd, buf, nr)) != nr) {
 				serrno = errno;
 				(void)unlink(to_name);