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