Merge pull request #12190 from rhvgoyal/deferred-removal

Devicemapper: Provide deferred device removal capability
This commit is contained in:
Vincent Batts 2015-05-04 14:22:52 -07:00
commit 1bf233b404
5 changed files with 157 additions and 32 deletions

View file

@ -55,6 +55,7 @@ var (
ErrTaskGetDeps = errors.New("dm_task_get_deps failed") ErrTaskGetDeps = errors.New("dm_task_get_deps failed")
ErrTaskGetInfo = errors.New("dm_task_get_info failed") ErrTaskGetInfo = errors.New("dm_task_get_info failed")
ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version 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") ErrTaskSetCookie = errors.New("dm_task_set_cookie failed")
ErrNilCookie = errors.New("cookie ptr can't be nil") ErrNilCookie = errors.New("cookie ptr can't be nil")
ErrAttachLoopbackDevice = errors.New("loopback mounting failed") ErrAttachLoopbackDevice = errors.New("loopback mounting failed")
@ -69,9 +70,11 @@ var (
ErrLoopbackSetCapacity = errors.New("Unable set loopback capacity") ErrLoopbackSetCapacity = errors.New("Unable set loopback capacity")
ErrBusy = errors.New("Device is Busy") ErrBusy = errors.New("Device is Busy")
ErrDeviceIdExists = errors.New("Device Id Exists") ErrDeviceIdExists = errors.New("Device Id Exists")
ErrEnxio = errors.New("No such device or address")
dmSawBusy bool dmSawBusy bool
dmSawExist bool dmSawExist bool
dmSawEnxio bool // No Such Device or Address
) )
type ( type (
@ -84,16 +87,17 @@ type (
Device []uint64 Device []uint64
} }
Info struct { Info struct {
Exists int Exists int
Suspended int Suspended int
LiveTable int LiveTable int
InactiveTable int InactiveTable int
OpenCount int32 OpenCount int32
EventNr uint32 EventNr uint32
Major uint32 Major uint32
Minor uint32 Minor uint32
ReadOnly int ReadOnly int
TargetCount int32 TargetCount int32
DeferredRemove int
} }
TaskType int TaskType int
AddNodeType int AddNodeType int
@ -219,6 +223,14 @@ func (t *Task) GetInfo() (*Info, error) {
return info, nil 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) { func (t *Task) GetDriverVersion() (string, error) {
res := DmTaskGetDriverVersion(t.unmanaged) res := DmTaskGetDriverVersion(t.unmanaged)
if res == "" { if res == "" {
@ -371,6 +383,55 @@ func RemoveDevice(name string) error {
return nil return nil
} }
func RemoveDeviceDeferred(name string) error {
logrus.Debugf("[devmapper] RemoveDeviceDeferred START(%s)", name)
defer logrus.Debugf("[devmapper] RemoveDeviceDeferred END(%s)", name)
task, err := TaskCreateNamed(DeviceRemove, name)
if task == nil {
return err
}
if err := DmTaskDeferredRemove(task.unmanaged); err != 1 {
return ErrTaskDeferredRemove
}
if err = task.Run(); err != nil {
return fmt.Errorf("Error running RemoveDeviceDeferred %s", err)
}
return nil
}
// Useful helper for cleanup
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("Can't set sector %s", err)
}
if err := task.SetMessage(fmt.Sprintf("@cancel_deferred_remove")); err != nil {
return fmt.Errorf("Can't set message %s", err)
}
dmSawBusy = false
dmSawEnxio = false
if err := task.Run(); err != nil {
// A device might be being deleted already
if dmSawBusy {
return ErrBusy
} else if dmSawEnxio {
return ErrEnxio
}
return fmt.Errorf("Error running CancelDeferredRemove %s", err)
}
return nil
}
func GetBlockDeviceSize(file *os.File) (uint64, error) { func GetBlockDeviceSize(file *os.File) (uint64, error) {
size, err := ioctlBlkGetSize64(file.Fd()) size, err := ioctlBlkGetSize64(file.Fd())
if err != nil { if err != nil {
@ -479,6 +540,17 @@ func GetInfo(name string) (*Info, error) {
return task.GetInfo() 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()
}
func GetDriverVersion() (string, error) { func GetDriverVersion() (string, error) {
task := TaskCreate(DeviceVersion) task := TaskCreate(DeviceVersion)
if task == nil { if task == nil {

View file

@ -22,6 +22,10 @@ func DevmapperLogCallback(level C.int, file *C.char, line C.int, dm_errno_or_cla
if strings.Contains(msg, "File exists") { if strings.Contains(msg, "File exists") {
dmSawExist = true dmSawExist = true
} }
if strings.Contains(msg, "No such device or address") {
dmSawEnxio = true
}
} }
if dmLogger != nil { if dmLogger != nil {

View file

@ -90,28 +90,30 @@ const (
) )
var ( var (
DmGetLibraryVersion = dmGetLibraryVersionFct DmGetLibraryVersion = dmGetLibraryVersionFct
DmGetNextTarget = dmGetNextTargetFct DmGetNextTarget = dmGetNextTargetFct
DmLogInitVerbose = dmLogInitVerboseFct DmLogInitVerbose = dmLogInitVerboseFct
DmSetDevDir = dmSetDevDirFct DmSetDevDir = dmSetDevDirFct
DmTaskAddTarget = dmTaskAddTargetFct DmTaskAddTarget = dmTaskAddTargetFct
DmTaskCreate = dmTaskCreateFct DmTaskCreate = dmTaskCreateFct
DmTaskDestroy = dmTaskDestroyFct DmTaskDestroy = dmTaskDestroyFct
DmTaskGetDeps = dmTaskGetDepsFct DmTaskGetDeps = dmTaskGetDepsFct
DmTaskGetInfo = dmTaskGetInfoFct DmTaskGetInfo = dmTaskGetInfoFct
DmTaskGetDriverVersion = dmTaskGetDriverVersionFct DmTaskGetDriverVersion = dmTaskGetDriverVersionFct
DmTaskRun = dmTaskRunFct DmTaskRun = dmTaskRunFct
DmTaskSetAddNode = dmTaskSetAddNodeFct DmTaskSetAddNode = dmTaskSetAddNodeFct
DmTaskSetCookie = dmTaskSetCookieFct DmTaskSetCookie = dmTaskSetCookieFct
DmTaskSetMessage = dmTaskSetMessageFct DmTaskSetMessage = dmTaskSetMessageFct
DmTaskSetName = dmTaskSetNameFct DmTaskSetName = dmTaskSetNameFct
DmTaskSetRo = dmTaskSetRoFct DmTaskSetRo = dmTaskSetRoFct
DmTaskSetSector = dmTaskSetSectorFct DmTaskSetSector = dmTaskSetSectorFct
DmUdevWait = dmUdevWaitFct DmUdevWait = dmUdevWaitFct
DmUdevSetSyncSupport = dmUdevSetSyncSupportFct DmUdevSetSyncSupport = dmUdevSetSyncSupportFct
DmUdevGetSyncSupport = dmUdevGetSyncSupportFct DmUdevGetSyncSupport = dmUdevGetSyncSupportFct
DmCookieSupported = dmCookieSupportedFct DmCookieSupported = dmCookieSupportedFct
LogWithErrnoInit = logWithErrnoInitFct LogWithErrnoInit = logWithErrnoInitFct
DmTaskDeferredRemove = dmTaskDeferredRemoveFct
DmTaskGetInfoWithDeferred = dmTaskGetInfoWithDeferredFct
) )
func free(p *C.char) { func free(p *C.char) {

View file

@ -0,0 +1,33 @@
// +build linux,!libdm_no_deferred_remove
package devicemapper
/*
#cgo LDFLAGS: -L. -ldevmapper
#include <libdevmapper.h>
*/
import "C"
const LibraryDeferredRemovalSupport = true
func dmTaskDeferredRemoveFct(task *CDmTask) int {
return int(C.dm_task_deferred_remove((*C.struct_dm_task)(task)))
}
func dmTaskGetInfoWithDeferredFct(task *CDmTask, info *Info) int {
Cinfo := C.struct_dm_info{}
defer func() {
info.Exists = int(Cinfo.exists)
info.Suspended = int(Cinfo.suspended)
info.LiveTable = int(Cinfo.live_table)
info.InactiveTable = int(Cinfo.inactive_table)
info.OpenCount = int32(Cinfo.open_count)
info.EventNr = uint32(Cinfo.event_nr)
info.Major = uint32(Cinfo.major)
info.Minor = uint32(Cinfo.minor)
info.ReadOnly = int(Cinfo.read_only)
info.TargetCount = int32(Cinfo.target_count)
info.DeferredRemove = int(Cinfo.deferred_remove)
}()
return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
}

View file

@ -0,0 +1,14 @@
// +build linux,libdm_no_deferred_remove
package devicemapper
const LibraryDeferredRemovalSupport = false
func dmTaskDeferredRemoveFct(task *CDmTask) int {
// Error. Nobody should be calling it.
return -1
}
func dmTaskGetInfoWithDeferredFct(task *CDmTask, info *Info) int {
return -1
}