github.com/openflowlabs/storage@v1.12.13/drivers/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/containers/storage/drivers" 13 "github.com/containers/storage/pkg/devicemapper" 14 "github.com/containers/storage/pkg/idtools" 15 "github.com/containers/storage/pkg/locker" 16 "github.com/containers/storage/pkg/mount" 17 "github.com/containers/storage/pkg/system" 18 units "github.com/docker/go-units" 19 "github.com/sirupsen/logrus" 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 graphdriver.Options) (graphdriver.Driver, error) { 38 deviceSet, err := NewDeviceSet(home, true, options.DriverOptions, options.UIDMaps, options.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: options.UIDMaps, 51 gidMaps: options.GIDMaps, 52 ctr: graphdriver.NewRefCounter(graphdriver.NewDefaultChecker()), 53 locker: locker.New(), 54 } 55 56 return graphdriver.NewNaiveDiffDriver(d, graphdriver.NewNaiveLayerIDMapUpdater(d)), 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", units.HumanSize(float64(s.SectorSize))}, 72 {"Base Device Size", units.HumanSize(float64(s.BaseDeviceSize))}, 73 {"Backing Filesystem", s.BaseDeviceFS}, 74 {"Data file", s.DataFile}, 75 {"Metadata file", s.MetadataFile}, 76 {"Data Space Used", units.HumanSize(float64(s.Data.Used))}, 77 {"Data Space Total", units.HumanSize(float64(s.Data.Total))}, 78 {"Data Space Available", units.HumanSize(float64(s.Data.Available))}, 79 {"Metadata Space Used", units.HumanSize(float64(s.Metadata.Used))}, 80 {"Metadata Space Total", units.HumanSize(float64(s.Metadata.Total))}, 81 {"Metadata Space Available", units.HumanSize(float64(s.Metadata.Available))}, 82 {"Thin Pool Minimum Free Space", 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 // Metadata returns a map of information about the device. 101 func (d *Driver) Metadata(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 // CreateFromTemplate creates a layer with the same contents and parent as another layer. 127 func (d *Driver) CreateFromTemplate(id, template string, templateIDMappings *idtools.IDMappings, parent string, parentIDMappings *idtools.IDMappings, opts *graphdriver.CreateOpts, readWrite bool) error { 128 return d.Create(id, template, opts) 129 } 130 131 // CreateReadWrite creates a layer that is writable for use as a container 132 // file system. 133 func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { 134 return d.Create(id, parent, opts) 135 } 136 137 // Create adds a device with a given id and the parent. 138 func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error { 139 var storageOpt map[string]string 140 if opts != nil { 141 storageOpt = opts.StorageOpt 142 } 143 144 if err := d.DeviceSet.AddDevice(id, parent, storageOpt); err != nil { 145 return err 146 } 147 148 return nil 149 } 150 151 // Remove removes a device with a given id, unmounts the filesystem. 152 func (d *Driver) Remove(id string) error { 153 d.locker.Lock(id) 154 defer d.locker.Unlock(id) 155 if !d.DeviceSet.HasDevice(id) { 156 // Consider removing a non-existing device a no-op 157 // This is useful to be able to progress on container removal 158 // if the underlying device has gone away due to earlier errors 159 return nil 160 } 161 162 // This assumes the device has been properly Get/Put:ed and thus is unmounted 163 if err := d.DeviceSet.DeleteDevice(id, false); err != nil { 164 return fmt.Errorf("failed to remove device %s: %v", id, err) 165 } 166 return system.EnsureRemoveAll(path.Join(d.home, "mnt", id)) 167 } 168 169 // Get mounts a device with given id into the root filesystem 170 func (d *Driver) Get(id string, options graphdriver.MountOpts) (string, error) { 171 d.locker.Lock(id) 172 defer d.locker.Unlock(id) 173 mp := path.Join(d.home, "mnt", id) 174 rootFs := path.Join(mp, "rootfs") 175 if count := d.ctr.Increment(mp); count > 1 { 176 return rootFs, nil 177 } 178 179 uid, gid, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) 180 if err != nil { 181 d.ctr.Decrement(mp) 182 return "", err 183 } 184 185 // Create the target directories if they don't exist 186 if err := idtools.MkdirAllAs(path.Join(d.home, "mnt"), 0755, uid, gid); err != nil && !os.IsExist(err) { 187 d.ctr.Decrement(mp) 188 return "", err 189 } 190 if err := idtools.MkdirAs(mp, 0755, uid, gid); err != nil && !os.IsExist(err) { 191 d.ctr.Decrement(mp) 192 return "", err 193 } 194 195 // Mount the device 196 if err := d.DeviceSet.MountDevice(id, mp, options); err != nil { 197 d.ctr.Decrement(mp) 198 return "", err 199 } 200 201 if err := idtools.MkdirAllAs(rootFs, 0755, uid, gid); err != nil && !os.IsExist(err) { 202 d.ctr.Decrement(mp) 203 d.DeviceSet.UnmountDevice(id, mp) 204 return "", err 205 } 206 207 idFile := path.Join(mp, "id") 208 if _, err := os.Stat(idFile); err != nil && os.IsNotExist(err) { 209 // Create an "id" file with the container/image id in it to help reconstruct this in case 210 // of later problems 211 if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil { 212 d.ctr.Decrement(mp) 213 d.DeviceSet.UnmountDevice(id, mp) 214 return "", err 215 } 216 } 217 218 return rootFs, nil 219 } 220 221 // Put unmounts a device and removes it. 222 func (d *Driver) Put(id string) error { 223 d.locker.Lock(id) 224 defer d.locker.Unlock(id) 225 mp := path.Join(d.home, "mnt", id) 226 if count := d.ctr.Decrement(mp); count > 0 { 227 return nil 228 } 229 err := d.DeviceSet.UnmountDevice(id, mp) 230 if err != nil { 231 logrus.Errorf("devmapper: Error unmounting device %s: %s", id, err) 232 } 233 return err 234 } 235 236 // Exists checks to see if the device exists. 237 func (d *Driver) Exists(id string) bool { 238 return d.DeviceSet.HasDevice(id) 239 } 240 241 // AdditionalImageStores returns additional image stores supported by the driver 242 func (d *Driver) AdditionalImageStores() []string { 243 return nil 244 }