Skip to content

c8d: Use reference counting while mounting a snapshot#45698

Merged
cpuguy83 merged 1 commit intomoby:masterfrom
rumpl:feat-dockerd-mounts-rootfs
Jun 8, 2023
Merged

c8d: Use reference counting while mounting a snapshot#45698
cpuguy83 merged 1 commit intomoby:masterfrom
rumpl:feat-dockerd-mounts-rootfs

Conversation

@rumpl
Copy link
Member

@rumpl rumpl commented Jun 5, 2023

- What I did

Some snapshotters (like overlayfs or zfs) can't mount the same directories twice. For example if the same directroy is used as an upper directory in two mounts the kernel will output this warning:

overlayfs: upperdir is in-use as upperdir/workdir of another mount, accessing files from both mounts will result in undefined behavior.

And indeed accessing the files from both mounts will result in an "No such file or directory" error.

This change introduces reference counts for the mounts, if a directory is already mounted the mount interface will only increment the mount counter and return the mount target effectively making sure that the filesystem doesn't end up in an undefined behavior.

This PR replaces #45383

- How I did it

Created a refCountMounter that makes sure things aren't mounted twice.

- How to verify it

You can use this script:

set -ex

pp () {
  read -s -k '?Press any key to continue.'
}

ID=$(docker run --name cp-test -d nginx)

docker exec $ID mount | wc -l

cat > test <<EOF
Hello cpa
EOF

docker cp test $ID:/test

docker exec $ID touch /etc/default/test-file

docker exec $ID touch /etc/default/test-file1

docker exec $ID mount | wc -l

docker stop $ID

# pp

docker cp test $ID:/test2
docker cp test $ID:/test2
docker cp test $ID:/test2
docker cp test $ID:/test2
docker cp test $ID:/test2
docker cp test $ID:/test2

docker rm cp-test

Note: Using this script you will see the kernel warning you that upperdir or workdir is already in-use by another mount. This is because unmounting happens async (MNT_DETACH is used, more info here), this happens during the last block of docker cp commands. This happens because cp does two calls:

  • First call: HEAD /v1.43/containers/<containerID>/archive?path=<patHh
  • Second call: PUT /v1.43/containers/<containerID>/archive?noOverwriteDirNonDir=true&path=<path>

The daemon calls Mount/Unmount for both of these calls, between the first Unmount and the second Mount the kernel didn't have the time to finish unmounting.

In this case this warning can be safely ignored. The same warning can be seen with graph drivers when running the script above.

- Description for the changelog

Fixed `docker cp` with the containerd integration

- A picture of a cute animal (not mandatory but encouraged)
IMG_2869

@rumpl rumpl added area/images Image Distribution kind/bugfix PR's that fix bugs containerd-integration Issues and PRs related to containerd integration labels Jun 5, 2023
@rumpl rumpl added this to the 25.0.0 milestone Jun 5, 2023
@rumpl rumpl force-pushed the feat-dockerd-mounts-rootfs branch 2 times, most recently from 22ae7eb to 93b6646 Compare June 5, 2023 15:23

// inSlice tests whether a string is contained in a slice of strings or not.
// Comparison is case sensitive
func inSlice(slice []string, s string) bool {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do have 5 implementations of this same function in the code, I could switch all of them with slices.Contains if we don't mind a new dependency

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The benefit of this particular dep is that it's core stdlib in 1.20+ 👀

https://pkg.go.dev/slices#Contains


import (
"github.com/containerd/containerd/mount"
"github.com/docker/docker/daemon/graphdriver"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feels a bit weird to make daemon/snapshotter depend on the daemon/graphdriver.
How cumbersome would it be to extract the common bits out of the daemon/graphdriver?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I wanted to keep this PR small-ish, I can add a commit to move it or in a followup

@rumpl rumpl force-pushed the feat-dockerd-mounts-rootfs branch 2 times, most recently from 2ca294f to efedc07 Compare June 7, 2023 13:18
Some snapshotters (like overlayfs or zfs) can't mount the same
directories twice. For example if the same directroy is used as an upper
directory in two mounts the kernel will output this warning:

    overlayfs: upperdir is in-use as upperdir/workdir of another mount, accessing files from both mounts will result in undefined behavior.

And indeed accessing the files from both mounts will result in an "No
such file or directory" error.

This change introduces reference counts for the mounts, if a directory
is already mounted the mount interface will only increment the mount
counter and return the mount target effectively making sure that the
filesystem doesn't end up in an undefined behavior.

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
@rumpl rumpl force-pushed the feat-dockerd-mounts-rootfs branch from efedc07 to 32d5814 Compare June 7, 2023 13:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/images Image Distribution containerd-integration Issues and PRs related to containerd integration kind/bugfix PR's that fix bugs process/cherry-picked status/4-merge

Projects

Development

Successfully merging this pull request may close these issues.

c8d: implement --read-only with containerd-integration enabled

6 participants