loopback.go 1.5 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. // +build linux,cgo
  2. package loopback // import "github.com/docker/docker/pkg/loopback"
  3. import (
  4. "fmt"
  5. "os"
  6. "github.com/sirupsen/logrus"
  7. "golang.org/x/sys/unix"
  8. )
  9. func getLoopbackBackingFile(file *os.File) (uint64, uint64, error) {
  10. loopInfo, err := ioctlLoopGetStatus64(file.Fd())
  11. if err != nil {
  12. logrus.Errorf("Error get loopback backing file: %s", err)
  13. return 0, 0, ErrGetLoopbackBackingFile
  14. }
  15. return loopInfo.loDevice, loopInfo.loInode, nil
  16. }
  17. // SetCapacity reloads the size for the loopback device.
  18. func SetCapacity(file *os.File) error {
  19. if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
  20. logrus.Errorf("Error loopbackSetCapacity: %s", err)
  21. return ErrSetCapacity
  22. }
  23. return nil
  24. }
  25. // FindLoopDeviceFor returns a loopback device file for the specified file which
  26. // is backing file of a loop back device.
  27. func FindLoopDeviceFor(file *os.File) *os.File {
  28. var stat unix.Stat_t
  29. err := unix.Stat(file.Name(), &stat)
  30. if err != nil {
  31. return nil
  32. }
  33. targetInode := stat.Ino
  34. // the type is 32bit on mips
  35. targetDevice := uint64(stat.Dev) // nolint: unconvert
  36. for i := 0; true; i++ {
  37. path := fmt.Sprintf("/dev/loop%d", i)
  38. file, err := os.OpenFile(path, os.O_RDWR, 0)
  39. if err != nil {
  40. if os.IsNotExist(err) {
  41. return nil
  42. }
  43. // Ignore all errors until the first not-exist
  44. // we want to continue looking for the file
  45. continue
  46. }
  47. dev, inode, err := getLoopbackBackingFile(file)
  48. if err == nil && dev == targetDevice && inode == targetInode {
  49. return file
  50. }
  51. file.Close()
  52. }
  53. return nil
  54. }