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"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
type DevmapperLogger interface {
|
||||
|
@ -565,109 +564,3 @@ func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseNa
|
|||
|
||||
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 (
|
||||
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
|
||||
|
@ -50,7 +66,6 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
DmAttachLoopDevice = dmAttachLoopDeviceFct
|
||||
DmGetBlockSize = dmGetBlockSizeFct
|
||||
DmGetLibraryVersion = dmGetLibraryVersionFct
|
||||
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))
|
||||
}
|
||||
|
||||
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 {
|
||||
Cinfo := C.struct_dm_info{}
|
||||
defer func() {
|
||||
|
@ -187,19 +185,21 @@ func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64, targ
|
|||
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 {
|
||||
|
|
Loading…
Add table
Reference in a new issue