Browse code

devicemapper: split out devicemapper bindings

This is a first pass at splitting out devicemapper into separate, usable
bindings.

Signed-off-by: Vincent Batts <vbatts@redhat.com>

Vincent Batts authored on 2014/11/06 08:10:38
Showing 12 changed files
1 1
deleted file mode 100644
... ...
@@ -1,129 +0,0 @@
1
-// +build linux
2
-
3
-package devmapper
4
-
5
-import (
6
-	"fmt"
7
-	"os"
8
-	"syscall"
9
-
10
-	log "github.com/Sirupsen/logrus"
11
-)
12
-
13
-func stringToLoopName(src string) [LoNameSize]uint8 {
14
-	var dst [LoNameSize]uint8
15
-	copy(dst[:], src[:])
16
-	return dst
17
-}
18
-
19
-func getNextFreeLoopbackIndex() (int, error) {
20
-	f, err := os.OpenFile("/dev/loop-control", os.O_RDONLY, 0644)
21
-	if err != nil {
22
-		return 0, err
23
-	}
24
-	defer f.Close()
25
-
26
-	index, err := ioctlLoopCtlGetFree(f.Fd())
27
-	if index < 0 {
28
-		index = 0
29
-	}
30
-	return index, err
31
-}
32
-
33
-func openNextAvailableLoopback(index int, sparseFile *os.File) (loopFile *os.File, err error) {
34
-	// Start looking for a free /dev/loop
35
-	for {
36
-		target := fmt.Sprintf("/dev/loop%d", index)
37
-		index++
38
-
39
-		fi, err := os.Stat(target)
40
-		if err != nil {
41
-			if os.IsNotExist(err) {
42
-				log.Errorf("There are no more loopback devices available.")
43
-			}
44
-			return nil, ErrAttachLoopbackDevice
45
-		}
46
-
47
-		if fi.Mode()&os.ModeDevice != os.ModeDevice {
48
-			log.Errorf("Loopback device %s is not a block device.", target)
49
-			continue
50
-		}
51
-
52
-		// OpenFile adds O_CLOEXEC
53
-		loopFile, err = os.OpenFile(target, os.O_RDWR, 0644)
54
-		if err != nil {
55
-			log.Errorf("Error opening loopback device: %s", err)
56
-			return nil, ErrAttachLoopbackDevice
57
-		}
58
-
59
-		// Try to attach to the loop file
60
-		if err := ioctlLoopSetFd(loopFile.Fd(), sparseFile.Fd()); err != nil {
61
-			loopFile.Close()
62
-
63
-			// If the error is EBUSY, then try the next loopback
64
-			if err != syscall.EBUSY {
65
-				log.Errorf("Cannot set up loopback device %s: %s", target, err)
66
-				return nil, ErrAttachLoopbackDevice
67
-			}
68
-
69
-			// Otherwise, we keep going with the loop
70
-			continue
71
-		}
72
-		// In case of success, we finished. Break the loop.
73
-		break
74
-	}
75
-
76
-	// This can't happen, but let's be sure
77
-	if loopFile == nil {
78
-		log.Errorf("Unreachable code reached! Error attaching %s to a loopback device.", sparseFile.Name())
79
-		return nil, ErrAttachLoopbackDevice
80
-	}
81
-
82
-	return loopFile, nil
83
-}
84
-
85
-// attachLoopDevice attaches the given sparse file to the next
86
-// available loopback device. It returns an opened *os.File.
87
-func attachLoopDevice(sparseName string) (loop *os.File, err error) {
88
-
89
-	// Try to retrieve the next available loopback device via syscall.
90
-	// If it fails, we discard error and start loopking for a
91
-	// loopback from index 0.
92
-	startIndex, err := getNextFreeLoopbackIndex()
93
-	if err != nil {
94
-		log.Debugf("Error retrieving the next available loopback: %s", err)
95
-	}
96
-
97
-	// OpenFile adds O_CLOEXEC
98
-	sparseFile, err := os.OpenFile(sparseName, os.O_RDWR, 0644)
99
-	if err != nil {
100
-		log.Errorf("Error opening sparse file %s: %s", sparseName, err)
101
-		return nil, ErrAttachLoopbackDevice
102
-	}
103
-	defer sparseFile.Close()
104
-
105
-	loopFile, err := openNextAvailableLoopback(startIndex, sparseFile)
106
-	if err != nil {
107
-		return nil, err
108
-	}
109
-
110
-	// Set the status of the loopback device
111
-	loopInfo := &LoopInfo64{
112
-		loFileName: stringToLoopName(loopFile.Name()),
113
-		loOffset:   0,
114
-		loFlags:    LoFlagsAutoClear,
115
-	}
116
-
117
-	if err := ioctlLoopSetStatus64(loopFile.Fd(), loopInfo); err != nil {
118
-		log.Errorf("Cannot set up loopback device info: %s", err)
119
-
120
-		// If the call failed, then free the loopback device
121
-		if err := ioctlLoopClrFd(loopFile.Fd()); err != nil {
122
-			log.Errorf("Error while cleaning up the loopback device")
123
-		}
124
-		loopFile.Close()
125
-		return nil, ErrAttachLoopbackDevice
126
-	}
127
-
128
-	return loopFile, nil
129
-}
... ...
@@ -20,6 +20,7 @@ import (
20 20
 
21 21
 	log "github.com/Sirupsen/logrus"
22 22
 	"github.com/docker/docker/daemon/graphdriver"
23
+	"github.com/docker/docker/pkg/devicemapper"
23 24
 	"github.com/docker/docker/pkg/parsers"
24 25
 	"github.com/docker/docker/pkg/units"
25 26
 	"github.com/docker/libcontainer/label"
... ...
@@ -228,7 +229,7 @@ func (devices *DeviceSet) saveMetadata(info *DevInfo) error {
228 228
 	}
229 229
 
230 230
 	if devices.NewTransactionId != devices.TransactionId {
231
-		if err = setTransactionId(devices.getPoolDevName(), devices.TransactionId, devices.NewTransactionId); err != nil {
231
+		if err = devicemapper.SetTransactionId(devices.getPoolDevName(), devices.TransactionId, devices.NewTransactionId); err != nil {
232 232
 			return fmt.Errorf("Error setting devmapper transition ID: %s", err)
233 233
 		}
234 234
 		devices.TransactionId = devices.NewTransactionId
... ...
@@ -280,11 +281,11 @@ func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*Dev
280 280
 func (devices *DeviceSet) activateDeviceIfNeeded(info *DevInfo) error {
281 281
 	log.Debugf("activateDeviceIfNeeded(%v)", info.Hash)
282 282
 
283
-	if devinfo, _ := getInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
283
+	if devinfo, _ := devicemapper.GetInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
284 284
 		return nil
285 285
 	}
286 286
 
287
-	return activateDevice(devices.getPoolDevName(), info.Name(), info.DeviceId, info.Size)
287
+	return devicemapper.ActivateDevice(devices.getPoolDevName(), info.Name(), info.DeviceId, info.Size)
288 288
 }
289 289
 
290 290
 func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
... ...
@@ -321,7 +322,7 @@ func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
321 321
 }
322 322
 
323 323
 func (devices *DeviceSet) initMetaData() error {
324
-	_, _, _, params, err := getStatus(devices.getPoolName())
324
+	_, _, _, params, err := devicemapper.GetStatus(devices.getPoolName())
325 325
 	if err != nil {
326 326
 		return err
327 327
 	}
... ...
@@ -400,7 +401,7 @@ func (devices *DeviceSet) setupBaseImage() error {
400 400
 	id := devices.nextDeviceId
401 401
 
402 402
 	// Create initial device
403
-	if err := createDevice(devices.getPoolDevName(), &id); err != nil {
403
+	if err := devicemapper.CreateDevice(devices.getPoolDevName(), &id); err != nil {
404 404
 		return err
405 405
 	}
406 406
 
... ...
@@ -410,7 +411,7 @@ func (devices *DeviceSet) setupBaseImage() error {
410 410
 	log.Debugf("Registering base device (id %v) with FS size %v", id, devices.baseFsSize)
411 411
 	info, err := devices.registerDevice(id, "", devices.baseFsSize)
412 412
 	if err != nil {
413
-		_ = deleteDevice(devices.getPoolDevName(), id)
413
+		_ = devicemapper.DeleteDevice(devices.getPoolDevName(), id)
414 414
 		return err
415 415
 	}
416 416
 
... ...
@@ -447,11 +448,12 @@ func setCloseOnExec(name string) {
447 447
 	}
448 448
 }
449 449
 
450
-func (devices *DeviceSet) log(level int, file string, line int, dmError int, message string) {
450
+func (devices *DeviceSet) DMLog(level int, file string, line int, dmError int, message string) {
451 451
 	if level >= 7 {
452 452
 		return // Ignore _LOG_DEBUG
453 453
 	}
454 454
 
455
+	// FIXME(vbatts) push this back into ./pkg/devicemapper/
455 456
 	log.Debugf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message)
456 457
 }
457 458
 
... ...
@@ -489,7 +491,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
489 489
 		return fmt.Errorf("Can't shrink file")
490 490
 	}
491 491
 
492
-	dataloopback := FindLoopDeviceFor(datafile)
492
+	dataloopback := devicemapper.FindLoopDeviceFor(datafile)
493 493
 	if dataloopback == nil {
494 494
 		return fmt.Errorf("Unable to find loopback mount for: %s", datafilename)
495 495
 	}
... ...
@@ -501,7 +503,7 @@ func (devices *DeviceSet) ResizePool(size int64) error {
501 501
 	}
502 502
 	defer metadatafile.Close()
503 503
 
504
-	metadataloopback := FindLoopDeviceFor(metadatafile)
504
+	metadataloopback := devicemapper.FindLoopDeviceFor(metadatafile)
505 505
 	if metadataloopback == nil {
506 506
 		return fmt.Errorf("Unable to find loopback mount for: %s", metadatafilename)
507 507
 	}
... ...
@@ -513,22 +515,22 @@ func (devices *DeviceSet) ResizePool(size int64) error {
513 513
 	}
514 514
 
515 515
 	// Reload size for loopback device
516
-	if err := LoopbackSetCapacity(dataloopback); err != nil {
516
+	if err := devicemapper.LoopbackSetCapacity(dataloopback); err != nil {
517 517
 		return fmt.Errorf("Unable to update loopback capacity: %s", err)
518 518
 	}
519 519
 
520 520
 	// Suspend the pool
521
-	if err := suspendDevice(devices.getPoolName()); err != nil {
521
+	if err := devicemapper.SuspendDevice(devices.getPoolName()); err != nil {
522 522
 		return fmt.Errorf("Unable to suspend pool: %s", err)
523 523
 	}
524 524
 
525 525
 	// Reload with the new block sizes
526
-	if err := reloadPool(devices.getPoolName(), dataloopback, metadataloopback, devices.thinpBlockSize); err != nil {
526
+	if err := devicemapper.ReloadPool(devices.getPoolName(), dataloopback, metadataloopback, devices.thinpBlockSize); err != nil {
527 527
 		return fmt.Errorf("Unable to reload pool: %s", err)
528 528
 	}
529 529
 
530 530
 	// Resume the pool
531
-	if err := resumeDevice(devices.getPoolName()); err != nil {
531
+	if err := devicemapper.ResumeDevice(devices.getPoolName()); err != nil {
532 532
 		return fmt.Errorf("Unable to resume pool: %s", err)
533 533
 	}
534 534
 
... ...
@@ -536,9 +538,10 @@ func (devices *DeviceSet) ResizePool(size int64) error {
536 536
 }
537 537
 
538 538
 func (devices *DeviceSet) initDevmapper(doInit bool) error {
539
-	logInit(devices)
539
+	// give ourselves to libdm as a log handler
540
+	devicemapper.LogInit(devices)
540 541
 
541
-	_, err := getDriverVersion()
542
+	_, err := devicemapper.GetDriverVersion()
542 543
 	if err != nil {
543 544
 		// Can't even get driver version, assume not supported
544 545
 		return graphdriver.ErrNotSupported
... ...
@@ -566,9 +569,9 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
566 566
 
567 567
 	// Check for the existence of the device <prefix>-pool
568 568
 	log.Debugf("Checking for existence of the pool '%s'", devices.getPoolName())
569
-	info, err := getInfo(devices.getPoolName())
569
+	info, err := devicemapper.GetInfo(devices.getPoolName())
570 570
 	if info == nil {
571
-		log.Debugf("Error device getInfo: %s", err)
571
+		log.Debugf("Error device devicemapper.GetInfo: %s", err)
572 572
 		return err
573 573
 	}
574 574
 
... ...
@@ -610,7 +613,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
610 610
 				return err
611 611
 			}
612 612
 
613
-			dataFile, err = attachLoopDevice(data)
613
+			dataFile, err = devicemapper.AttachLoopDevice(data)
614 614
 			if err != nil {
615 615
 				return err
616 616
 			}
... ...
@@ -641,7 +644,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
641 641
 				return err
642 642
 			}
643 643
 
644
-			metadataFile, err = attachLoopDevice(metadata)
644
+			metadataFile, err = devicemapper.AttachLoopDevice(metadata)
645 645
 			if err != nil {
646 646
 				return err
647 647
 			}
... ...
@@ -653,7 +656,7 @@ func (devices *DeviceSet) initDevmapper(doInit bool) error {
653 653
 		}
654 654
 		defer metadataFile.Close()
655 655
 
656
-		if err := createPool(devices.getPoolName(), dataFile, metadataFile, devices.thinpBlockSize); err != nil {
656
+		if err := devicemapper.CreatePool(devices.getPoolName(), dataFile, metadataFile, devices.thinpBlockSize); err != nil {
657 657
 			return err
658 658
 		}
659 659
 	}
... ...
@@ -695,7 +698,7 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
695 695
 
696 696
 	deviceId := devices.nextDeviceId
697 697
 
698
-	if err := createSnapDevice(devices.getPoolDevName(), &deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
698
+	if err := devicemapper.CreateSnapDevice(devices.getPoolDevName(), &deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
699 699
 		log.Debugf("Error creating snap device: %s", err)
700 700
 		return err
701 701
 	}
... ...
@@ -704,7 +707,7 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
704 704
 	devices.nextDeviceId = (deviceId + 1) & 0xffffff
705 705
 
706 706
 	if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil {
707
-		deleteDevice(devices.getPoolDevName(), deviceId)
707
+		devicemapper.DeleteDevice(devices.getPoolDevName(), deviceId)
708 708
 		log.Debugf("Error registering device: %s", err)
709 709
 		return err
710 710
 	}
... ...
@@ -717,13 +720,13 @@ func (devices *DeviceSet) deleteDevice(info *DevInfo) error {
717 717
 		// on the thin pool when we remove a thinp device, so we do it
718 718
 		// manually
719 719
 		if err := devices.activateDeviceIfNeeded(info); err == nil {
720
-			if err := BlockDeviceDiscard(info.DevName()); err != nil {
720
+			if err := devicemapper.BlockDeviceDiscard(info.DevName()); err != nil {
721 721
 				log.Debugf("Error discarding block on device: %s (ignoring)", err)
722 722
 			}
723 723
 		}
724 724
 	}
725 725
 
726
-	devinfo, _ := getInfo(info.Name())
726
+	devinfo, _ := devicemapper.GetInfo(info.Name())
727 727
 	if devinfo != nil && devinfo.Exists != 0 {
728 728
 		if err := devices.removeDeviceAndWait(info.Name()); err != nil {
729 729
 			log.Debugf("Error removing device: %s", err)
... ...
@@ -731,7 +734,7 @@ func (devices *DeviceSet) deleteDevice(info *DevInfo) error {
731 731
 		}
732 732
 	}
733 733
 
734
-	if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
734
+	if err := devicemapper.DeleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
735 735
 		log.Debugf("Error deleting device: %s", err)
736 736
 		return err
737 737
 	}
... ...
@@ -772,16 +775,16 @@ func (devices *DeviceSet) deactivatePool() error {
772 772
 	defer log.Debugf("[devmapper] deactivatePool END")
773 773
 	devname := devices.getPoolDevName()
774 774
 
775
-	devinfo, err := getInfo(devname)
775
+	devinfo, err := devicemapper.GetInfo(devname)
776 776
 	if err != nil {
777 777
 		return err
778 778
 	}
779
-	if d, err := getDeps(devname); err == nil {
779
+	if d, err := devicemapper.GetDeps(devname); err == nil {
780 780
 		// Access to more Debug output
781
-		log.Debugf("[devmapper] getDeps() %s: %#v", devname, d)
781
+		log.Debugf("[devmapper] devicemapper.GetDeps() %s: %#v", devname, d)
782 782
 	}
783 783
 	if devinfo.Exists != 0 {
784
-		return removeDevice(devname)
784
+		return devicemapper.RemoveDevice(devname)
785 785
 	}
786 786
 
787 787
 	return nil
... ...
@@ -797,7 +800,7 @@ func (devices *DeviceSet) deactivateDevice(info *DevInfo) error {
797 797
 		log.Errorf("Warning: error waiting for device %s to close: %s", info.Hash, err)
798 798
 	}
799 799
 
800
-	devinfo, err := getInfo(info.Name())
800
+	devinfo, err := devicemapper.GetInfo(info.Name())
801 801
 	if err != nil {
802 802
 		return err
803 803
 	}
... ...
@@ -816,11 +819,11 @@ func (devices *DeviceSet) removeDeviceAndWait(devname string) error {
816 816
 	var err error
817 817
 
818 818
 	for i := 0; i < 1000; i++ {
819
-		err = removeDevice(devname)
819
+		err = devicemapper.RemoveDevice(devname)
820 820
 		if err == nil {
821 821
 			break
822 822
 		}
823
-		if err != ErrBusy {
823
+		if err != devicemapper.ErrBusy {
824 824
 			return err
825 825
 		}
826 826
 
... ...
@@ -848,7 +851,7 @@ func (devices *DeviceSet) waitRemove(devname string) error {
848 848
 	defer log.Debugf("[deviceset %s] waitRemove(%s) END", devices.devicePrefix, devname)
849 849
 	i := 0
850 850
 	for ; i < 1000; i++ {
851
-		devinfo, err := getInfo(devname)
851
+		devinfo, err := devicemapper.GetInfo(devname)
852 852
 		if err != nil {
853 853
 			// If there is an error we assume the device doesn't exist.
854 854
 			// The error might actually be something else, but we can't differentiate.
... ...
@@ -877,7 +880,7 @@ func (devices *DeviceSet) waitRemove(devname string) error {
877 877
 func (devices *DeviceSet) waitClose(info *DevInfo) error {
878 878
 	i := 0
879 879
 	for ; i < 1000; i++ {
880
-		devinfo, err := getInfo(info.Name())
880
+		devinfo, err := devicemapper.GetInfo(info.Name())
881 881
 		if err != nil {
882 882
 			return err
883 883
 		}
... ...
@@ -898,7 +901,6 @@ func (devices *DeviceSet) waitClose(info *DevInfo) error {
898 898
 }
899 899
 
900 900
 func (devices *DeviceSet) Shutdown() error {
901
-
902 901
 	log.Debugf("[deviceset %s] shutdown()", devices.devicePrefix)
903 902
 	log.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
904 903
 	defer log.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
... ...
@@ -1065,7 +1067,7 @@ func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
1065 1065
 	devices.Lock()
1066 1066
 	defer devices.Unlock()
1067 1067
 
1068
-	devinfo, _ := getInfo(info.Name())
1068
+	devinfo, _ := devicemapper.GetInfo(info.Name())
1069 1069
 	return devinfo != nil && devinfo.Exists != 0
1070 1070
 }
1071 1071
 
... ...
@@ -1087,7 +1089,7 @@ func (devices *DeviceSet) List() []string {
1087 1087
 
1088 1088
 func (devices *DeviceSet) deviceStatus(devName string) (sizeInSectors, mappedSectors, highestMappedSector uint64, err error) {
1089 1089
 	var params string
1090
-	_, sizeInSectors, _, params, err = getStatus(devName)
1090
+	_, sizeInSectors, _, params, err = devicemapper.GetStatus(devName)
1091 1091
 	if err != nil {
1092 1092
 		return
1093 1093
 	}
... ...
@@ -1132,7 +1134,7 @@ func (devices *DeviceSet) GetDeviceStatus(hash string) (*DevStatus, error) {
1132 1132
 
1133 1133
 func (devices *DeviceSet) poolStatus() (totalSizeInSectors, transactionId, dataUsed, dataTotal, metadataUsed, metadataTotal uint64, err error) {
1134 1134
 	var params string
1135
-	if _, totalSizeInSectors, _, params, err = getStatus(devices.getPoolName()); err == nil {
1135
+	if _, totalSizeInSectors, _, params, err = devicemapper.GetStatus(devices.getPoolName()); err == nil {
1136 1136
 		_, err = fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionId, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal)
1137 1137
 	}
1138 1138
 	return
... ...
@@ -1175,7 +1177,7 @@ func (devices *DeviceSet) Status() *Status {
1175 1175
 }
1176 1176
 
1177 1177
 func NewDeviceSet(root string, doInit bool, options []string) (*DeviceSet, error) {
1178
-	SetDevDir("/dev")
1178
+	devicemapper.SetDevDir("/dev")
1179 1179
 
1180 1180
 	devices := &DeviceSet{
1181 1181
 		root:                 root,
1182 1182
deleted file mode 100644
... ...
@@ -1,671 +0,0 @@
1
-// +build linux
2
-
3
-package devmapper
4
-
5
-import (
6
-	"errors"
7
-	"fmt"
8
-	"os"
9
-	"runtime"
10
-	"syscall"
11
-
12
-	log "github.com/Sirupsen/logrus"
13
-)
14
-
15
-type DevmapperLogger interface {
16
-	log(level int, file string, line int, dmError int, message string)
17
-}
18
-
19
-const (
20
-	DeviceCreate TaskType = iota
21
-	DeviceReload
22
-	DeviceRemove
23
-	DeviceRemoveAll
24
-	DeviceSuspend
25
-	DeviceResume
26
-	DeviceInfo
27
-	DeviceDeps
28
-	DeviceRename
29
-	DeviceVersion
30
-	DeviceStatus
31
-	DeviceTable
32
-	DeviceWaitevent
33
-	DeviceList
34
-	DeviceClear
35
-	DeviceMknodes
36
-	DeviceListVersions
37
-	DeviceTargetMsg
38
-	DeviceSetGeometry
39
-)
40
-
41
-const (
42
-	AddNodeOnResume AddNodeType = iota
43
-	AddNodeOnCreate
44
-)
45
-
46
-var (
47
-	ErrTaskRun                = errors.New("dm_task_run failed")
48
-	ErrTaskSetName            = errors.New("dm_task_set_name failed")
49
-	ErrTaskSetMessage         = errors.New("dm_task_set_message failed")
50
-	ErrTaskSetAddNode         = errors.New("dm_task_set_add_node failed")
51
-	ErrTaskSetRo              = errors.New("dm_task_set_ro failed")
52
-	ErrTaskAddTarget          = errors.New("dm_task_add_target failed")
53
-	ErrTaskSetSector          = errors.New("dm_task_set_sector failed")
54
-	ErrTaskGetDeps            = errors.New("dm_task_get_deps failed")
55
-	ErrTaskGetInfo            = errors.New("dm_task_get_info failed")
56
-	ErrTaskGetDriverVersion   = errors.New("dm_task_get_driver_version failed")
57
-	ErrTaskSetCookie          = errors.New("dm_task_set_cookie failed")
58
-	ErrNilCookie              = errors.New("cookie ptr can't be nil")
59
-	ErrAttachLoopbackDevice   = errors.New("loopback mounting failed")
60
-	ErrGetBlockSize           = errors.New("Can't get block size")
61
-	ErrUdevWait               = errors.New("wait on udev cookie failed")
62
-	ErrSetDevDir              = errors.New("dm_set_dev_dir failed")
63
-	ErrGetLibraryVersion      = errors.New("dm_get_library_version failed")
64
-	ErrCreateRemoveTask       = errors.New("Can't create task of type DeviceRemove")
65
-	ErrRunRemoveDevice        = errors.New("running removeDevice failed")
66
-	ErrInvalidAddNode         = errors.New("Invalide AddNoce type")
67
-	ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
68
-	ErrLoopbackSetCapacity    = errors.New("Unable set loopback capacity")
69
-	ErrBusy                   = errors.New("Device is Busy")
70
-
71
-	dmSawBusy  bool
72
-	dmSawExist bool
73
-)
74
-
75
-type (
76
-	Task struct {
77
-		unmanaged *CDmTask
78
-	}
79
-	Deps struct {
80
-		Count  uint32
81
-		Filler uint32
82
-		Device []uint64
83
-	}
84
-	Info struct {
85
-		Exists        int
86
-		Suspended     int
87
-		LiveTable     int
88
-		InactiveTable int
89
-		OpenCount     int32
90
-		EventNr       uint32
91
-		Major         uint32
92
-		Minor         uint32
93
-		ReadOnly      int
94
-		TargetCount   int32
95
-	}
96
-	TaskType    int
97
-	AddNodeType int
98
-)
99
-
100
-func (t *Task) destroy() {
101
-	if t != nil {
102
-		DmTaskDestroy(t.unmanaged)
103
-		runtime.SetFinalizer(t, nil)
104
-	}
105
-}
106
-
107
-func TaskCreate(tasktype TaskType) *Task {
108
-	Ctask := DmTaskCreate(int(tasktype))
109
-	if Ctask == nil {
110
-		return nil
111
-	}
112
-	task := &Task{unmanaged: Ctask}
113
-	runtime.SetFinalizer(task, (*Task).destroy)
114
-	return task
115
-}
116
-
117
-func (t *Task) Run() error {
118
-	if res := DmTaskRun(t.unmanaged); res != 1 {
119
-		return ErrTaskRun
120
-	}
121
-	return nil
122
-}
123
-
124
-func (t *Task) SetName(name string) error {
125
-	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
126
-		return ErrTaskSetName
127
-	}
128
-	return nil
129
-}
130
-
131
-func (t *Task) SetMessage(message string) error {
132
-	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
133
-		return ErrTaskSetMessage
134
-	}
135
-	return nil
136
-}
137
-
138
-func (t *Task) SetSector(sector uint64) error {
139
-	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
140
-		return ErrTaskSetSector
141
-	}
142
-	return nil
143
-}
144
-
145
-func (t *Task) SetCookie(cookie *uint, flags uint16) error {
146
-	if cookie == nil {
147
-		return ErrNilCookie
148
-	}
149
-	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
150
-		return ErrTaskSetCookie
151
-	}
152
-	return nil
153
-}
154
-
155
-func (t *Task) SetAddNode(addNode AddNodeType) error {
156
-	if addNode != AddNodeOnResume && addNode != AddNodeOnCreate {
157
-		return ErrInvalidAddNode
158
-	}
159
-	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
160
-		return ErrTaskSetAddNode
161
-	}
162
-	return nil
163
-}
164
-
165
-func (t *Task) SetRo() error {
166
-	if res := DmTaskSetRo(t.unmanaged); res != 1 {
167
-		return ErrTaskSetRo
168
-	}
169
-	return nil
170
-}
171
-
172
-func (t *Task) AddTarget(start, size uint64, ttype, params string) error {
173
-	if res := DmTaskAddTarget(t.unmanaged, start, size,
174
-		ttype, params); res != 1 {
175
-		return ErrTaskAddTarget
176
-	}
177
-	return nil
178
-}
179
-
180
-func (t *Task) GetDeps() (*Deps, error) {
181
-	var deps *Deps
182
-	if deps = DmTaskGetDeps(t.unmanaged); deps == nil {
183
-		return nil, ErrTaskGetDeps
184
-	}
185
-	return deps, nil
186
-}
187
-
188
-func (t *Task) GetInfo() (*Info, error) {
189
-	info := &Info{}
190
-	if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
191
-		return nil, ErrTaskGetInfo
192
-	}
193
-	return info, nil
194
-}
195
-
196
-func (t *Task) GetDriverVersion() (string, error) {
197
-	res := DmTaskGetDriverVersion(t.unmanaged)
198
-	if res == "" {
199
-		return "", ErrTaskGetDriverVersion
200
-	}
201
-	return res, nil
202
-}
203
-
204
-func (t *Task) GetNextTarget(next uintptr) (nextPtr uintptr, start uint64,
205
-	length uint64, targetType string, params string) {
206
-
207
-	return DmGetNextTarget(t.unmanaged, next, &start, &length,
208
-			&targetType, &params),
209
-		start, length, targetType, params
210
-}
211
-
212
-func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
213
-	loopInfo, err := ioctlLoopGetStatus64(file.Fd())
214
-	if err != nil {
215
-		log.Errorf("Error get loopback backing file: %s", err)
216
-		return 0, 0, ErrGetLoopbackBackingFile
217
-	}
218
-	return loopInfo.loDevice, loopInfo.loInode, nil
219
-}
220
-
221
-func LoopbackSetCapacity(file *os.File) error {
222
-	if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
223
-		log.Errorf("Error loopbackSetCapacity: %s", err)
224
-		return ErrLoopbackSetCapacity
225
-	}
226
-	return nil
227
-}
228
-
229
-func FindLoopDeviceFor(file *os.File) *os.File {
230
-	stat, err := file.Stat()
231
-	if err != nil {
232
-		return nil
233
-	}
234
-	targetInode := stat.Sys().(*syscall.Stat_t).Ino
235
-	targetDevice := stat.Sys().(*syscall.Stat_t).Dev
236
-
237
-	for i := 0; true; i++ {
238
-		path := fmt.Sprintf("/dev/loop%d", i)
239
-
240
-		file, err := os.OpenFile(path, os.O_RDWR, 0)
241
-		if err != nil {
242
-			if os.IsNotExist(err) {
243
-				return nil
244
-			}
245
-
246
-			// Ignore all errors until the first not-exist
247
-			// we want to continue looking for the file
248
-			continue
249
-		}
250
-
251
-		dev, inode, err := getLoopbackBackingFile(file)
252
-		if err == nil && dev == targetDevice && inode == targetInode {
253
-			return file
254
-		}
255
-		file.Close()
256
-	}
257
-
258
-	return nil
259
-}
260
-
261
-func UdevWait(cookie uint) error {
262
-	if res := DmUdevWait(cookie); res != 1 {
263
-		log.Debugf("Failed to wait on udev cookie %d", cookie)
264
-		return ErrUdevWait
265
-	}
266
-	return nil
267
-}
268
-
269
-func LogInitVerbose(level int) {
270
-	DmLogInitVerbose(level)
271
-}
272
-
273
-var dmLogger DevmapperLogger = nil
274
-
275
-func logInit(logger DevmapperLogger) {
276
-	dmLogger = logger
277
-	LogWithErrnoInit()
278
-}
279
-
280
-func SetDevDir(dir string) error {
281
-	if res := DmSetDevDir(dir); res != 1 {
282
-		log.Debugf("Error dm_set_dev_dir")
283
-		return ErrSetDevDir
284
-	}
285
-	return nil
286
-}
287
-
288
-func GetLibraryVersion() (string, error) {
289
-	var version string
290
-	if res := DmGetLibraryVersion(&version); res != 1 {
291
-		return "", ErrGetLibraryVersion
292
-	}
293
-	return version, nil
294
-}
295
-
296
-// Useful helper for cleanup
297
-func RemoveDevice(name string) error {
298
-	task := TaskCreate(DeviceRemove)
299
-	if task == nil {
300
-		return ErrCreateRemoveTask
301
-	}
302
-	if err := task.SetName(name); err != nil {
303
-		log.Debugf("Can't set task name %s", name)
304
-		return err
305
-	}
306
-	if err := task.Run(); err != nil {
307
-		return ErrRunRemoveDevice
308
-	}
309
-	return nil
310
-}
311
-
312
-func GetBlockDeviceSize(file *os.File) (uint64, error) {
313
-	size, err := ioctlBlkGetSize64(file.Fd())
314
-	if err != nil {
315
-		log.Errorf("Error getblockdevicesize: %s", err)
316
-		return 0, ErrGetBlockSize
317
-	}
318
-	return uint64(size), nil
319
-}
320
-
321
-func BlockDeviceDiscard(path string) error {
322
-	file, err := os.OpenFile(path, os.O_RDWR, 0)
323
-	if err != nil {
324
-		return err
325
-	}
326
-	defer file.Close()
327
-
328
-	size, err := GetBlockDeviceSize(file)
329
-	if err != nil {
330
-		return err
331
-	}
332
-
333
-	if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil {
334
-		return err
335
-	}
336
-
337
-	// Without this sometimes the remove of the device that happens after
338
-	// discard fails with EBUSY.
339
-	syscall.Sync()
340
-
341
-	return nil
342
-}
343
-
344
-// This is the programmatic example of "dmsetup create"
345
-func createPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
346
-	task, err := createTask(DeviceCreate, poolName)
347
-	if task == nil {
348
-		return err
349
-	}
350
-
351
-	size, err := GetBlockDeviceSize(dataFile)
352
-	if err != nil {
353
-		return fmt.Errorf("Can't get data size %s", err)
354
-	}
355
-
356
-	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
357
-	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
358
-		return fmt.Errorf("Can't add target %s", err)
359
-	}
360
-
361
-	var cookie uint = 0
362
-	if err := task.SetCookie(&cookie, 0); err != nil {
363
-		return fmt.Errorf("Can't set cookie %s", err)
364
-	}
365
-
366
-	if err := task.Run(); err != nil {
367
-		return fmt.Errorf("Error running DeviceCreate (createPool) %s", err)
368
-	}
369
-
370
-	UdevWait(cookie)
371
-
372
-	return nil
373
-}
374
-
375
-func reloadPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
376
-	task, err := createTask(DeviceReload, poolName)
377
-	if task == nil {
378
-		return err
379
-	}
380
-
381
-	size, err := GetBlockDeviceSize(dataFile)
382
-	if err != nil {
383
-		return fmt.Errorf("Can't get data size %s", err)
384
-	}
385
-
386
-	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
387
-	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
388
-		return fmt.Errorf("Can't add target %s", err)
389
-	}
390
-
391
-	if err := task.Run(); err != nil {
392
-		return fmt.Errorf("Error running DeviceCreate %s", err)
393
-	}
394
-
395
-	return nil
396
-}
397
-
398
-func createTask(t TaskType, name string) (*Task, error) {
399
-	task := TaskCreate(t)
400
-	if task == nil {
401
-		return nil, fmt.Errorf("Can't create task of type %d", int(t))
402
-	}
403
-	if err := task.SetName(name); err != nil {
404
-		return nil, fmt.Errorf("Can't set task name %s", name)
405
-	}
406
-	return task, nil
407
-}
408
-
409
-func getDeps(name string) (*Deps, error) {
410
-	task, err := createTask(DeviceDeps, name)
411
-	if task == nil {
412
-		return nil, err
413
-	}
414
-	if err := task.Run(); err != nil {
415
-		return nil, err
416
-	}
417
-	return task.GetDeps()
418
-}
419
-
420
-func getInfo(name string) (*Info, error) {
421
-	task, err := createTask(DeviceInfo, name)
422
-	if task == nil {
423
-		return nil, err
424
-	}
425
-	if err := task.Run(); err != nil {
426
-		return nil, err
427
-	}
428
-	return task.GetInfo()
429
-}
430
-
431
-func getDriverVersion() (string, error) {
432
-	task := TaskCreate(DeviceVersion)
433
-	if task == nil {
434
-		return "", fmt.Errorf("Can't create DeviceVersion task")
435
-	}
436
-	if err := task.Run(); err != nil {
437
-		return "", err
438
-	}
439
-	return task.GetDriverVersion()
440
-}
441
-
442
-func getStatus(name string) (uint64, uint64, string, string, error) {
443
-	task, err := createTask(DeviceStatus, name)
444
-	if task == nil {
445
-		log.Debugf("getStatus: Error createTask: %s", err)
446
-		return 0, 0, "", "", err
447
-	}
448
-	if err := task.Run(); err != nil {
449
-		log.Debugf("getStatus: Error Run: %s", err)
450
-		return 0, 0, "", "", err
451
-	}
452
-
453
-	devinfo, err := task.GetInfo()
454
-	if err != nil {
455
-		log.Debugf("getStatus: Error GetInfo: %s", err)
456
-		return 0, 0, "", "", err
457
-	}
458
-	if devinfo.Exists == 0 {
459
-		log.Debugf("getStatus: Non existing device %s", name)
460
-		return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
461
-	}
462
-
463
-	_, start, length, targetType, params := task.GetNextTarget(0)
464
-	return start, length, targetType, params, nil
465
-}
466
-
467
-func setTransactionId(poolName string, oldId uint64, newId uint64) error {
468
-	task, err := createTask(DeviceTargetMsg, poolName)
469
-	if task == nil {
470
-		return err
471
-	}
472
-
473
-	if err := task.SetSector(0); err != nil {
474
-		return fmt.Errorf("Can't set sector %s", err)
475
-	}
476
-
477
-	if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
478
-		return fmt.Errorf("Can't set message %s", err)
479
-	}
480
-
481
-	if err := task.Run(); err != nil {
482
-		return fmt.Errorf("Error running setTransactionId %s", err)
483
-	}
484
-	return nil
485
-}
486
-
487
-func suspendDevice(name string) error {
488
-	task, err := createTask(DeviceSuspend, name)
489
-	if task == nil {
490
-		return err
491
-	}
492
-	if err := task.Run(); err != nil {
493
-		return fmt.Errorf("Error running DeviceSuspend %s", err)
494
-	}
495
-	return nil
496
-}
497
-
498
-func resumeDevice(name string) error {
499
-	task, err := createTask(DeviceResume, name)
500
-	if task == nil {
501
-		return err
502
-	}
503
-
504
-	var cookie uint = 0
505
-	if err := task.SetCookie(&cookie, 0); err != nil {
506
-		return fmt.Errorf("Can't set cookie %s", err)
507
-	}
508
-
509
-	if err := task.Run(); err != nil {
510
-		return fmt.Errorf("Error running DeviceResume %s", err)
511
-	}
512
-
513
-	UdevWait(cookie)
514
-
515
-	return nil
516
-}
517
-
518
-func createDevice(poolName string, deviceId *int) error {
519
-	log.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, *deviceId)
520
-
521
-	for {
522
-		task, err := createTask(DeviceTargetMsg, poolName)
523
-		if task == nil {
524
-			return err
525
-		}
526
-
527
-		if err := task.SetSector(0); err != nil {
528
-			return fmt.Errorf("Can't set sector %s", err)
529
-		}
530
-
531
-		if err := task.SetMessage(fmt.Sprintf("create_thin %d", *deviceId)); err != nil {
532
-			return fmt.Errorf("Can't set message %s", err)
533
-		}
534
-
535
-		dmSawExist = false
536
-		if err := task.Run(); err != nil {
537
-			if dmSawExist {
538
-				// Already exists, try next id
539
-				*deviceId++
540
-				continue
541
-			}
542
-			return fmt.Errorf("Error running createDevice %s", err)
543
-		}
544
-		break
545
-	}
546
-	return nil
547
-}
548
-
549
-func deleteDevice(poolName string, deviceId int) error {
550
-	task, err := createTask(DeviceTargetMsg, poolName)
551
-	if task == nil {
552
-		return err
553
-	}
554
-
555
-	if err := task.SetSector(0); err != nil {
556
-		return fmt.Errorf("Can't set sector %s", err)
557
-	}
558
-
559
-	if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
560
-		return fmt.Errorf("Can't set message %s", err)
561
-	}
562
-
563
-	if err := task.Run(); err != nil {
564
-		return fmt.Errorf("Error running deleteDevice %s", err)
565
-	}
566
-	return nil
567
-}
568
-
569
-func removeDevice(name string) error {
570
-	log.Debugf("[devmapper] removeDevice START")
571
-	defer log.Debugf("[devmapper] removeDevice END")
572
-	task, err := createTask(DeviceRemove, name)
573
-	if task == nil {
574
-		return err
575
-	}
576
-	dmSawBusy = false
577
-	if err = task.Run(); err != nil {
578
-		if dmSawBusy {
579
-			return ErrBusy
580
-		}
581
-		return fmt.Errorf("Error running removeDevice %s", err)
582
-	}
583
-	return nil
584
-}
585
-
586
-func activateDevice(poolName string, name string, deviceId int, size uint64) error {
587
-	task, err := createTask(DeviceCreate, name)
588
-	if task == nil {
589
-		return err
590
-	}
591
-
592
-	params := fmt.Sprintf("%s %d", poolName, deviceId)
593
-	if err := task.AddTarget(0, size/512, "thin", params); err != nil {
594
-		return fmt.Errorf("Can't add target %s", err)
595
-	}
596
-	if err := task.SetAddNode(AddNodeOnCreate); err != nil {
597
-		return fmt.Errorf("Can't add node %s", err)
598
-	}
599
-
600
-	var cookie uint = 0
601
-	if err := task.SetCookie(&cookie, 0); err != nil {
602
-		return fmt.Errorf("Can't set cookie %s", err)
603
-	}
604
-
605
-	if err := task.Run(); err != nil {
606
-		return fmt.Errorf("Error running DeviceCreate (activateDevice) %s", err)
607
-	}
608
-
609
-	UdevWait(cookie)
610
-
611
-	return nil
612
-}
613
-
614
-func createSnapDevice(poolName string, deviceId *int, baseName string, baseDeviceId int) error {
615
-	devinfo, _ := getInfo(baseName)
616
-	doSuspend := devinfo != nil && devinfo.Exists != 0
617
-
618
-	if doSuspend {
619
-		if err := suspendDevice(baseName); err != nil {
620
-			return err
621
-		}
622
-	}
623
-
624
-	for {
625
-		task, err := createTask(DeviceTargetMsg, poolName)
626
-		if task == nil {
627
-			if doSuspend {
628
-				resumeDevice(baseName)
629
-			}
630
-			return err
631
-		}
632
-
633
-		if err := task.SetSector(0); err != nil {
634
-			if doSuspend {
635
-				resumeDevice(baseName)
636
-			}
637
-			return fmt.Errorf("Can't set sector %s", err)
638
-		}
639
-
640
-		if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", *deviceId, baseDeviceId)); err != nil {
641
-			if doSuspend {
642
-				resumeDevice(baseName)
643
-			}
644
-			return fmt.Errorf("Can't set message %s", err)
645
-		}
646
-
647
-		dmSawExist = false
648
-		if err := task.Run(); err != nil {
649
-			if dmSawExist {
650
-				// Already exists, try next id
651
-				*deviceId++
652
-				continue
653
-			}
654
-
655
-			if doSuspend {
656
-				resumeDevice(baseName)
657
-			}
658
-			return fmt.Errorf("Error running DeviceCreate (createSnapDevice) %s", err)
659
-		}
660
-
661
-		break
662
-	}
663
-
664
-	if doSuspend {
665
-		if err := resumeDevice(baseName); err != nil {
666
-			return err
667
-		}
668
-	}
669
-
670
-	return nil
671
-}
672 1
deleted file mode 100644
... ...
@@ -1,30 +0,0 @@
1
-// +build linux
2
-
3
-package devmapper
4
-
5
-import "C"
6
-
7
-import (
8
-	"strings"
9
-)
10
-
11
-// Due to the way cgo works this has to be in a separate file, as devmapper.go has
12
-// definitions in the cgo block, which is incompatible with using "//export"
13
-
14
-//export DevmapperLogCallback
15
-func DevmapperLogCallback(level C.int, file *C.char, line C.int, dm_errno_or_class C.int, message *C.char) {
16
-	msg := C.GoString(message)
17
-	if level < 7 {
18
-		if strings.Contains(msg, "busy") {
19
-			dmSawBusy = true
20
-		}
21
-
22
-		if strings.Contains(msg, "File exists") {
23
-			dmSawExist = true
24
-		}
25
-	}
26
-
27
-	if dmLogger != nil {
28
-		dmLogger.log(int(level), C.GoString(file), int(line), int(dm_errno_or_class), msg)
29
-	}
30
-}
31 1
deleted file mode 100644
... ...
@@ -1,254 +0,0 @@
1
-// +build linux
2
-
3
-package devmapper
4
-
5
-/*
6
-#cgo LDFLAGS: -L. -ldevmapper
7
-#include <libdevmapper.h>
8
-#include <linux/loop.h> // FIXME: present only for defines, maybe we can remove it?
9
-#include <linux/fs.h>   // FIXME: present only for BLKGETSIZE64, maybe we can remove it?
10
-
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
-
19
-// FIXME: Can't we find a way to do the logging in pure Go?
20
-extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
21
-
22
-static void	log_cb(int level, const char *file, int line, int dm_errno_or_class, const char *f, ...)
23
-{
24
-  char buffer[256];
25
-  va_list ap;
26
-
27
-  va_start(ap, f);
28
-  vsnprintf(buffer, 256, f, ap);
29
-  va_end(ap);
30
-
31
-  DevmapperLogCallback(level, (char *)file, line, dm_errno_or_class, buffer);
32
-}
33
-
34
-static void	log_with_errno_init()
35
-{
36
-  dm_log_with_errno_init(log_cb);
37
-}
38
-*/
39
-import "C"
40
-
41
-import "unsafe"
42
-
43
-type (
44
-	CDmTask C.struct_dm_task
45
-
46
-	CLoopInfo64 C.struct_loop_info64
47
-	LoopInfo64  struct {
48
-		loDevice           uint64 /* ioctl r/o */
49
-		loInode            uint64 /* ioctl r/o */
50
-		loRdevice          uint64 /* ioctl r/o */
51
-		loOffset           uint64
52
-		loSizelimit        uint64 /* bytes, 0 == max available */
53
-		loNumber           uint32 /* ioctl r/o */
54
-		loEncrypt_type     uint32
55
-		loEncrypt_key_size uint32 /* ioctl w/o */
56
-		loFlags            uint32 /* ioctl r/o */
57
-		loFileName         [LoNameSize]uint8
58
-		loCryptName        [LoNameSize]uint8
59
-		loEncryptKey       [LoKeySize]uint8 /* ioctl w/o */
60
-		loInit             [2]uint64
61
-	}
62
-)
63
-
64
-// IOCTL consts
65
-const (
66
-	BlkGetSize64 = C.BLKGETSIZE64
67
-	BlkDiscard   = C.BLKDISCARD
68
-
69
-	LoopSetFd       = C.LOOP_SET_FD
70
-	LoopCtlGetFree  = C.LOOP_CTL_GET_FREE
71
-	LoopGetStatus64 = C.LOOP_GET_STATUS64
72
-	LoopSetStatus64 = C.LOOP_SET_STATUS64
73
-	LoopClrFd       = C.LOOP_CLR_FD
74
-	LoopSetCapacity = C.LOOP_SET_CAPACITY
75
-)
76
-
77
-const (
78
-	LoFlagsAutoClear = C.LO_FLAGS_AUTOCLEAR
79
-	LoFlagsReadOnly  = C.LO_FLAGS_READ_ONLY
80
-	LoFlagsPartScan  = C.LO_FLAGS_PARTSCAN
81
-	LoKeySize        = C.LO_KEY_SIZE
82
-	LoNameSize       = C.LO_NAME_SIZE
83
-)
84
-
85
-var (
86
-	DmGetLibraryVersion    = dmGetLibraryVersionFct
87
-	DmGetNextTarget        = dmGetNextTargetFct
88
-	DmLogInitVerbose       = dmLogInitVerboseFct
89
-	DmSetDevDir            = dmSetDevDirFct
90
-	DmTaskAddTarget        = dmTaskAddTargetFct
91
-	DmTaskCreate           = dmTaskCreateFct
92
-	DmTaskDestroy          = dmTaskDestroyFct
93
-	DmTaskGetDeps          = dmTaskGetDepsFct
94
-	DmTaskGetInfo          = dmTaskGetInfoFct
95
-	DmTaskGetDriverVersion = dmTaskGetDriverVersionFct
96
-	DmTaskRun              = dmTaskRunFct
97
-	DmTaskSetAddNode       = dmTaskSetAddNodeFct
98
-	DmTaskSetCookie        = dmTaskSetCookieFct
99
-	DmTaskSetMessage       = dmTaskSetMessageFct
100
-	DmTaskSetName          = dmTaskSetNameFct
101
-	DmTaskSetRo            = dmTaskSetRoFct
102
-	DmTaskSetSector        = dmTaskSetSectorFct
103
-	DmUdevWait             = dmUdevWaitFct
104
-	LogWithErrnoInit       = logWithErrnoInitFct
105
-)
106
-
107
-func free(p *C.char) {
108
-	C.free(unsafe.Pointer(p))
109
-}
110
-
111
-func dmTaskDestroyFct(task *CDmTask) {
112
-	C.dm_task_destroy((*C.struct_dm_task)(task))
113
-}
114
-
115
-func dmTaskCreateFct(taskType int) *CDmTask {
116
-	return (*CDmTask)(C.dm_task_create(C.int(taskType)))
117
-}
118
-
119
-func dmTaskRunFct(task *CDmTask) int {
120
-	ret, _ := C.dm_task_run((*C.struct_dm_task)(task))
121
-	return int(ret)
122
-}
123
-
124
-func dmTaskSetNameFct(task *CDmTask, name string) int {
125
-	Cname := C.CString(name)
126
-	defer free(Cname)
127
-
128
-	return int(C.dm_task_set_name((*C.struct_dm_task)(task), Cname))
129
-}
130
-
131
-func dmTaskSetMessageFct(task *CDmTask, message string) int {
132
-	Cmessage := C.CString(message)
133
-	defer free(Cmessage)
134
-
135
-	return int(C.dm_task_set_message((*C.struct_dm_task)(task), Cmessage))
136
-}
137
-
138
-func dmTaskSetSectorFct(task *CDmTask, sector uint64) int {
139
-	return int(C.dm_task_set_sector((*C.struct_dm_task)(task), C.uint64_t(sector)))
140
-}
141
-
142
-func dmTaskSetCookieFct(task *CDmTask, cookie *uint, flags uint16) int {
143
-	cCookie := C.uint32_t(*cookie)
144
-	defer func() {
145
-		*cookie = uint(cCookie)
146
-	}()
147
-	return int(C.dm_task_set_cookie((*C.struct_dm_task)(task), &cCookie, C.uint16_t(flags)))
148
-}
149
-
150
-func dmTaskSetAddNodeFct(task *CDmTask, addNode AddNodeType) int {
151
-	return int(C.dm_task_set_add_node((*C.struct_dm_task)(task), C.dm_add_node_t(addNode)))
152
-}
153
-
154
-func dmTaskSetRoFct(task *CDmTask) int {
155
-	return int(C.dm_task_set_ro((*C.struct_dm_task)(task)))
156
-}
157
-
158
-func dmTaskAddTargetFct(task *CDmTask,
159
-	start, size uint64, ttype, params string) int {
160
-
161
-	Cttype := C.CString(ttype)
162
-	defer free(Cttype)
163
-
164
-	Cparams := C.CString(params)
165
-	defer free(Cparams)
166
-
167
-	return int(C.dm_task_add_target((*C.struct_dm_task)(task), C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
168
-}
169
-
170
-func dmTaskGetDepsFct(task *CDmTask) *Deps {
171
-	Cdeps := C.dm_task_get_deps((*C.struct_dm_task)(task))
172
-	if Cdeps == nil {
173
-		return nil
174
-	}
175
-	deps := &Deps{
176
-		Count:  uint32(Cdeps.count),
177
-		Filler: uint32(Cdeps.filler),
178
-	}
179
-	for _, device := range Cdeps.device {
180
-		deps.Device = append(deps.Device, (uint64)(device))
181
-	}
182
-	return deps
183
-}
184
-
185
-func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
186
-	Cinfo := C.struct_dm_info{}
187
-	defer func() {
188
-		info.Exists = int(Cinfo.exists)
189
-		info.Suspended = int(Cinfo.suspended)
190
-		info.LiveTable = int(Cinfo.live_table)
191
-		info.InactiveTable = int(Cinfo.inactive_table)
192
-		info.OpenCount = int32(Cinfo.open_count)
193
-		info.EventNr = uint32(Cinfo.event_nr)
194
-		info.Major = uint32(Cinfo.major)
195
-		info.Minor = uint32(Cinfo.minor)
196
-		info.ReadOnly = int(Cinfo.read_only)
197
-		info.TargetCount = int32(Cinfo.target_count)
198
-	}()
199
-	return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
200
-}
201
-
202
-func dmTaskGetDriverVersionFct(task *CDmTask) string {
203
-	buffer := C.malloc(128)
204
-	defer C.free(buffer)
205
-	res := C.dm_task_get_driver_version((*C.struct_dm_task)(task), (*C.char)(buffer), 128)
206
-	if res == 0 {
207
-		return ""
208
-	}
209
-	return C.GoString((*C.char)(buffer))
210
-}
211
-
212
-func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64, target, params *string) uintptr {
213
-	var (
214
-		Cstart, Clength      C.uint64_t
215
-		CtargetType, Cparams *C.char
216
-	)
217
-	defer func() {
218
-		*start = uint64(Cstart)
219
-		*length = uint64(Clength)
220
-		*target = C.GoString(CtargetType)
221
-		*params = C.GoString(Cparams)
222
-	}()
223
-
224
-	nextp := C.dm_get_next_target((*C.struct_dm_task)(task), unsafe.Pointer(next), &Cstart, &Clength, &CtargetType, &Cparams)
225
-	return uintptr(nextp)
226
-}
227
-
228
-func dmUdevWaitFct(cookie uint) int {
229
-	return int(C.dm_udev_wait(C.uint32_t(cookie)))
230
-}
231
-
232
-func dmLogInitVerboseFct(level int) {
233
-	C.dm_log_init_verbose(C.int(level))
234
-}
235
-
236
-func logWithErrnoInitFct() {
237
-	C.log_with_errno_init()
238
-}
239
-
240
-func dmSetDevDirFct(dir string) int {
241
-	Cdir := C.CString(dir)
242
-	defer free(Cdir)
243
-
244
-	return int(C.dm_set_dev_dir(Cdir))
245
-}
246
-
247
-func dmGetLibraryVersionFct(version *string) int {
248
-	buffer := C.CString(string(make([]byte, 128)))
249
-	defer free(buffer)
250
-	defer func() {
251
-		*version = C.GoString(buffer)
252
-	}()
253
-	return int(C.dm_get_library_version(buffer, 128))
254
-}
... ...
@@ -10,6 +10,7 @@ import (
10 10
 
11 11
 	log "github.com/Sirupsen/logrus"
12 12
 	"github.com/docker/docker/daemon/graphdriver"
13
+	"github.com/docker/docker/pkg/devicemapper"
13 14
 	"github.com/docker/docker/pkg/mount"
14 15
 	"github.com/docker/docker/pkg/units"
15 16
 )
... ...
@@ -63,7 +64,7 @@ func (d *Driver) Status() [][2]string {
63 63
 		{"Metadata Space Used", fmt.Sprintf("%s", units.HumanSize(int64(s.Metadata.Used)))},
64 64
 		{"Metadata Space Total", fmt.Sprintf("%s", units.HumanSize(int64(s.Metadata.Total)))},
65 65
 	}
66
-	if vStr, err := GetLibraryVersion(); err == nil {
66
+	if vStr, err := devicemapper.GetLibraryVersion(); err == nil {
67 67
 		status = append(status, [2]string{"Library Version", vStr})
68 68
 	}
69 69
 	return status
70 70
deleted file mode 100644
... ...
@@ -1,72 +0,0 @@
1
-// +build linux
2
-
3
-package devmapper
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
-}
54
-
55
-func ioctlBlkGetSize64(fd uintptr) (int64, error) {
56
-	var size int64
57
-	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, BlkGetSize64, uintptr(unsafe.Pointer(&size))); err != 0 {
58
-		return 0, err
59
-	}
60
-	return size, nil
61
-}
62
-
63
-func ioctlBlkDiscard(fd uintptr, offset, length uint64) error {
64
-	var r [2]uint64
65
-	r[0] = offset
66
-	r[1] = length
67
-
68
-	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, BlkDiscard, uintptr(unsafe.Pointer(&r[0]))); err != 0 {
69
-		return err
70
-	}
71
-	return nil
72
-}
73 1
new file mode 100644
... ...
@@ -0,0 +1,129 @@
0
+// +build linux
1
+
2
+package devicemapper
3
+
4
+import (
5
+	"fmt"
6
+	"os"
7
+	"syscall"
8
+
9
+	log "github.com/Sirupsen/logrus"
10
+)
11
+
12
+func stringToLoopName(src string) [LoNameSize]uint8 {
13
+	var dst [LoNameSize]uint8
14
+	copy(dst[:], src[:])
15
+	return dst
16
+}
17
+
18
+func getNextFreeLoopbackIndex() (int, error) {
19
+	f, err := os.OpenFile("/dev/loop-control", os.O_RDONLY, 0644)
20
+	if err != nil {
21
+		return 0, err
22
+	}
23
+	defer f.Close()
24
+
25
+	index, err := ioctlLoopCtlGetFree(f.Fd())
26
+	if index < 0 {
27
+		index = 0
28
+	}
29
+	return index, err
30
+}
31
+
32
+func openNextAvailableLoopback(index int, sparseFile *os.File) (loopFile *os.File, err error) {
33
+	// Start looking for a free /dev/loop
34
+	for {
35
+		target := fmt.Sprintf("/dev/loop%d", index)
36
+		index++
37
+
38
+		fi, err := os.Stat(target)
39
+		if err != nil {
40
+			if os.IsNotExist(err) {
41
+				log.Errorf("There are no more loopback devices available.")
42
+			}
43
+			return nil, ErrAttachLoopbackDevice
44
+		}
45
+
46
+		if fi.Mode()&os.ModeDevice != os.ModeDevice {
47
+			log.Errorf("Loopback device %s is not a block device.", target)
48
+			continue
49
+		}
50
+
51
+		// OpenFile adds O_CLOEXEC
52
+		loopFile, err = os.OpenFile(target, os.O_RDWR, 0644)
53
+		if err != nil {
54
+			log.Errorf("Error opening loopback device: %s", err)
55
+			return nil, ErrAttachLoopbackDevice
56
+		}
57
+
58
+		// Try to attach to the loop file
59
+		if err := ioctlLoopSetFd(loopFile.Fd(), sparseFile.Fd()); err != nil {
60
+			loopFile.Close()
61
+
62
+			// If the error is EBUSY, then try the next loopback
63
+			if err != syscall.EBUSY {
64
+				log.Errorf("Cannot set up loopback device %s: %s", target, err)
65
+				return nil, ErrAttachLoopbackDevice
66
+			}
67
+
68
+			// Otherwise, we keep going with the loop
69
+			continue
70
+		}
71
+		// In case of success, we finished. Break the loop.
72
+		break
73
+	}
74
+
75
+	// This can't happen, but let's be sure
76
+	if loopFile == nil {
77
+		log.Errorf("Unreachable code reached! Error attaching %s to a loopback device.", sparseFile.Name())
78
+		return nil, ErrAttachLoopbackDevice
79
+	}
80
+
81
+	return loopFile, nil
82
+}
83
+
84
+// attachLoopDevice attaches the given sparse file to the next
85
+// available loopback device. It returns an opened *os.File.
86
+func AttachLoopDevice(sparseName string) (loop *os.File, err error) {
87
+
88
+	// Try to retrieve the next available loopback device via syscall.
89
+	// If it fails, we discard error and start loopking for a
90
+	// loopback from index 0.
91
+	startIndex, err := getNextFreeLoopbackIndex()
92
+	if err != nil {
93
+		log.Debugf("Error retrieving the next available loopback: %s", err)
94
+	}
95
+
96
+	// OpenFile adds O_CLOEXEC
97
+	sparseFile, err := os.OpenFile(sparseName, os.O_RDWR, 0644)
98
+	if err != nil {
99
+		log.Errorf("Error opening sparse file %s: %s", sparseName, err)
100
+		return nil, ErrAttachLoopbackDevice
101
+	}
102
+	defer sparseFile.Close()
103
+
104
+	loopFile, err := openNextAvailableLoopback(startIndex, sparseFile)
105
+	if err != nil {
106
+		return nil, err
107
+	}
108
+
109
+	// Set the status of the loopback device
110
+	loopInfo := &LoopInfo64{
111
+		loFileName: stringToLoopName(loopFile.Name()),
112
+		loOffset:   0,
113
+		loFlags:    LoFlagsAutoClear,
114
+	}
115
+
116
+	if err := ioctlLoopSetStatus64(loopFile.Fd(), loopInfo); err != nil {
117
+		log.Errorf("Cannot set up loopback device info: %s", err)
118
+
119
+		// If the call failed, then free the loopback device
120
+		if err := ioctlLoopClrFd(loopFile.Fd()); err != nil {
121
+			log.Errorf("Error while cleaning up the loopback device")
122
+		}
123
+		loopFile.Close()
124
+		return nil, ErrAttachLoopbackDevice
125
+	}
126
+
127
+	return loopFile, nil
128
+}
0 129
new file mode 100644
... ...
@@ -0,0 +1,673 @@
0
+// +build linux
1
+
2
+package devicemapper
3
+
4
+import (
5
+	"errors"
6
+	"fmt"
7
+	"os"
8
+	"runtime"
9
+	"syscall"
10
+
11
+	log "github.com/Sirupsen/logrus"
12
+)
13
+
14
+type DevmapperLogger interface {
15
+	DMLog(level int, file string, line int, dmError int, message string)
16
+}
17
+
18
+const (
19
+	DeviceCreate TaskType = iota
20
+	DeviceReload
21
+	DeviceRemove
22
+	DeviceRemoveAll
23
+	DeviceSuspend
24
+	DeviceResume
25
+	DeviceInfo
26
+	DeviceDeps
27
+	DeviceRename
28
+	DeviceVersion
29
+	DeviceStatus
30
+	DeviceTable
31
+	DeviceWaitevent
32
+	DeviceList
33
+	DeviceClear
34
+	DeviceMknodes
35
+	DeviceListVersions
36
+	DeviceTargetMsg
37
+	DeviceSetGeometry
38
+)
39
+
40
+const (
41
+	AddNodeOnResume AddNodeType = iota
42
+	AddNodeOnCreate
43
+)
44
+
45
+var (
46
+	ErrTaskRun                = errors.New("dm_task_run failed")
47
+	ErrTaskSetName            = errors.New("dm_task_set_name failed")
48
+	ErrTaskSetMessage         = errors.New("dm_task_set_message failed")
49
+	ErrTaskSetAddNode         = errors.New("dm_task_set_add_node failed")
50
+	ErrTaskSetRo              = errors.New("dm_task_set_ro failed")
51
+	ErrTaskAddTarget          = errors.New("dm_task_add_target failed")
52
+	ErrTaskSetSector          = errors.New("dm_task_set_sector failed")
53
+	ErrTaskGetDeps            = errors.New("dm_task_get_deps failed")
54
+	ErrTaskGetInfo            = errors.New("dm_task_get_info failed")
55
+	ErrTaskGetDriverVersion   = errors.New("dm_task_get_driver_version failed")
56
+	ErrTaskSetCookie          = errors.New("dm_task_set_cookie failed")
57
+	ErrNilCookie              = errors.New("cookie ptr can't be nil")
58
+	ErrAttachLoopbackDevice   = errors.New("loopback mounting failed")
59
+	ErrGetBlockSize           = errors.New("Can't get block size")
60
+	ErrUdevWait               = errors.New("wait on udev cookie failed")
61
+	ErrSetDevDir              = errors.New("dm_set_dev_dir failed")
62
+	ErrGetLibraryVersion      = errors.New("dm_get_library_version failed")
63
+	ErrCreateRemoveTask       = errors.New("Can't create task of type DeviceRemove")
64
+	ErrRunRemoveDevice        = errors.New("running removeDevice failed")
65
+	ErrInvalidAddNode         = errors.New("Invalide AddNoce type")
66
+	ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
67
+	ErrLoopbackSetCapacity    = errors.New("Unable set loopback capacity")
68
+	ErrBusy                   = errors.New("Device is Busy")
69
+
70
+	dmSawBusy  bool
71
+	dmSawExist bool
72
+)
73
+
74
+type (
75
+	Task struct {
76
+		unmanaged *CDmTask
77
+	}
78
+	Deps struct {
79
+		Count  uint32
80
+		Filler uint32
81
+		Device []uint64
82
+	}
83
+	Info struct {
84
+		Exists        int
85
+		Suspended     int
86
+		LiveTable     int
87
+		InactiveTable int
88
+		OpenCount     int32
89
+		EventNr       uint32
90
+		Major         uint32
91
+		Minor         uint32
92
+		ReadOnly      int
93
+		TargetCount   int32
94
+	}
95
+	TaskType    int
96
+	AddNodeType int
97
+)
98
+
99
+func (t *Task) destroy() {
100
+	if t != nil {
101
+		DmTaskDestroy(t.unmanaged)
102
+		runtime.SetFinalizer(t, nil)
103
+	}
104
+}
105
+
106
+func TaskCreate(tasktype TaskType) *Task {
107
+	Ctask := DmTaskCreate(int(tasktype))
108
+	if Ctask == nil {
109
+		return nil
110
+	}
111
+	task := &Task{unmanaged: Ctask}
112
+	runtime.SetFinalizer(task, (*Task).destroy)
113
+	return task
114
+}
115
+
116
+func (t *Task) Run() error {
117
+	if res := DmTaskRun(t.unmanaged); res != 1 {
118
+		return ErrTaskRun
119
+	}
120
+	return nil
121
+}
122
+
123
+func (t *Task) SetName(name string) error {
124
+	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
125
+		return ErrTaskSetName
126
+	}
127
+	return nil
128
+}
129
+
130
+func (t *Task) SetMessage(message string) error {
131
+	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
132
+		return ErrTaskSetMessage
133
+	}
134
+	return nil
135
+}
136
+
137
+func (t *Task) SetSector(sector uint64) error {
138
+	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
139
+		return ErrTaskSetSector
140
+	}
141
+	return nil
142
+}
143
+
144
+func (t *Task) SetCookie(cookie *uint, flags uint16) error {
145
+	if cookie == nil {
146
+		return ErrNilCookie
147
+	}
148
+	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
149
+		return ErrTaskSetCookie
150
+	}
151
+	return nil
152
+}
153
+
154
+func (t *Task) SetAddNode(addNode AddNodeType) error {
155
+	if addNode != AddNodeOnResume && addNode != AddNodeOnCreate {
156
+		return ErrInvalidAddNode
157
+	}
158
+	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
159
+		return ErrTaskSetAddNode
160
+	}
161
+	return nil
162
+}
163
+
164
+func (t *Task) SetRo() error {
165
+	if res := DmTaskSetRo(t.unmanaged); res != 1 {
166
+		return ErrTaskSetRo
167
+	}
168
+	return nil
169
+}
170
+
171
+func (t *Task) AddTarget(start, size uint64, ttype, params string) error {
172
+	if res := DmTaskAddTarget(t.unmanaged, start, size,
173
+		ttype, params); res != 1 {
174
+		return ErrTaskAddTarget
175
+	}
176
+	return nil
177
+}
178
+
179
+func (t *Task) GetDeps() (*Deps, error) {
180
+	var deps *Deps
181
+	if deps = DmTaskGetDeps(t.unmanaged); deps == nil {
182
+		return nil, ErrTaskGetDeps
183
+	}
184
+	return deps, nil
185
+}
186
+
187
+func (t *Task) GetInfo() (*Info, error) {
188
+	info := &Info{}
189
+	if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
190
+		return nil, ErrTaskGetInfo
191
+	}
192
+	return info, nil
193
+}
194
+
195
+func (t *Task) GetDriverVersion() (string, error) {
196
+	res := DmTaskGetDriverVersion(t.unmanaged)
197
+	if res == "" {
198
+		return "", ErrTaskGetDriverVersion
199
+	}
200
+	return res, nil
201
+}
202
+
203
+func (t *Task) GetNextTarget(next uintptr) (nextPtr uintptr, start uint64,
204
+	length uint64, targetType string, params string) {
205
+
206
+	return DmGetNextTarget(t.unmanaged, next, &start, &length,
207
+			&targetType, &params),
208
+		start, length, targetType, params
209
+}
210
+
211
+func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
212
+	loopInfo, err := ioctlLoopGetStatus64(file.Fd())
213
+	if err != nil {
214
+		log.Errorf("Error get loopback backing file: %s", err)
215
+		return 0, 0, ErrGetLoopbackBackingFile
216
+	}
217
+	return loopInfo.loDevice, loopInfo.loInode, nil
218
+}
219
+
220
+func LoopbackSetCapacity(file *os.File) error {
221
+	if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
222
+		log.Errorf("Error loopbackSetCapacity: %s", err)
223
+		return ErrLoopbackSetCapacity
224
+	}
225
+	return nil
226
+}
227
+
228
+func FindLoopDeviceFor(file *os.File) *os.File {
229
+	stat, err := file.Stat()
230
+	if err != nil {
231
+		return nil
232
+	}
233
+	targetInode := stat.Sys().(*syscall.Stat_t).Ino
234
+	targetDevice := stat.Sys().(*syscall.Stat_t).Dev
235
+
236
+	for i := 0; true; i++ {
237
+		path := fmt.Sprintf("/dev/loop%d", i)
238
+
239
+		file, err := os.OpenFile(path, os.O_RDWR, 0)
240
+		if err != nil {
241
+			if os.IsNotExist(err) {
242
+				return nil
243
+			}
244
+
245
+			// Ignore all errors until the first not-exist
246
+			// we want to continue looking for the file
247
+			continue
248
+		}
249
+
250
+		dev, inode, err := getLoopbackBackingFile(file)
251
+		if err == nil && dev == targetDevice && inode == targetInode {
252
+			return file
253
+		}
254
+		file.Close()
255
+	}
256
+
257
+	return nil
258
+}
259
+
260
+func UdevWait(cookie uint) error {
261
+	if res := DmUdevWait(cookie); res != 1 {
262
+		log.Debugf("Failed to wait on udev cookie %d", cookie)
263
+		return ErrUdevWait
264
+	}
265
+	return nil
266
+}
267
+
268
+func LogInitVerbose(level int) {
269
+	DmLogInitVerbose(level)
270
+}
271
+
272
+var dmLogger DevmapperLogger = nil
273
+
274
+// initialize the logger for the device mapper library
275
+func LogInit(logger DevmapperLogger) {
276
+	dmLogger = logger
277
+	LogWithErrnoInit()
278
+}
279
+
280
+func SetDevDir(dir string) error {
281
+	if res := DmSetDevDir(dir); res != 1 {
282
+		log.Debugf("Error dm_set_dev_dir")
283
+		return ErrSetDevDir
284
+	}
285
+	return nil
286
+}
287
+
288
+func GetLibraryVersion() (string, error) {
289
+	var version string
290
+	if res := DmGetLibraryVersion(&version); res != 1 {
291
+		return "", ErrGetLibraryVersion
292
+	}
293
+	return version, nil
294
+}
295
+
296
+// Useful helper for cleanup
297
+func RemoveDevice(name string) error {
298
+	// TODO(vbatts) just use the other removeDevice()
299
+	task := TaskCreate(DeviceRemove)
300
+	if task == nil {
301
+		return ErrCreateRemoveTask
302
+	}
303
+	if err := task.SetName(name); err != nil {
304
+		log.Debugf("Can't set task name %s", name)
305
+		return err
306
+	}
307
+	if err := task.Run(); err != nil {
308
+		return ErrRunRemoveDevice
309
+	}
310
+	return nil
311
+}
312
+
313
+func GetBlockDeviceSize(file *os.File) (uint64, error) {
314
+	size, err := ioctlBlkGetSize64(file.Fd())
315
+	if err != nil {
316
+		log.Errorf("Error getblockdevicesize: %s", err)
317
+		return 0, ErrGetBlockSize
318
+	}
319
+	return uint64(size), nil
320
+}
321
+
322
+func BlockDeviceDiscard(path string) error {
323
+	file, err := os.OpenFile(path, os.O_RDWR, 0)
324
+	if err != nil {
325
+		return err
326
+	}
327
+	defer file.Close()
328
+
329
+	size, err := GetBlockDeviceSize(file)
330
+	if err != nil {
331
+		return err
332
+	}
333
+
334
+	if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil {
335
+		return err
336
+	}
337
+
338
+	// Without this sometimes the remove of the device that happens after
339
+	// discard fails with EBUSY.
340
+	syscall.Sync()
341
+
342
+	return nil
343
+}
344
+
345
+// This is the programmatic example of "dmsetup create"
346
+func CreatePool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
347
+	task, err := createTask(DeviceCreate, poolName)
348
+	if task == nil {
349
+		return err
350
+	}
351
+
352
+	size, err := GetBlockDeviceSize(dataFile)
353
+	if err != nil {
354
+		return fmt.Errorf("Can't get data size %s", err)
355
+	}
356
+
357
+	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
358
+	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
359
+		return fmt.Errorf("Can't add target %s", err)
360
+	}
361
+
362
+	var cookie uint = 0
363
+	if err := task.SetCookie(&cookie, 0); err != nil {
364
+		return fmt.Errorf("Can't set cookie %s", err)
365
+	}
366
+
367
+	if err := task.Run(); err != nil {
368
+		return fmt.Errorf("Error running DeviceCreate (CreatePool) %s", err)
369
+	}
370
+
371
+	UdevWait(cookie)
372
+
373
+	return nil
374
+}
375
+
376
+func ReloadPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
377
+	task, err := createTask(DeviceReload, poolName)
378
+	if task == nil {
379
+		return err
380
+	}
381
+
382
+	size, err := GetBlockDeviceSize(dataFile)
383
+	if err != nil {
384
+		return fmt.Errorf("Can't get data size %s", err)
385
+	}
386
+
387
+	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
388
+	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
389
+		return fmt.Errorf("Can't add target %s", err)
390
+	}
391
+
392
+	if err := task.Run(); err != nil {
393
+		return fmt.Errorf("Error running DeviceCreate %s", err)
394
+	}
395
+
396
+	return nil
397
+}
398
+
399
+func createTask(t TaskType, name string) (*Task, error) {
400
+	task := TaskCreate(t)
401
+	if task == nil {
402
+		return nil, fmt.Errorf("Can't create task of type %d", int(t))
403
+	}
404
+	if err := task.SetName(name); err != nil {
405
+		return nil, fmt.Errorf("Can't set task name %s", name)
406
+	}
407
+	return task, nil
408
+}
409
+
410
+func GetDeps(name string) (*Deps, error) {
411
+	task, err := createTask(DeviceDeps, name)
412
+	if task == nil {
413
+		return nil, err
414
+	}
415
+	if err := task.Run(); err != nil {
416
+		return nil, err
417
+	}
418
+	return task.GetDeps()
419
+}
420
+
421
+func GetInfo(name string) (*Info, error) {
422
+	task, err := createTask(DeviceInfo, name)
423
+	if task == nil {
424
+		return nil, err
425
+	}
426
+	if err := task.Run(); err != nil {
427
+		return nil, err
428
+	}
429
+	return task.GetInfo()
430
+}
431
+
432
+func GetDriverVersion() (string, error) {
433
+	task := TaskCreate(DeviceVersion)
434
+	if task == nil {
435
+		return "", fmt.Errorf("Can't create DeviceVersion task")
436
+	}
437
+	if err := task.Run(); err != nil {
438
+		return "", err
439
+	}
440
+	return task.GetDriverVersion()
441
+}
442
+
443
+func GetStatus(name string) (uint64, uint64, string, string, error) {
444
+	task, err := createTask(DeviceStatus, name)
445
+	if task == nil {
446
+		log.Debugf("GetStatus: Error createTask: %s", err)
447
+		return 0, 0, "", "", err
448
+	}
449
+	if err := task.Run(); err != nil {
450
+		log.Debugf("GetStatus: Error Run: %s", err)
451
+		return 0, 0, "", "", err
452
+	}
453
+
454
+	devinfo, err := task.GetInfo()
455
+	if err != nil {
456
+		log.Debugf("GetStatus: Error GetInfo: %s", err)
457
+		return 0, 0, "", "", err
458
+	}
459
+	if devinfo.Exists == 0 {
460
+		log.Debugf("GetStatus: Non existing device %s", name)
461
+		return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
462
+	}
463
+
464
+	_, start, length, targetType, params := task.GetNextTarget(0)
465
+	return start, length, targetType, params, nil
466
+}
467
+
468
+func SetTransactionId(poolName string, oldId uint64, newId uint64) error {
469
+	task, err := createTask(DeviceTargetMsg, poolName)
470
+	if task == nil {
471
+		return err
472
+	}
473
+
474
+	if err := task.SetSector(0); err != nil {
475
+		return fmt.Errorf("Can't set sector %s", err)
476
+	}
477
+
478
+	if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
479
+		return fmt.Errorf("Can't set message %s", err)
480
+	}
481
+
482
+	if err := task.Run(); err != nil {
483
+		return fmt.Errorf("Error running SetTransactionId %s", err)
484
+	}
485
+	return nil
486
+}
487
+
488
+func SuspendDevice(name string) error {
489
+	task, err := createTask(DeviceSuspend, name)
490
+	if task == nil {
491
+		return err
492
+	}
493
+	if err := task.Run(); err != nil {
494
+		return fmt.Errorf("Error running DeviceSuspend %s", err)
495
+	}
496
+	return nil
497
+}
498
+
499
+func ResumeDevice(name string) error {
500
+	task, err := createTask(DeviceResume, name)
501
+	if task == nil {
502
+		return err
503
+	}
504
+
505
+	var cookie uint = 0
506
+	if err := task.SetCookie(&cookie, 0); err != nil {
507
+		return fmt.Errorf("Can't set cookie %s", err)
508
+	}
509
+
510
+	if err := task.Run(); err != nil {
511
+		return fmt.Errorf("Error running DeviceResume %s", err)
512
+	}
513
+
514
+	UdevWait(cookie)
515
+
516
+	return nil
517
+}
518
+
519
+func CreateDevice(poolName string, deviceId *int) error {
520
+	log.Debugf("[devmapper] CreateDevice(poolName=%v, deviceId=%v)", poolName, *deviceId)
521
+
522
+	for {
523
+		task, err := createTask(DeviceTargetMsg, poolName)
524
+		if task == nil {
525
+			return err
526
+		}
527
+
528
+		if err := task.SetSector(0); err != nil {
529
+			return fmt.Errorf("Can't set sector %s", err)
530
+		}
531
+
532
+		if err := task.SetMessage(fmt.Sprintf("create_thin %d", *deviceId)); err != nil {
533
+			return fmt.Errorf("Can't set message %s", err)
534
+		}
535
+
536
+		dmSawExist = false
537
+		if err := task.Run(); err != nil {
538
+			if dmSawExist {
539
+				// Already exists, try next id
540
+				*deviceId++
541
+				continue
542
+			}
543
+			return fmt.Errorf("Error running CreateDevice %s", err)
544
+		}
545
+		break
546
+	}
547
+	return nil
548
+}
549
+
550
+func DeleteDevice(poolName string, deviceId int) error {
551
+	task, err := createTask(DeviceTargetMsg, poolName)
552
+	if task == nil {
553
+		return err
554
+	}
555
+
556
+	if err := task.SetSector(0); err != nil {
557
+		return fmt.Errorf("Can't set sector %s", err)
558
+	}
559
+
560
+	if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
561
+		return fmt.Errorf("Can't set message %s", err)
562
+	}
563
+
564
+	if err := task.Run(); err != nil {
565
+		return fmt.Errorf("Error running DeleteDevice %s", err)
566
+	}
567
+	return nil
568
+}
569
+
570
+func removeDevice(name string) error {
571
+	log.Debugf("[devmapper] RemoveDevice START")
572
+	defer log.Debugf("[devmapper] RemoveDevice END")
573
+	task, err := createTask(DeviceRemove, name)
574
+	if task == nil {
575
+		return err
576
+	}
577
+	dmSawBusy = false
578
+	if err = task.Run(); err != nil {
579
+		if dmSawBusy {
580
+			return ErrBusy
581
+		}
582
+		return fmt.Errorf("Error running RemoveDevice %s", err)
583
+	}
584
+	return nil
585
+}
586
+
587
+func ActivateDevice(poolName string, name string, deviceId int, size uint64) error {
588
+	task, err := createTask(DeviceCreate, name)
589
+	if task == nil {
590
+		return err
591
+	}
592
+
593
+	params := fmt.Sprintf("%s %d", poolName, deviceId)
594
+	if err := task.AddTarget(0, size/512, "thin", params); err != nil {
595
+		return fmt.Errorf("Can't add target %s", err)
596
+	}
597
+	if err := task.SetAddNode(AddNodeOnCreate); err != nil {
598
+		return fmt.Errorf("Can't add node %s", err)
599
+	}
600
+
601
+	var cookie uint = 0
602
+	if err := task.SetCookie(&cookie, 0); err != nil {
603
+		return fmt.Errorf("Can't set cookie %s", err)
604
+	}
605
+
606
+	if err := task.Run(); err != nil {
607
+		return fmt.Errorf("Error running DeviceCreate (ActivateDevice) %s", err)
608
+	}
609
+
610
+	UdevWait(cookie)
611
+
612
+	return nil
613
+}
614
+
615
+func CreateSnapDevice(poolName string, deviceId *int, baseName string, baseDeviceId int) error {
616
+	devinfo, _ := GetInfo(baseName)
617
+	doSuspend := devinfo != nil && devinfo.Exists != 0
618
+
619
+	if doSuspend {
620
+		if err := SuspendDevice(baseName); err != nil {
621
+			return err
622
+		}
623
+	}
624
+
625
+	for {
626
+		task, err := createTask(DeviceTargetMsg, poolName)
627
+		if task == nil {
628
+			if doSuspend {
629
+				ResumeDevice(baseName)
630
+			}
631
+			return err
632
+		}
633
+
634
+		if err := task.SetSector(0); err != nil {
635
+			if doSuspend {
636
+				ResumeDevice(baseName)
637
+			}
638
+			return fmt.Errorf("Can't set sector %s", err)
639
+		}
640
+
641
+		if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", *deviceId, baseDeviceId)); err != nil {
642
+			if doSuspend {
643
+				ResumeDevice(baseName)
644
+			}
645
+			return fmt.Errorf("Can't set message %s", err)
646
+		}
647
+
648
+		dmSawExist = false
649
+		if err := task.Run(); err != nil {
650
+			if dmSawExist {
651
+				// Already exists, try next id
652
+				*deviceId++
653
+				continue
654
+			}
655
+
656
+			if doSuspend {
657
+				ResumeDevice(baseName)
658
+			}
659
+			return fmt.Errorf("Error running DeviceCreate (createSnapDevice) %s", err)
660
+		}
661
+
662
+		break
663
+	}
664
+
665
+	if doSuspend {
666
+		if err := ResumeDevice(baseName); err != nil {
667
+			return err
668
+		}
669
+	}
670
+
671
+	return nil
672
+}
0 673
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+// +build linux
1
+
2
+package devicemapper
3
+
4
+import "C"
5
+
6
+import (
7
+	"strings"
8
+)
9
+
10
+// Due to the way cgo works this has to be in a separate file, as devmapper.go has
11
+// definitions in the cgo block, which is incompatible with using "//export"
12
+
13
+//export DevmapperLogCallback
14
+func DevmapperLogCallback(level C.int, file *C.char, line C.int, dm_errno_or_class C.int, message *C.char) {
15
+	msg := C.GoString(message)
16
+	if level < 7 {
17
+		if strings.Contains(msg, "busy") {
18
+			dmSawBusy = true
19
+		}
20
+
21
+		if strings.Contains(msg, "File exists") {
22
+			dmSawExist = true
23
+		}
24
+	}
25
+
26
+	if dmLogger != nil {
27
+		dmLogger.DMLog(int(level), C.GoString(file), int(line), int(dm_errno_or_class), msg)
28
+	}
29
+}
0 30
new file mode 100644
... ...
@@ -0,0 +1,254 @@
0
+// +build linux
1
+
2
+package devicemapper
3
+
4
+/*
5
+#cgo LDFLAGS: -L. -ldevmapper
6
+#include <libdevmapper.h>
7
+#include <linux/loop.h> // FIXME: present only for defines, maybe we can remove it?
8
+#include <linux/fs.h>   // FIXME: present only for BLKGETSIZE64, maybe we can remove it?
9
+
10
+#ifndef LOOP_CTL_GET_FREE
11
+  #define LOOP_CTL_GET_FREE 0x4C82
12
+#endif
13
+
14
+#ifndef LO_FLAGS_PARTSCAN
15
+  #define LO_FLAGS_PARTSCAN 8
16
+#endif
17
+
18
+// FIXME: Can't we find a way to do the logging in pure Go?
19
+extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
20
+
21
+static void	log_cb(int level, const char *file, int line, int dm_errno_or_class, const char *f, ...)
22
+{
23
+  char buffer[256];
24
+  va_list ap;
25
+
26
+  va_start(ap, f);
27
+  vsnprintf(buffer, 256, f, ap);
28
+  va_end(ap);
29
+
30
+  DevmapperLogCallback(level, (char *)file, line, dm_errno_or_class, buffer);
31
+}
32
+
33
+static void	log_with_errno_init()
34
+{
35
+  dm_log_with_errno_init(log_cb);
36
+}
37
+*/
38
+import "C"
39
+
40
+import "unsafe"
41
+
42
+type (
43
+	CDmTask C.struct_dm_task
44
+
45
+	CLoopInfo64 C.struct_loop_info64
46
+	LoopInfo64  struct {
47
+		loDevice           uint64 /* ioctl r/o */
48
+		loInode            uint64 /* ioctl r/o */
49
+		loRdevice          uint64 /* ioctl r/o */
50
+		loOffset           uint64
51
+		loSizelimit        uint64 /* bytes, 0 == max available */
52
+		loNumber           uint32 /* ioctl r/o */
53
+		loEncrypt_type     uint32
54
+		loEncrypt_key_size uint32 /* ioctl w/o */
55
+		loFlags            uint32 /* ioctl r/o */
56
+		loFileName         [LoNameSize]uint8
57
+		loCryptName        [LoNameSize]uint8
58
+		loEncryptKey       [LoKeySize]uint8 /* ioctl w/o */
59
+		loInit             [2]uint64
60
+	}
61
+)
62
+
63
+// IOCTL consts
64
+const (
65
+	BlkGetSize64 = C.BLKGETSIZE64
66
+	BlkDiscard   = C.BLKDISCARD
67
+
68
+	LoopSetFd       = C.LOOP_SET_FD
69
+	LoopCtlGetFree  = C.LOOP_CTL_GET_FREE
70
+	LoopGetStatus64 = C.LOOP_GET_STATUS64
71
+	LoopSetStatus64 = C.LOOP_SET_STATUS64
72
+	LoopClrFd       = C.LOOP_CLR_FD
73
+	LoopSetCapacity = C.LOOP_SET_CAPACITY
74
+)
75
+
76
+const (
77
+	LoFlagsAutoClear = C.LO_FLAGS_AUTOCLEAR
78
+	LoFlagsReadOnly  = C.LO_FLAGS_READ_ONLY
79
+	LoFlagsPartScan  = C.LO_FLAGS_PARTSCAN
80
+	LoKeySize        = C.LO_KEY_SIZE
81
+	LoNameSize       = C.LO_NAME_SIZE
82
+)
83
+
84
+var (
85
+	DmGetLibraryVersion    = dmGetLibraryVersionFct
86
+	DmGetNextTarget        = dmGetNextTargetFct
87
+	DmLogInitVerbose       = dmLogInitVerboseFct
88
+	DmSetDevDir            = dmSetDevDirFct
89
+	DmTaskAddTarget        = dmTaskAddTargetFct
90
+	DmTaskCreate           = dmTaskCreateFct
91
+	DmTaskDestroy          = dmTaskDestroyFct
92
+	DmTaskGetDeps          = dmTaskGetDepsFct
93
+	DmTaskGetInfo          = dmTaskGetInfoFct
94
+	DmTaskGetDriverVersion = dmTaskGetDriverVersionFct
95
+	DmTaskRun              = dmTaskRunFct
96
+	DmTaskSetAddNode       = dmTaskSetAddNodeFct
97
+	DmTaskSetCookie        = dmTaskSetCookieFct
98
+	DmTaskSetMessage       = dmTaskSetMessageFct
99
+	DmTaskSetName          = dmTaskSetNameFct
100
+	DmTaskSetRo            = dmTaskSetRoFct
101
+	DmTaskSetSector        = dmTaskSetSectorFct
102
+	DmUdevWait             = dmUdevWaitFct
103
+	LogWithErrnoInit       = logWithErrnoInitFct
104
+)
105
+
106
+func free(p *C.char) {
107
+	C.free(unsafe.Pointer(p))
108
+}
109
+
110
+func dmTaskDestroyFct(task *CDmTask) {
111
+	C.dm_task_destroy((*C.struct_dm_task)(task))
112
+}
113
+
114
+func dmTaskCreateFct(taskType int) *CDmTask {
115
+	return (*CDmTask)(C.dm_task_create(C.int(taskType)))
116
+}
117
+
118
+func dmTaskRunFct(task *CDmTask) int {
119
+	ret, _ := C.dm_task_run((*C.struct_dm_task)(task))
120
+	return int(ret)
121
+}
122
+
123
+func dmTaskSetNameFct(task *CDmTask, name string) int {
124
+	Cname := C.CString(name)
125
+	defer free(Cname)
126
+
127
+	return int(C.dm_task_set_name((*C.struct_dm_task)(task), Cname))
128
+}
129
+
130
+func dmTaskSetMessageFct(task *CDmTask, message string) int {
131
+	Cmessage := C.CString(message)
132
+	defer free(Cmessage)
133
+
134
+	return int(C.dm_task_set_message((*C.struct_dm_task)(task), Cmessage))
135
+}
136
+
137
+func dmTaskSetSectorFct(task *CDmTask, sector uint64) int {
138
+	return int(C.dm_task_set_sector((*C.struct_dm_task)(task), C.uint64_t(sector)))
139
+}
140
+
141
+func dmTaskSetCookieFct(task *CDmTask, cookie *uint, flags uint16) int {
142
+	cCookie := C.uint32_t(*cookie)
143
+	defer func() {
144
+		*cookie = uint(cCookie)
145
+	}()
146
+	return int(C.dm_task_set_cookie((*C.struct_dm_task)(task), &cCookie, C.uint16_t(flags)))
147
+}
148
+
149
+func dmTaskSetAddNodeFct(task *CDmTask, addNode AddNodeType) int {
150
+	return int(C.dm_task_set_add_node((*C.struct_dm_task)(task), C.dm_add_node_t(addNode)))
151
+}
152
+
153
+func dmTaskSetRoFct(task *CDmTask) int {
154
+	return int(C.dm_task_set_ro((*C.struct_dm_task)(task)))
155
+}
156
+
157
+func dmTaskAddTargetFct(task *CDmTask,
158
+	start, size uint64, ttype, params string) int {
159
+
160
+	Cttype := C.CString(ttype)
161
+	defer free(Cttype)
162
+
163
+	Cparams := C.CString(params)
164
+	defer free(Cparams)
165
+
166
+	return int(C.dm_task_add_target((*C.struct_dm_task)(task), C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
167
+}
168
+
169
+func dmTaskGetDepsFct(task *CDmTask) *Deps {
170
+	Cdeps := C.dm_task_get_deps((*C.struct_dm_task)(task))
171
+	if Cdeps == nil {
172
+		return nil
173
+	}
174
+	deps := &Deps{
175
+		Count:  uint32(Cdeps.count),
176
+		Filler: uint32(Cdeps.filler),
177
+	}
178
+	for _, device := range Cdeps.device {
179
+		deps.Device = append(deps.Device, (uint64)(device))
180
+	}
181
+	return deps
182
+}
183
+
184
+func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
185
+	Cinfo := C.struct_dm_info{}
186
+	defer func() {
187
+		info.Exists = int(Cinfo.exists)
188
+		info.Suspended = int(Cinfo.suspended)
189
+		info.LiveTable = int(Cinfo.live_table)
190
+		info.InactiveTable = int(Cinfo.inactive_table)
191
+		info.OpenCount = int32(Cinfo.open_count)
192
+		info.EventNr = uint32(Cinfo.event_nr)
193
+		info.Major = uint32(Cinfo.major)
194
+		info.Minor = uint32(Cinfo.minor)
195
+		info.ReadOnly = int(Cinfo.read_only)
196
+		info.TargetCount = int32(Cinfo.target_count)
197
+	}()
198
+	return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
199
+}
200
+
201
+func dmTaskGetDriverVersionFct(task *CDmTask) string {
202
+	buffer := C.malloc(128)
203
+	defer C.free(buffer)
204
+	res := C.dm_task_get_driver_version((*C.struct_dm_task)(task), (*C.char)(buffer), 128)
205
+	if res == 0 {
206
+		return ""
207
+	}
208
+	return C.GoString((*C.char)(buffer))
209
+}
210
+
211
+func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64, target, params *string) uintptr {
212
+	var (
213
+		Cstart, Clength      C.uint64_t
214
+		CtargetType, Cparams *C.char
215
+	)
216
+	defer func() {
217
+		*start = uint64(Cstart)
218
+		*length = uint64(Clength)
219
+		*target = C.GoString(CtargetType)
220
+		*params = C.GoString(Cparams)
221
+	}()
222
+
223
+	nextp := C.dm_get_next_target((*C.struct_dm_task)(task), unsafe.Pointer(next), &Cstart, &Clength, &CtargetType, &Cparams)
224
+	return uintptr(nextp)
225
+}
226
+
227
+func dmUdevWaitFct(cookie uint) int {
228
+	return int(C.dm_udev_wait(C.uint32_t(cookie)))
229
+}
230
+
231
+func dmLogInitVerboseFct(level int) {
232
+	C.dm_log_init_verbose(C.int(level))
233
+}
234
+
235
+func logWithErrnoInitFct() {
236
+	C.log_with_errno_init()
237
+}
238
+
239
+func dmSetDevDirFct(dir string) int {
240
+	Cdir := C.CString(dir)
241
+	defer free(Cdir)
242
+
243
+	return int(C.dm_set_dev_dir(Cdir))
244
+}
245
+
246
+func dmGetLibraryVersionFct(version *string) int {
247
+	buffer := C.CString(string(make([]byte, 128)))
248
+	defer free(buffer)
249
+	defer func() {
250
+		*version = C.GoString(buffer)
251
+	}()
252
+	return int(C.dm_get_library_version(buffer, 128))
253
+}
0 254
new file mode 100644
... ...
@@ -0,0 +1,72 @@
0
+// +build linux
1
+
2
+package devicemapper
3
+
4
+import (
5
+	"syscall"
6
+	"unsafe"
7
+)
8
+
9
+func ioctlLoopCtlGetFree(fd uintptr) (int, error) {
10
+	index, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, LoopCtlGetFree, 0)
11
+	if err != 0 {
12
+		return 0, err
13
+	}
14
+	return int(index), nil
15
+}
16
+
17
+func ioctlLoopSetFd(loopFd, sparseFd uintptr) error {
18
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetFd, sparseFd); err != 0 {
19
+		return err
20
+	}
21
+	return nil
22
+}
23
+
24
+func ioctlLoopSetStatus64(loopFd uintptr, loopInfo *LoopInfo64) error {
25
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
26
+		return err
27
+	}
28
+	return nil
29
+}
30
+
31
+func ioctlLoopClrFd(loopFd uintptr) error {
32
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopClrFd, 0); err != 0 {
33
+		return err
34
+	}
35
+	return nil
36
+}
37
+
38
+func ioctlLoopGetStatus64(loopFd uintptr) (*LoopInfo64, error) {
39
+	loopInfo := &LoopInfo64{}
40
+
41
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopGetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
42
+		return nil, err
43
+	}
44
+	return loopInfo, nil
45
+}
46
+
47
+func ioctlLoopSetCapacity(loopFd uintptr, value int) error {
48
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, loopFd, LoopSetCapacity, uintptr(value)); err != 0 {
49
+		return err
50
+	}
51
+	return nil
52
+}
53
+
54
+func ioctlBlkGetSize64(fd uintptr) (int64, error) {
55
+	var size int64
56
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, BlkGetSize64, uintptr(unsafe.Pointer(&size))); err != 0 {
57
+		return 0, err
58
+	}
59
+	return size, nil
60
+}
61
+
62
+func ioctlBlkDiscard(fd uintptr, offset, length uint64) error {
63
+	var r [2]uint64
64
+	r[0] = offset
65
+	r[1] = length
66
+
67
+	if _, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, BlkDiscard, uintptr(unsafe.Pointer(&r[0]))); err != 0 {
68
+		return err
69
+	}
70
+	return nil
71
+}