Skip to content

Commit

Permalink
Add mount functionality to 'Directory' (#177)
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.

Co-authored-by: Nils Wireklint <nils@meroton.com>
  • Loading branch information
stagnation and stagnation authored Dec 20, 2023
1 parent b14f4ae commit 18fd05d
Show file tree
Hide file tree
Showing 9 changed files with 241 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 @@ -1489,6 +1489,7 @@ def go_dependencies():
go_repository(
name = "org_golang_x_sys",
importpath = "golang.org/x/sys",
patches = ["//:patches/org_golang_x_sys/golang-issue-59357.diff"],
sum = "h1:Vz7Qs629MkJkGyHxUlRHizWJRG2j8fbQKjELVSNhy7Q=",
version = "v0.14.0",
)
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, 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, 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, fstype string) error {
return status.Error(codes.Unimplemented, "Mount is not supported")
}
36 changes: 36 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,38 @@ 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, fstype string) error {
mountname := mountpoint.String()
fd, err := unix.Fsopen(fstype, unix.FSOPEN_CLOEXEC)
if err != nil {
return util.StatusWrapf(err, "Fsopen '%s'", fstype)
}
defer unix.Close(fd)

err = unix.FsconfigSetString(fd, "source", source)
if err != nil {
return util.StatusWrapf(err, "Fsconfig source '%s'", 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 '%s' 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, 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 18fd05d

Please sign in to comment.