From b5906f1fbfec16600468e3eeb8b6ed66551307d9 Mon Sep 17 00:00:00 2001 From: zhangsong34 Date: Wed, 22 Jan 2020 02:43:06 -0500 Subject: [PATCH] syscontainer-tools: internal change Signed-off-by: zhangsong34 --- hooks/syscontainer-hooks/prestart.go | 1 + libdevice/container_work.go | 13 +++- libdevice/devices_unix.go | 100 +++++++++++++++++++++++++-- types/device.go | 1 + 4 files changed, 110 insertions(+), 5 deletions(-) diff --git a/hooks/syscontainer-hooks/prestart.go b/hooks/syscontainer-hooks/prestart.go index 43ef6e3..080ccba 100644 --- a/hooks/syscontainer-hooks/prestart.go +++ b/hooks/syscontainer-hooks/prestart.go @@ -96,6 +96,7 @@ func AddDevices(state *configs.HookState, hookConfig *hconfig.ContainerHookConfi // re-calc the dest path of device. resolvDev := calcPathForDevice(state.Root, dev) device, err := libdevice.ParseDevice(resolvDev) + device.Root = state.Root if err != nil { logrus.Errorf("[device-hook] Add device (%s), parse device failed: %v", resolvDev, err) return err diff --git a/libdevice/container_work.go b/libdevice/container_work.go index 0d4edbe..0007f0a 100644 --- a/libdevice/container_work.go +++ b/libdevice/container_work.go @@ -237,6 +237,12 @@ func doAddDevice(pipe *os.File) error { if err := MknodDevice(device.Path, device); err != nil { return fmt.Errorf("Current OS kernel do not support mknod in container user namespace for root, err: %s", err) } + if device.Type == "b" { + // fdisk: add device soft link to /sys/block + if err := AddDeviceToSysBlock(device); err != nil { + return fmt.Errorf("Add device to /sys/block failed: %s", device, err) + } + } return nil } @@ -255,7 +261,12 @@ func doRemoveDevice(pipe *os.File) error { if _, err := DeviceFromPath(device.Path, ""); err != nil { return err } - + if device.Type == "b" { + // fdisk: remove device symlink in /sys/block + if err := RemoveDeviceFromSysBlock(device.Path); err != nil { + return err + } + } // need strict check here? return os.Remove(device.Path) } diff --git a/libdevice/devices_unix.go b/libdevice/devices_unix.go index 4fe3a33..36a6ada 100644 --- a/libdevice/devices_unix.go +++ b/libdevice/devices_unix.go @@ -18,20 +18,26 @@ package libdevice import ( "errors" "fmt" + "github.com/mrunalp/fileutils" + "github.com/sirupsen/logrus" + "golang.org/x/sys/unix" + "isula.org/syscontainer-tools/types" "os" "os/exec" "path/filepath" "strings" "syscall" - - "isula.org/syscontainer-tools/types" - - "github.com/sirupsen/logrus" ) var ( // ErrNotADevice not a device error ErrNotADevice = errors.New("not a device") + // MountSourcePath mount source path + MountSourcePath = "/mnt/sys/block" + // DevBlockPath device block path + DevBlockPath = "/sys/dev/block" + // MountDestPath mount dest path + MountDestPath = "/sys/block" ) // Testing dependencies @@ -243,6 +249,92 @@ func MknodDevice(dest string, node *types.Device) error { return syscall.Chown(dest, int(node.UID), int(node.GID)) } +// prepareSysBlockMount bind mount /mnt/sys/block to /sys/block +func prepareSysBlockMount(root string) error { + if unix.Access(filepath.Join(root, MountDestPath), unix.W_OK) == nil { + return nil + } + if err := os.RemoveAll(filepath.Join(root, MountSourcePath)); err != nil { + return err + } + if err := fileutils.CopyDirectory( + filepath.Join(root, MountDestPath), + filepath.Join(root, MountSourcePath)); err != nil { + return err + } + if err := syscall.Mount( + filepath.Join(root, MountSourcePath), + filepath.Join(root, MountDestPath), + "", + syscall.MS_BIND|syscall.MS_REC, ""); err != nil { + return err + } + return nil +} + +// AddDeviceToSysBlock add device to /sys/block in container +func AddDeviceToSysBlock(node *types.Device) error { + if err := prepareSysBlockMount(node.Root); err != nil { + return err + } + devStr := fmt.Sprintf("%d:%d", node.Major, node.Minor) + linkPath := filepath.Join(DevBlockPath, devStr) + if _, err := os.Lstat(linkPath); os.IsNotExist(err) { + return err + } + realPath, err := os.Readlink(linkPath) + if err != nil { + return err + } + hostDeviceName := filepath.Base(realPath) + containerDeviceName := filepath.Base(node.Path) + if err := os.Chdir(filepath.Join(node.Root, MountSourcePath)); err != nil { + return err + } + if _, err := os.Lstat(containerDeviceName); err == nil { + if err := os.Remove(containerDeviceName); err != nil { + return err + } + } + destPath := strings.Replace(realPath, "../", "", 1) + if destPath == "" { + return nil + } + if err := os.Symlink(destPath, containerDeviceName); err != nil { + return err + } + if err := os.Chdir(filepath.Join(node.Root, "/dev")); err != nil { + return err + } + if hostDeviceName != containerDeviceName { + if _, err := os.Stat(hostDeviceName); os.IsNotExist(err) { + return os.Symlink(containerDeviceName, hostDeviceName) + } + } + return nil +} + +// RemoveDeviceFromSysBlock remove device from /sys/block in container +func RemoveDeviceFromSysBlock(path string) error { + containerDeviceName := filepath.Base(path) + linkPath := filepath.Join(MountDestPath, containerDeviceName) + realPath, err := os.Readlink(linkPath) + if err != nil { + return err + } + hostDeviceName := filepath.Base(realPath) + devPath := filepath.Join("/dev", hostDeviceName) + if _, err := os.Lstat(linkPath); err == nil { + if err := os.Remove(linkPath); err != nil { + return err + } + } + if hostDeviceName != containerDeviceName { + return os.Remove(devPath) + } + return nil +} + // SetDefaultPath set default path for device func SetDefaultPath(dev *types.Device) { if dev.Path == "" { diff --git a/types/device.go b/types/device.go index f913763..2e8d2ed 100644 --- a/types/device.go +++ b/types/device.go @@ -72,6 +72,7 @@ type Device struct { GID uint32 // Group ID Allow bool // Used to differ add or remove Parent string // Parent device name(pathonhost) + Root string // Rootfs path, prestart hook needed. } // Qos is the device Qos structure