This is a first pass at splitting out devicemapper into separate, usable
bindings.
Signed-off-by: Vincent Batts <vbatts@redhat.com>
| 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, ¶ms), |
|
| 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, ¶ms), |
|
| 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 |
+} |