[fs] Avoid running out of memory during maxfile test

Since we currently do not support paging out large files,
avoid surpassing total physical system memory during
maxfile tests.

ZX-1604 #comment In Progress

Change-Id: Ibc8ab7fae77fc201e747e2b15f22347d09ec33b3
diff --git a/system/utest/fs/test-maxfile.cpp b/system/utest/fs/test-maxfile.cpp
index c324451..db4f49c 100644
--- a/system/utest/fs/test-maxfile.cpp
+++ b/system/utest/fs/test-maxfile.cpp
@@ -11,6 +11,7 @@
 #include <unistd.h>
 
 #include <fbl/algorithm.h>
+#include <zircon/syscalls.h>
 
 #include "filesystems.h"
 #include "misc.h"
@@ -34,6 +35,12 @@
         return true;
     }
 
+    // TODO(ZX-1735): We avoid making files that consume more than half
+    // of physical memory. When we can page out files, this restriction
+    // should be removed.
+    const size_t physmem = zx_system_get_physmem();
+    const size_t max_cap = physmem / 2;
+
     int fd = open("::bigfile", O_CREAT | O_RDWR, 0644);
     ASSERT_GT(fd, 0);
     char data_a[8192];
@@ -42,7 +49,7 @@
     memset(data_a, 0xaa, sizeof(data_a));
     memset(data_b, 0xbb, sizeof(data_b));
     memset(data_c, 0xcc, sizeof(data_c));
-    ssize_t sz = 0;
+    size_t sz = 0;
     ssize_t r;
 
     auto rotate = [&](const char* data) {
@@ -57,6 +64,12 @@
 
     const char* data = data_a;
     for (;;) {
+        if (sz >= max_cap) {
+            fprintf(stderr, "Approaching physical memory capacity: %zd bytes\n", sz);
+            r = 0;
+            break;
+        }
+
         if ((r = write(fd, data, sizeof(data_a))) < 0) {
             fprintf(stderr, "bigfile received error: %s\n", strerror(errno));
             if ((errno == EFBIG) || (errno == ENOSPC)) {
@@ -68,23 +81,20 @@
             break;
         }
         if ((sz + r) % PRINT_SIZE < (sz % PRINT_SIZE)) {
-            fprintf(stderr, "wrote %lu MB\n", static_cast<size_t>((sz + r) / MB));
+            fprintf(stderr, "wrote %lu MB\n", (sz + r) / MB);
         }
         sz += r;
-        if (r < (ssize_t)(sizeof(data_a))) {
-            fprintf(stderr, "bigfile write short write of %ld bytes\n", r);
-            break;
-        }
+        ASSERT_EQ(r, sizeof(data_a));
 
         // Rotate which data buffer we use
         data = rotate(data);
     }
     ASSERT_EQ(r, 0, "Saw an unexpected error from write");
-    fprintf(stderr, "wrote %lu bytes\n", static_cast<size_t>(sz));
+    fprintf(stderr, "wrote %lu bytes\n", sz);
 
     struct stat buf;
     ASSERT_EQ(fstat(fd, &buf), 0, "Couldn't stat max file");
-    ASSERT_EQ(buf.st_size, sz, "Unexpected max file size");
+    ASSERT_EQ(buf.st_size, static_cast<ssize_t>(sz), "Unexpected max file size");
 
     // Try closing, re-opening, and verifying the file
     ASSERT_EQ(close(fd), 0);
@@ -94,13 +104,13 @@
     fd = open("::bigfile", O_RDWR, 0644);
     ASSERT_GT(fd, 0);
     ASSERT_EQ(fstat(fd, &buf), 0, "Couldn't stat max file");
-    ASSERT_EQ(buf.st_size, sz, "Unexpected max file size");
+    ASSERT_EQ(buf.st_size, static_cast<ssize_t>(sz), "Unexpected max file size");
     char readbuf[8192];
-    ssize_t bytes_read = 0;
+    size_t bytes_read = 0;
     data = data_a;
     while (bytes_read < sz) {
         r = read(fd, readbuf, sizeof(readbuf));
-        ASSERT_EQ(r, fbl::min(sz - bytes_read, static_cast<ssize_t>(sizeof(readbuf))));
+        ASSERT_EQ(r, static_cast<ssize_t>(fbl::min(sz - bytes_read, sizeof(readbuf))));
         ASSERT_EQ(memcmp(readbuf, data, r), 0, "File failed to verify");
         data = rotate(data);
         bytes_read += r;
@@ -126,6 +136,12 @@
         return true;
     }
 
+    // TODO(ZX-1735): We avoid making files that consume more than half
+    // of physical memory. When we can page out files, this restriction
+    // should be removed.
+    const size_t physmem = zx_system_get_physmem();
+    const size_t max_cap = physmem / 4;
+
     int fda = open("::bigfile-A", O_CREAT | O_RDWR, 0644);
     int fdb = open("::bigfile-B", O_CREAT | O_RDWR, 0644);
     ASSERT_GT(fda, 0);
@@ -134,14 +150,20 @@
     char data_b[8192];
     memset(data_a, 0xaa, sizeof(data_a));
     memset(data_b, 0xbb, sizeof(data_b));
-    ssize_t sz_a = 0;
-    ssize_t sz_b = 0;
+    size_t sz_a = 0;
+    size_t sz_b = 0;
     ssize_t r;
 
-    ssize_t* sz = &sz_a;
+    size_t* sz = &sz_a;
     int fd = fda;
     const char* data = data_a;
     for (;;) {
+        if (*sz >= max_cap) {
+            fprintf(stderr, "Approaching physical memory capacity: %zd bytes\n", *sz);
+            r = 0;
+            break;
+        }
+
         if ((r = write(fd, data, sizeof(data_a))) <= 0) {
             fprintf(stderr, "bigfile received error: %s\n", strerror(errno));
             // Either the file should be too big (EFBIG) or the file should
@@ -151,22 +173,23 @@
             break;
         }
         if ((*sz + r) % PRINT_SIZE < (*sz % PRINT_SIZE)) {
-            fprintf(stderr, "wrote %lu MB\n", static_cast<size_t>((*sz + r) / MB));
+            fprintf(stderr, "wrote %lu MB\n", (*sz + r) / MB);
         }
         *sz += r;
+        ASSERT_EQ(r, sizeof(data_a));
 
         fd = (fd == fda) ? fdb : fda;
         data = (data == data_a) ? data_b : data_a;
         sz = (sz == &sz_a) ? &sz_b : &sz_a;
     }
-    fprintf(stderr, "wrote %lu bytes (to A)\n", static_cast<size_t>(sz_a));
-    fprintf(stderr, "wrote %lu bytes (to B)\n", static_cast<size_t>(sz_b));
+    fprintf(stderr, "wrote %lu bytes (to A)\n", sz_a);
+    fprintf(stderr, "wrote %lu bytes (to B)\n", sz_b);
 
     struct stat buf;
     ASSERT_EQ(fstat(fda, &buf), 0, "Couldn't stat max file");
-    ASSERT_EQ(buf.st_size, sz_a, "Unexpected max file size");
+    ASSERT_EQ(buf.st_size, static_cast<ssize_t>(sz_a), "Unexpected max file size");
     ASSERT_EQ(fstat(fdb, &buf), 0, "Couldn't stat max file");
-    ASSERT_EQ(buf.st_size, sz_b, "Unexpected max file size");
+    ASSERT_EQ(buf.st_size, static_cast<ssize_t>(sz_b), "Unexpected max file size");
 
     // Try closing, re-opening, and verifying the file
     ASSERT_EQ(close(fda), 0);
@@ -180,16 +203,16 @@
     ASSERT_GT(fdb, 0);
 
     char readbuf[8192];
-    ssize_t bytes_read_a = 0;
-    ssize_t bytes_read_b = 0;
+    size_t bytes_read_a = 0;
+    size_t bytes_read_b = 0;
 
     fd = fda;
     data = data_a;
     sz = &sz_a;
-    ssize_t* bytes_read = &bytes_read_a;
+    size_t* bytes_read = &bytes_read_a;
     while (*bytes_read < *sz) {
         r = read(fd, readbuf, sizeof(readbuf));
-        ASSERT_EQ(r, fbl::min(*sz - *bytes_read, static_cast<ssize_t>(sizeof(readbuf))));
+        ASSERT_EQ(r, static_cast<ssize_t>(fbl::min(*sz - *bytes_read, sizeof(readbuf))));
         ASSERT_EQ(memcmp(readbuf, data, r), 0, "File failed to verify");
         *bytes_read += r;