Repository navigation
Add mount operations to the broker core - #1838
Draft
Weidong Cui (wdcui) wants to merge 10 commits into
Draft
Weidong Cui (wdcui) wants to merge 10 commits into
Weidong Cui (wdcui) wants to merge 10 commits into
Conversation
Threads can now change their mount namespace's tree: mount a new empty in-memory file system or a given backend on a directory, bind a file or directory elsewhere, optionally with the mounts below it, make a mount read-only, and unmount, refusing a busy mount unless detaching it and its subtree. Each change resolves its operands, pins the point it attaches at and checks the node is still there, then commits under the namespace's lock only if the tree hasn't changed meanwhile. Mount points are registered per backend, so removing or renaming one, or a directory above one, fails as busy through any mount, bind or namespace, and read-only mounts refuse writes, while a file open for writing keeps its mount writable. Threads can also change their root and working directory to any directory. Hosts can give guest-mounted backends devices from their composer's allocators. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5406de6-bab4-4f3b-b232-ae238032c2c2
A thread can now make a mount below its root the root of its mount namespace, as Linux's pivot_root does: the caller's root mount moves to the given directory at or below the new root, the new root's mount takes the old root mount's place, and every root and working directory at the old root, in any process and namespace, moves to the new root. With both operands the caller's working directory at a mount's root, the old root is stacked on the new root's root, which lets runc pivot into a bind of its root file system and then detach the old root. The operands are checked as Linux checks them: the caller's root must be its mount's root, the new root a mount's root below it and not the root mount itself, and the old root's new place at or below the new root. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5406de6-bab4-4f3b-b232-ae238032c2c2
NamespaceKinds gains a mount namespace kind and a file-system context kind, each a new bit in the namespace byte, which decoding checks strictly. Unsharing the context kind gives a thread a private copy of its context if it shares one. Unsharing the mount kind gives it a private context in a copy of its mount namespace, whose new mounts show the same nodes in the same tree and change independently, with its root and working directory moved onto the copies, while open files stay on the original mounts; moving the initial thread's context moves the process's default context too. A child allocated with the mount kind gets such a copy of its creating thread's context. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5406de6-bab4-4f3b-b232-ae238032c2c2
Mounts and binds, the copies a recursive bind makes, and the mount namespaces and mounts made by unsharing or creating a child with a new mount namespace are now charged to the process that made them, its job and the broker, with new broker-wide, per-job and per-process limits in BrokerCoreLimits like the PID namespace ones. Each charge is released when the mount or namespace drops, and an operation that would exceed a limit fails with ResourceExhausted without changing anything, so a sandboxed process can't grow the broker's mount state without bound. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5406de6-bab4-4f3b-b232-ae238032c2c2
Copying a mount namespace now holds the source namespace's mutation lock from its tree snapshot through the last pin, re-pinning each point its original already pins, so no unmount, removal or rename can slip in between and the copy never fails or pins a point that no longer exists; partial copies drop after the lock. The registry of mount points now lives with the inode allocators, so every namespace and file service created from the same allocators shares it, and this is documented where hosts choose them. Attaching a mount or pivoting now checks that the pinned point still exists by walking its path inside the backend, rather than trusting a retained directory handle that may name a removed directory. Opening a file read-only with truncation no longer counts as a writer on its mount once the open is done, so it doesn't stop the mount from being made read-only, and O_PATH opens never do. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5406de6-bab4-4f3b-b232-ae238032c2c2
Copying a context with its mount namespace now takes the context's root and working directory under the source namespace's mutation lock, together with the copy of its tree, so a concurrent pivot (which moves contexts under the same lock) can't leave the copy rooted at the old root's copy beneath the new root. Changing the root or working directory to a directory on a backend that enforces permissions itself, such as 9P, can't check search permission on it, as 9P has no way to ask; this is now documented with the other differences on such backends, rather than probed with a hack. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5406de6-bab4-4f3b-b232-ae238032c2c2
Copies of file-system contexts are now taken and registered under the core's context registry lock, which a pivot holds while it moves roots and working directories, so a fork, a context unshare or a mount namespace copy racing a pivot can't register a copy still rooted at the old root. A thread's new context becomes the process default under the threads lock, so process teardown can't miss it or have it put back afterwards. A mount's read-only flag and writer count now share one atomic word, so a write starts only while the mount is writable and the mount becomes read-only only with no writer, without a refused change briefly failing writes. Pivot now checks its operands in Linux's order, returning Busy when the new root or the mount on top at put_old is the caller's root mount before the other invalid-argument checks. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5406de6-bab4-4f3b-b232-ae238032c2c2
A new root process's file-system context now reads its namespace's root and registers itself under the namespace's mutation lock and then the context registry lock. A pivot moves the registered contexts and publishes its new tree under the same mutation lock, so a context created concurrently either starts at the new root or is moved there, rather than starting at the old root after it moved under put_old and keeping it busy. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5406de6-bab4-4f3b-b232-ae238032c2c2
Unsharing now prepares every namespace it gives first, then installs the thread's new file-system context (and the process default, for the initial thread) and its children's PID namespace under one acquisition of the threads lock, all or nothing. A thread that exits meanwhile, or whose children went to another PID namespace meanwhile, makes the unshare fail without changing anything, and what wasn't installed or was replaced drops outside the lock. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5406de6-bab4-4f3b-b232-ae238032c2c2
Creating a child for a thread, and unsharing a thread's namespaces, now read the thread's children PID namespace and its file-system context under one acquisition of the threads lock, then copy and allocate outside it. A concurrent unshare naming the same thread, which an untrusted runner can send, can no longer give a child a PID namespace and a file-system context that the thread never held together. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: f5406de6-bab4-4f3b-b232-ae238032c2c2
|
ℹ️ Note: This semver check was run against the 🤖 SemverChecks 🤖 Click for details |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds mount operations to the broker core's mount trees from #1837 (which it is stacked on). A thread can mount a new in-memory file system or a given backend on a directory, bind a file or directory (optionally with the mounts below it) onto another, make a mount read-only (refused while files are open for writing; every modification through a read-only mount then fails), unmount the topmost mount on a node (refused while it has children or users, unless detached, which takes its subtree along while open files keep working), change its root or working directory to any directory handle, and pivot the root of its mount namespace with Linux's checks and errors, which moves every context rooted or working on the old root. Mount points are pinned by backend and path in a registry shared by everything built from the same inode allocators, so a mount point can't be removed or renamed through any alias, and attachments re-check their point after pinning.
NamespaceKindsgains mount and file-system-context kinds: unsharing them gives the thread a private context, and a copy of its mount namespace whose mounts share the original backends (open files stay on the old mounts), and a new child can get such a copy too. Mounts and mount namespaces count against new broker-wide, per-job and per-process limits. Tree changes are serialized per namespace and published as copy-on-write snapshots, context copies and pivots are serialized through the core's context registry, and no backend call or final drop happens under a lock.