github.com/gunjan5/docker@v1.8.2/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 type Driver struct { 29 *DeviceSet 30 home string 31 } 32 33 var backingFs = "<unknown>" 34 35 func Init(home string, options []string) (graphdriver.Driver, error) { 36 fsMagic, err := graphdriver.GetFSMagic(home) 37 if err != nil { 38 return nil, err 39 } 40 if fsName, ok := graphdriver.FsNames[fsMagic]; ok { 41 backingFs = fsName 42 } 43 44 deviceSet, err := NewDeviceSet(home, true, options) 45 if err != nil { 46 return nil, err 47 } 48 49 if err := mount.MakePrivate(home); err != nil { 50 return nil, err 51 } 52 53 d := &Driver{ 54 DeviceSet: deviceSet, 55 home: home, 56 } 57 58 return graphdriver.NaiveDiffDriver(d), nil 59 } 60 61 func (d *Driver) String() string { 62 return "devicemapper" 63 } 64 65 func (d *Driver) Status() [][2]string { 66 s := d.DeviceSet.Status() 67 68 status := [][2]string{ 69 {"Pool Name", s.PoolName}, 70 {"Pool Blocksize", fmt.Sprintf("%s", units.HumanSize(float64(s.SectorSize)))}, 71 {"Backing Filesystem", backingFs}, 72 {"Data file", s.DataFile}, 73 {"Metadata file", s.MetadataFile}, 74 {"Data Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Used)))}, 75 {"Data Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Total)))}, 76 {"Data Space Available", fmt.Sprintf("%s", units.HumanSize(float64(s.Data.Available)))}, 77 {"Metadata Space Used", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Used)))}, 78 {"Metadata Space Total", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Total)))}, 79 {"Metadata Space Available", fmt.Sprintf("%s", units.HumanSize(float64(s.Metadata.Available)))}, 80 {"Udev Sync Supported", fmt.Sprintf("%v", s.UdevSyncSupported)}, 81 {"Deferred Removal Enabled", fmt.Sprintf("%v", s.DeferredRemoveEnabled)}, 82 } 83 if len(s.DataLoopback) > 0 { 84 status = append(status, [2]string{"Data loop file", s.DataLoopback}) 85 } 86 if len(s.MetadataLoopback) > 0 { 87 status = append(status, [2]string{"Metadata loop file", s.MetadataLoopback}) 88 } 89 if vStr, err := devicemapper.GetLibraryVersion(); err == nil { 90 status = append(status, [2]string{"Library Version", vStr}) 91 } 92 return status 93 } 94 95 func (d *Driver) GetMetadata(id string) (map[string]string, error) { 96 m, err := d.DeviceSet.ExportDeviceMetadata(id) 97 98 if err != nil { 99 return nil, err 100 } 101 102 metadata := make(map[string]string) 103 metadata["DeviceId"] = strconv.Itoa(m.deviceId) 104 metadata["DeviceSize"] = strconv.FormatUint(m.deviceSize, 10) 105 metadata["DeviceName"] = m.deviceName 106 return metadata, nil 107 } 108 109 func (d *Driver) Cleanup() error { 110 err := d.DeviceSet.Shutdown() 111 112 if err2 := mount.Unmount(d.home); err == nil { 113 err = err2 114 } 115 116 return err 117 } 118 119 func (d *Driver) Create(id, parent string) error { 120 if err := d.DeviceSet.AddDevice(id, parent); err != nil { 121 return err 122 } 123 124 return nil 125 } 126 127 func (d *Driver) Remove(id string) error { 128 if !d.DeviceSet.HasDevice(id) { 129 // Consider removing a non-existing device a no-op 130 // This is useful to be able to progress on container removal 131 // if the underlying device has gone away due to earlier errors 132 return nil 133 } 134 135 // This assumes the device has been properly Get/Put:ed and thus is unmounted 136 if err := d.DeviceSet.DeleteDevice(id); err != nil { 137 return err 138 } 139 140 mp := path.Join(d.home, "mnt", id) 141 if err := os.RemoveAll(mp); err != nil && !os.IsNotExist(err) { 142 return err 143 } 144 145 return nil 146 } 147 148 func (d *Driver) Get(id, mountLabel string) (string, error) { 149 mp := path.Join(d.home, "mnt", id) 150 151 // Create the target directories if they don't exist 152 if err := os.MkdirAll(mp, 0755); err != nil && !os.IsExist(err) { 153 return "", err 154 } 155 156 // Mount the device 157 if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil { 158 return "", err 159 } 160 161 rootFs := path.Join(mp, "rootfs") 162 if err := os.MkdirAll(rootFs, 0755); err != nil && !os.IsExist(err) { 163 d.DeviceSet.UnmountDevice(id) 164 return "", err 165 } 166 167 idFile := path.Join(mp, "id") 168 if _, err := os.Stat(idFile); err != nil && os.IsNotExist(err) { 169 // Create an "id" file with the container/image id in it to help reconscruct this in case 170 // of later problems 171 if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil { 172 d.DeviceSet.UnmountDevice(id) 173 return "", err 174 } 175 } 176 177 return rootFs, nil 178 } 179 180 func (d *Driver) Put(id string) error { 181 err := d.DeviceSet.UnmountDevice(id) 182 if err != nil { 183 logrus.Errorf("Error unmounting device %s: %s", id, err) 184 } 185 return err 186 } 187 188 func (d *Driver) Exists(id string) bool { 189 return d.DeviceSet.HasDevice(id) 190 }