github.com/amylindburg/docker@v1.7.0/daemon/graphdriver/devmapper/driver.go (about) 1 // +build linux 2 3 package devmapper 4 5 import ( 6 "fmt" 7 "io/ioutil" 8 "os" 9 "path" 10 11 "github.com/Sirupsen/logrus" 12 "github.com/docker/docker/daemon/graphdriver" 13 "github.com/docker/docker/pkg/devicemapper" 14 "github.com/docker/docker/pkg/mount" 15 "github.com/docker/docker/pkg/units" 16 ) 17 18 func init() { 19 graphdriver.Register("devicemapper", Init) 20 } 21 22 // Placeholder interfaces, to be replaced 23 // at integration. 24 25 // End of placeholder interfaces. 26 27 type Driver struct { 28 *DeviceSet 29 home string 30 } 31 32 var backingFs = "<unknown>" 33 34 func Init(home string, options []string) (graphdriver.Driver, error) { 35 fsMagic, err := graphdriver.GetFSMagic(home) 36 if err != nil { 37 return nil, err 38 } 39 if fsName, ok := graphdriver.FsNames[fsMagic]; ok { 40 backingFs = fsName 41 } 42 43 deviceSet, err := NewDeviceSet(home, true, options) 44 if err != nil { 45 return nil, err 46 } 47 48 if err := mount.MakePrivate(home); err != nil { 49 return nil, err 50 } 51 52 d := &Driver{ 53 DeviceSet: deviceSet, 54 home: home, 55 } 56 57 return graphdriver.NaiveDiffDriver(d), nil 58 } 59 60 func (d *Driver) String() string { 61 return "devicemapper" 62 } 63 64 func (d *Driver) Status() [][2]string { 65 s := d.DeviceSet.Status() 66 67 status := [][2]string{ 68 {"Pool Name", s.PoolName}, 69 {"Pool Blocksize", fmt.Sprintf("%s", units.HumanSize(float64(s.SectorSize)))}, 70 {"Backing Filesystem", backingFs}, 71 {"Data file", s.DataFile}, 72 {"Metadata file", s.MetadataFile}, 73 {"Data Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Used)))}, 74 {"Data Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Total)))}, 75 {"Data Space Available", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Available)))}, 76 {"Metadata Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Used)))}, 77 {"Metadata Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Total)))}, 78 {"Metadata Space Available", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Available)))}, 79 {"Udev Sync Supported", fmt.Sprintf("%v", s.UdevSyncSupported)}, 80 {"Deferred Removal Enabled", fmt.Sprintf("%v", s.DeferredRemoveEnabled)}, 81 } 82 if len(s.DataLoopback) > 0 { 83 status = append(status, [2]string{"Data loop file", s.DataLoopback}) 84 } 85 if len(s.MetadataLoopback) > 0 { 86 status = append(status, [2]string{"Metadata loop file", s.MetadataLoopback}) 87 } 88 if vStr, err := devicemapper.GetLibraryVersion(); err == nil { 89 status = append(status, [2]string{"Library Version", vStr}) 90 } 91 return status 92 } 93 94 func (d *Driver) Cleanup() error { 95 err := d.DeviceSet.Shutdown() 96 97 if err2 := mount.Unmount(d.home); err == nil { 98 err = err2 99 } 100 101 return err 102 } 103 104 func (d *Driver) Create(id, parent string) error { 105 if err := d.DeviceSet.AddDevice(id, parent); err != nil { 106 return err 107 } 108 109 return nil 110 } 111 112 func (d *Driver) Remove(id string) error { 113 if !d.DeviceSet.HasDevice(id) { 114 // Consider removing a non-existing device a no-op 115 // This is useful to be able to progress on container removal 116 // if the underlying device has gone away due to earlier errors 117 return nil 118 } 119 120 // This assumes the device has been properly Get/Put:ed and thus is unmounted 121 if err := d.DeviceSet.DeleteDevice(id); err != nil { 122 return err 123 } 124 125 mp := path.Join(d.home, "mnt", id) 126 if err := os.RemoveAll(mp); err != nil && !os.IsNotExist(err) { 127 return err 128 } 129 130 return nil 131 } 132 133 func (d *Driver) Get(id, mountLabel string) (string, error) { 134 mp := path.Join(d.home, "mnt", id) 135 136 // Create the target directories if they don't exist 137 if err := os.MkdirAll(mp, 0755); err != nil && !os.IsExist(err) { 138 return "", err 139 } 140 141 // Mount the device 142 if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil { 143 return "", err 144 } 145 146 rootFs := path.Join(mp, "rootfs") 147 if err := os.MkdirAll(rootFs, 0755); err != nil && !os.IsExist(err) { 148 d.DeviceSet.UnmountDevice(id) 149 return "", err 150 } 151 152 idFile := path.Join(mp, "id") 153 if _, err := os.Stat(idFile); err != nil && os.IsNotExist(err) { 154 // Create an "id" file with the container/image id in it to help reconscruct this in case 155 // of later problems 156 if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil { 157 d.DeviceSet.UnmountDevice(id) 158 return "", err 159 } 160 } 161 162 return rootFs, nil 163 } 164 165 func (d *Driver) Put(id string) error { 166 err := d.DeviceSet.UnmountDevice(id) 167 if err != nil { 168 logrus.Errorf("Error unmounting device %s: %s", id, err) 169 } 170 return err 171 } 172 173 func (d *Driver) Exists(id string) bool { 174 return d.DeviceSet.HasDevice(id) 175 }