Skip to content

Commit af59752

Browse files
committed
loopback: separate loop logic from devicemapper
The loopback logic is not technically exclusive to the devicemapper driver. This reorganizes the code such that the loopback code is usable outside of the devicemapper package and driver. Signed-off-by: Vincent Batts <[email protected]>
1 parent a292c04 commit af59752

8 files changed

Lines changed: 208 additions & 172 deletions

File tree

daemon/graphdriver/devmapper/deviceset.go

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/docker/docker/daemon/graphdriver"
2525
"github.com/docker/docker/pkg/devicemapper"
2626
"github.com/docker/docker/pkg/idtools"
27+
"github.com/docker/docker/pkg/loopback"
2728
"github.com/docker/docker/pkg/mount"
2829
"github.com/docker/docker/pkg/parsers"
2930
"github.com/docker/go-units"
@@ -1170,7 +1171,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
11701171
return fmt.Errorf("devmapper: Can't shrink file")
11711172
}
11721173

1173-
dataloopback := devicemapper.FindLoopDeviceFor(datafile)
1174+
dataloopback := loopback.FindLoopDeviceFor(datafile)
11741175
if dataloopback == nil {
11751176
return fmt.Errorf("devmapper: Unable to find loopback mount for: %s", datafilename)
11761177
}
@@ -1182,7 +1183,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
11821183
}
11831184
defer metadatafile.Close()
11841185

1185-
metadataloopback := devicemapper.FindLoopDeviceFor(metadatafile)
1186+
metadataloopback := loopback.FindLoopDeviceFor(metadatafile)
11861187
if metadataloopback == nil {
11871188
return fmt.Errorf("devmapper: Unable to find loopback mount for: %s", metadatafilename)
11881189
}
@@ -1194,8 +1195,8 @@ func (devices *DeviceSet) ResizePool(size int64) error {
11941195
}
11951196

11961197
// Reload size for loopback device
1197-
if err := devicemapper.LoopbackSetCapacity(dataloopback); err != nil {
1198-
return fmt.Errorf("devmapper: Unable to update loopback capacity: %s", err)
1198+
if err := loopback.SetCapacity(dataloopback); err != nil {
1199+
return fmt.Errorf("Unable to update loopback capacity: %s", err)
11991200
}
12001201

12011202
// Suspend the pool
@@ -1414,7 +1415,7 @@ func getLoopFileDeviceMajMin(filename string) (string, uint64, uint64, error) {
14141415
}
14151416

14161417
defer file.Close()
1417-
loopbackDevice := devicemapper.FindLoopDeviceFor(file)
1418+
loopbackDevice := loopback.FindLoopDeviceFor(file)
14181419
if loopbackDevice == nil {
14191420
return "", 0, 0, fmt.Errorf("devmapper: Unable to find loopback mount for: %s", filename)
14201421
}
@@ -1622,7 +1623,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
16221623
return err
16231624
}
16241625

1625-
dataFile, err = devicemapper.AttachLoopDevice(data)
1626+
dataFile, err = loopback.AttachLoopDevice(data)
16261627
if err != nil {
16271628
return err
16281629
}
@@ -1655,7 +1656,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
16551656
return err
16561657
}
16571658

1658-
metadataFile, err = devicemapper.AttachLoopDevice(metadata)
1659+
metadataFile, err = loopback.AttachLoopDevice(metadata)
16591660
if err != nil {
16601661
return err
16611662
}

pkg/devicemapper/devmapper.go

Lines changed: 23 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -47,32 +47,29 @@ const (
4747

4848
// List of errors returned when using devicemapper.
4949
var (
50-
ErrTaskRun = errors.New("dm_task_run failed")
51-
ErrTaskSetName = errors.New("dm_task_set_name failed")
52-
ErrTaskSetMessage = errors.New("dm_task_set_message failed")
53-
ErrTaskSetAddNode = errors.New("dm_task_set_add_node failed")
54-
ErrTaskSetRo = errors.New("dm_task_set_ro failed")
55-
ErrTaskAddTarget = errors.New("dm_task_add_target failed")
56-
ErrTaskSetSector = errors.New("dm_task_set_sector failed")
57-
ErrTaskGetDeps = errors.New("dm_task_get_deps failed")
58-
ErrTaskGetInfo = errors.New("dm_task_get_info failed")
59-
ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version failed")
60-
ErrTaskDeferredRemove = errors.New("dm_task_deferred_remove failed")
61-
ErrTaskSetCookie = errors.New("dm_task_set_cookie failed")
62-
ErrNilCookie = errors.New("cookie ptr can't be nil")
63-
ErrAttachLoopbackDevice = errors.New("loopback mounting failed")
64-
ErrGetBlockSize = errors.New("Can't get block size")
65-
ErrUdevWait = errors.New("wait on udev cookie failed")
66-
ErrSetDevDir = errors.New("dm_set_dev_dir failed")
67-
ErrGetLibraryVersion = errors.New("dm_get_library_version failed")
68-
ErrCreateRemoveTask = errors.New("Can't create task of type deviceRemove")
69-
ErrRunRemoveDevice = errors.New("running RemoveDevice failed")
70-
ErrInvalidAddNode = errors.New("Invalid AddNode type")
71-
ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
72-
ErrLoopbackSetCapacity = errors.New("Unable set loopback capacity")
73-
ErrBusy = errors.New("Device is Busy")
74-
ErrDeviceIDExists = errors.New("Device Id Exists")
75-
ErrEnxio = errors.New("No such device or address")
50+
ErrTaskRun = errors.New("dm_task_run failed")
51+
ErrTaskSetName = errors.New("dm_task_set_name failed")
52+
ErrTaskSetMessage = errors.New("dm_task_set_message failed")
53+
ErrTaskSetAddNode = errors.New("dm_task_set_add_node failed")
54+
ErrTaskSetRo = errors.New("dm_task_set_ro failed")
55+
ErrTaskAddTarget = errors.New("dm_task_add_target failed")
56+
ErrTaskSetSector = errors.New("dm_task_set_sector failed")
57+
ErrTaskGetDeps = errors.New("dm_task_get_deps failed")
58+
ErrTaskGetInfo = errors.New("dm_task_get_info failed")
59+
ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version failed")
60+
ErrTaskDeferredRemove = errors.New("dm_task_deferred_remove failed")
61+
ErrTaskSetCookie = errors.New("dm_task_set_cookie failed")
62+
ErrNilCookie = errors.New("cookie ptr can't be nil")
63+
ErrGetBlockSize = errors.New("Can't get block size")
64+
ErrUdevWait = errors.New("wait on udev cookie failed")
65+
ErrSetDevDir = errors.New("dm_set_dev_dir failed")
66+
ErrGetLibraryVersion = errors.New("dm_get_library_version failed")
67+
ErrCreateRemoveTask = errors.New("Can't create task of type deviceRemove")
68+
ErrRunRemoveDevice = errors.New("running RemoveDevice failed")
69+
ErrInvalidAddNode = errors.New("Invalid AddNode type")
70+
ErrBusy = errors.New("Device is Busy")
71+
ErrDeviceIDExists = errors.New("Device Id Exists")
72+
ErrEnxio = errors.New("No such device or address")
7673
)
7774

7875
var (
@@ -257,58 +254,6 @@ func (t *Task) getNextTarget(next unsafe.Pointer) (nextPtr unsafe.Pointer, start
257254
start, length, targetType, params
258255
}
259256

260-
func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
261-
loopInfo, err := ioctlLoopGetStatus64(file.Fd())
262-
if err != nil {
263-
logrus.Errorf("devicemapper: Error get loopback backing file: %s", err)
264-
return 0, 0, ErrGetLoopbackBackingFile
265-
}
266-
return loopInfo.loDevice, loopInfo.loInode, nil
267-
}
268-
269-
// LoopbackSetCapacity reloads the size for the loopback device.
270-
func LoopbackSetCapacity(file *os.File) error {
271-
if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
272-
logrus.Errorf("devicemapper: Error loopbackSetCapacity: %s", err)
273-
return ErrLoopbackSetCapacity
274-
}
275-
return nil
276-
}
277-
278-
// FindLoopDeviceFor returns a loopback device file for the specified file which
279-
// is backing file of a loop back device.
280-
func FindLoopDeviceFor(file *os.File) *os.File {
281-
stat, err := file.Stat()
282-
if err != nil {
283-
return nil
284-
}
285-
targetInode := stat.Sys().(*syscall.Stat_t).Ino
286-
targetDevice := stat.Sys().(*syscall.Stat_t).Dev
287-
288-
for i := 0; true; i++ {
289-
path := fmt.Sprintf("/dev/loop%d", i)
290-
291-
file, err := os.OpenFile(path, os.O_RDWR, 0)
292-
if err != nil {
293-
if os.IsNotExist(err) {
294-
return nil
295-
}
296-
297-
// Ignore all errors until the first not-exist
298-
// we want to continue looking for the file
299-
continue
300-
}
301-
302-
dev, inode, err := getLoopbackBackingFile(file)
303-
if err == nil && dev == targetDevice && inode == targetInode {
304-
return file
305-
}
306-
file.Close()
307-
}
308-
309-
return nil
310-
}
311-
312257
// UdevWait waits for any processes that are waiting for udev to complete the specified cookie.
313258
func UdevWait(cookie *uint) error {
314259
if res := DmUdevWait(*cookie); res != 1 {

pkg/devicemapper/devmapper_wrapper.go

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,8 @@ package devicemapper
55
/*
66
#cgo LDFLAGS: -L. -ldevmapper
77
#include <libdevmapper.h>
8-
#include <linux/loop.h> // FIXME: present only for defines, maybe we can remove it?
98
#include <linux/fs.h> // FIXME: present only for BLKGETSIZE64, maybe we can remove it?
109
11-
#ifndef LOOP_CTL_GET_FREE
12-
#define LOOP_CTL_GET_FREE 0x4C82
13-
#endif
14-
15-
#ifndef LO_FLAGS_PARTSCAN
16-
#define LO_FLAGS_PARTSCAN 8
17-
#endif
18-
1910
// FIXME: Can't we find a way to do the logging in pure Go?
2011
extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
2112
@@ -45,44 +36,12 @@ import (
4536

4637
type (
4738
cdmTask C.struct_dm_task
48-
49-
loopInfo64 struct {
50-
loDevice uint64 /* ioctl r/o */
51-
loInode uint64 /* ioctl r/o */
52-
loRdevice uint64 /* ioctl r/o */
53-
loOffset uint64
54-
loSizelimit uint64 /* bytes, 0 == max available */
55-
loNumber uint32 /* ioctl r/o */
56-
loEncryptType uint32
57-
loEncryptKeySize uint32 /* ioctl w/o */
58-
loFlags uint32 /* ioctl r/o */
59-
loFileName [LoNameSize]uint8
60-
loCryptName [LoNameSize]uint8
61-
loEncryptKey [LoKeySize]uint8 /* ioctl w/o */
62-
loInit [2]uint64
63-
}
6439
)
6540

6641
// IOCTL consts
6742
const (
6843
BlkGetSize64 = C.BLKGETSIZE64
6944
BlkDiscard = C.BLKDISCARD
70-
71-
LoopSetFd = C.LOOP_SET_FD
72-
LoopCtlGetFree = C.LOOP_CTL_GET_FREE
73-
LoopGetStatus64 = C.LOOP_GET_STATUS64
74-
LoopSetStatus64 = C.LOOP_SET_STATUS64
75-
LoopClrFd = C.LOOP_CLR_FD
76-
LoopSetCapacity = C.LOOP_SET_CAPACITY
77-
)
78-
79-
// LOOP consts.
80-
const (
81-
LoFlagsAutoClear = C.LO_FLAGS_AUTOCLEAR
82-
LoFlagsReadOnly = C.LO_FLAGS_READ_ONLY
83-
LoFlagsPartScan = C.LO_FLAGS_PARTSCAN
84-
LoKeySize = C.LO_KEY_SIZE
85-
LoNameSize = C.LO_NAME_SIZE
8645
)
8746

8847
// Devicemapper cookie flags.

pkg/devicemapper/ioctl.go

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,51 +7,6 @@ import (
77
"unsafe"
88
)
99

10-
func ioctlLoopCtlGetFree(fd uintptr) (int, error) {
11-
index, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, LoopCtlGetFree, 0)
12-
if err != 0 {
13-
return 0, err
14-
}
15-
return int(index), nil
16-
}
17-
18-
func ioctlLoopSetFd(loopFd, sparseFd uintptr) error {
19-
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetFd, sparseFd); err != 0 {
20-
return err
21-
}
22-
return nil
23-
}
24-
25-
func ioctlLoopSetStatus64(loopFd uintptr, loopInfo *loopInfo64) error {
26-
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
27-
return err
28-
}
29-
return nil
30-
}
31-
32-
func ioctlLoopClrFd(loopFd uintptr) error {
33-
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopClrFd, 0); err != 0 {
34-
return err
35-
}
36-
return nil
37-
}
38-
39-
func ioctlLoopGetStatus64(loopFd uintptr) (*loopInfo64, error) {
40-
loopInfo := &loopInfo64{}
41-
42-
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopGetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
43-
return nil, err
44-
}
45-
return loopInfo, nil
46-
}
47-
48-
func ioctlLoopSetCapacity(loopFd uintptr, value int) error {
49-
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetCapacity, uintptr(value)); err != 0 {
50-
return err
51-
}
52-
return nil
53-
}
54-
5510
func ioctlBlkGetSize64(fd uintptr) (int64, error) {
5611
var size int64
5712
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, BlkGetSize64, uintptr(unsafe.Pointer(&size))); err != 0 {
Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
// +build linux
22

3-
package devicemapper
3+
package loopback
44

55
import (
6+
"errors"
67
"fmt"
78
"os"
89
"syscall"
910

1011
"github.com/Sirupsen/logrus"
1112
)
1213

14+
// Loopback related errors
15+
var (
16+
ErrAttachLoopbackDevice = errors.New("loopback attach failed")
17+
ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
18+
ErrSetCapacity = errors.New("Unable set loopback capacity")
19+
)
20+
1321
func stringToLoopName(src string) [LoNameSize]uint8 {
1422
var dst [LoNameSize]uint8
1523
copy(dst[:], src[:])

pkg/loopback/ioctl.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
// +build linux
2+
3+
package loopback
4+
5+
import (
6+
"syscall"
7+
"unsafe"
8+
)
9+
10+
func ioctlLoopCtlGetFree(fd uintptr) (int, error) {
11+
index, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, LoopCtlGetFree, 0)
12+
if err != 0 {
13+
return 0, err
14+
}
15+
return int(index), nil
16+
}
17+
18+
func ioctlLoopSetFd(loopFd, sparseFd uintptr) error {
19+
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetFd, sparseFd); err != 0 {
20+
return err
21+
}
22+
return nil
23+
}
24+
25+
func ioctlLoopSetStatus64(loopFd uintptr, loopInfo *loopInfo64) error {
26+
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
27+
return err
28+
}
29+
return nil
30+
}
31+
32+
func ioctlLoopClrFd(loopFd uintptr) error {
33+
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopClrFd, 0); err != 0 {
34+
return err
35+
}
36+
return nil
37+
}
38+
39+
func ioctlLoopGetStatus64(loopFd uintptr) (*loopInfo64, error) {
40+
loopInfo := &loopInfo64{}
41+
42+
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopGetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
43+
return nil, err
44+
}
45+
return loopInfo, nil
46+
}
47+
48+
func ioctlLoopSetCapacity(loopFd uintptr, value int) error {
49+
if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetCapacity, uintptr(value)); err != 0 {
50+
return err
51+
}
52+
return nil
53+
}

0 commit comments

Comments
 (0)