Ver código fonte

Move attach loop device to its own file

Guillaume J. Charmes 11 anos atrás
pai
commit
eb528b959e

+ 178 - 0
graphdriver/devmapper/attachLoopback.go

@@ -0,0 +1,178 @@
+package devmapper
+
+import (
+	"fmt"
+	"github.com/dotcloud/docker/utils"
+	"unsafe"
+)
+
+func ioctlLoopCtlGetFree(fd uintptr) (int, error) {
+	index, _, err := sysSyscall(sysSysIoctl, fd, LoopCtlGetFree, 0)
+	if err != 0 {
+		return 0, err
+	}
+	return int(index), nil
+}
+
+func ioctlLoopSetFd(loopFd, sparseFd uintptr) error {
+	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetFd, sparseFd); err != 0 {
+		return err
+	}
+	return nil
+}
+
+func ioctlLoopSetStatus64(loopFd uintptr, loopInfo *LoopInfo64) error {
+	_, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetStatus64, uintptr(unsafe.Pointer(loopInfo)))
+	if err != 0 {
+		return err
+	}
+	return nil
+}
+
+func ioctlLoopClrFd(loopFd uintptr) error {
+	_, _, err := sysSyscall(sysSysIoctl, loopFd, LoopClrFd, 0)
+	if err != 0 {
+		return err
+	}
+	return nil
+}
+
+// //func dmGetLoopbackBackingFileFct(fd uintptr) (uint64, uint64, sysErrno) {
+// func ioctlLoopGetStatus64(loopFd uintptr) (*LoopInfo64, error) {
+// 	var lo64 C.struct_loop_info64
+// 	_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_GET_STATUS64, uintptr(unsafe.Pointer(&lo64)))
+// 	return uint64(lo64.lo_device), uint64(lo64.lo_inode), sysErrno(err)
+// }
+
+// func dmLoopbackSetCapacityFct(fd uintptr) sysErrno {
+// 	_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_SET_CAPACITY, 0)
+// 	return sysErrno(err)
+// }
+
+// func dmGetBlockSizeFct(fd uintptr) (int64, sysErrno) {
+// 	var size int64
+// 	_, _, err := sysSyscall(sysSysIoctl, fd, C.BLKGETSIZE64, uintptr(unsafe.Pointer(&size)))
+// 	return size, sysErrno(err)
+// }
+
+// func getBlockSizeFct(fd uintptr, size *uint64) sysErrno {
+// 	_, _, err := sysSyscall(sysSysIoctl, fd, C.BLKGETSIZE64, uintptr(unsafe.Pointer(&size)))
+// 	return sysErrno(err)
+// }
+
+func getNextFreeLoopbackIndex() (int, error) {
+	f, err := osOpenFile("/dev/loop-control", osORdOnly, 0644)
+	if err != nil {
+		return 0, err
+	}
+	defer f.Close()
+
+	index, err := ioctlLoopCtlGetFree(f.Fd())
+	if index < 0 {
+		index = 0
+	}
+	return index, err
+}
+
+func openNextAvailableLoopback(index int, sparseFile *osFile) (loopFile *osFile, err error) {
+	// Start looking for a free /dev/loop
+	for {
+		target := fmt.Sprintf("/dev/loop%d", index)
+		index++
+
+		fi, err := osStat(target)
+		if err != nil {
+			if osIsNotExist(err) {
+				utils.Errorf("There are no more loopback device available.")
+			}
+			return nil, ErrAttachLoopbackDevice
+		}
+
+		// FIXME: Check here if target is a block device (in C: S_ISBLK(mode))
+		if fi.IsDir() {
+		}
+
+		// Open the targeted loopback (use OpenFile because Open sets O_CLOEXEC)
+		loopFile, err = osOpenFile(target, osORdWr, 0644)
+		if err != nil {
+			utils.Errorf("Error openning loopback device: %s", err)
+			return nil, ErrAttachLoopbackDevice
+		}
+
+		// Try to attach to the loop file
+		if err := ioctlLoopSetFd(loopFile.Fd(), sparseFile.Fd()); err != nil {
+			loopFile.Close()
+
+			// If the error is EBUSY, then try the next loopback
+			if err != sysEBusy {
+				utils.Errorf("Cannot set up loopback device %s: %s", target, err)
+				return nil, ErrAttachLoopbackDevice
+			}
+
+			// Otherwise, we keep going with the loop
+			continue
+		}
+		// In case of success, we finished. Break the loop.
+		break
+	}
+
+	// This can't happen, but let's be sure
+	if loopFile == nil {
+		utils.Errorf("Unreachable code reached! Error attaching %s to a loopback device.", sparseFile.Name())
+		return nil, ErrAttachLoopbackDevice
+	}
+
+	return loopFile, nil
+}
+
+func stringToLoopName(src string) [LoNameSize]uint8 {
+	var dst [LoNameSize]uint8
+	copy(dst[:], src[:])
+	return dst
+}
+
+// attachLoopDevice attaches the given sparse file to the next
+// available loopback device. It returns an opened *osFile.
+func attachLoopDevice(sparseName string) (loop *osFile, err error) {
+
+	// Try to retrieve the next available loopback device via syscall.
+	// If it fails, we discard error and start loopking for a
+	// loopback from index 0.
+	startIndex, err := getNextFreeLoopbackIndex()
+	if err != nil {
+		utils.Debugf("Error retrieving the next available loopback: %s", err)
+	}
+
+	// Open the given sparse file (use OpenFile because Open sets O_CLOEXEC)
+	sparseFile, err := osOpenFile(sparseName, osORdWr, 0644)
+	if err != nil {
+		utils.Errorf("Error openning sparse file %s: %s", sparseName, err)
+		return nil, ErrAttachLoopbackDevice
+	}
+	defer sparseFile.Close()
+
+	loopFile, err := openNextAvailableLoopback(startIndex, sparseFile)
+	if err != nil {
+		return nil, err
+	}
+
+	// Set the status of the loopback device
+	loopInfo := &LoopInfo64{
+		loFileName: stringToLoopName(loopFile.Name()),
+		loOffset:   0,
+		loFlags:    LoFlagsAutoClear,
+	}
+
+	if err := ioctlLoopSetStatus64(loopFile.Fd(), loopInfo); err != nil {
+		utils.Errorf("Cannot set up loopback device info: %s", err)
+
+		// If the call failed, then free the loopback device
+		if err := ioctlLoopClrFd(loopFile.Fd()); err != nil {
+			utils.Errorf("Error while cleaning up the loopback device")
+		}
+		loopFile.Close()
+		return nil, ErrAttachLoopbackDevice
+	}
+
+	return loopFile, nil
+}

+ 0 - 107
graphdriver/devmapper/devmapper.go

@@ -5,7 +5,6 @@ import (
 	"fmt"
 	"fmt"
 	"github.com/dotcloud/docker/utils"
 	"github.com/dotcloud/docker/utils"
 	"runtime"
 	"runtime"
-	"unsafe"
 )
 )
 
 
 type DevmapperLogger interface {
 type DevmapperLogger interface {
@@ -565,109 +564,3 @@ func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseNa
 
 
 	return nil
 	return nil
 }
 }
-
-type LoopInfo64 struct {
-	loDevice           uint64 /* ioctl r/o */
-	loInode            uint64 /* ioctl r/o */
-	loRdevice          uint64 /* ioctl r/o */
-	loOffset           uint64
-	loSizelimit        uint64 /* bytes, 0 == max available */
-	loNumber           uint32 /* ioctl r/o */
-	loEncrypt_type     uint32
-	loEncrypt_key_size uint32 /* ioctl w/o */
-	loFlags            uint32 /* ioctl r/o */
-	loFileName         [LoNameSize]uint8
-	loCryptName        [LoNameSize]uint8
-	loEncryptKey       [LoKeySize]uint8 /* ioctl w/o */
-	loInit             [2]uint64
-}
-
-// attachLoopDevice attaches the given sparse file to the next
-// available loopback device. It returns an opened *osFile.
-func attachLoopDevice(filename string) (loop *osFile, err error) {
-	startIndex := 0
-
-	// Try to retrieve the next available loopback device via syscall.
-	// If it fails, we discard error and start loopking for a
-	// loopback from index 0.
-	if f, err := osOpenFile("/dev/loop-control", osORdOnly, 0644); err == nil {
-		if index, _, err := sysSyscall(sysSysIoctl, f.Fd(), LoopCtlGetFree, 0); err != 0 {
-			utils.Debugf("Error retrieving the next available loopback: %s", err)
-		} else if index > 0 {
-			startIndex = int(index)
-		}
-		f.Close()
-	}
-
-	// Open the given sparse file (use OpenFile because Open sets O_CLOEXEC)
-	f, err := osOpenFile(filename, osORdWr, 0644)
-	if err != nil {
-		return nil, err
-	}
-	defer f.Close()
-
-	var (
-		target   string
-		loopFile *osFile
-	)
-	// Start looking for a free /dev/loop
-	for i := startIndex; ; {
-		target = fmt.Sprintf("/dev/loop%d", i)
-
-		fi, err := osStat(target)
-		if err != nil {
-			if osIsNotExist(err) {
-				utils.Errorf("There are no more loopback device available.")
-			}
-		}
-
-		// FIXME: Check here if target is a block device (in C: S_ISBLK(mode))
-		if fi.IsDir() {
-		}
-
-		// Open the targeted loopback (use OpenFile because Open sets O_CLOEXEC)
-		loopFile, err = osOpenFile(target, osORdWr, 0644)
-		if err != nil {
-			return nil, err
-		}
-
-		// Try to attach to the loop file
-		if _, _, err := sysSyscall(sysSysIoctl, loopFile.Fd(), LoopSetFd, f.Fd()); err != 0 {
-			loopFile.Close()
-			// If the error is EBUSY, then try the next loopback
-			if err != sysEBusy {
-				utils.Errorf("Cannot set up loopback device %s: %s", target, err)
-				return nil, err
-			}
-		} else {
-			// In case of success, we finished. Break the loop.
-			break
-		}
-		// In case of EBUSY error, the loop keep going.
-	}
-
-	// This can't happen, but let's be sure
-	if loopFile == nil {
-		return nil, fmt.Errorf("Unreachable code reached! Error attaching %s to a loopback device.", filename)
-	}
-
-	// Set the status of the loopback device
-	var loopInfo LoopInfo64
-
-	// Due to type incompatibility (string vs [64]uint8), we copy data
-	copy(loopInfo.loFileName[:], target[:])
-	loopInfo.loOffset = 0
-	loopInfo.loFlags = LoFlagsAutoClear
-
-	if _, _, err := sysSyscall(sysSysIoctl, loopFile.Fd(), LoopSetStatus64, uintptr(unsafe.Pointer(&loopInfo))); err != 0 {
-		// If the call failed, then free the loopback device
-		utils.Errorf("Cannot set up loopback device info: %s", err)
-		if _, _, err := sysSyscall(sysSysIoctl, loopFile.Fd(), LoopClrFd, 0); err != 0 {
-			utils.Errorf("Error while cleaning up the loopback device")
-		}
-		loopFile.Close()
-		return nil, err
-	}
-
-	return loopFile, nil
-}

+ 30 - 30
graphdriver/devmapper/devmapper_wrapper.go

@@ -33,7 +33,23 @@ import (
 )
 )
 
 
 type (
 type (
-	CDmTask C.struct_dm_task
+	CDmTask     C.struct_dm_task
+	CLoopInfo64 C.struct_loop_info64
+	LoopInfo64  struct {
+		loDevice           uint64 /* ioctl r/o */
+		loInode            uint64 /* ioctl r/o */
+		loRdevice          uint64 /* ioctl r/o */
+		loOffset           uint64
+		loSizelimit        uint64 /* bytes, 0 == max available */
+		loNumber           uint32 /* ioctl r/o */
+		loEncrypt_type     uint32
+		loEncrypt_key_size uint32 /* ioctl w/o */
+		loFlags            uint32 /* ioctl r/o */
+		loFileName         [LoNameSize]uint8
+		loCryptName        [LoNameSize]uint8
+		loEncryptKey       [LoKeySize]uint8 /* ioctl w/o */
+		loInit             [2]uint64
+	}
 )
 )
 
 
 // FIXME: Make sure the values are defined in C
 // FIXME: Make sure the values are defined in C
@@ -50,7 +66,6 @@ const (
 )
 )
 
 
 var (
 var (
-	DmAttachLoopDevice       = dmAttachLoopDeviceFct
 	DmGetBlockSize           = dmGetBlockSizeFct
 	DmGetBlockSize           = dmGetBlockSizeFct
 	DmGetLibraryVersion      = dmGetLibraryVersionFct
 	DmGetLibraryVersion      = dmGetLibraryVersionFct
 	DmGetNextTarget          = dmGetNextTargetFct
 	DmGetNextTarget          = dmGetNextTargetFct
@@ -137,23 +152,6 @@ func dmTaskAddTargetFct(task *CDmTask,
 	return int(C.dm_task_add_target((*C.struct_dm_task)(task), C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
 	return int(C.dm_task_add_target((*C.struct_dm_task)(task), C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
 }
 }
 
 
-func dmGetLoopbackBackingFileFct(fd uintptr) (uint64, uint64, sysErrno) {
-	var lo64 C.struct_loop_info64
-	_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_GET_STATUS64, uintptr(unsafe.Pointer(&lo64)))
-	return uint64(lo64.lo_device), uint64(lo64.lo_inode), sysErrno(err)
-}
-
-func dmLoopbackSetCapacityFct(fd uintptr) sysErrno {
-	_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_SET_CAPACITY, 0)
-	return sysErrno(err)
-}
-
-func dmGetBlockSizeFct(fd uintptr) (int64, sysErrno) {
-	var size int64
-	_, _, err := sysSyscall(sysSysIoctl, fd, C.BLKGETSIZE64, uintptr(unsafe.Pointer(&size)))
-	return size, sysErrno(err)
-}
-
 func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
 func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
 	Cinfo := C.struct_dm_info{}
 	Cinfo := C.struct_dm_info{}
 	defer func() {
 	defer func() {
@@ -187,19 +185,21 @@ func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64, targ
 	return uintptr(nextp)
 	return uintptr(nextp)
 }
 }
 
 
-func dmAttachLoopDeviceFct(filename string, fd *int) string {
-	return ""
-	// cFilename := C.CString(filename)
-	// defer free(cFilename)
+func dmGetLoopbackBackingFileFct(fd uintptr) (uint64, uint64, sysErrno) {
+	var lo64 C.struct_loop_info64
+	_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_GET_STATUS64, uintptr(unsafe.Pointer(&lo64)))
+	return uint64(lo64.lo_device), uint64(lo64.lo_inode), sysErrno(err)
+}
 
 
-	// var cFd C.int
-	// defer func() {
-	// 	*fd = int(cFd)
-	// }()
+func dmLoopbackSetCapacityFct(fd uintptr) sysErrno {
+	_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_SET_CAPACITY, 0)
+	return sysErrno(err)
+}
 
 
-	// ret := C.attach_loop_device(cFilename, &cFd)
-	// defer free(ret)
-	// return C.GoString(ret)
+func dmGetBlockSizeFct(fd uintptr) (int64, sysErrno) {
+	var size int64
+	_, _, err := sysSyscall(sysSysIoctl, fd, C.BLKGETSIZE64, uintptr(unsafe.Pointer(&size)))
+	return size, sysErrno(err)
 }
 }
 
 
 func getBlockSizeFct(fd uintptr, size *uint64) sysErrno {
 func getBlockSizeFct(fd uintptr, size *uint64) sysErrno {