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