func GetDriverVersion() (string, error) {
	task := TaskCreate(deviceVersion)
	if task == nil {
		return "", fmt.Errorf("devicemapper: Can't create deviceVersion task")
	}
	if err := task.run(); err != nil {
		return "", err
	}
	return task.getDriverVersion()
}
GetDriverVersion is the programmatic example of "dmsetup version".
It outputs version information of the driver.
package devicemapper
import (
	"errors"
	"fmt"
	"os"
	"runtime"
	"unsafe"
	"github.com/sirupsen/logrus"
	"golang.org/x/sys/unix"
)
const (
	deviceCreate TaskType = iota
	deviceReload
	deviceRemove
	deviceRemoveAll
	deviceSuspend
	deviceResume
	deviceInfo
	deviceDeps
	deviceRename
	deviceVersion
	deviceStatus
	deviceTable
	deviceWaitevent
	deviceList
	deviceClear
	deviceMknodes
	deviceListVersions
	deviceTargetMsg
	deviceSetGeometry
)
const (
	addNodeOnResume AddNodeType = iota
	addNodeOnCreate
)
var (
	ErrTaskRun              = errors.New("dm_task_run failed")
	ErrTaskSetName          = errors.New("dm_task_set_name failed")
	ErrTaskSetMessage       = errors.New("dm_task_set_message failed")
	ErrTaskSetAddNode       = errors.New("dm_task_set_add_node failed")
	ErrTaskSetRo            = errors.New("dm_task_set_ro failed")
	ErrTaskAddTarget        = errors.New("dm_task_add_target failed")
	ErrTaskSetSector        = errors.New("dm_task_set_sector failed")
	ErrTaskGetDeps          = errors.New("dm_task_get_deps failed")
	ErrTaskGetInfo          = errors.New("dm_task_get_info failed")
	ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version failed")
	ErrTaskDeferredRemove   = errors.New("dm_task_deferred_remove failed")
	ErrTaskSetCookie        = errors.New("dm_task_set_cookie failed")
	ErrNilCookie            = errors.New("cookie ptr can't be nil")
	ErrGetBlockSize         = errors.New("Can't get block size")
	ErrUdevWait             = errors.New("wait on udev cookie failed")
	ErrSetDevDir            = errors.New("dm_set_dev_dir failed")
	ErrGetLibraryVersion    = errors.New("dm_get_library_version failed")
	ErrCreateRemoveTask     = errors.New("Can't create task of type deviceRemove")
	ErrRunRemoveDevice      = errors.New("running RemoveDevice failed")
	ErrInvalidAddNode       = errors.New("Invalid AddNode type")
	ErrBusy                 = errors.New("Device is Busy")
	ErrDeviceIDExists       = errors.New("Device Id Exists")
	ErrEnxio                = errors.New("No such device or address")
)
var (
	dmSawBusy  bool
	dmSawExist bool
	dmSawEnxio bool  
)
type (
	Task struct {
		unmanaged *cdmTask
	}
	Deps struct {
		Count  uint32
		Filler uint32
		Device []uint64
	}
	Info struct {
		Exists         int
		Suspended      int
		LiveTable      int
		InactiveTable  int
		OpenCount      int32
		EventNr        uint32
		Major          uint32
		Minor          uint32
		ReadOnly       int
		TargetCount    int32
		DeferredRemove int
	}
	TaskType int
	AddNodeType int
)
func DeviceIDExists(err error) bool {
	return fmt.Sprint(err) == fmt.Sprint(ErrDeviceIDExists)
}
func (t *Task) destroy() {
	if t != nil {
		DmTaskDestroy(t.unmanaged)
		runtime.SetFinalizer(t, nil)
	}
}
func TaskCreateNamed(t TaskType, name string) (*Task, error) {
	task := TaskCreate(t)
	if task == nil {
		return nil, fmt.Errorf("devicemapper: Can't create task of type %d", int(t))
	}
	if err := task.setName(name); err != nil {
		return nil, fmt.Errorf("devicemapper: Can't set task name %s", name)
	}
	return task, nil
}
func TaskCreate(tasktype TaskType) *Task {
	Ctask := DmTaskCreate(int(tasktype))
	if Ctask == nil {
		return nil
	}
	task := &Task{unmanaged: Ctask}
	runtime.SetFinalizer(task, (*Task).destroy)
	return task
}
func (t *Task) run() error {
	if res := DmTaskRun(t.unmanaged); res != 1 {
		return ErrTaskRun
	}
	runtime.KeepAlive(t)
	return nil
}
func (t *Task) setName(name string) error {
	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
		return ErrTaskSetName
	}
	return nil
}
func (t *Task) setMessage(message string) error {
	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
		return ErrTaskSetMessage
	}
	return nil
}
func (t *Task) setSector(sector uint64) error {
	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
		return ErrTaskSetSector
	}
	return nil
}
func (t *Task) setCookie(cookie *uint, flags uint16) error {
	if cookie == nil {
		return ErrNilCookie
	}
	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
		return ErrTaskSetCookie
	}
	return nil
}
func (t *Task) setAddNode(addNode AddNodeType) error {
	if addNode != addNodeOnResume && addNode != addNodeOnCreate {
		return ErrInvalidAddNode
	}
	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
		return ErrTaskSetAddNode
	}
	return nil
}
func (t *Task) setRo() error {
	if res := DmTaskSetRo(t.unmanaged); res != 1 {
		return ErrTaskSetRo
	}
	return nil
}
func (t *Task) addTarget(start, size uint64, ttype, params string) error {
	if res := DmTaskAddTarget(t.unmanaged, start, size,
		ttype, params); res != 1 {
		return ErrTaskAddTarget
	}
	return nil
}
func (t *Task) getDeps() (*Deps, error) {
	var deps *Deps
	if deps = DmTaskGetDeps(t.unmanaged); deps == nil {
		return nil, ErrTaskGetDeps
	}
	return deps, nil
}
func (t *Task) getInfo() (*Info, error) {
	info := &Info{}
	if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
		return nil, ErrTaskGetInfo
	}
	return info, nil
}
func (t *Task) getInfoWithDeferred() (*Info, error) {
	info := &Info{}
	if res := DmTaskGetInfoWithDeferred(t.unmanaged, info); res != 1 {
		return nil, ErrTaskGetInfo
	}
	return info, nil
}
func (t *Task) getDriverVersion() (string, error) {
	res := DmTaskGetDriverVersion(t.unmanaged)
	if res == "" {
		return "", ErrTaskGetDriverVersion
	}
	return res, nil
}
func (t *Task) getNextTarget(next unsafe.Pointer) (nextPtr unsafe.Pointer, start uint64,
	length uint64, targetType string, params string) {
	return DmGetNextTarget(t.unmanaged, next, &start, &length,
			&targetType, &params),
		start, length, targetType, params
}
func UdevWait(cookie *uint) error {
	if res := DmUdevWait(*cookie); res != 1 {
		logrus.Debugf("devicemapper: Failed to wait on udev cookie %d, %d", *cookie, res)
		return ErrUdevWait
	}
	return nil
}
func SetDevDir(dir string) error {
	if res := DmSetDevDir(dir); res != 1 {
		logrus.Debug("devicemapper: Error dm_set_dev_dir")
		return ErrSetDevDir
	}
	return nil
}
func GetLibraryVersion() (string, error) {
	var version string
	if res := DmGetLibraryVersion(&version); res != 1 {
		return "", ErrGetLibraryVersion
	}
	return version, nil
}
func UdevSyncSupported() bool {
	return DmUdevGetSyncSupport() != 0
}
func UdevSetSyncSupport(enable bool) bool {
	if enable {
		DmUdevSetSyncSupport(1)
	} else {
		DmUdevSetSyncSupport(0)
	}
	return UdevSyncSupported()
}
func CookieSupported() bool {
	return DmCookieSupported() != 0
}
func RemoveDevice(name string) error {
	task, err := TaskCreateNamed(deviceRemove, name)
	if task == nil {
		return err
	}
	cookie := new(uint)
	if err := task.setCookie(cookie, 0); err != nil {
		return fmt.Errorf("devicemapper: Can not set cookie: %s", err)
	}
	defer UdevWait(cookie)
	dmSawBusy = false  
	dmSawEnxio = false
	if err = task.run(); err != nil {
		if dmSawBusy {
			return ErrBusy
		}
		if dmSawEnxio {
			return ErrEnxio
		}
		return fmt.Errorf("devicemapper: Error running RemoveDevice %s", err)
	}
	return nil
}
func RemoveDeviceDeferred(name string) error {
	logrus.Debugf("devicemapper: RemoveDeviceDeferred START(%s)", name)
	defer logrus.Debugf("devicemapper: RemoveDeviceDeferred END(%s)", name)
	task, err := TaskCreateNamed(deviceRemove, name)
	if task == nil {
		return err
	}
	if err := DmTaskDeferredRemove(task.unmanaged); err != 1 {
		return ErrTaskDeferredRemove
	}
	cookie := new(uint)
	var flags uint16
	flags = DmUdevDisableLibraryFallback
	if err := task.setCookie(cookie, flags); err != nil {
		return fmt.Errorf("devicemapper: Can not set cookie: %s", err)
	}
	defer UdevWait(cookie)
	dmSawEnxio = false
	if err = task.run(); err != nil {
		if dmSawEnxio {
			return ErrEnxio
		}
		return fmt.Errorf("devicemapper: Error running RemoveDeviceDeferred %s", err)
	}
	return nil
}
func CancelDeferredRemove(deviceName string) error {
	task, err := TaskCreateNamed(deviceTargetMsg, deviceName)
	if task == nil {
		return err
	}
	if err := task.setSector(0); err != nil {
		return fmt.Errorf("devicemapper: Can't set sector %s", err)
	}
	if err := task.setMessage(fmt.Sprintf("@cancel_deferred_remove")); err != nil {
		return fmt.Errorf("devicemapper: Can't set message %s", err)
	}
	dmSawBusy = false
	dmSawEnxio = false
	if err := task.run(); err != nil {
		if dmSawBusy {
			return ErrBusy
		} else if dmSawEnxio {
			return ErrEnxio
		}
		return fmt.Errorf("devicemapper: Error running CancelDeferredRemove %s", err)
	}
	return nil
}
func GetBlockDeviceSize(file *os.File) (uint64, error) {
	size, err := ioctlBlkGetSize64(file.Fd())
	if err != nil {
		logrus.Errorf("devicemapper: Error getblockdevicesize: %s", err)
		return 0, ErrGetBlockSize
	}
	return uint64(size), nil
}
func BlockDeviceDiscard(path string) error {
	file, err := os.OpenFile(path, os.O_RDWR, 0)
	if err != nil {
		return err
	}
	defer file.Close()
	size, err := GetBlockDeviceSize(file)
	if err != nil {
		return err
	}
	if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil {
		return err
	}
	unix.Sync()
	return nil
}
func CreatePool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
	task, err := TaskCreateNamed(deviceCreate, poolName)
	if task == nil {
		return err
	}
	size, err := GetBlockDeviceSize(dataFile)
	if err != nil {
		return fmt.Errorf("devicemapper: Can't get data size %s", err)
	}
	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
	if err := task.addTarget(0, size/512, "thin-pool", params); err != nil {
		return fmt.Errorf("devicemapper: Can't add target %s", err)
	}
	cookie := new(uint)
	var flags uint16
	flags = DmUdevDisableSubsystemRulesFlag | DmUdevDisableDiskRulesFlag | DmUdevDisableOtherRulesFlag
	if err := task.setCookie(cookie, flags); err != nil {
		return fmt.Errorf("devicemapper: Can't set cookie %s", err)
	}
	defer UdevWait(cookie)
	if err := task.run(); err != nil {
		return fmt.Errorf("devicemapper: Error running deviceCreate (CreatePool) %s", err)
	}
	return nil
}
func ReloadPool(poolName string, dataFile, metadataFile *os.File, poolBlockSize uint32) error {
	task, err := TaskCreateNamed(deviceReload, poolName)
	if task == nil {
		return err
	}
	size, err := GetBlockDeviceSize(dataFile)
	if err != nil {
		return fmt.Errorf("devicemapper: Can't get data size %s", err)
	}
	params := fmt.Sprintf("%s %s %d 32768 1 skip_block_zeroing", metadataFile.Name(), dataFile.Name(), poolBlockSize)
	if err := task.addTarget(0, size/512, "thin-pool", params); err != nil {
		return fmt.Errorf("devicemapper: Can't add target %s", err)
	}
	if err := task.run(); err != nil {
		return fmt.Errorf("devicemapper: Error running ReloadPool %s", err)
	}
	return nil
}
func GetDeps(name string) (*Deps, error) {
	task, err := TaskCreateNamed(deviceDeps, name)
	if task == nil {
		return nil, err
	}
	if err := task.run(); err != nil {
		return nil, err
	}
	return task.getDeps()
}
func GetInfo(name string) (*Info, error) {
	task, err := TaskCreateNamed(deviceInfo, name)
	if task == nil {
		return nil, err
	}
	if err := task.run(); err != nil {
		return nil, err
	}
	return task.getInfo()
}
func GetInfoWithDeferred(name string) (*Info, error) {
	task, err := TaskCreateNamed(deviceInfo, name)
	if task == nil {
		return nil, err
	}
	if err := task.run(); err != nil {
		return nil, err
	}
	return task.getInfoWithDeferred()
}