1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #18651 from vbatts/dm-cleanup

loopback (and devicemapper) cleanup
This commit is contained in:
David Calavera 2015-12-18 15:13:28 -08:00
commit 54f945994a
8 changed files with 208 additions and 173 deletions

View file

@ -24,6 +24,7 @@ import (
"github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/pkg/devicemapper" "github.com/docker/docker/pkg/devicemapper"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/loopback"
"github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/go-units" "github.com/docker/go-units"
@ -1170,7 +1171,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
return fmt.Errorf("devmapper: Can't shrink file") return fmt.Errorf("devmapper: Can't shrink file")
} }
dataloopback := devicemapper.FindLoopDeviceFor(datafile) dataloopback := loopback.FindLoopDeviceFor(datafile)
if dataloopback == nil { if dataloopback == nil {
return fmt.Errorf("devmapper: Unable to find loopback mount for: %s", datafilename) return fmt.Errorf("devmapper: Unable to find loopback mount for: %s", datafilename)
} }
@ -1182,7 +1183,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
} }
defer metadatafile.Close() defer metadatafile.Close()
metadataloopback := devicemapper.FindLoopDeviceFor(metadatafile) metadataloopback := loopback.FindLoopDeviceFor(metadatafile)
if metadataloopback == nil { if metadataloopback == nil {
return fmt.Errorf("devmapper: Unable to find loopback mount for: %s", metadatafilename) return fmt.Errorf("devmapper: Unable to find loopback mount for: %s", metadatafilename)
} }
@ -1194,8 +1195,8 @@ func (devices *DeviceSet) ResizePool(size int64) error {
} }
// Reload size for loopback device // Reload size for loopback device
if err := devicemapper.LoopbackSetCapacity(dataloopback); err != nil { if err := loopback.SetCapacity(dataloopback); err != nil {
return fmt.Errorf("devmapper: Unable to update loopback capacity: %s", err) return fmt.Errorf("Unable to update loopback capacity: %s", err)
} }
// Suspend the pool // Suspend the pool
@ -1414,7 +1415,7 @@ func getLoopFileDeviceMajMin(filename string) (string, uint64, uint64, error) {
} }
defer file.Close() defer file.Close()
loopbackDevice := devicemapper.FindLoopDeviceFor(file) loopbackDevice := loopback.FindLoopDeviceFor(file)
if loopbackDevice == nil { if loopbackDevice == nil {
return "", 0, 0, fmt.Errorf("devmapper: Unable to find loopback mount for: %s", filename) return "", 0, 0, fmt.Errorf("devmapper: Unable to find loopback mount for: %s", filename)
} }
@ -1622,7 +1623,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
return err return err
} }
dataFile, err = devicemapper.AttachLoopDevice(data) dataFile, err = loopback.AttachLoopDevice(data)
if err != nil { if err != nil {
return err return err
} }
@ -1655,7 +1656,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
return err return err
} }
metadataFile, err = devicemapper.AttachLoopDevice(metadata) metadataFile, err = loopback.AttachLoopDevice(metadata)
if err != nil { if err != nil {
return err return err
} }

View file

@ -60,7 +60,6 @@ var (
ErrTaskDeferredRemove = errors.New("dm_task_deferred_remove failed") ErrTaskDeferredRemove = errors.New("dm_task_deferred_remove failed")
ErrTaskSetCookie = errors.New("dm_task_set_cookie failed") ErrTaskSetCookie = errors.New("dm_task_set_cookie failed")
ErrNilCookie = errors.New("cookie ptr can't be nil") ErrNilCookie = errors.New("cookie ptr can't be nil")
ErrAttachLoopbackDevice = errors.New("loopback mounting failed")
ErrGetBlockSize = errors.New("Can't get block size") ErrGetBlockSize = errors.New("Can't get block size")
ErrUdevWait = errors.New("wait on udev cookie failed") ErrUdevWait = errors.New("wait on udev cookie failed")
ErrSetDevDir = errors.New("dm_set_dev_dir failed") ErrSetDevDir = errors.New("dm_set_dev_dir failed")
@ -68,8 +67,6 @@ var (
ErrCreateRemoveTask = errors.New("Can't create task of type deviceRemove") ErrCreateRemoveTask = errors.New("Can't create task of type deviceRemove")
ErrRunRemoveDevice = errors.New("running RemoveDevice failed") ErrRunRemoveDevice = errors.New("running RemoveDevice failed")
ErrInvalidAddNode = errors.New("Invalid AddNode type") ErrInvalidAddNode = errors.New("Invalid AddNode type")
ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
ErrLoopbackSetCapacity = errors.New("Unable set loopback capacity")
ErrBusy = errors.New("Device is Busy") ErrBusy = errors.New("Device is Busy")
ErrDeviceIDExists = errors.New("Device Id Exists") ErrDeviceIDExists = errors.New("Device Id Exists")
ErrEnxio = errors.New("No such device or address") ErrEnxio = errors.New("No such device or address")
@ -257,58 +254,6 @@ func (t *Task) getNextTarget(next unsafe.Pointer) (nextPtr unsafe.Pointer, start
start, length, targetType, params start, length, targetType, params
} }
func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
loopInfo, err := ioctlLoopGetStatus64(file.Fd())
if err != nil {
logrus.Errorf("devicemapper: Error get loopback backing file: %s", err)
return 0, 0, ErrGetLoopbackBackingFile
}
return loopInfo.loDevice, loopInfo.loInode, nil
}
// LoopbackSetCapacity reloads the size for the loopback device.
func LoopbackSetCapacity(file *os.File) error {
if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
logrus.Errorf("devicemapper: Error loopbackSetCapacity: %s", err)
return ErrLoopbackSetCapacity
}
return nil
}
// FindLoopDeviceFor returns a loopback device file for the specified file which
// is backing file of a loop back device.
func FindLoopDeviceFor(file *os.File) *os.File {
stat, err := file.Stat()
if err != nil {
return nil
}
targetInode := stat.Sys().(*syscall.Stat_t).Ino
targetDevice := stat.Sys().(*syscall.Stat_t).Dev
for i := 0; true; i++ {
path := fmt.Sprintf("/dev/loop%d", i)
file, err := os.OpenFile(path, os.O_RDWR, 0)
if err != nil {
if os.IsNotExist(err) {
return nil
}
// Ignore all errors until the first not-exist
// we want to continue looking for the file
continue
}
dev, inode, err := getLoopbackBackingFile(file)
if err == nil && dev == targetDevice && inode == targetInode {
return file
}
file.Close()
}
return nil
}
// UdevWait waits for any processes that are waiting for udev to complete the specified cookie. // UdevWait waits for any processes that are waiting for udev to complete the specified cookie.
func UdevWait(cookie *uint) error { func UdevWait(cookie *uint) error {
if res := DmUdevWait(*cookie); res != 1 { if res := DmUdevWait(*cookie); res != 1 {

View file

@ -5,17 +5,8 @@ package devicemapper
/* /*
#cgo LDFLAGS: -L. -ldevmapper #cgo LDFLAGS: -L. -ldevmapper
#include <libdevmapper.h> #include <libdevmapper.h>
#include <linux/loop.h> // FIXME: present only for defines, maybe we can remove it?
#include <linux/fs.h> // FIXME: present only for BLKGETSIZE64, maybe we can remove it? #include <linux/fs.h> // FIXME: present only for BLKGETSIZE64, maybe we can remove it?
#ifndef LOOP_CTL_GET_FREE
#define LOOP_CTL_GET_FREE 0x4C82
#endif
#ifndef LO_FLAGS_PARTSCAN
#define LO_FLAGS_PARTSCAN 8
#endif
// FIXME: Can't we find a way to do the logging in pure Go? // FIXME: Can't we find a way to do the logging in pure Go?
extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str); extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
@ -45,45 +36,12 @@ 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 */
loEncryptType uint32
loEncryptKeySize uint32 /* ioctl w/o */
loFlags uint32 /* ioctl r/o */
loFileName [LoNameSize]uint8
loCryptName [LoNameSize]uint8
loEncryptKey [LoKeySize]uint8 /* ioctl w/o */
loInit [2]uint64
}
) )
// IOCTL consts // IOCTL consts
const ( const (
BlkGetSize64 = C.BLKGETSIZE64 BlkGetSize64 = C.BLKGETSIZE64
BlkDiscard = C.BLKDISCARD BlkDiscard = C.BLKDISCARD
LoopSetFd = C.LOOP_SET_FD
LoopCtlGetFree = C.LOOP_CTL_GET_FREE
LoopGetStatus64 = C.LOOP_GET_STATUS64
LoopSetStatus64 = C.LOOP_SET_STATUS64
LoopClrFd = C.LOOP_CLR_FD
LoopSetCapacity = C.LOOP_SET_CAPACITY
)
// LOOP consts.
const (
LoFlagsAutoClear = C.LO_FLAGS_AUTOCLEAR
LoFlagsReadOnly = C.LO_FLAGS_READ_ONLY
LoFlagsPartScan = C.LO_FLAGS_PARTSCAN
LoKeySize = C.LO_KEY_SIZE
LoNameSize = C.LO_NAME_SIZE
) )
// Devicemapper cookie flags. // Devicemapper cookie flags.

View file

@ -7,51 +7,6 @@ import (
"unsafe" "unsafe"
) )
func ioctlLoopCtlGetFree(fd uintptr) (int, error) {
index, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, LoopCtlGetFree, 0)
if err != 0 {
return 0, err
}
return int(index), nil
}
func ioctlLoopSetFd(loopFd, sparseFd uintptr) error {
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetFd, sparseFd); err != 0 {
return err
}
return nil
}
func ioctlLoopSetStatus64(loopFd uintptr, loopInfo *loopInfo64) error {
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
return err
}
return nil
}
func ioctlLoopClrFd(loopFd uintptr) error {
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopClrFd, 0); err != 0 {
return err
}
return nil
}
func ioctlLoopGetStatus64(loopFd uintptr) (*loopInfo64, error) {
loopInfo := &loopInfo64{}
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopGetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
return nil, err
}
return loopInfo, nil
}
func ioctlLoopSetCapacity(loopFd uintptr, value int) error {
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetCapacity, uintptr(value)); err != 0 {
return err
}
return nil
}
func ioctlBlkGetSize64(fd uintptr) (int64, error) { func ioctlBlkGetSize64(fd uintptr) (int64, error) {
var size int64 var size int64
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, BlkGetSize64, uintptr(unsafe.Pointer(&size))); err != 0 { if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, BlkGetSize64, uintptr(unsafe.Pointer(&size))); err != 0 {

View file

@ -1,8 +1,9 @@
// +build linux // +build linux
package devicemapper package loopback
import ( import (
"errors"
"fmt" "fmt"
"os" "os"
"syscall" "syscall"
@ -10,6 +11,13 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
) )
// Loopback related errors
var (
ErrAttachLoopbackDevice = errors.New("loopback attach failed")
ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
ErrSetCapacity = errors.New("Unable set loopback capacity")
)
func stringToLoopName(src string) [LoNameSize]uint8 { func stringToLoopName(src string) [LoNameSize]uint8 {
var dst [LoNameSize]uint8 var dst [LoNameSize]uint8
copy(dst[:], src[:]) copy(dst[:], src[:])

53
pkg/loopback/ioctl.go Normal file
View file

@ -0,0 +1,53 @@
// +build linux
package loopback
import (
"syscall"
"unsafe"
)
func ioctlLoopCtlGetFree(fd uintptr) (int, error) {
index, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, LoopCtlGetFree, 0)
if err != 0 {
return 0, err
}
return int(index), nil
}
func ioctlLoopSetFd(loopFd, sparseFd uintptr) error {
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetFd, sparseFd); err != 0 {
return err
}
return nil
}
func ioctlLoopSetStatus64(loopFd uintptr, loopInfo *loopInfo64) error {
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
return err
}
return nil
}
func ioctlLoopClrFd(loopFd uintptr) error {
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopClrFd, 0); err != 0 {
return err
}
return nil
}
func ioctlLoopGetStatus64(loopFd uintptr) (*loopInfo64, error) {
loopInfo := &loopInfo64{}
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopGetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
return nil, err
}
return loopInfo, nil
}
func ioctlLoopSetCapacity(loopFd uintptr, value int) error {
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetCapacity, uintptr(value)); err != 0 {
return err
}
return nil
}

View file

@ -0,0 +1,52 @@
// +build linux
package loopback
/*
#include <linux/loop.h> // FIXME: present only for defines, maybe we can remove it?
#ifndef LOOP_CTL_GET_FREE
#define LOOP_CTL_GET_FREE 0x4C82
#endif
#ifndef LO_FLAGS_PARTSCAN
#define LO_FLAGS_PARTSCAN 8
#endif
*/
import "C"
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 */
loEncryptType uint32
loEncryptKeySize uint32 /* ioctl w/o */
loFlags uint32 /* ioctl r/o */
loFileName [LoNameSize]uint8
loCryptName [LoNameSize]uint8
loEncryptKey [LoKeySize]uint8 /* ioctl w/o */
loInit [2]uint64
}
// IOCTL consts
const (
LoopSetFd = C.LOOP_SET_FD
LoopCtlGetFree = C.LOOP_CTL_GET_FREE
LoopGetStatus64 = C.LOOP_GET_STATUS64
LoopSetStatus64 = C.LOOP_SET_STATUS64
LoopClrFd = C.LOOP_CLR_FD
LoopSetCapacity = C.LOOP_SET_CAPACITY
)
// LOOP consts.
const (
LoFlagsAutoClear = C.LO_FLAGS_AUTOCLEAR
LoFlagsReadOnly = C.LO_FLAGS_READ_ONLY
LoFlagsPartScan = C.LO_FLAGS_PARTSCAN
LoKeySize = C.LO_KEY_SIZE
LoNameSize = C.LO_NAME_SIZE
)

63
pkg/loopback/loopback.go Normal file
View file

@ -0,0 +1,63 @@
// +build linux
package loopback
import (
"fmt"
"os"
"syscall"
"github.com/Sirupsen/logrus"
)
func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
loopInfo, err := ioctlLoopGetStatus64(file.Fd())
if err != nil {
logrus.Errorf("Error get loopback backing file: %s", err)
return 0, 0, ErrGetLoopbackBackingFile
}
return loopInfo.loDevice, loopInfo.loInode, nil
}
// SetCapacity reloads the size for the loopback device.
func SetCapacity(file *os.File) error {
if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
logrus.Errorf("Error loopbackSetCapacity: %s", err)
return ErrSetCapacity
}
return nil
}
// FindLoopDeviceFor returns a loopback device file for the specified file which
// is backing file of a loop back device.
func FindLoopDeviceFor(file *os.File) *os.File {
stat, err := file.Stat()
if err != nil {
return nil
}
targetInode := stat.Sys().(*syscall.Stat_t).Ino
targetDevice := stat.Sys().(*syscall.Stat_t).Dev
for i := 0; true; i++ {
path := fmt.Sprintf("/dev/loop%d", i)
file, err := os.OpenFile(path, os.O_RDWR, 0)
if err != nil {
if os.IsNotExist(err) {
return nil
}
// Ignore all errors until the first not-exist
// we want to continue looking for the file
continue
}
dev, inode, err := getLoopbackBackingFile(file)
if err == nil && dev == targetDevice && inode == targetInode {
return file
}
file.Close()
}
return nil
}