mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Move attach loop device to its own file
This commit is contained in:
parent
74c8f7af75
commit
eb528b959e
3 changed files with 208 additions and 137 deletions
178
graphdriver/devmapper/attachLoopback.go
Normal file
178
graphdriver/devmapper/attachLoopback.go
Normal file
|
@ -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
|
||||||
|
}
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 {
|
func dmGetLoopbackBackingFileFct(fd uintptr) (uint64, uint64, sysErrno) {
|
||||||
return ""
|
var lo64 C.struct_loop_info64
|
||||||
// cFilename := C.CString(filename)
|
_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_GET_STATUS64, uintptr(unsafe.Pointer(&lo64)))
|
||||||
// defer free(cFilename)
|
return uint64(lo64.lo_device), uint64(lo64.lo_inode), sysErrno(err)
|
||||||
|
}
|
||||||
|
|
||||||
// var cFd C.int
|
func dmLoopbackSetCapacityFct(fd uintptr) sysErrno {
|
||||||
// defer func() {
|
_, _, err := sysSyscall(sysSysIoctl, fd, C.LOOP_SET_CAPACITY, 0)
|
||||||
// *fd = int(cFd)
|
return sysErrno(err)
|
||||||
// }()
|
}
|
||||||
|
|
||||||
// ret := C.attach_loop_device(cFilename, &cFd)
|
func dmGetBlockSizeFct(fd uintptr) (int64, sysErrno) {
|
||||||
// defer free(ret)
|
var size int64
|
||||||
// return C.GoString(ret)
|
_, _, 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 {
|
||||||
|
|
Loading…
Add table
Reference in a new issue