From db2bc43017b45dbb4e2aa51e093eab3fbb86ead1 Mon Sep 17 00:00:00 2001 From: Daniel Sweet Date: Sun, 21 Apr 2019 21:38:40 -0400 Subject: [PATCH] Use correct `LOOP_CTL_GET_FREE` API in `pkg/loopback` The `ioctl` interface for the `LOOP_CTL_GET_FREE` request on `/dev/loop-control` is a little different from what `unix.IoctlGetInt` expects: the first index is the returned status in `r1`, not an `int` pointer as the first parameter. Unfortunately we have to go a little lower level to get the appropriate loop device index out, using `unix.Syscall` directly to read from `r1`. Internally, the index is returned as a signed integer to match the internal `ioctl` expectations of interpreting a negative signed integer as an error at the userspace ABI boundary, so the direct interface of `ioctlLoopCtlGetFree` can remain as-is. [@kolyshkin: it still worked before this fix because of /dev scan fallback in ioctlLoopCtlGetFree()] Signed-off-by: Daniel Sweet Signed-off-by: Kir Kolyshkin --- pkg/loopback/ioctl.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/pkg/loopback/ioctl.go b/pkg/loopback/ioctl.go index ab4f6e55c7..35b03d1f14 100644 --- a/pkg/loopback/ioctl.go +++ b/pkg/loopback/ioctl.go @@ -9,11 +9,15 @@ import ( ) func ioctlLoopCtlGetFree(fd uintptr) (int, error) { - index, err := unix.IoctlGetInt(int(fd), LoopCtlGetFree) - if err != nil { + // The ioctl interface for /dev/loop-control (since Linux 3.1) is a bit + // off compared to what you'd expect: instead of writing an integer to a + // parameter pointer like unix.IoctlGetInt() expects, it returns the first + // available loop device index directly. + ioctlReturn, _, err := unix.Syscall(unix.SYS_IOCTL, fd, LoopCtlGetFree, 0) + if err != 0 { return 0, err } - return index, nil + return int(ioctlReturn), nil } func ioctlLoopSetFd(loopFd, sparseFd uintptr) error {