From a782fd6da2fa9fa350ef754b68b5e80261cfeddc Mon Sep 17 00:00:00 2001 From: Alexandru Matei Date: Wed, 27 Sep 2023 12:10:42 +0300 Subject: [PATCH] Use LOOP_CONFIGURE when creating loop devices LOOP_CONFIGURE is a new ioctl that is a lot faster than the LOOP_SET_FD+LOOP_SET_STATUS64 calls Signed-off-by: Alexandru Matei --- mount/losetup_linux.go | 47 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/mount/losetup_linux.go b/mount/losetup_linux.go index e3647e954..99cc1dce2 100644 --- a/mount/losetup_linux.go +++ b/mount/losetup_linux.go @@ -21,8 +21,11 @@ import ( "fmt" "os" "strings" + "syscall" "time" + "unsafe" + kernel "github.com/containerd/containerd/contrib/seccomp/kernelversion" "github.com/containerd/containerd/pkg/randutil" "golang.org/x/sys/unix" ) @@ -32,8 +35,26 @@ const ( loopDevFormat = "/dev/loop%d" ebusyString = "device or resource busy" + + loopConfigureIoctl = 0x4c0a ) +type LoopConfig struct { + Fd uint32 + BlockSize uint32 + Info unix.LoopInfo64 + Reserved [8]uint64 +} + +func ioctlConfigure(fd int, value *LoopConfig) error { + _, _, err := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), uintptr(loopConfigureIoctl), uintptr(unsafe.Pointer(value))) + if err == 0 { + return nil + } + + return err +} + // LoopParams parameters to control loop device setup type LoopParams struct { // Loop device should forbid write @@ -84,6 +105,32 @@ func setupLoopDev(backingFile, loopDev string, param LoopParams) (_ *os.File, re } }() + fiveDotEight := kernel.KernelVersion{Kernel: 5, Major: 8} + if ok, err := kernel.GreaterEqualThan(fiveDotEight); err == nil && ok { + config := LoopConfig{ + Fd: uint32(back.Fd()), + } + + copy(config.Info.File_name[:], backingFile) + if param.Readonly { + config.Info.Flags |= unix.LO_FLAGS_READ_ONLY + } + + if param.Autoclear { + config.Info.Flags |= unix.LO_FLAGS_AUTOCLEAR + } + + if param.Direct { + config.Info.Flags |= unix.LO_FLAGS_DIRECT_IO + } + + if err := ioctlConfigure(int(loop.Fd()), &config); err != nil { + return nil, fmt.Errorf("failed to configure loop device: %s: %w", loopDev, err) + } + + return loop, nil + } + // 2. Set FD if err := unix.IoctlSetInt(int(loop.Fd()), unix.LOOP_SET_FD, int(back.Fd())); err != nil { return nil, fmt.Errorf("could not set loop fd for device: %s: %w", loopDev, err)