Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add mount functionality to 'Directory' #177

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
stagnation marked this conversation as resolved.
Show resolved Hide resolved
}

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")
}
Loading