Skip to content

Commit

Permalink
Merge pull request #29 from kolyshkin/openat2
Browse files Browse the repository at this point in the history
mountinfo.Mounted: add fast path for Linux using openat2
  • Loading branch information
thaJeztah committed Sep 15, 2020
2 parents 1d9043a + 9c884dc commit bbb236c
Show file tree
Hide file tree
Showing 13 changed files with 470 additions and 43 deletions.
31 changes: 31 additions & 0 deletions .ci/Vagrantfile.fedora32
@@ -0,0 +1,31 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
# Fedora box is used for testing cgroup v2 support
config.vm.box = "fedora/32-cloud-base"
config.vm.provider :virtualbox do |v|
v.memory = 2048
v.cpus = 2
end
config.vm.provider :libvirt do |v|
v.memory = 2048
v.cpus = 2
end
config.vm.provision "shell", inline: <<-SHELL
set -e -u -o pipefail
# Work around dnf mirror failures by retrying a few times
for i in $(seq 0 2); do
sleep $i
cat << EOF | dnf -y shell && break
config exclude kernel,kernel-core
config install_weak_deps false
update
install make golang-go libseccomp-devel git-core
ts run
EOF
done
dnf clean all
SHELL
end
20 changes: 20 additions & 0 deletions .ci/install-vagrant.sh
@@ -0,0 +1,20 @@
#!/bin/bash
set -eux -o pipefail
VAGRANT_VERSION="2.2.10"

# Based on code from https://github.com/opencontainers/runc
DEB="vagrant_${VAGRANT_VERSION}_$(uname -m).deb"
wget "https://releases.hashicorp.com/vagrant/${VAGRANT_VERSION}/$DEB"
apt-get update
apt-get install -q -y \
bridge-utils \
dnsmasq-base \
ebtables \
libvirt-bin \
libvirt-dev \
qemu-kvm \
qemu-utils \
ruby-dev \
./"$DEB"
rm -f "$DEB"
vagrant plugin install vagrant-libvirt
2 changes: 1 addition & 1 deletion .github/workflows/test.yml
Expand Up @@ -4,7 +4,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.13.x, 1.14.x]
go-version: [1.14.x, 1.15.x]
platform: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.platform }}
steps:
Expand Down
15 changes: 15 additions & 0 deletions .travis.yml
@@ -0,0 +1,15 @@
dist: bionic
os: linux
language: minimal
cache:
directories:
- /home/travis/.vagrant.d/boxes
jobs:
include:
- name: "Fedora 32"
before_install:
- sudo .ci/install-vagrant.sh
- ln -sf .ci/Vagrantfile.fedora32 Vagrantfile
- sudo vagrant up && sudo mkdir -p /root/.ssh && sudo sh -c "vagrant ssh-config >> /root/.ssh/config"
script:
- sudo ssh default -t 'cd /vagrant && sudo make'
5 changes: 2 additions & 3 deletions mountinfo/doc.go
Expand Up @@ -14,9 +14,8 @@
// parse filters while reading mountinfo. A filter can skip some entries, or stop
// processing the rest of the file once the needed information is found.
//
// For functions that have path as an argument (such as Mounted or various filters),
// the argument must be
// - an absolute path;
// For mountinfo filters that accept path as an argument, the path must be:
// - absolute;
// - having all symlinks resolved;
// - being cleaned.
//
Expand Down
2 changes: 1 addition & 1 deletion mountinfo/go.mod
Expand Up @@ -2,4 +2,4 @@ module github.com/moby/sys/mountinfo

go 1.14

require golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae
require golang.org/x/sys v0.0.0-20200909081042-eff7692f9009
4 changes: 2 additions & 2 deletions mountinfo/go.sum
@@ -1,2 +1,2 @@
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae h1:/WDfKMnPU+m5M4xB+6x4kaepxRw6jWvR5iDRdvjHgy8=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009 h1:W0lCpv29Hv0UaM1LXb9QlBHLNP8UFfcKjblhVCWftOM=
golang.org/x/sys v0.0.0-20200909081042-eff7692f9009/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
58 changes: 58 additions & 0 deletions mountinfo/mounted_linux.go
@@ -0,0 +1,58 @@
package mountinfo

import (
"os"
"path/filepath"

"golang.org/x/sys/unix"
)

// mountedByOpenat2 is a method of detecting a mount that works for all kinds
// of mounts (incl. bind mounts), but requires a recent (v5.6+) linux kernel.
func mountedByOpenat2(path string) (bool, error) {
dir, last := filepath.Split(path)

dirfd, err := unix.Openat2(unix.AT_FDCWD, dir, &unix.OpenHow{
Flags: unix.O_PATH | unix.O_CLOEXEC,
})
if err != nil {
if err == unix.ENOENT { // not a mount
return false, nil
}
return false, &os.PathError{Op: "openat2", Path: dir, Err: err}
}
fd, err := unix.Openat2(dirfd, last, &unix.OpenHow{
Flags: unix.O_PATH | unix.O_CLOEXEC | unix.O_NOFOLLOW,
Resolve: unix.RESOLVE_NO_XDEV,
})
_ = unix.Close(dirfd)
switch err {
case nil: // definitely not a mount
_ = unix.Close(fd)
return false, nil
case unix.EXDEV: // definitely a mount
return true, nil
case unix.ENOENT: // not a mount
return false, nil
}
// not sure
return false, &os.PathError{Op: "openat2", Path: path, Err: err}
}

func mounted(path string) (bool, error) {
// Try a fast path, using openat2() with RESOLVE_NO_XDEV.
mounted, err := mountedByOpenat2(path)
if err == nil {
return mounted, nil
}
// Another fast path: compare st.st_dev fields.
mounted, err = mountedByStat(path)
// This does not work for bind mounts, so false negative
// is possible, therefore only trust if return is true.
if mounted && err == nil {
return mounted, nil
}

// Fallback to parsing mountinfo
return mountedByMountinfo(path)
}

0 comments on commit bbb236c

Please sign in to comment.