-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #15962 from dfr/freebsd-volume
Add volume support for FreeBSD
- Loading branch information
Showing
8 changed files
with
249 additions
and
195 deletions.
There are no files selected for viewing
4 changes: 2 additions & 2 deletions
4
libpod/runtime_volume_linux.go → libpod/runtime_volume_common.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
//go:build linux | ||
// +build linux | ||
//go:build linux || freebsd | ||
// +build linux freebsd | ||
|
||
package libpod | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
//go:build !linux | ||
// +build !linux | ||
//go:build !linux && !freebsd | ||
// +build !linux,!freebsd | ||
|
||
package libpod | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
//go:build freebsd | ||
// +build freebsd | ||
|
||
package libpod | ||
|
||
import ( | ||
"errors" | ||
"syscall" | ||
|
||
spec "github.com/opencontainers/runtime-spec/specs-go" | ||
"github.com/sirupsen/logrus" | ||
"golang.org/x/sys/unix" | ||
) | ||
|
||
// systemdSliceFromPath makes a new systemd slice under the given parent with | ||
// the given name. | ||
// The parent must be a slice. The name must NOT include ".slice" | ||
func systemdSliceFromPath(parent, name string, resources *spec.LinuxResources) (string, error) { | ||
return "", errors.New("not implemented systemdSliceFromPath") | ||
} | ||
|
||
// No equivalent on FreeBSD? | ||
func LabelVolumePath(path string) error { | ||
return nil | ||
} | ||
|
||
// Unmount umounts a target directory | ||
func Unmount(mount string) { | ||
if err := unix.Unmount(mount, unix.MNT_FORCE); err != nil { | ||
if err != syscall.EINVAL { | ||
logrus.Warnf("Failed to unmount %s : %v", mount, err) | ||
} else { | ||
logrus.Debugf("failed to unmount %s : %v", mount, err) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
//go:build !linux | ||
// +build !linux | ||
//go:build !linux && !freebsd | ||
// +build !linux,!freebsd | ||
|
||
package libpod | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,194 @@ | ||
//go:build linux || freebsd | ||
// +build linux freebsd | ||
|
||
package libpod | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"os/exec" | ||
"strings" | ||
|
||
"github.com/containers/podman/v4/libpod/define" | ||
pluginapi "github.com/docker/go-plugins-helpers/volume" | ||
"github.com/sirupsen/logrus" | ||
"golang.org/x/sys/unix" | ||
) | ||
|
||
// This is a pseudo-container ID to use when requesting a mount or unmount from | ||
// the volume plugins. | ||
// This is the shas256 of the string "placeholder\n". | ||
const pseudoCtrID = "2f73349cfc4630255319c6c8dfc1b46a8996ace9d14d8e07563b165915918ec2" | ||
|
||
// mount mounts the volume if necessary. | ||
// A mount is necessary if a volume has any options set. | ||
// If a mount is necessary, v.state.MountCount will be incremented. | ||
// If it was 0 when the increment occurred, the volume will be mounted on the | ||
// host. Otherwise, we assume it is already mounted. | ||
// Must be done while the volume is locked. | ||
// Is a no-op on volumes that do not require a mount (as defined by | ||
// volumeNeedsMount()). | ||
func (v *Volume) mount() error { | ||
if !v.needsMount() { | ||
return nil | ||
} | ||
|
||
// Update the volume from the DB to get an accurate mount counter. | ||
if err := v.update(); err != nil { | ||
return err | ||
} | ||
|
||
// If the count is non-zero, the volume is already mounted. | ||
// Nothing to do. | ||
if v.state.MountCount > 0 { | ||
v.state.MountCount++ | ||
logrus.Debugf("Volume %s mount count now at %d", v.Name(), v.state.MountCount) | ||
return v.save() | ||
} | ||
|
||
// Volume plugins implement their own mount counter, based on the ID of | ||
// the mounting container. But we already have one, and honestly I trust | ||
// ours more. So hardcode container ID to something reasonable, and use | ||
// the same one for everything. | ||
if v.UsesVolumeDriver() { | ||
if v.plugin == nil { | ||
return fmt.Errorf("volume plugin %s (needed by volume %s) missing: %w", v.Driver(), v.Name(), define.ErrMissingPlugin) | ||
} | ||
|
||
req := new(pluginapi.MountRequest) | ||
req.Name = v.Name() | ||
req.ID = pseudoCtrID | ||
mountPoint, err := v.plugin.MountVolume(req) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
v.state.MountCount++ | ||
v.state.MountPoint = mountPoint | ||
return v.save() | ||
} else if v.config.Driver == define.VolumeDriverImage { | ||
mountPoint, err := v.runtime.storageService.MountContainerImage(v.config.StorageID) | ||
if err != nil { | ||
return fmt.Errorf("mounting volume %s image failed: %w", v.Name(), err) | ||
} | ||
|
||
v.state.MountCount++ | ||
v.state.MountPoint = mountPoint | ||
return v.save() | ||
} | ||
|
||
volDevice := v.config.Options["device"] | ||
volType := v.config.Options["type"] | ||
volOptions := v.config.Options["o"] | ||
|
||
// Some filesystems (tmpfs) don't have a device, but we still need to | ||
// give the kernel something. | ||
if volDevice == "" && volType != "" { | ||
volDevice = volType | ||
} | ||
|
||
// We need to use the actual mount command. | ||
// Convincing unix.Mount to use the same semantics as the mount command | ||
// itself seems prohibitively difficult. | ||
// TODO: might want to cache this path in the runtime? | ||
mountPath, err := exec.LookPath("mount") | ||
if err != nil { | ||
return fmt.Errorf("locating 'mount' binary: %w", err) | ||
} | ||
mountArgs := []string{} | ||
if volOptions != "" { | ||
mountArgs = append(mountArgs, "-o", volOptions) | ||
} | ||
switch volType { | ||
case "": | ||
case "bind": | ||
mountArgs = append(mountArgs, "-o", volType) | ||
default: | ||
mountArgs = append(mountArgs, "-t", volType) | ||
} | ||
|
||
mountArgs = append(mountArgs, volDevice, v.config.MountPoint) | ||
mountCmd := exec.Command(mountPath, mountArgs...) | ||
|
||
logrus.Debugf("Running mount command: %s %s", mountPath, strings.Join(mountArgs, " ")) | ||
if output, err := mountCmd.CombinedOutput(); err != nil { | ||
logrus.Debugf("Mount %v failed with %v", mountCmd, err) | ||
return errors.New(string(output)) | ||
} | ||
|
||
logrus.Debugf("Mounted volume %s", v.Name()) | ||
|
||
// Increment the mount counter | ||
v.state.MountCount++ | ||
logrus.Debugf("Volume %s mount count now at %d", v.Name(), v.state.MountCount) | ||
return v.save() | ||
} | ||
|
||
// unmount unmounts the volume if necessary. | ||
// Unmounting a volume that is not mounted is a no-op. | ||
// Unmounting a volume that does not require a mount is a no-op. | ||
// The volume must be locked for this to occur. | ||
// The mount counter will be decremented if non-zero. If the counter reaches 0, | ||
// the volume will really be unmounted, as no further containers are using the | ||
// volume. | ||
// If force is set, the volume will be unmounted regardless of mount counter. | ||
func (v *Volume) unmount(force bool) error { | ||
if !v.needsMount() { | ||
return nil | ||
} | ||
|
||
// Update the volume from the DB to get an accurate mount counter. | ||
if err := v.update(); err != nil { | ||
return err | ||
} | ||
|
||
if v.state.MountCount == 0 { | ||
logrus.Debugf("Volume %s already unmounted", v.Name()) | ||
return nil | ||
} | ||
|
||
if !force { | ||
v.state.MountCount-- | ||
} else { | ||
v.state.MountCount = 0 | ||
} | ||
|
||
logrus.Debugf("Volume %s mount count now at %d", v.Name(), v.state.MountCount) | ||
|
||
if v.state.MountCount == 0 { | ||
if v.UsesVolumeDriver() { | ||
if v.plugin == nil { | ||
return fmt.Errorf("volume plugin %s (needed by volume %s) missing: %w", v.Driver(), v.Name(), define.ErrMissingPlugin) | ||
} | ||
|
||
req := new(pluginapi.UnmountRequest) | ||
req.Name = v.Name() | ||
req.ID = pseudoCtrID | ||
if err := v.plugin.UnmountVolume(req); err != nil { | ||
return err | ||
} | ||
|
||
v.state.MountPoint = "" | ||
return v.save() | ||
} else if v.config.Driver == define.VolumeDriverImage { | ||
if _, err := v.runtime.storageService.UnmountContainerImage(v.config.StorageID, force); err != nil { | ||
return fmt.Errorf("unmounting volume %s image: %w", v.Name(), err) | ||
} | ||
|
||
v.state.MountPoint = "" | ||
return v.save() | ||
} | ||
|
||
// Unmount the volume | ||
if err := detachUnmount(v.config.MountPoint); err != nil { | ||
if err == unix.EINVAL { | ||
// Ignore EINVAL - the mount no longer exists. | ||
return nil | ||
} | ||
return fmt.Errorf("unmounting volume %s: %w", v.Name(), err) | ||
} | ||
logrus.Debugf("Unmounted volume %s", v.Name()) | ||
} | ||
|
||
return v.save() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package libpod | ||
|
||
import ( | ||
"golang.org/x/sys/unix" | ||
) | ||
|
||
func detachUnmount(mountPoint string) error { | ||
return unix.Unmount(mountPoint, unix.MNT_FORCE) | ||
} |
Oops, something went wrong.