Commit Graph

72 Commits

Author SHA1 Message Date
Andrew Halaney
5525003608 core/mount/*linux: Do idmap bind mounts as private and recursive
Recursive is needed to catch mounts under the bind mount, for example
erofs mount points. i.e. with that in place things like:

    /foo/erofs1
    /foo/erofs2

    bind mount + idmap /foo/ -> /foo-idmapped/

makes it so erofs1 and erofs2 are at /foo-idmapped/, allowing us to use
that when constructing the final overlay mount erofs snapshotters use.
This let's the snapshotter claim to support idmap support later without
issue (right now it goes through remapfs).

As part of this, we want to make the bind mount have private mount
propagation. If you umount /foo-idmapped/erofs1 it shouldn't affect
/foo/erofs1, which could be reused in another container's lowerdirs and
idmapped bind mount.

Signed-off-by: Andrew Halaney <ahalaney@netflix.com>
2026-01-02 09:44:53 -06:00
Andrew Halaney
44751e28b3 core/mount: Don't apply uidmap/gidmap during ro instrospection
containerd will do a read only mount of the mount string to inspect
things like /etc/passwd for a username to uid mapping. It doesn't need
to do a uidmap/gidmap for this, that's entirely for the actual container
mount later.

Let's stop doing the idmap here, its extra work and not necessary.
Further, it causes complications when the mount manager is involved.
Mount manager will by default create erofs layers at
/run/containerd/io.containerd.mount-manager.v1.bolt/t/8103/1, and the
snapshotter's upperdir is at (if configured to use a different path)
/mnt/containerd/io.containerd.snapshotter.v1.erofs/snapshots/25795/fs.

During the read only mount this upperdir is shoved into the lowerdirs
list, and then the idmap code tries to find the common parent directory of
all lowerdirs. In this case its "/", which is invalid, so the process
fails.

Let's stop doing the extra work and get away from this class of
problems by doing less.

Signed-off-by: Andrew Halaney <ahalaney@netflix.com>
2026-01-02 09:44:53 -06:00
Akihiro Suda
f37f951f56 Merge pull request #12545 from erofs/fixes
Avoid using redundant loop devices to run mkfs for mount manager tests.
2025-11-28 07:13:24 +00:00
Wei Fu
a5c84021c8 core/mount: should not call removeLoop when set autoclear
In CI we run make root-test via gotestsum, which executes multiple
package tests concurrently. TestAutoclearTrueLoop attempts to invoke
LOOP_CLR_FD using a device name, which introduces a race condition.

Example race:

Process P1 represents mount.test which runs TestAutoclearTrueLoop
Process P2 represents manager.test which runs TestLoopbackMount

T1: P1 closes fd of loop-device (loop3) (kernel unsets backing-file on close)
T2: P2 gets loop3 from /dev/loop-control
T3: P2 configures loop3 with backing file successfully
T4: P1 invokes removeLoop to clear backing file for loop3

You might see that failure like this

```
=== FAIL: core/mount/manager TestLoopbackMount (0.05s)
    log_hook.go:47: time="2025-10-23T21:49:22.532811960Z" level=debug msg="activating mount" func="manager.(*mountManager).Activate" file="/home/runner/work/containerd/containerd/core/mount/manager/manager.go:134" mounts="[{loop /tmp/TestLoopbackMount989607109/001/fs-1621892597  []} {format/ext4 {{ mount 0 }}  []}]" name=id1 testcase=TestLoopbackMount
    helpers.go💯 unmount /tmp/TestLoopbackMount989607109/001/test-mount-3030342351
    manager_linux_test.go:80:
        	Error Trace:	/home/runner/work/containerd/containerd/core/mount/manager/manager_linux_test.go:80
        	            				/home/runner/work/containerd/containerd/core/mount/manager/manager_linux_test.go:105
        	Error:      	Received unexpected error:
        	            	failed to get loop device info: no such device or address
        	Test:       	TestLoopbackMount
```

To fix this, the test now compares backing-file's inode directly and does
not call removeLoop when autoclear is set.

Signed-off-by: Wei Fu <fuweid89@gmail.com>
2025-11-23 21:31:08 -05:00
Gao Xiang
190ed6b677 Avoid using redundant loop devices to run mkfs for mount manager tests.
mkfs.ext4 supports creating filesystems from regular files.

Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2025-11-19 11:50:01 +08:00
Gao Xiang
5b9d871fea Add EROFS mount handler plugin
Commit ee8ae9d569 ("Update erofs snapshotter to use mount manager")
temporarily removed the file-backed mount feature to adapt to the new
mount manager infrastructure as a quick start.

After the mount manager was introduced, a specific mount type can be
handled with a mount handler plugin to provide a dedicated mount
process (e.g. setup loopback devices in advance or calling external
mount helpers).

This commit adds a default EROFS mount handler for the Linux hosts
to set up loop devices for mount sources and "device=" external file
blobs if necessary (i.e. when file-backed mounts are unavailable),
allowing common runtimes such as runC to work directly, e.g.
 ``` sh
 mount -t erofs /var/lib/containerd/io.containerd.snapshotter.v1.erofs/snapshots/1/layer.erofs \
  /run/containerd/io.containerd.mount-manager.v1.bolt/t/346/1
 ```
 will be handled as
 ``` sh
 mount -t erofs /dev/loop1 /run/containerd/io.containerd.mount-manager.v1.bolt/t/346/1
 ```
and
 ``` sh
 mount -t erofs /var/lib/containerd/io.containerd.snapshotter.v1.erofs/snapshots/7/fsmeta.erofs \
   -odevice=/var/lib/containerd/io.containerd.snapshotter.v1.erofs/snapshots/1/layer.erofs,\
     device=/var/lib/containerd/io.containerd.snapshotter.v1.erofs/snapshots/2/layer.erofs,\
     ...
     device=/var/lib/containerd/io.containerd.snapshotter.v1.erofs/snapshots/7/layer.erofs
   /run/containerd/io.containerd.mount-manager.v1.bolt/t/335/1
 ```
 will be handled as
 ``` sh
 mount -t erofs /dev/loop1 -odevice=/dev/loop2,device=/dev/loop3,... \
   /run/containerd/io.containerd.mount-manager.v1.bolt/t/335/1
 ```
if file-backed mounts are unavailable.

For other host platforms (e.g. Darwin hosts) or specific runtimes
that require EROFS raw mounts instead of parsed mounts, this plugin
can be explicitly masked off by users.

Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2025-10-22 22:57:42 +08:00
Gao Xiang
8a6e6263f8 Support arbitary mkfs size (not only in MiB)
Rename `default_size_mb` to `default_size` so that it's similar to
Docker's `--storage-opt size=30G` flag.  For example,

``` toml
[plugins."io.containerd.snapshotter.v1.erofs"]
  default_size = "5GB"
```

Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2025-10-21 15:35:05 +08:00
Gao Xiang
3cc411c8b2 Fix backreference support for mount manager
The mount manager GC seems to be broken on my local setup.

According to commit df87a8f71b ("Add support for backreferences
in gc"), the interface name should be "ActiveWithBackRefs" instead.

After this patch, erofs and ext4 mounts won't be GCed in advance.

Fixes: 184fae60fc ("Add backreference support to mount manager")
Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com>
2025-10-21 15:06:20 +08:00
Derek McGowan
0d62c71885 Update loopback test to make initialization more robust
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-10-19 13:38:40 -07:00
Derek McGowan
25c3871baa Switch mount manager tests to ext4
Reduce the size of the test files. Even using sparse files, the reported
large size may cause issues in some test environments.

Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-10-16 16:58:37 -07:00
Derek McGowan
55d5d5b500 Add Close method to mount manager
Adding a close method allows the mount manager to close any open file
descriptors. The method will also be called automatically by containerd
on shutdown.

Ensure the tests call Close to avoid leaking file descriptors or errors
on Windows cleaning up directories that are in use.

Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-10-16 16:01:29 -07:00
Derek McGowan
be9f183f45 Add mount transformers to mount manager
Extend the mount manager to support more transformers than format. The
transformers allow altering the mount before it is passed to the mount
handlers. These could be one-time actions which are needed to perform
the mount.

Adds mkdir and mkfs actions which can be used to prepare the arguments
for a mount. The actions can be limited to actions within the target
mount directory or plugin directories.

Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-10-14 16:35:53 -07:00
Derek McGowan
c7b3114ebb Update mount manager code documentation
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-30 13:37:11 -07:00
Derek McGowan
94e6bcea50 Add support for allowing custom types through mount manager
Allow the mount manager to skip handling of custom types. Ensure that
custom types are still working with formatted mounts.

Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:38 -07:00
Derek McGowan
dd9c43150a Add option to allow formatted mounts
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:38 -07:00
Derek McGowan
9c21e867ed Handle flaky case for loop autoclear
The autoclear may take a bit of time to clear out the file, check
multiple times for the file to get removed before returning an error.

Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:37 -07:00
Derek McGowan
f7b77e649c Update mount manager cleanup logic
Avoid keeping file descriptor open to directory which is getting
removed. Update error handling and wrapping to provide more clarity
around failures.

Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:37 -07:00
Derek McGowan
fa327566bb Fix mount manager deactivate errors
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:36 -07:00
Derek McGowan
9c0cc4a424 Add mount manager format test
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:36 -07:00
Derek McGowan
5b4de2c34f Add implementation of list and get mount activation
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:34 -07:00
Derek McGowan
184fae60fc Add backreference support to mount manager
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:34 -07:00
Derek McGowan
9794addcea Add mount formatting test
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:34 -07:00
Derek McGowan
d8e5cdd76a Fix gc cleanup and add unit tests for gc
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:34 -07:00
Derek McGowan
c8e7674cc9 Add temporary mount support to manager
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:33 -07:00
Derek McGowan
75ed5e0037 Fix mount manager gc
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:32 -07:00
Derek McGowan
8db3010865 Add mounts api service
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:31 -07:00
Derek McGowan
4d34b01ce0 Add loopback and overlay mount manager tests
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-29 17:08:31 -07:00
Derek McGowan
6243cf5627 Add mount manager tests
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-18 17:08:43 -07:00
Derek McGowan
f4b7b9344c Improve formatting and support for deactivate
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-18 17:08:43 -07:00
Derek McGowan
55ff117377 Add loopback mount handler
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-18 17:08:43 -07:00
Derek McGowan
ed03f3a710 Add mount manager plugin and types
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-18 17:08:43 -07:00
Derek McGowan
c715986227 Add mount manager interface to mount package
Signed-off-by: Derek McGowan <derek@mcg.dev>
2025-09-18 17:08:42 -07:00
Enji Cooper
f45716efed Clean up issues cited by usetesting package with golangci
This commit makes all of the recommended changes to use the `testing`
package helper functions instead of doing the equivalent longhand
versions of the same thing.

This change was needed in order to properly detect errors, as the code
would previously skip running `tenv` stating that it had been deprecated
in favor of `usetesting`.

Signed-off-by: Enji Cooper <yaneurabeya@gmail.com>
2025-09-07 14:07:40 -07:00
Rodrigo Campos
41953f7ac1 cri: Fix userns with Dockerfile VOLUME mounts that need copy
If a Dockerfile is using a `VOLUME` directive and the directory exists
in the rootfs, like in this example:

	FROM docker.io/library/alpine:latest
	VOLUME [ "/run" ]

The alpine container image already contains a "/run" directory. This
will force the code in WithVolumes() to copy its  content to the new
volume created for the VOLUME directive. This copies the content as well
as the ownership.

However, as we perform the mounts from the host POV without being inside
a userns, the idmap option will just shift the IDs in ways that will
screw up the ownerships when copied. We should only use the idmap option
when running the container inside a userns, so the ownerships are fine
(the userns will do a shift and the idmap another, to make it all seem
as if there was no UID/GID shift in the first place).

This PR does just that, remove the idmap option from mounts so we copy
the files without any ID transformations. It's simpler and easier to
reason about if we just don't mount with the idmap option here: all
files are copied just fine without ID transformations and ID
transformation is applied via the idmap option at mount time when
running the pod.

Also, note that `VOLUME` directives that refer to directories that don't
exist on the rootfs work fine (`VOLUME [ "/rata" ]` for example), as
there is no copy done in that case so the permissions weren't changed.

Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
2025-08-26 11:15:55 +02:00
Rodrigo Campos
da3dc1ef6c core/mount: Retry unmounting idmapped directories
When a lot of pods are created all at the same time, the umount fails
with EBUSY sometimes. This causes some mounts to be leaked. A way to
repro this issue is here:
	https://github.com/containerd/containerd/issues/12139#issuecomment-3165305904

While using lsof/fuser it was not possible to get the culprits on time
(the mount is busy for a few ms), @fuwei has found what is causing the
mount to be busy:
	https://github.com/containerd/containerd/issues/12139#issuecomment-3184544534

When we fork in `GetUsernsFD()`, if a call to prepareIDMappedOverlay()
is ongoing and has an open fd to the path to idmap, then the unmount
callback will fail as the forked process still has an open fd to it.

Let's handle the idmap unmounts in the same way other temp mounts are
done, using the Unmount() helper, that retries the unmount.

This retry fixes it 100% of the times on my system and in the systems
of @halaney that reported the issue too.

This was originally fixed by #10721 by using a detached mount, but the
mount was switched to non-detached again in #10955 and we started to
leak mounts. As @fuwei mentioned, using a detached mount is quite
invisible for the admin and, therefore, a retry is a better alternative.

It seems these umounts are a great candidate for #11303, which will
manage the life-cycle of mounts and can handle these retries whenever
needed.

[1]: To do it, I just run as root "unshare -m", that creates a mntns
with private propagation, and then run the containerd daemon.

Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
2025-08-19 17:38:00 +02:00
Rodrigo Campos
27ba690a1e core/mount: Test cleanup of DoPrepareIDMappedOverlay()
Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
2025-08-19 14:58:09 +02:00
Rodrigo Campos
dd7fe0b76f core/mount: Properly cleanup on doPrepareIDMappedOverlay errors
Before this patch, the cleanup was unconditionally trying an unmount,
which is not needed if the mount never succeeded in the first place.
This causes logs of failed stuff, that should never be there.
Also, one function was creating the tmpDir and the nested one removing
it (in the cleanup function), which complicates the reasoning about
not leaking resources.

This patch on one hand moves the creation of the tmpDir into the
function that will remove it later and renames the parameter. On the
other hand, it also separates the cleanup function in two functions:
cleanDir() and cleanMount(). Each one will clean the directory or the
mount, only if needed, and a new cleanup function that just calls
cleanDir() and cleanMount() is returned as the cleanup function handler.

Because we now create the tmp directory inside the function, we need to
adjust the test: the directory passed as param now will exist, but it
shoild be empty. Therefore, we change the os.Stat() to an os.Remove().
If it's not empty (the cleanup didn't work), the remove will fail.

Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
2025-08-19 14:58:09 +02:00
Rodrigo Campos
7a19c94d6c core/mount: Don't call nil function on errors
doPrepareIDMappedOverlay() can return nil as the cleanup function. As
the function mandates for the callback to be called, even when errors
are returned, we end-up calling the nil function that of course causes:

        panic: runtime error: invalid memory address or nil pointer dereference

The containerd daemon continues to run fine, though.

With the current structure of always calling the cleanup function, we
would either need to check which error it is, to call it only on
specific errors (ugly) or return a "stub function" that doesn't do
anything on those cases (so the call works). None of these options seem
very nice.

Let's just switch the logic to a pattern more common on go: only need to
cleanup if it returned fine. This makes it easier for callers to not do
the wrong thing.

For this change we need to do the cleanup when returning errors on the
function itself, so the user doesn't need to do it for us.

Signed-off-by: Rodrigo Campos <rodrigoca@microsoft.com>
2025-08-18 07:01:16 -03:00
Akihiro Suda
0649e9b280 Merge pull request #12092 from halaney/ahalaney/use-one-idmap-per-overlayfs
Only idmap once per overlayfs, not per layer
2025-08-17 05:07:34 +00:00
Andrew Halaney
6e9b6eadac core/mount: Only idmap once per overlayfs, not per layer
Per layer idmap'ed bind mounts are costly to performance, as shown in
[0]. Each one requires taking various kernel locks, and each one shows
up in the host's mount table leading to some components like systemd
processing all these temporary mounts unnecessarily.

Let's instead go ahead and idmap the common directory of all the
layers to achieve the same effect. Now instead of being a function of
the number of layers, its a constant idmap per overlayfs! This can have
a big impact. For example, imagine running 100 containers at once, each
with 50 layers. That's going from doing 100 * 50 (5000) bind mounts, to
just 100. In reality both the shim and containerd proper do this, so its
actually double that!

[0]: https://github.com/containerd/containerd/issues/12048#issuecomment-3050444019
Signed-off-by: Andrew Halaney <ahalaney@netflix.com>
2025-08-12 16:28:00 -05:00
Wei Fu
6ce7f6d87a pkg/sys: check SupportsPidFD first
Checking this earlier and bailing is preferable to checking this to after we
try to StartProcess.

Signed-off-by: Wei Fu <fuweid89@gmail.com>
2025-08-12 14:53:29 -04:00
Amit Barve
009625290b Block CIM snapshotter & differ
Add new snapshotter & differ plugins that can leverage the block CIM layer writers to
store pulled/imported images in the block CIM format.

Signed-off-by: Amit Barve <ambarve@microsoft.com>
2025-07-30 14:46:59 -04:00
Fu Wei
87742bd35f Merge pull request #11857 from djdongjin/remove-go-version-specific-code
chore: remove go version specific code
2025-07-06 19:02:31 +00:00
yashsingh74
b3eec6d8e9 fix: ST1005: error strings should not end with punctuation or newlines
Signed-off-by: yashsingh74 <yashsingh1774@gmail.com>
2025-06-18 14:16:41 +05:30
Jin Dong
734d52c39c chore: remove specific go version code
Now that we have 1.24.x as go min version, I think
we can remove this go code specific to a lower
version.

Signed-off-by: Jin Dong <djdongjin95@gmail.com>
2025-06-12 21:35:09 -04:00
ningmingxiao
fb6dd2cf15 client:improve mount error message
Signed-off-by: ningmingxiao <ning.mingxiao@zte.com.cn>
2025-05-17 09:57:04 +08:00
Phil Estes
98af40b752 Merge pull request #10722 from henry118/uidmap2
Support multiple uid/gid mappings [2/2]
2025-01-17 18:34:40 +00:00
Mike Baynton
1e3d10dc29 Make ovl idmap mounts read-only
This is a planned follow-on from #10721 primarily at the request of
@fuweid, exchanging MNT_DETACH at unmount time for MOUNT_ATTR_RDONLY at
mount time. The effect is to increase risk of unmount failure due to
EBUSY (as observed in the wild) but add an additional protection that the
then-leaked bind mount does not act as a conduit for inadvertent modification
of the underlying data, including our own efforts to clean up the mountpoint.

Tests covering the lifecycle of the temporary idmap mounts and integrity
of the underlying lower layer data is also included in the normal and
failed-unmount case.

Fixes #10704

Signed-off-by: Mike Baynton <mike@mbaynton.com>
2024-12-21 16:02:33 -06:00
Henry Wang
168ec21dbd Update idmapped mount to support multiple uid/gid mappings
Signed-off-by: Henry Wang <henwang@amazon.com>
2024-12-11 18:03:59 +00:00
Marat Radchenko
e9d560f1e8 Unsorted platform conditionals cleanup
* container_update_resources.go: it is Windows and Linux that need special handling
* local*.go: all platforms use the same list of tasks
* temp_unix.go/temp_unsupported.go: Darwin is a Unix
* util_unix.go/util_unsupported.go: use generic unix tag

The only user-visible effect of these changes is that tempMountLocation is now properly handled on Darwin

Signed-off-by: Marat Radchenko <marat@slonopotamus.org>
2024-11-26 20:05:33 +03:00