github.com/mheon/docker@v0.11.2-0.20150922122814-44f47903a831/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 "github.com/docker/docker/daemon/graphdriver" 14 "github.com/docker/docker/pkg/devicemapper" 15 "github.com/docker/docker/pkg/mount" 16 "github.com/docker/docker/pkg/units" 17 ) 18 19 func init() { 20 graphdriver.Register("devicemapper", Init) 21 } 22 23 // Placeholder interfaces, to be replaced 24 // at integration. 25 26 // End of placeholder interfaces. 27 28 // Driver contains the device set mounted and the home directory 29 type Driver struct { 30 *DeviceSet 31 home string 32 } 33 34 var backingFs = "<unknown>" 35 36 // Init creates a driver with the given home and the set of options. 37 func Init(home string, options []string) (graphdriver.Driver, error) { 38 fsMagic, err := graphdriver.GetFSMagic(home) 39 if err != nil { 40 return nil, err 41 } 42 if fsName, ok := graphdriver.FsNames[fsMagic]; ok { 43 backingFs = fsName 44 } 45 46 deviceSet, err := NewDeviceSet(home, true, options) 47 if err != nil { 48 return nil, err 49 } 50 51 if err := mount.MakePrivate(home); err != nil { 52 return nil, err 53 } 54 55 d := &Driver{ 56 DeviceSet: deviceSet, 57 home: home, 58 } 59 60 return graphdriver.NaiveDiffDriver(d), nil 61 } 62 63 func (d *Driver) String() string { 64 return "devicemapper" 65 } 66 67 // Status returns the status about the driver in a printable format. 68 // Information returned contains Pool Name, Data File, Metadata file, disk usage by 69 // the data and metadata, etc. 70 func (d *Driver) Status() [][2]string { 71 s := d.DeviceSet.Status() 72 73 status := [][2]string{ 74 {"Pool Name", s.PoolName}, 75 {"Pool Blocksize", fmt.Sprintf("%s", units.HumanSize(float64(s.SectorSize)))}, 76 {"Backing Filesystem", backingFs}, 77 {"Data file", s.DataFile}, 78 {"Metadata file", s.MetadataFile}, 79 {"Data Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Used)))}, 80 {"Data Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Total)))}, 81 {"Data Space Available", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Available)))}, 82 {"Metadata Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Used)))}, 83 {"Metadata Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Total)))}, 84 {"Metadata Space Available", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Available)))}, 85 {"Udev Sync Supported", fmt.Sprintf("%v", s.UdevSyncSupported)}, 86 {"Deferred Removal Enabled", fmt.Sprintf("%v", s.DeferredRemoveEnabled)}, 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() 118 119 if err2 := mount.Unmount(d.home); err == nil { 120 err = err2 121 } 122 123 return err 124 } 125 126 // Create adds a device with a given id and the parent. 127 func (d *Driver) Create(id, parent string) error { 128 if err := d.DeviceSet.AddDevice(id, parent); err != nil { 129 return err 130 } 131 132 return nil 133 } 134 135 // Remove removes a device with a given id, unmounts the filesystem. 136 func (d *Driver) Remove(id string) error { 137 if !d.DeviceSet.HasDevice(id) { 138 // Consider removing a non-existing device a no-op 139 // This is useful to be able to progress on container removal 140 // if the underlying device has gone away due to earlier errors 141 return nil 142 } 143 144 // This assumes the device has been properly Get/Put:ed and thus is unmounted 145 if err := d.DeviceSet.DeleteDevice(id); err != nil { 146 return err 147 } 148 149 mp := path.Join(d.home, "mnt", id) 150 if err := os.RemoveAll(mp); err != nil && !os.IsNotExist(err) { 151 return err 152 } 153 154 return nil 155 } 156 157 // Get mounts a device with given id into the root filesystem 158 func (d *Driver) Get(id, mountLabel string) (string, error) { 159 mp := path.Join(d.home, "mnt", id) 160 161 // Create the target directories if they don't exist 162 if err := os.MkdirAll(mp, 0755); err != nil { 163 return "", err 164 } 165 166 // Mount the device 167 if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil { 168 return "", err 169 } 170 171 rootFs := path.Join(mp, "rootfs") 172 if err := os.MkdirAll(rootFs, 0755); err != nil { 173 d.DeviceSet.UnmountDevice(id) 174 return "", err 175 } 176 177 idFile := path.Join(mp, "id") 178 if _, err := os.Stat(idFile); err != nil && os.IsNotExist(err) { 179 // Create an "id" file with the container/image id in it to help reconscruct this in case 180 // of later problems 181 if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil { 182 d.DeviceSet.UnmountDevice(id) 183 return "", err 184 } 185 } 186 187 return rootFs, nil 188 } 189 190 // Put unmounts a device and removes it. 191 func (d *Driver) Put(id string) error { 192 err := d.DeviceSet.UnmountDevice(id) 193 if err != nil { 194 logrus.Errorf("Error unmounting device %s: %s", id, err) 195 } 196 return err 197 } 198 199 // Exists checks to see if the device is mounted. 200 func (d *Driver) Exists(id string) bool { 201 return d.DeviceSet.HasDevice(id) 202 }