fuse: Set `max_pages` in `InitOut`

This field acts as a global upper bound on the size of any request so
read and write requests are truncated to fit this size even if
`max_readahead` and `max_write` are set to larger values.  Initialize
this field to the number of pages needed to fit the largest supported
requset size.

BUG=none
TEST=arc.PlayStore.vm

Change-Id: Ia82d3e5709971c642312c45b26c288a953dedb18
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3299973
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Commit-Queue: Chirantan Ekbote <chirantan@chromium.org>
diff --git a/fuse/src/server.rs b/fuse/src/server.rs
index 77ad89b..4a6362e 100644
--- a/fuse/src/server.rs
+++ b/fuse/src/server.rs
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+use std::cmp::{max, min};
 use std::convert::TryInto;
 use std::ffi::CStr;
 use std::io;
@@ -954,6 +955,7 @@
             | FsOptions::DO_READDIRPLUS
             | FsOptions::READDIRPLUS_AUTO
             | FsOptions::ATOMIC_O_TRUNC
+            | FsOptions::MAX_PAGES
             | FsOptions::MAP_ALIGNMENT;
 
         let capable = FsOptions::from_bits_truncate(flags);
@@ -973,6 +975,11 @@
                     enabled.remove(FsOptions::ATOMIC_O_TRUNC);
                 }
 
+                let max_write = self.fs.max_buffer_size();
+                let max_pages = min(
+                    max(max_readahead, max_write) / pagesize() as u32,
+                    u16::MAX as u32,
+                ) as u16;
                 let out = InitOut {
                     major: KERNEL_VERSION,
                     minor: KERNEL_MINOR_VERSION,
@@ -980,8 +987,9 @@
                     flags: enabled.bits(),
                     max_background: ::std::u16::MAX,
                     congestion_threshold: (::std::u16::MAX / 4) * 3,
-                    max_write: self.fs.max_buffer_size(),
+                    max_write,
                     time_gran: 1, // nanoseconds
+                    max_pages,
                     map_alignment: pagesize().trailing_zeros() as u16,
                     ..Default::default()
                 };
diff --git a/fuse/src/sys.rs b/fuse/src/sys.rs
index 0c3af6a..07e1b6a 100644
--- a/fuse/src/sys.rs
+++ b/fuse/src/sys.rs
@@ -363,6 +363,13 @@
         /// mapping requests are pagesize-aligned. This field automatically set by the server and
         /// this feature is enabled by default.
         const MAP_ALIGNMENT = MAP_ALIGNMENT;
+
+
+        /// Indicates that the `max_pages` field of the `InitOut` struct is valid.
+        ///
+        /// This field is used by the kernel driver to determine the maximum number of pages that
+        /// may be used for any read or write requests.
+        const MAX_PAGES = MAX_PAGES;
     }
 }