100 Commits
Author SHA1 Message Date
Nayana BidariandgVisor bot 021a58b69d Automated rollback of changelist 964518735
PiperOrigin-RevId: 966690028
2026-08-18 11:04:14 -07:00
Nayana BidariandgVisor bot 0890b4de46 Support combined restore of full snapshot and filesystem snapshot.
This change extends the split filesystem checkpoint/restore feature to support
saving and restoring only a subset of filesystems (specified by paths). This
supports a "combined restore" mechanism where some memory files (tmpfs backings)
are restored from the filesystem checkpoint, while others are restored from the
main sentry checkpoint.
- Added `SplitFSCheckpointPaths` to `SaveOpts` to allow specifying paths for
  partial FS checkpoints.
- Updated `createPrivateMemoryFile` to return whether it successfully loaded
  state from the filesystem checkpoint.
- Track which memory files were loaded from the FS checkpoint during restore
  (`fsCheckpointedMfs`) and pass this information to the kernel via context
  (`CtxFSCheckpointedMemoryFiles`).
- In `loadPrivateMemoryFiles` (during sentry restore), only load memory files
  from the sentry checkpoint if they were not already loaded from the FS
  checkpoint.
- Added validation to ensure each memory file is restored from exactly one
  source (no duplicates, and none are missed).

PiperOrigin-RevId: 964518735
2026-08-13 23:52:38 -07:00
gVisor bot da2b92aaba Merge pull request #14031 from ayushr2:pin-cow-fork
PiperOrigin-RevId: 964280051
2026-08-13 14:06:32 -07:00
Konstantin BogomolovandgVisor bot 391478c9f7 Convert memoryFileSaved to MemoryFileMetadataProto.
Replace memoryFileSaved Go struct serialization (via pkg/state) with
a stable, length-prefixed Protobuf schema (MemoryFileMetadataProto)
in pkg/sentry/pgalloc/pgalloc.proto. This decouples MemoryFile checkpointing
from internal Go struct layouts across all save/restore modes.

PiperOrigin-RevId: 962261330
2026-08-10 11:18:36 -07:00
Ayush Ranjan 43e55de71f mm: implement copy-on-fork for pinned pages
MemoryManager.Pin() is used by device proxies (nvproxy, tpuproxy,
rdmaproxy) to pin application pages for DMA, analogous to Linux's
pin_user_pages(FOLL_LONGTERM). Fork() previously made all private pmas
copy-on-write, including pinned ones. The parent's next write to a
pinned page would break copy-on-write and move the parent to a new copy
of the page, while the device continues to DMA to/from the original
page, silently desynchronizing the two. Linux fixed the same bug in
5.9; see Linux commit 70e806e4e645 ("mm: Do early cow for pinned pages
during fork() for ptes").

Match Linux:

- Pin() now breaks copy-on-write on the pinned range, even for
  read-only pins, so that pinned pages are exclusively owned by the
  pinning MemoryManager; compare Linux's
  mm/internal.h:gup_must_unshare(). This also makes pinned pages
  precisely detectable at fork time: they are exactly the pages in
  private non-copy-on-write pmas with more than one reference on the
  MemoryFile.

- Fork() copies possibly-pinned pages to the child immediately, leaving
  the parent's mappings unchanged, instead of making them
  copy-on-write; compare Linux's mm/memory.c:copy_present_ptes() =>
  folio_needs_cow_for_dma(). Detection is gated on the new
  MemoryManager.hasPinned, set by Pin() and never cleared; compare
  Linux's MMF_HAS_PINNED.
2026-08-09 20:51:14 +00:00
Ayush Ranjan 80edb05576 pgalloc: throttle UpdateUsage() scans in proportion to their cost
MemoryFile.UpdateUsage() detects newly-committed pages by asking the
host, via mincore(), about every page not already known to be committed.
This is O(uncommitted pages); in a sandbox with hundreds of GB of memory
under allocation churn, where pages are constantly decommitted and
recommitted, a single scan takes seconds.

Scans were throttled to CONFIG_HZ, which assumes that they are cheap.
Worse, the 10ms deadline was armed before the scan rather than after it,
so a scan exceeding 10ms did not prevent concurrent callers from starting
their own redundant scans.

Both are easy to hit, since reads of /proc/meminfo call UpdateUsage() and
are commonly polled. In a 2-node 8xH200 training job with a ~100GB
resident set, where a Ray memory monitor and the trainer's per-step
logging both read /proc/meminfo periodically, the sentry spent 78% of its
CPU in UpdateUsage() -- 1.65 CPUs' worth, i.e. more than one scan running
at all times. Scanning also contends for the lock that page allocation
needs, so this slowed the application itself: NCCL weight-sync buckets
took ~10s instead of the ~0.23s they take under runc.

Arm the deadline after the scan instead, at commitScanIntervalRatio times
the duration of the scan just completed, bounding scans to 1/8th of a CPU
regardless of sandbox size, and skip scans that would duplicate one
already in progress. Both apply only to full scans (memCgIDs == nil); a
scan restricted to specific memory cgroups is much cheaper and runs
unthrottled, so per-cgroup statistics stay fresh.

Track the in-progress scan in an atomic checked before mu is locked, so
that callers arriving during a scan neither block on mu nor contend for
it with the scan and with page allocation. Such a caller goes on to read
usage.MemoryAccounting, which the ongoing scan updates incrementally
under a different lock, so it observes a partially updated snapshot
rather than a stale one; since a scan only ever increases the counters,
that snapshot lies between the pre-scan and post-scan values. Callers
could already observe a scan's intermediate state, as they read
usage.MemoryAccounting after UpdateUsage() has returned and released mu.

All callers report statistics (/proc/meminfo, cgroupfs memory files,
`runsc events`, `runsc usage`) and already tolerated both the previous
throttle and scans skipped during checkpointing.
2026-07-31 20:33:19 +00:00
Jamie LiuandgVisor bot 8eb346df75 Add runsc wait --fscheckpoint/fsrestore.
Note that runsc wait --fsrestore only waits for filesystem restore operations
to complete for the given container, rather than the whole sandbox (like wait
--fscheckpoint, --checkpoint, and --restore do).

PiperOrigin-RevId: 886982088
2026-03-20 14:44:50 -07:00
Jamie LiuandgVisor bot 33513684bc Implement filesystem-only checkpointing.
- `runsc fscheckpoint` saves a filesystem checkpoint, analogous to `runsc
    checkpoint`. `-direct` and `-leave-running` flags are supported for
    compatibility with `runsc checkpoint`. `-save-restore-exec*` is currently
    not supported due to lack of a use case. `-compression` support is not
    planned (specific files in filesystem checkpoint images may use compression
    as appropriate, but this is an implementation detail).
    `-exclude-committed-zero-pages` is inapplicable.

  - `runsc create -fs-restore-image-path` restores a filesystem checkpoint. The
    `-fs-restore-direct` flag has the same effect as `runsc restore -direct`.
    The behavior of `runsc restore -background` is always in effect for
    filesystem checkpoints.

PiperOrigin-RevId: 885914969
2026-03-18 19:44:48 -07:00
Jamie LiuandgVisor bot 84bc4e3f8f Move vfs.RestoreID to checkpoint.ResourceID.
... and use it everywhere in preference to its string. This is to be able to
reliably inspect pgalloc.MemoryFile.ResourceID().Path in cl/879147587.

PiperOrigin-RevId: 883274090
2026-03-13 12:02:56 -07:00
gVisor bot 64d70682d9 Merge pull request #12656 from nblintao:arm64-64k-pagesize
PiperOrigin-RevId: 880984354
2026-03-09 12:34:22 -07:00
Tao Lin a9f716e19e Address review feedback
- Update copyright year to 2026 for all new files
- Update comment in hostarch_arm64.go to mention 64K page support
  via pagesize_64k build tag
- Add PageSize checks in KVM and Systrap New() constructors to
  fail early on non-4K page sizes
2026-03-04 14:00:13 -08:00
Tao Lin 28cf7f346d Add 64K page size support for ARM64
This adds support for running gVisor on ARM64 systems with 64K page
size (e.g., NVIDIA Grace CPU).

Key changes:

1. hostarch: Split page size constants into separate files selected by
   the `pagesize_64k` build tag. 64K pages use PageShift=16 and
   HugePageShift=29 (512MB huge pages). Remove uint16 from the
   bytecount interface since 64K (2^16) cannot be represented by uint16.

2. ring0: Move page table layout constants to page-size-specific files.
   64K pages use larger page table entries (64K per table) and skip the
   PUD level.

3. ring0/pagetables: Add 3-level page table walker for 64K pages
   (PGD→PMD→PTE, no PUD). Each level indexes 8192 entries (13 bits)
   with 512MB sect pages at the PMD level.

4. sentry/arch: Fix mmap layout constants that overflowed the 48-bit
   address space with 64K pages. Use fixed values for maxMmapRand64
   (1<<45 = 32TB) and minMmapRand64 (1<<30 = 1GB), and compute
   maxStackRand64 using hostarch.PageShift.

5. Bazel build system: Add `--define=pagesize=64k` support that
   propagates the `pagesize_64k` Go build tag to all binaries and tests.

Build with `bazel build --define=pagesize=64k //runsc:runsc` to enable.

Note: Currently only the ptrace platform is supported for 64K pages.
KVM and systrap platforms require additional work.

Updates #8196
2026-03-04 14:00:13 -08:00
Tamir Duberstein 50e6d6f796 Fix S1019 violations and drop suppression 2026-02-10 11:56:13 -08:00
Tamir Duberstein 8791d70dd3 Fix QF1006 violations and drop suppression 2026-02-10 11:55:50 -08:00
Jamie LiuandgVisor bot 063b9ef3db pgalloc: reload ma before ma.commitSeq <= lastCommitSeq check
Otherwise ma is maseg.ValuePtr() from before MemoryFile.mu was dropped for
mincore(), and thus may have been invalidated.

PiperOrigin-RevId: 860549423
2026-01-24 10:04:31 -08:00
Jamie LiuandgVisor bot 8e1e776c58 pgalloc: issue async writes in SaveTo while scanning pages
The amount of time this saves during checkpointing depends on the distribution
of zero pages in MemoryFiles.

PiperOrigin-RevId: 855875693
2026-01-13 14:12:41 -08:00
Jamie LiuandgVisor bot 406172e308 pgalloc,stateio: implement async page saving
Aside from improving checkpointing performance by using AIO to better utilize
disk bandwidth, this makes it possible to parallelize writing pages with
scanning for zero pages (in a following CL).

As part of this, update and document ownership semantics for the state file,
pages metadata file, and pages file, with the following goals:

- Since io.WriteCloser.Close() may flush buffers, it must return a nil error
  before write success is reported

- The pages metadata file is closed while async page saving is in progress (to
  hide the latency of the former)

PiperOrigin-RevId: 814315485
2025-10-02 11:32:53 -07:00
Jamie LiuandgVisor bot a674fce511 Add //pkg/sentry/state/stateio and use it for async page loading.
PiperOrigin-RevId: 812843550
2025-09-29 10:26:57 -07:00
Jamie LiuandgVisor bot c2b981881d pgalloc: one async page loader per pages file
This resolves the "future work" described in MemoryFile.LoadFrom().

PiperOrigin-RevId: 808400892
2025-09-17 22:17:08 -07:00
Etienne PerotandgVisor bot e5a7bf0453 Measure and report the time taken during the sandbox restore process.
PiperOrigin-RevId: 758919824
2025-05-14 18:50:02 -07:00
Etienne PerotandgVisor bot c64198d84b Read pages from the main MemoryFile as early as possible during restore
This change modifies the sandbox restore process such that if the memory
pages are stored as separate files, their contents are optimistically read
from these files as soon as possible during the sandbox restore process,
as opposed to the previous behavior where they were read only after the last
container of the sandbox had been restored.

When memory page data is stored as separate files, the process of restoring
multiple `MemoryFile`s is a bit more intertwined than it appears, for two
reasons:

- The pages metadata file stores data for all `MemoryFile`s one after the
  other. So we must also plumb the pages metadata file reader that is used
  for reading the main `MemoryFile` metadata to the code that also loads the
  private `MemoryFile`s, and ensure that these operations are correctly
  serialized, since the primary `MemoryFile` metadata comes earlier in the
  file.
- The `MemoryFile` page contents are all in the same file, and the byte offset
  within this file at which each each `MemoryFile` begins must be known before
  kicking off async loading of that MemoryFile.

So this change introduces a `PagesFileLoader`, which is meant to be a
thread-safe struct that keeps track of this process. It owns the FDs for the
pages and page metadata files and handles the serialization of the operations
executed using these FDs.

Support for the previous checkpoint/restore format (with all data in a single
file) is maintained using a synchronous alternative that implements the same
interface but simply loads everything from the shared state file reader when
the time to do so comes around.

PiperOrigin-RevId: 743727664
2025-04-03 15:59:05 -07:00
Jamie LiuandgVisor bot ca3b10bf13 pgalloc: mark aborted async page load segments as unstarted
Fixes #11592

PiperOrigin-RevId: 741587758
2025-03-28 11:22:23 -07:00
Jamie LiuandgVisor bot ea32cf5371 pgalloc: avoid unnecessary aplOp allocation in async page loading
PiperOrigin-RevId: 740398585
2025-03-25 10:32:00 -07:00
Jamie LiuandgVisor bot fadb41f605 pgalloc: log async page loading progress and info about awaited loads
PiperOrigin-RevId: 738555942
2025-03-19 15:17:36 -07:00
Jamie LiuandgVisor bot 4e2d9c777b Add memmap.File.MemoryType()
This has no effect (outside of debug logging) until cl/723723715.

Updates #11436

PiperOrigin-RevId: 736686635
2025-03-13 17:08:52 -07:00
Jamie LiuandgVisor bot c1e549ae3d pgalloc: no-op MemoryFile.UpdateUsage() during saving
During checkpointing, MemoryFile.SaveTo() narrows the set of pages known by
memory accounting to be "committed" to those containing non-zero bytes, in
order to avoid saving zero pages and therefore bloating the checkpoint. In the
process of doing so, it needs to touch pages in order to determine whether they
contain non-zero bytes, and does so without holding MemoryFile.mu (in a
MemoryFile.updateUsageLocked() callback). Thus, a concurrent call to
MemoryFile.UpdateUsage() => MemoryFile.updateUsageLocked() can racily observe
that touched zero pages are committed (via mincore()) and mark them
known-committed accordingly, causing them to be unintentionally saved in the
checkpoint.

When SaveOpts.ExcludeCommittedZeroPages is set, MemoryFile.SaveTo() does not
decommit previously-known-committed zero pages, since doing so would cost time;
the motivation for decommitting zero pages is to avoid increasing (real, host)
memory usage during checkpointing, but previously-known-committed pages must
have been using memory even before being touched. However, this significantly
widens the race window described above, since any future call to
MemoryFile.UpdateUsage() will observe said pages to be committed and mark them
known-committed again, effectively negating SaveOpts.ExcludeCommittedZeroPages.

To fix this, inhibit MemoryFile.UpdateUsage() during MemoryFile.SaveTo(); in
essence, when MemoryFile.SaveTo() is in progress, it exclusively defines what
pages are known-committed.

PiperOrigin-RevId: 733876220
2025-03-05 14:50:59 -08:00
Ayush RanjanandgVisor bot b835273cbe Add more context to errors during restore.
This will help with debugging restore failures.

PiperOrigin-RevId: 693436013
2024-11-05 12:18:57 -08:00
Jamie LiuandgVisor bot 146cf1a2f2 mm: limit AddressSpace overmapping during async page loading
On platforms that do not create page table entries in
platform.AddressSpace.MapFile(precommit=false), i.e. platforms for which
platform.Platform.MapUnit() == 0, platform.AddressSpace.MapFile() is generally
implemented as some form of host mmap(), which only synchronously creates host
kernel VMAs (virtual memory areas) and creates page table entries lazily in
response to application faults. On such platforms, MM.mapAsLocked() creates the
largest possible host VMAs since doing so reduces future sentry-handled page
faults and has effectively no additional cost. However, when async page loading
is active, this must wait for all mapped pages to be loaded, which may result
in the faulting application blocking for significantly longer than expected (in
experiments, a single page fault could result in waiting for up to 64GB of data
to be loaded). In such cases, additionally constrain mapped sizes to limit wait
times.

PiperOrigin-RevId: 680699946
2024-09-30 13:39:11 -07:00
Jamie LiuandgVisor bot 20bc6bdeb0 pgalloc: integrate async page loading
When a pages file is provided to `runsc restore`, reads from that file are
asynchronous (via statefile.AsyncReader) in order to maximize throughput.
However, all such reads must complete before Kernel.LoadFrom() returns, so
applications cannot execute before MemoryFile loading is complete. The main
objective of this CL is to allow reads to continue after Kernel.LoadFrom()
returns, allowing applications to execute while MemoryFile loading is still in
progress. This behavior is user-visible: it affects whether deleting the pages
file frees disk space immediately on POSIX filesystems, may affect whether
deletion is possible on non-POSIX filesystems, and prevents unmounting
regardless. Thus it is flag-guarded as `runsc restore --background`.

MemoryFile ranges that have yet to be loaded, but that are being waited-for by
applications, should be prioritized over ranges for which no application is
waiting. This requires that application requests for data (calls to
MemoryFile.(memmap.File).DataFD/MapInternal()) are able to determine which
ranges have not yet been loaded, request reads for such ranges with elevated
priority, and wait for only those reads to be completed; none of these are
supported by the existing statefile.AsyncReader.

Thus:

- Add //pkg/sentry/pgalloc/aio, which provides an async I/O API that is
  designed to be easily implementable using a goroutine pool, Linux native AIO,
  or io_uring, though only includes a goroutine pool implementation. (io_uring
  is widely disabled due to security vulnerabilities. In my testing, Linux
  native AIO is slower than the goroutine pool, but this may change with lower
  GOMAXPROCS which needs further testing.)

- Move I/O scheduling into pgalloc: introduce an async page loader goroutine
  that is started by MemoryFile.LoadFrom() when async page loading is requested
  (implicitly, via the existence of a pages file), which is responsible for
  driving submission of read requests and handling their completions.

PiperOrigin-RevId: 679321884
2024-09-26 15:51:13 -07:00
Jamie LiuandgVisor bot e5cce3dbe2 Add memmap.File.DataFD().
This is used in cl/674746696 to ensure that users of MemoryFile data wait until
that data has been loaded.

PiperOrigin-RevId: 679255898
2024-09-26 12:51:20 -07:00
Jamie LiuandgVisor bot 173455bb07 state/wire: do not use sync.Pool for single-byte buffers
This package critically depends on reading/writing single bytes. Since
arguments to interface methods io.Reader.Read / io.Writer.Write escape, a naive
implementation would heap-allocate a one-byte array per read/write.

Prior to cl/625167495, the wire package provided custom Reader/Writer
interfaces, implementations of which were required to provide their own
ReadByte/WriteByte methods that did not take any escaping arguments.
cl/625167495 eliminated these interfaces and made the wire package use
sync.Pool to allocate one-byte arrays instead, simplifying the pipelining of
readers and writers but introducing non-trivial overhead. This CL re-introduces
wire.Reader/Writer, but as structs combining an io.Reader/Writer and a one-byte
array; this preserves the relative ease of using arbitrary io.Readers/Writers,
while eliminating sync.Pool overhead by essentially having callers of the wire
package provide the persistent buffer.

PiperOrigin-RevId: 666946511
2024-08-23 15:45:22 -07:00
Jamie LiuandgVisor bot 3961c65662 pgalloc: log additional save/load stats
PiperOrigin-RevId: 666569217
2024-08-22 18:32:33 -07:00
Jamie LiuandgVisor bot a83fa49ef9 Add explicit huge page and memory recycling support to pgalloc.MemoryFile.
This CL addresses the following major issues:

- When an application releases memory to the sentry, the sentry unconditionally
  releases that memory to the host, rather than allowing it to be reused for
  future allocations, in order to ensure that new allocations are uniformly
  decommitted (use no memory): cl/145016083. In most cases, this should have
  relatively little performance impact; since releasing memory from the
  application to the OS is expensive even outside of gVisor, application memory
  allocators optimizing for performance already limit the rate at which they
  release memory to the OS. However, in applications that involve frequent
  process creation and exit (e.g. build systems), this practice prevents reuse
  of memory deallocated by exiting processes for memory allocated by new
  processes, resulting in both performance degradation and a spike in memory
  usage (since the sentry may not have released all deallocated memory to the
  host by the time new allocations occur).

- gVisor's historical approach to application THP is based on THP being enabled
  on a per-memfd basis, using the MFD_HUGEPAGE flag not merged into the
  upstream Linux kernel
  (https://patchwork.kernel.org/project/linux-mm/patch/[email protected]/).
  Thus, on vanilla Linux kernels, gVisor cannot use THP for application memory
  without requiring the system to enable THP for all tmpfs files and memfds (by
  setting /sys/kernel/mm/transparent_hugepage/shmem_enabled to "always" or
  "force").

- Both MM and the application page allocator (pgalloc) are agnostic as to
  whether the underlying memory file will be THP-backed. Instead, both attempt
  to align hugepage-sized and larger allocations to hugepage boundaries, such
  that if the memory file happens to support THP then such allocations will be
  appropriately aligned to use THP. This is suboptimal since many allocations
  do not benefit from THP, resulting in memory underutilization.

These issues are especially relevant to platforms based on hardware
virtualization, where acquiring memory from the host is significantly more
expensive due to EPT/NPT fault overhead; when effective, THP reduces the
frequency with which said cost is incurred by a factor of 512, and page reuse
avoids incurring it at all.

Thus:

- Instead of inferring whether THP use is desired from allocation size,
  indicate this explicitly as AllocOpts.Huge, and only set it to true for
  allocations for non-stack private anonymous mappings.

- Add AllocateCallerIndirectCommit, a new possible value for AllocOpts.Mode
  that indicates that the caller will commit all pages in the allocation. In
  such cases, pgalloc can reuse deallocated pages without risking increased
  memory usage, internally referred to as "recycling".
  AllocateCallerIndirectCommit is used primarily for page faults on a
  THP-backed region. (It is also used for single-page allocations on non-THP
  backed regions, but due to expansion of faults to mm.privateAllocUnit-aligned
  ranges, this is relatively uncommon.)

- Allow different chunks in pgalloc.MemoryFile's backing file to have varying
  THP-ness, indicated to the host using MADV_HUGEPAGE/NOHUGEPAGE.

- Split pgalloc.MemoryFile's existing page metadata set into two sets tracking
  deallocated pages for small/huge-page-backed regions respectively; two sets
  tracking in-use pages for small/huge-page-backed regions respectively; and a
  fifth set tracking memory accounting state.

- Add MemoryFileOpts.DisableMemoryAccounting; this is primarily intended for
  pgalloc tests, but may also be applicable to disk-backed MemoryFiles.

Cleanup:

- Remove MemoryFile.usageSwapped; the UpdateUsage() optimization it enabled,
  described in updateUsageLocked(), was based on the condition that
  MemoryFile.mu would be locked throughout the call to updateUsageLocked(),
  which was invalidated by cl/337865250.

- Remove MemoryFileOpts.ManualZeroing, which is unused.

- Rename "reclaiming" to "releasing"; the former is confusing since "reclaim"
  in Linux has a significantly different meaning (essentially "eviction" in
  pgalloc), and the latter seems to be conventional in user-mode memory
  allocators.

Using THP for application memory requires setting
/sys/kernel/mm/transparent_hugepage/shmem_enabled to "advise", in order to
allow runsc to request THP from the kernel.

After this CL, pgalloc.MemoryFile still releases memory to the host as fast as
possible, limiting the effectiveness of page recycling. A following CL adds
optional memory release throttling to improve this.

Performance outcomes vary by workload and platform. (In all of the below,
"baseline" is without this CL, "expt" is with this CL, and "expt2" is with this
CL + reclaim throttling (cl/575046398).)

For systrap in GKE: As noted, this change is required to enable application THP
without forcing it on all host shmem users. In conjunction with recycling
(which has a relatively small effect on systrap since it does not use hardware
virtualization), THP use slightly improves performance, although whether this
is measurable is case-dependent. On an idle VM, with shmem_enabled = "advise":

```
goos: linux
goarch: amd64
cpu: Intel(R) Xeon(R) CPU @ 2.80GHz
                                                │  baseline  │               expt                │               expt2               │
                                                │   sec/op   │   sec/op    vs base               │   sec/op    vs base               │
BuildABSL/page_cache.clean/filesystem.bindfs-16   39.09 ± 4%   38.84 ± 5%       ~ (p=0.947 n=30)   38.84 ± 3%       ~ (p=0.854 n=30)
BuildABSL/page_cache.dirty/filesystem.bindfs-16   37.83 ± 3%   36.58 ± 4%       ~ (p=0.057 n=30)   36.83 ± 5%       ~ (p=0.314 n=30)
BuildABSL/page_cache.clean/filesystem.tmpfs-16    39.34 ± 3%   38.59 ± 4%       ~ (p=0.350 n=30)   38.58 ± 4%       ~ (p=0.300 n=30)
BuildABSL/page_cache.dirty/filesystem.tmpfs-16    37.83 ± 3%   36.08 ± 4%  -4.64% (p=0.026 n=30)   36.58 ± 4%       ~ (p=0.123 n=30)
BuildABSL/page_cache.clean/filesystem.rootfs-16   39.59 ± 4%   38.83 ± 3%       ~ (p=0.485 n=30)   40.09 ± 5%       ~ (p=0.971 n=30)
BuildABSL/page_cache.dirty/filesystem.rootfs-16   36.83 ± 3%   38.08 ± 5%       ~ (p=0.307 n=30)   38.08 ± 1%       ~ (p=0.242 n=30)
BuildABSL/page_cache.clean/filesystem.fusefs-16   38.34 ± 3%   37.59 ± 5%       ~ (p=0.752 n=30)   38.59 ± 3%       ~ (p=0.982 n=30)
BuildABSL/page_cache.dirty/filesystem.fusefs-16   37.58 ± 4%   38.08 ± 5%       ~ (p=0.708 n=30)   36.08 ± 6%       ~ (p=0.127 n=30)
BuildGRPC/page_cache.clean/filesystem.bindfs-16   212.7 ± 2%   211.0 ± 1%       ~ (p=0.138 n=30)   211.2 ± 1%       ~ (p=0.458 n=30)
BuildGRPC/page_cache.dirty/filesystem.bindfs-16   210.0 ± 1%   210.0 ± 1%       ~ (p=0.542 n=30)   209.7 ± 1%       ~ (p=0.665 n=30)
BuildGRPC/page_cache.clean/filesystem.rootfs-16   210.5 ± 1%   210.0 ± 1%       ~ (p=0.423 n=30)   210.0 ± 1%       ~ (p=0.142 n=30)
BuildGRPC/page_cache.dirty/filesystem.rootfs-16   210.2 ± 1%   209.0 ± 1%       ~ (p=0.219 n=30)   209.5 ± 1%       ~ (p=0.230 n=30)
geomean                                           67.62        66.97       -0.96%                  67.12       -0.74%
```

The KVM platform benefits significantly from reduced nested page faults due to
huge pages, and to a lesser extent due to recycling:

```
goos: linux
goarch: amd64
cpu: Intel(R) Xeon(R) W-2135 CPU @ 3.70GHz
                                                │  baseline  │                 expt                  │                 expt2                 │
                                                │   sec/op   │   sec/op    vs base                   │   sec/op    vs base                   │
BuildABSL/page_cache.clean/filesystem.bindfs-12   43.11 ± 2%   39.35 ± 3%   -8.71% (p=0.000 n=20)      38.10 ± 4%  -11.63% (p=0.000 n=20+19)
BuildABSL/page_cache.dirty/filesystem.bindfs-12   42.35 ± 3%   39.09 ± 4%   -7.69% (p=0.000 n=20+19)   39.09 ± 5%   -7.69% (p=0.000 n=20+19)
BuildABSL/page_cache.clean/filesystem.tmpfs-12    42.35 ± 3%   38.34 ± 5%   -9.46% (p=0.000 n=20)      38.59 ± 3%   -8.87% (p=0.000 n=20+19)
BuildABSL/page_cache.dirty/filesystem.tmpfs-12    42.09 ± 1%   37.59 ± 4%  -10.70% (p=0.000 n=20)      38.09 ± 4%   -9.51% (p=0.000 n=20+19)
BuildABSL/page_cache.clean/filesystem.rootfs-12   42.85 ± 3%   38.84 ± 3%   -9.35% (p=0.000 n=20)      39.09 ± 3%   -8.77% (p=0.000 n=20+17)
BuildABSL/page_cache.dirty/filesystem.rootfs-12   41.85 ± 2%   39.59 ± 6%   -5.40% (p=0.000 n=20+19)   38.09 ± 3%   -9.00% (p=0.000 n=20+19)
BuildABSL/page_cache.clean/filesystem.fusefs-12   42.60 ± 2%   38.34 ± 2%  -10.00% (p=0.000 n=20)      39.59 ± 3%   -7.06% (p=0.000 n=20+19)
BuildABSL/page_cache.dirty/filesystem.fusefs-12   42.09 ± 4%   39.09 ± 3%   -7.13% (p=0.000 n=20)      38.09 ± 3%   -9.52% (p=0.000 n=20+19)
BuildGRPC/page_cache.clean/filesystem.bindfs-12   207.7 ± 1%   206.4 ± 0%   -0.60% (p=0.018 n=20)      205.9 ± 1%   -0.85% (p=0.001 n=20+19)
BuildGRPC/page_cache.dirty/filesystem.bindfs-12   206.9 ± 1%   206.9 ± 1%        ~ (p=0.121 n=20)      204.4 ± 1%   -1.22% (p=0.004 n=20+19)
BuildGRPC/page_cache.clean/filesystem.rootfs-12   207.7 ± 1%   204.9 ± 1%   -1.33% (p=0.004 n=20)      203.9 ± 0%   -1.81% (p=0.000 n=20+19)
BuildGRPC/page_cache.dirty/filesystem.rootfs-12   206.9 ± 1%   204.9 ± 0%   -0.97% (p=0.004 n=20+19)   203.9 ± 0%   -1.45% (p=0.000 n=20+19)
geomean                                           71.97        67.63        -6.03%                     67.28        -6.52%
```
PiperOrigin-RevId: 647771821
2024-06-28 12:56:46 -07:00
Jamie LiuandgVisor bot 8ca4f24b53 Automated rollback of changelist 633961720
PiperOrigin-RevId: 636602151
2024-05-23 10:50:10 -07:00
Konstantin BogomolovandgVisor bot a380c4ef5f Set limit on how big MemoryFile.Allocate calls can be.
Either TotalHostMem or TotalMem are good candidates for limits
because in case either of these is set we should not be going over
them.

The motivations of this is to help catch syscalls causing allocations
with size values that are blatantly bad.

PiperOrigin-RevId: 633961720
2024-05-15 08:23:50 -07:00
Jamie LiuandgVisor bot 0738d6be70 pgalloc: add SaveOpts.ExcludeCommittedZeroPages
This option, enabled via `runsc checkpoint --exclude-committed-zero-pages`,
instructs `pgalloc.MemoryFile.SaveTo()` to also exclude definitely-committed
zero pages from checkpointing (in addition to possibly-committed zero pages,
which are always scanned for and excluded). This is useful when the application
being checkpointed is known to have a large number of committed zero pages:
pages that (1) have been touched by application memory accesses, a syscall such
as read(), or page pinning by e.g. a driver, and (2) have not been subsequently
released by the application to the operating system by e.g. munmap() or
madvise(MADV_DONTNEED) (+ page unpinning if necessary), and (3) are filled with
zero bytes.

Minor changes:

- In `MemoryFile.updateUsageLocked()`, pass file offset to `checkCommitted` so
  that `MemoryFile.SaveTo()`'s `checkCommitted` can use `FALLOC_FL_PUNCH_HOLE`
  to decommit pages rather than `MADV_REMOVE` (which translates addresses to
  file offsets and then invokes `FALLOC_FL_PUNCH_HOLE`).

- In `MemoryFile.SaveTo()`, buffer up to a hugepage worth of pages to decommit
  rather than decommitting one page per syscall.

- Increment `MemoryFile.usageExpected` in `MemoryFile.LoadFrom()`, such that
  the first following call to `MemoryFile.UpdateUsage()` might skip the call
  to `MemoryFile.updateUsageLocked()` (if memory usage hasn't changed since
  loading).

PiperOrigin-RevId: 632370455
2024-05-09 21:50:58 -07:00
Jamie LiuandgVisor bot caa8c25d28 mm: add fallback to buffered I/O when memmap.File.MapInternal() is unavailable
MapInternal() returns a coherent memory mapping of the host file descriptor
represented by a memmap.File, in the sentry's address space. This is
principally used when the sentry needs to access the contents of application
memory (for e.g. syscall arguments passed by pointer, or the source/destination
of a write()/read() syscall); it usually looks up the memmap.Files backing
application addresses and obtains mappings via MapInternal().

/dev/nvidia-uvm cannot generally be mapped into the sentry's address space, for
reasons described by
https://github.com/google/gvisor/blob/master/g3doc/proposals/nvidia_driver_proxy.md#unified-virtual-memory-uvm
(in short, nvidia-uvm requires that a given page at file offset X can only be
mapped at address X). To allow the sentry to access the contents of such
mappings, make it possible for memmap.File.MapInternal() to indicate that a
fallback to buffered I/O is required, add interface methods
memmap.File.Buffer{Read,Write}At() to perform this buffered I/O, and implement
this fallback in the MM I/O path.

This CL does not use the new buffered I/O fallback anywhere; a following CL
adds it to nvproxy's nvidia-uvm.

Updates #10331

PiperOrigin-RevId: 629830825
2024-05-01 14:05:55 -07:00
Ayush RanjanandgVisor bot da93b16e83 Add AsyncReader implementation in statefile package.
This type allows reading asynchronously and provides a Wait() method as a
barrier operation.

PiperOrigin-RevId: 627520473
2024-04-23 15:20:56 -07:00
Ayush RanjanandgVisor bot b0bdb5d545 Delete wire.Reader and wire.Writer.
These interfaces only existed to add ReadByte() and WriteByte() methods. There
were only 4 implementors of these methods: compressio.{Simple}{Reader/Writer}.
And there were only 2 users of this.

Using io.{Reader/Writer} is more extendible. For instance, it allows using
*os.File with the `wire` package without any wrappers.

Updated the 2 users to implement their own {read/write}Byte(). To avoid heap
allocation of the [1]byte storage during call to io.Reader.Read or
io.Writer.Write due to interface call, used sync.Pool. Earlier, calls to
compressio.Simple{Reader/Writer}'s implementation of {Read/Write}Byte would
cause a heap allocation.

PiperOrigin-RevId: 625167495
2024-04-15 19:40:27 -07:00
Ayush RanjanandgVisor bot 0241829fb8 Create separate pages.img checkpoint file when compression=none.
PiperOrigin-RevId: 624210535
2024-04-12 09:57:06 -07:00
Ayush RanjanandgVisor bot f3a6c7491e Delete pgalloc.MemoryFileProvider.
The work done in a9af2d309b ("Plumb restore context to afterLoad()") makes
pgalloc.MemoryFileProvider redundant as structs can now easily restore
pgalloc.MemoryFile in stateify's afterLoad() method. This allows structs to
have a pgalloc.MemoryFile field and use that directly, instead of going through
the provided interface.

This cleans up a lot of code and also should be more performant (avoids an
interface method call on many hot paths).

PiperOrigin-RevId: 615258927
2024-03-12 20:06:58 -07:00
Ayush RanjanandgVisor bot 5b9b30e511 Reassociate pma.file to the correct pgalloc.MemoryFile on restore.
Earlier we were always restoring pma.file to mm.mfp.MemoryFile(). However,
534c2e3ce0 ("Add support for saving PMAs referencing tmpfs filestore files.")
added support for saving PMAs that reference "private" pgalloc.MemoryFiles that
are different from mm.mfp.MemoryFile().

We achieve the correct restore by:
- Adding a "RestoreID" field to pgalloc.MemoryFile. Private MemoryFiles set
  this with a vfs.RestoreID.String(). Non-private MemoryFile does not set it.
- MemoryFile struct is not savable by itself, but pma.file field is saved as a
  string. We store the RestoreID string there.
- On restore, if RestoreID is "", then restore using CtxMemoryFile. If it has a
  non-empty RestoreID, then restore using CtxMemoryFileMap.
- Cleanup: vfs.CtxFilesystemMemoryFileMap was moved to pgalloc.CtxMemoryFileMap
  so we can now provide a pgalloc.MemoryFileMapFromContext() method which
  cleans up some code. Also the key to this map (MemoryFileOpts.RestoreID)
  belongs to pgalloc, so it seems like the right place to have this context.

PiperOrigin-RevId: 614903073
2024-03-11 21:44:03 -07:00
NymanRobinandrobin.nyman b6001724e6 Convert atomic.Value to atomic.Pointer[T] 2024-03-05 11:09:23 +02:00
Ayush RanjanandgVisor bot 956704aba4 Plumb safemem.ReaderFunc through pgalloc.Allocate() to avoid heap allocations.
The safemem.Reader interface receiver was causing the implementation to escape
to heap (as at compile time, the compiler can not prove anything about the
implementation).

Using generics for io.ReadFullToBlocks() does not help in avoiding the heap
allocation.

With this change, we avoid at least these allocations:
- rw variable in kcov.Kcov.TaskWork().
- safemem.BlockSeqReader struct in in mm.MemoryManager.getPMAsInternalLocked().
- gr variable in fsutil.FileRangeSet.Fill().
- h variable in gofer.dentry.Translate().
- h variable in gofer.dentryReadWriter.ReadToBlocks().

Some of these are on hot paths for IO workloads.

PiperOrigin-RevId: 609805848
2024-02-23 12:32:25 -08:00
Ayush RanjanandgVisor bot 534c2e3ce0 Add support for saving PMAs referencing tmpfs filestore files.
The rootfs is such a mount (with default overlay2=root:self configuration).
It should be possible to checkpoint this mount when application has active
VMAs that have allocated PMAs from the backing filestore file.

1479bc389e ("Add checkpoint/restore support for tmpfs with file backend.")
added support for saving such a tmpfs filestore file during checkpoint and
restoring it correctly. Hence, after restore, the VMAs and PMAs should be
valid.

PiperOrigin-RevId: 605766485
2024-02-09 16:50:24 -08:00
Jing ChenandgVisor bot 70ce036c8a Re-order loads in BUILD files to make transformations reversible in Copybara.
PiperOrigin-RevId: 598898756
2024-01-16 11:21:40 -08:00
prof awk c3f5d31237 use new clear builtin to clear bufs 2023-11-27 19:43:25 +02:00
Jamie LiuandgVisor bot 8ce145a027 segment.Set API improvements.
- Replace Add with TryInsertRange; for symmetry with RemoveRange, to establish
  the convention that *Range methods perform an implicit search in the set, and
  so that we can fork InsertRange which has Insert-like semantics (panics on
  conflict), which the majority of callers want.

- Rename MergeRange and MergeAdjacent to MergeInsideRange and MergeOutsideRange
  respectively; for the same convention, and to more clearly describe the
  difference between these functions.

- Add MergePrev and MergeNext. These solve the longstanding problem of
  requiring a separate call to Merge{Inside,Outside}Range (which will perform
  additional searches) after mutating a set in a relatively simple manner.

- Add SplitBefore and SplitAfter, which are halves of Isolate. These are
  slightly preferable to Isolate in many use cases for the latter (when
  iterating segments within a range, only the first segment can include a key
  before the start, so this saves some useless comparisons in almost every
  iteration of such loops), and are useful in some more complex algorithms.
  Also add LowerBoundSegmentSplitBefore and UpperBoundSegmentSplitAfter as
  ergonomic aids for the former use case.

- Add {Visit,Mutate}[Full]Range, which are convenience wrappers around the
  iterator API (including new functions) for simple use cases (and hence also
  serve to demonstrate how the new iterator functions are used).
  MutateFullRange in particular replaces ApplyContiguous and adds merging
  during iteration.

- Add RemoveFullRange, which (analogous to {Visit,Mutate}FullRange) is a
  variant of RemoveRange that checks that the range is fully covered by
  segments.

- Add Unisolate, which combines MergePrev and MergeNext in the same way that
  Isolate combines SplitBefore and SplitAfter. This is useful for merging after
  mutation of a single segment.

- Add {First,Last,LowerBound,UpperBound}LargeEnoughGap, which are convenient
  loop starters when using gap tracking.

- Replace SegmentDataSlices with FlatSegment, which is easier to use when
  specifying "set literals" (as in tests).

- Make {prev,next}LargeEnoughGapHelper iterative rather than tail-recursive.

- Slightly optimize Iterator.{Prev,Next}NonEmpty: GapIterator.{Start,End} needs
  to find the corresponding Iterator, so call Iterator.{Prev,Next}Segment
  directly rather than doing so twice.

PiperOrigin-RevId: 583506148
2023-11-17 15:51:12 -08:00
Jamie LiuandgVisor bot c013c18e1b Remove MM.privateRefs.
MM.privateRefs counted pgalloc.MemoryFile references before platform.File
refcounting was added in cl/191858388. Since that CL, MM.privateRefs is
vestigial.

PiperOrigin-RevId: 581379213
2023-11-10 15:02:48 -08:00
Andrei Vagin 43bd258fcf Fix a few typos
It is an idea of running codespell as part of our presubmit checks.
Before enabling it for new changes, let's fix what it has found.

Signed-off-by: Andrei Vagin <[email protected]>
2023-10-25 12:13:42 -07:00