devicemapper: split out devicemapper bindings
This is a first pass at splitting out devicemapper into separate, usable bindings. Signed-off-by: Vincent Batts <vbatts@redhat.com>
This commit is contained in:
parent
bf0a0e9ca7
commit
a5ad3ec0b7
5 changed files with 1158 additions and 0 deletions
129
devicemapper/attach_loopback.go
Normal file
129
devicemapper/attach_loopback.go
Normal file
|
@ -0,0 +1,129 @@
|
|||
// +build linux
|
||||
|
||||
package devicemapper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"syscall"
|
||||
|
||||
log "github.com/Sirupsen/logrus"
|
||||
)
|
||||
|
||||
func stringToLoopName(src string) [LoNameSize]uint8 {
|
||||
var dst [LoNameSize]uint8
|
||||
copy(dst[:], src[:])
|
||||
return dst
|
||||
}
|
||||
|
||||
func getNextFreeLoopbackIndex() (int, error) {
|
||||
f, err := os.OpenFile("/dev/loop-control", os.O_RDONLY, 0644)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
index, err := ioctlLoopCtlGetFree(f.Fd())
|
||||
if index < 0 {
|
||||
index = 0
|
||||
}
|
||||
return index, err
|
||||
}
|
||||
|
||||
func openNextAvailableLoopback(index int, sparseFile *os.File) (loopFile *os.File, err error) {
|
||||
// Start looking for a free /dev/loop
|
||||
for {
|
||||
target := fmt.Sprintf("/dev/loop%d", index)
|
||||
index++
|
||||
|
||||
fi, err := os.Stat(target)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
log.Errorf("There are no more loopback devices available.")
|
||||
}
|
||||
return nil, ErrAttachLoopbackDevice
|
||||
}
|
||||
|
||||
if fi.Mode()&os.ModeDevice != os.ModeDevice {
|
||||
log.Errorf("Loopback device %s is not a block device.", target)
|
||||
continue
|
||||
}
|
||||
|
||||
// OpenFile adds O_CLOEXEC
|
||||
loopFile, err = os.OpenFile(target, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
log.Errorf("Error opening loopback device: %s", err)
|
||||
return nil, ErrAttachLoopbackDevice
|
||||
}
|
||||
|
||||
// Try to attach to the loop file
|
||||
if err := ioctlLoopSetFd(loopFile.Fd(), sparseFile.Fd()); err != nil {
|
||||
loopFile.Close()
|
||||
|
||||
// If the error is EBUSY, then try the next loopback
|
||||
if err != syscall.EBUSY {
|
||||
log.Errorf("Cannot set up loopback device %s: %s", target, err)
|
||||
return nil, ErrAttachLoopbackDevice
|
||||
}
|
||||
|
||||
// Otherwise, we keep going with the loop
|
||||
continue
|
||||
}
|
||||
// In case of success, we finished. Break the loop.
|
||||
break
|
||||
}
|
||||
|
||||
// This can't happen, but let's be sure
|
||||
if loopFile == nil {
|
||||
log.Errorf("Unreachable code reached! Error attaching %s to a loopback device.", sparseFile.Name())
|
||||
return nil, ErrAttachLoopbackDevice
|
||||
}
|
||||
|
||||
return loopFile, nil
|
||||
}
|
||||
|
||||
// attachLoopDevice attaches the given sparse file to the next
|
||||
// available loopback device. It returns an opened *os.File.
|
||||
func AttachLoopDevice(sparseName string) (loop *os.File, err error) {
|
||||
|
||||
// Try to retrieve the next available loopback device via syscall.
|
||||
// If it fails, we discard error and start loopking for a
|
||||
// loopback from index 0.
|
||||
startIndex, err := getNextFreeLoopbackIndex()
|
||||
if err != nil {
|
||||
log.Debugf("Error retrieving the next available loopback: %s", err)
|
||||
}
|
||||
|
||||
// OpenFile adds O_CLOEXEC
|
||||
sparseFile, err := os.OpenFile(sparseName, os.O_RDWR, 0644)
|
||||
if err != nil {
|
||||
log.Errorf("Error opening sparse file %s: %s", sparseName, err)
|
||||
return nil, ErrAttachLoopbackDevice
|
||||
}
|
||||
defer sparseFile.Close()
|
||||
|
||||
loopFile, err := openNextAvailableLoopback(startIndex, sparseFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Set the status of the loopback device
|
||||
loopInfo := &LoopInfo64{
|
||||
loFileName: stringToLoopName(loopFile.Name()),
|
||||
loOffset: 0,
|
||||
loFlags: LoFlagsAutoClear,
|
||||
}
|
||||
|
||||
if err := ioctlLoopSetStatus64(loopFile.Fd(), loopInfo); err != nil {
|
||||
log.Errorf("Cannot set up loopback device info: %s", err)
|
||||
|
||||
// If the call failed, then free the loopback device
|
||||
if err := ioctlLoopClrFd(loopFile.Fd()); err != nil {
|
||||
log.Errorf("Error while cleaning up the loopback device")
|
||||
}
|
||||
loopFile.Close()
|
||||
return nil, ErrAttachLoopbackDevice
|
||||
}
|
||||
|
||||
return loopFile, nil
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue