github.com/ojongerius/docker@v1.11.2/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 "strconv" 11 12 "github.com/Sirupsen/logrus" 13 14 "github.com/docker/docker/daemon/graphdriver" 15 "github.com/docker/docker/pkg/devicemapper" 16 "github.com/docker/docker/pkg/idtools" 17 "github.com/docker/docker/pkg/mount" 18 "github.com/docker/go-units" 19 ) 20 21 func init() { 22 graphdriver.Register("devicemapper", Init) 23 } 24 25 // Driver contains the device set mounted and the home directory 26 type Driver struct { 27 *DeviceSet 28 home string 29 uidMaps []idtools.IDMap 30 gidMaps []idtools.IDMap 31 ctr *graphdriver.RefCounter 32 } 33 34 // Init creates a driver with the given home and the set of options. 35 func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { 36 deviceSet, err := NewDeviceSet(home, true, options, uidMaps, gidMaps) 37 if err != nil { 38 return nil, err 39 } 40 41 if err := mount.MakePrivate(home); err != nil { 42 return nil, err 43 } 44 45 d := &Driver{ 46 DeviceSet: deviceSet, 47 home: home, 48 uidMaps: uidMaps, 49 gidMaps: gidMaps, 50 ctr: graphdriver.NewRefCounter(), 51 } 52 53 return graphdriver.NewNaiveDiffDriver(d, uidMaps, gidMaps), nil 54 } 55 56 func (d *Driver) String() string { 57 return "devicemapper" 58 } 59 60 // Status returns the status about the driver in a printable format. 61 // Information returned contains Pool Name, Data File, Metadata file, disk usage by 62 // the data and metadata, etc. 63 func (d *Driver) Status() [][2]string { 64 s := d.DeviceSet.Status() 65 66 status := [][2]string{ 67 {"Pool Name", s.PoolName}, 68 {"Pool Blocksize", fmt.Sprintf("%s", units.HumanSize(float64(s.SectorSize)))}, 69 {"Base Device Size", fmt.Sprintf("%s", units.HumanSize(float64(s.BaseDeviceSize)))}, 70 {"Backing Filesystem", s.BaseDeviceFS}, 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 {"Deferred Deletion Enabled", fmt.Sprintf("%v", s.DeferredDeleteEnabled)}, 82 {"Deferred Deleted Device Count", fmt.Sprintf("%v", s.DeferredDeletedDeviceCount)}, 83 } 84 if len(s.DataLoopback) > 0 { 85 status = append(status, [2]string{"Data loop file", s.DataLoopback}) 86 } 87 if len(s.MetadataLoopback) > 0 { 88 status = append(status, [2]string{"Metadata loop file", s.MetadataLoopback}) 89 } 90 if vStr, err := devicemapper.GetLibraryVersion(); err == nil { 91 status = append(status, [2]string{"Library Version", vStr}) 92 } 93 return status 94 } 95 96 // GetMetadata returns a map of information about the device. 97 func (d *Driver) GetMetadata(id string) (map[string]string, error) { 98 m, err := d.DeviceSet.exportDeviceMetadata(id) 99 100 if err != nil { 101 return nil, err 102 } 103 104 metadata := make(map[string]string) 105 metadata["DeviceId"] = strconv.Itoa(m.deviceID) 106 metadata["DeviceSize"] = strconv.FormatUint(m.deviceSize, 10) 107 metadata["DeviceName"] = m.deviceName 108 return metadata, nil 109 } 110 111 // Cleanup unmounts a device. 112 func (d *Driver) Cleanup() error { 113 err := d.DeviceSet.Shutdown(d.home) 114 115 if err2 := mount.Unmount(d.home); err == nil { 116 err = err2 117 } 118 119 return err 120 } 121 122 // Create adds a device with a given id and the parent. 123 func (d *Driver) Create(id, parent, mountLabel string) error { 124 if err := d.DeviceSet.AddDevice(id, parent); err != nil { 125 return err 126 } 127 128 return nil 129 } 130 131 // Remove removes a device with a given id, unmounts the filesystem. 132 func (d *Driver) Remove(id string) error { 133 if !d.DeviceSet.HasDevice(id) { 134 // Consider removing a non-existing device a no-op 135 // This is useful to be able to progress on container removal 136 // if the underlying device has gone away due to earlier errors 137 return nil 138 } 139 140 // This assumes the device has been properly Get/Put:ed and thus is unmounted 141 if err := d.DeviceSet.DeleteDevice(id, false); err != nil { 142 return err 143 } 144 145 mp := path.Join(d.home, "mnt", id) 146 if err := os.RemoveAll(mp); err != nil && !os.IsNotExist(err) { 147 return err 148 } 149 150 return nil 151 } 152 153 // Get mounts a device with given id into the root filesystem 154 func (d *Driver) Get(id, mountLabel string) (string, error) { 155 mp := path.Join(d.home, "mnt", id) 156 rootFs := path.Join(mp, "rootfs") 157 if count := d.ctr.Increment(id); count > 1 { 158 return rootFs, nil 159 } 160 161 uid, gid, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) 162 if err != nil { 163 d.ctr.Decrement(id) 164 return "", err 165 } 166 167 // Create the target directories if they don't exist 168 if err := idtools.MkdirAllAs(path.Join(d.home, "mnt"), 0755, uid, gid); err != nil && !os.IsExist(err) { 169 d.ctr.Decrement(id) 170 return "", err 171 } 172 if err := idtools.MkdirAs(mp, 0755, uid, gid); err != nil && !os.IsExist(err) { 173 d.ctr.Decrement(id) 174 return "", err 175 } 176 177 // Mount the device 178 if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil { 179 d.ctr.Decrement(id) 180 return "", err 181 } 182 183 if err := idtools.MkdirAllAs(rootFs, 0755, uid, gid); err != nil && !os.IsExist(err) { 184 d.ctr.Decrement(id) 185 d.DeviceSet.UnmountDevice(id, mp) 186 return "", err 187 } 188 189 idFile := path.Join(mp, "id") 190 if _, err := os.Stat(idFile); err != nil && os.IsNotExist(err) { 191 // Create an "id" file with the container/image id in it to help reconstruct this in case 192 // of later problems 193 if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil { 194 d.ctr.Decrement(id) 195 d.DeviceSet.UnmountDevice(id, mp) 196 return "", err 197 } 198 } 199 200 return rootFs, nil 201 } 202 203 // Put unmounts a device and removes it. 204 func (d *Driver) Put(id string) error { 205 if count := d.ctr.Decrement(id); count > 0 { 206 return nil 207 } 208 mp := path.Join(d.home, "mnt", id) 209 err := d.DeviceSet.UnmountDevice(id, mp) 210 if err != nil { 211 logrus.Errorf("devmapper: Error unmounting device %s: %s", id, err) 212 } 213 return err 214 } 215 216 // Exists checks to see if the device exists. 217 func (d *Driver) Exists(id string) bool { 218 return d.DeviceSet.HasDevice(id) 219 }