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