Skip to content

Commit

Permalink
Add mount functionality to 'Directory'
Browse files Browse the repository at this point in the history
This is needed for 'chroot' runners that must mount the special
filesystems '/proc' and '/sys' in the input root.
The necessary syscalls are not yet merged into the 'sys' package,
so this includes a patch while we work to upstream the code.
  • Loading branch information
stagnation committed Dec 13, 2023
1 parent 8de3263 commit 646f697
Show file tree
Hide file tree
Showing 9 changed files with 243 additions and 3 deletions.
2 changes: 1 addition & 1 deletion BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
load("@bazel_gazelle//:def.bzl", "gazelle")
load("@com_github_bazelbuild_buildtools//buildifier:def.bzl", "buildifier")
load("@npm//:defs.bzl", "npm_link_all_packages", "npm_link_targets")
load("@npm//:defs.bzl", "npm_link_all_packages")

# gazelle:prefix github.com/buildbarn/bb-storage
# gazelle:resolve proto build/bazel/remote/execution/v2/remote_execution.proto @com_github_bazelbuild_remote_apis//build/bazel/remote/execution/v2:remote_execution_proto
Expand Down
1 change: 1 addition & 0 deletions go_dependencies.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -1491,6 +1491,7 @@ def go_dependencies():
importpath = "golang.org/x/sys",
sum = "h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=",
version = "v0.14.0",
patches = ["//:patches/org_golang_x_sys/golang-issue-59357.diff"],
)
go_repository(
name = "org_golang_x_term",
Expand Down
181 changes: 181 additions & 0 deletions patches/org_golang_x_sys/golang-issue-59357.diff
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
From 9313951415ca77dcf5e84ba5fa41483b5c16d121 Mon Sep 17 00:00:00 2001
From: Ilya Hanov <ilya.hanov@huawei-partners.com>
Date: Sat, 30 Sep 2023 12:02:48 +0300
Subject: [PATCH] unix: add API for fsconfig system call

Fixes golang/go#59537

Change-Id: I8d806ace3adad423c633813455d8f758706cee1d
---

diff --git unix/linux/types.go unix/linux/types.go
index 25b9279..b9419f3 100644
--- unix/linux/types.go
+++ unix/linux/types.go
@@ -972,6 +972,15 @@
FSPICK_EMPTY_PATH = C.FSPICK_EMPTY_PATH

FSMOUNT_CLOEXEC = C.FSMOUNT_CLOEXEC
+
+ FSCONFIG_SET_FLAG = C.FSCONFIG_SET_FLAG
+ FSCONFIG_SET_STRING = C.FSCONFIG_SET_STRING
+ FSCONFIG_SET_BINARY = C.FSCONFIG_SET_BINARY
+ FSCONFIG_SET_PATH = C.FSCONFIG_SET_PATH
+ FSCONFIG_SET_PATH_EMPTY = C.FSCONFIG_SET_PATH_EMPTY
+ FSCONFIG_SET_FD = C.FSCONFIG_SET_FD
+ FSCONFIG_CMD_CREATE = C.FSCONFIG_CMD_CREATE
+ FSCONFIG_CMD_RECONFIGURE = C.FSCONFIG_CMD_RECONFIGURE
)

type OpenHow C.struct_open_how
diff --git unix/syscall_linux.go unix/syscall_linux.go
index d844b16..80aadf2 100644
--- unix/syscall_linux.go
+++ unix/syscall_linux.go
@@ -1840,6 +1840,105 @@
//sys Fsmount(fd int, flags int, mountAttrs int) (fsfd int, err error)
//sys Fsopen(fsName string, flags int) (fd int, err error)
//sys Fspick(dirfd int, pathName string, flags int) (fd int, err error)
+
+//sys fsconfig(fd int, cmd uint, key *byte, value *byte, aux int) (err error)
+
+func fsconfigCommon(fd int, cmd uint, key string, value *byte, aux int) (err error) {
+ var keyp *byte
+ if keyp, err = BytePtrFromString(key); err != nil {
+ return
+ }
+ return fsconfig(fd, cmd, keyp, value, aux)
+}
+
+// FsconfigSetFlag is equivalent to fsconfig(2) called
+// with cmd == FSCONFIG_SET_FLAG.
+//
+// fd is the filesystem context to act upon.
+// key the parameter key to set.
+func FsconfigSetFlag(fd int, key string) (err error) {
+ return fsconfigCommon(fd, FSCONFIG_SET_FLAG, key, nil, 0)
+}
+
+// FsconfigSetString is equivalent to fsconfig(2) called
+// with cmd == FSCONFIG_SET_STRING.
+//
+// fd is the filesystem context to act upon.
+// key the parameter key to set.
+// value is the parameter value to set.
+func FsconfigSetString(fd int, key string, value string) (err error) {
+ var valuep *byte
+ if valuep, err = BytePtrFromString(value); err != nil {
+ return
+ }
+ return fsconfigCommon(fd, FSCONFIG_SET_STRING, key, valuep, 0)
+}
+
+// FsconfigSetBinary is equivalent to fsconfig(2) called
+// with cmd == FSCONFIG_SET_BINARY.
+//
+// fd is the filesystem context to act upon.
+// key the parameter key to set.
+// value is the parameter value to set.
+func FsconfigSetBinary(fd int, key string, value []byte) (err error) {
+ if len(value) == 0 {
+ return EINVAL
+ }
+ return fsconfigCommon(fd, FSCONFIG_SET_BINARY, key, &value[0], len(value))
+}
+
+// FsconfigSetPath is equivalent to fsconfig(2) called
+// with cmd == FSCONFIG_SET_PATH.
+//
+// fd is the filesystem context to act upon.
+// key the parameter key to set.
+// path is a non-empty path for specified key.
+// atfd is a file descriptor at which to start lookup from or AT_FDCWD.
+func FsconfigSetPath(fd int, key string, path string, atfd int) (err error) {
+ var valuep *byte
+ if valuep, err = BytePtrFromString(path); err != nil {
+ return
+ }
+ return fsconfigCommon(fd, FSCONFIG_SET_PATH, key, valuep, atfd)
+}
+
+// FsconfigSetPathEmpty is equivalent to fsconfig(2) called
+// with cmd == FSCONFIG_SET_PATH_EMPTY. The same as
+// FconfigSetPath but with AT_PATH_EMPTY implied.
+func FsconfigSetPathEmpty(fd int, key string, path string, atfd int) (err error) {
+ var valuep *byte
+ if valuep, err = BytePtrFromString(path); err != nil {
+ return
+ }
+ return fsconfigCommon(fd, FSCONFIG_SET_PATH_EMPTY, key, valuep, atfd)
+}
+
+// FsconfigSetFd is equivalent to fsconfig(2) called
+// with cmd == FSCONFIG_SET_FD.
+//
+// fd is the filesystem context to act upon.
+// key the parameter key to set.
+// value is a file descriptor to be assigned to specified key.
+func FsconfigSetFd(fd int, key string, value int) (err error) {
+ return fsconfigCommon(fd, FSCONFIG_SET_FD, key, nil, value)
+}
+
+// FsconfigCreate is equivalent to fsconfig(2) called
+// with cmd == FSCONFIG_CMD_CREATE.
+//
+// fd is the filesystem context to act upon.
+func FsconfigCreate(fd int) (err error) {
+ return fsconfig(fd, FSCONFIG_CMD_CREATE, nil, nil, 0)
+}
+
+// FsconfigReconfigure is equivalent to fsconfig(2) called
+// with cmd == FSCONFIG_CMD_RECONFIGURE.
+//
+// fd is the filesystem context to act upon.
+func FsconfigReconfigure(fd int) (err error) {
+ return fsconfig(fd, FSCONFIG_CMD_RECONFIGURE, nil, nil, 0)
+}
+
//sys Getdents(fd int, buf []byte) (n int, err error) = SYS_GETDENTS64
//sysnb Getpgid(pid int) (pgid int, err error)

diff --git unix/zsyscall_linux.go unix/zsyscall_linux.go
index 14ab34a..dd1720f 100644
--- unix/zsyscall_linux.go
+++ unix/zsyscall_linux.go
@@ -892,6 +892,16 @@

// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT

+func fsconfig(fd int, cmd uint, key *byte, value *byte, aux int) (err error) {
+ _, _, e1 := Syscall6(SYS_FSCONFIG, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(key)), uintptr(unsafe.Pointer(value)), uintptr(aux), 0)
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func Getdents(fd int, buf []byte) (n int, err error) {
var _p0 unsafe.Pointer
if len(buf) > 0 {
diff --git unix/ztypes_linux.go unix/ztypes_linux.go
index 18aa70b..3c9bfa2 100644
--- unix/ztypes_linux.go
+++ unix/ztypes_linux.go
@@ -833,6 +833,15 @@
FSPICK_EMPTY_PATH = 0x8

FSMOUNT_CLOEXEC = 0x1
+
+ FSCONFIG_SET_FLAG = 0x0
+ FSCONFIG_SET_STRING = 0x1
+ FSCONFIG_SET_BINARY = 0x2
+ FSCONFIG_SET_PATH = 0x3
+ FSCONFIG_SET_PATH_EMPTY = 0x4
+ FSCONFIG_SET_FD = 0x5
+ FSCONFIG_CMD_CREATE = 0x6
+ FSCONFIG_CMD_RECONFIGURE = 0x7
)

type OpenHow struct {
4 changes: 4 additions & 0 deletions pkg/filesystem/directory.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ type Directory interface {
// Function that base types may use to implement calls that
// require double dispatching, such as hardlinking and renaming.
Apply(arg interface{}) error

// Mount and Unmount.
Mount(mountpoint path.Component, source string, fstype string) error
Unmount(mountpoint path.Component) error
}

// DirectoryCloser is a Directory handle that can be released.
Expand Down
4 changes: 4 additions & 0 deletions pkg/filesystem/local_directory_darwin.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,7 @@ func (d *localDirectory) Mknod(name path.Component, perm os.FileMode, deviceNumb
func clonefileImpl(oldFD int, oldName string, newFD int, newName string) error {
return unix.Clonefileat(oldFD, oldName, newFD, newName, unix.CLONE_NOFOLLOW)
}

func (d *localDirectory) Mount(mountpoint path.Component, source string, fstype string) error {
return status.Error(codes.Unimplemented, "Mount is not supported")
}
4 changes: 4 additions & 0 deletions pkg/filesystem/local_directory_freebsd.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ func (d *localDirectory) Mknod(name path.Component, perm os.FileMode, deviceNumb
func clonefileImpl(oldFD int, oldName string, newFD int, newName string) error {
return status.Error(codes.Unimplemented, "Clonefile is only supported on Darwin")
}

func (d *localDirectory) Mount(mountpoint path.Component, source string, fstype string) error {
return status.Error(codes.Unimplemented, "Mount is not supported")
}
38 changes: 38 additions & 0 deletions pkg/filesystem/local_directory_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"runtime"

"github.com/buildbarn/bb-storage/pkg/filesystem/path"
"github.com/buildbarn/bb-storage/pkg/util"

"golang.org/x/sys/unix"
"google.golang.org/grpc/codes"
Expand All @@ -34,3 +35,40 @@ func (d *localDirectory) Mknod(name path.Component, perm os.FileMode, deviceNumb
func clonefileImpl(oldFD int, oldName string, newFD int, newName string) error {
return status.Error(codes.Unimplemented, "Clonefile is only supported on Darwin")
}

func (d *localDirectory) Mount(mountpoint path.Component, source string, fstype string) error {
defer runtime.KeepAlive(d)

mountname := mountpoint.String()
fd, err := unix.Fsopen(fstype, unix.FSOPEN_CLOEXEC)
if err != nil {
return util.StatusWrapf(err, "Fsopen %#v", fstype)
}
defer unix.Close(fd)

err = unix.FsconfigSetString(fd, "source", source)
if err != nil {
return util.StatusWrapf(err, "Fsconfig source %#v", source)
}

err = unix.FsconfigCreate(fd)
if err != nil {
return util.StatusWrap(err, "Fsconfig create")
}

mfd, err := unix.Fsmount(fd, unix.FSMOUNT_CLOEXEC, unix.MS_NOEXEC)
if err != nil {
return util.StatusWrap(err, "Fsmount")
}
// NB: `Fsmount` creates a file descriptor to the mount object, that can be
// used to move it again. But we will not do so, so it is best to close it.
// Unmount will fail with `EBUSY` if it is left open.
defer unix.Close(mfd)

err = unix.MoveMount(mfd, "", d.fd, mountname, unix.MOVE_MOUNT_F_EMPTY_PATH)
if err != nil {
return util.StatusWrapf(err, "Movemount mountname %#v in file descriptor %d", mountname, d.fd)
}

return nil
}
4 changes: 2 additions & 2 deletions pkg/filesystem/local_directory_unix.go
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ func (d *localDirectory) Remove(name path.Component) error {

var workingDirectoryLock sync.Mutex

func (d *localDirectory) unmount(name path.Component) error {
func (d *localDirectory) Unmount(name path.Component) error {
defer runtime.KeepAlive(d)

// POSIX systems provide no umountat() system call that permits
Expand Down Expand Up @@ -302,7 +302,7 @@ func (d *localDirectory) removeAllChildren(parentDeviceNumber rawDeviceNumber) e
// unmount until the remaining directory is on the same
// file system.
for parentDeviceNumber != childDeviceNumber {
if err := d.unmount(component); err != nil {
if err := d.Unmount(component); err != nil {
return err
}
fileType, childDeviceNumber, _, err = d.lstat(component)
Expand Down
8 changes: 8 additions & 0 deletions pkg/filesystem/local_directory_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -978,3 +978,11 @@ func (d *localDirectory) Apply(arg interface{}) error {
return syscall.EXDEV
}
}

func (d *localDirectory) Mount(mountpoint path.Component, source string, fstype string) error {
return status.Error(codes.Unimplemented, "Mount is not supported")
}

func (d *localDirectory) Unmount(mountpoint path.Component) error {
return status.Error(codes.Unimplemented, "Unmount is not supported")
}

0 comments on commit 646f697

Please sign in to comment.