linux-sandbox: Retry remount-ro on EBUSY (https://github.com/bazelbuild/bazel/pull/29433)

### Description
MakeFilesystemMostlyReadOnly issues MS_BIND|MS_REMOUNT|MS_RDONLY for every entry in /proc/self/mounts. On busy mounts (notably "/") this races with concurrent symlink path lookups: pick_link() in fs/namei.c calls touch_atime(), which holds the per-mount writer counter via mnt_get_write_access() across the inode update. mnt_hold_writers() in the remount path returns -EBUSY if the counter is non-zero, causing the sandbox setup to die.

The race window is short (a single update_time call), so a brief backoff-and-retry resolves it cleanly. Use the same constants runc has shipped since 2014 (5 attempts, 100 ms apart).

This is my proposal for https://github.com/bazelbuild/bazel/issues/29424.

### Motivation
Fixes https://github.com/bazelbuild/bazel/issues/29424.

### Build API Changes
No

### Checklist

- [x] I have added tests for the new use cases (if any).
- [x] I have updated the documentation (if applicable).

### Release Notes

RELNOTES: None

Closes #29433.

PiperOrigin-RevId: 922094350
Change-Id: I7ff8b1b5ad7992f164b44a6742c4f70cadb18f00
diff --git a/src/main/tools/linux-sandbox-pid1.cc b/src/main/tools/linux-sandbox-pid1.cc
index f832104..b867c08 100644
--- a/src/main/tools/linux-sandbox-pid1.cc
+++ b/src/main/tools/linux-sandbox-pid1.cc
@@ -40,6 +40,7 @@
 #include <sys/wait.h>
 #include <unistd.h>
 
+#include <ctime>
 #include <string>
 #include <unordered_set>
 
@@ -400,7 +401,24 @@
 
     PRINT_DEBUG("remount %s: %s", (mountFlags & MS_RDONLY) ? "ro" : "rw",
                 ent->mnt_dir);
-    if (mount(nullptr, ent->mnt_dir, nullptr, mountFlags, nullptr) < 0) {
+    // The remount races with concurrent path lookups elsewhere on the host:
+    // walking through a symlink calls touch_atime(), which briefly bumps the
+    // per-mount writer counter (mnt_get_write_access -> mnt_inc_writers).
+    // MS_BIND|MS_REMOUNT|MS_RDONLY goes through mnt_hold_writers() which
+    // returns -EBUSY if that counter is non-zero. The window is tiny but on
+    // active mounts (especially "/") it can sometimes hit. Retry on EBUSY.
+    // This behavior mimics runc's handling of EBUSY during readonly remounts:
+    // https://github.com/opencontainers/runc/blob/eb7eaf19b6eec5d1143b257057899e4a7b738c81/libcontainer/rootfs_linux.go#L1305-L1309
+    int rc;
+    for (int i = 0; i < 5; ++i) {
+      rc = mount(nullptr, ent->mnt_dir, nullptr, mountFlags, nullptr);
+      if (rc == 0 || errno != EBUSY || i == 4) break;
+      struct timespec delay;
+      delay.tv_sec = 0;
+      delay.tv_nsec = 100 * 1000 * 1000;  // 100 milliseconds
+      nanosleep(&delay, nullptr);
+    }
+    if (rc < 0) {
       // If we get EACCES or EPERM, this might be a mount-point for which we
       // don't have read access. Not much we can do about this, but it also
       // won't do any harm, so let's go on. The same goes for EINVAL or ENOENT,