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