github.com/titanous/docker@v1.4.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 11 log "github.com/Sirupsen/logrus" 12 "github.com/docker/docker/daemon/graphdriver" 13 "github.com/docker/docker/pkg/devicemapper" 14 "github.com/docker/docker/pkg/mount" 15 "github.com/docker/docker/pkg/units" 16 ) 17 18 func init() { 19 graphdriver.Register("devicemapper", Init) 20 } 21 22 // Placeholder interfaces, to be replaced 23 // at integration. 24 25 // End of placeholder interfaces. 26 27 type Driver struct { 28 *DeviceSet 29 home string 30 } 31 32 func Init(home string, options []string) (graphdriver.Driver, error) { 33 deviceSet, err := NewDeviceSet(home, true, options) 34 if err != nil { 35 return nil, err 36 } 37 38 if err := mount.MakePrivate(home); err != nil { 39 return nil, err 40 } 41 42 d := &Driver{ 43 DeviceSet: deviceSet, 44 home: home, 45 } 46 47 return graphdriver.NaiveDiffDriver(d), nil 48 } 49 50 func (d *Driver) String() string { 51 return "devicemapper" 52 } 53 54 func (d *Driver) Status() [][2]string { 55 s := d.DeviceSet.Status() 56 57 status := [][2]string{ 58 {"Pool Name", s.PoolName}, 59 {"Pool Blocksize", fmt.Sprintf("%s", units.HumanSize(int64(s.SectorSize)))}, 60 {"Data file", s.DataLoopback}, 61 {"Metadata file", s.MetadataLoopback}, 62 {"Data Space Used", fmt.Sprintf("%s", units.HumanSize(int64(s.Data.Used)))}, 63 {"Data Space Total", fmt.Sprintf("%s", units.HumanSize(int64(s.Data.Total)))}, 64 {"Metadata Space Used", fmt.Sprintf("%s", units.HumanSize(int64(s.Metadata.Used)))}, 65 {"Metadata Space Total", fmt.Sprintf("%s", units.HumanSize(int64(s.Metadata.Total)))}, 66 } 67 if vStr, err := devicemapper.GetLibraryVersion(); err == nil { 68 status = append(status, [2]string{"Library Version", vStr}) 69 } 70 return status 71 } 72 73 func (d *Driver) Cleanup() error { 74 err := d.DeviceSet.Shutdown() 75 76 if err2 := mount.Unmount(d.home); err == nil { 77 err = err2 78 } 79 80 return err 81 } 82 83 func (d *Driver) Create(id, parent string) error { 84 if err := d.DeviceSet.AddDevice(id, parent); err != nil { 85 return err 86 } 87 88 return nil 89 } 90 91 func (d *Driver) Remove(id string) error { 92 if !d.DeviceSet.HasDevice(id) { 93 // Consider removing a non-existing device a no-op 94 // This is useful to be able to progress on container removal 95 // if the underlying device has gone away due to earlier errors 96 return nil 97 } 98 99 // This assumes the device has been properly Get/Put:ed and thus is unmounted 100 if err := d.DeviceSet.DeleteDevice(id); err != nil { 101 return err 102 } 103 104 mp := path.Join(d.home, "mnt", id) 105 if err := os.RemoveAll(mp); err != nil && !os.IsNotExist(err) { 106 return err 107 } 108 109 return nil 110 } 111 112 func (d *Driver) Get(id, mountLabel string) (string, error) { 113 mp := path.Join(d.home, "mnt", id) 114 115 // Create the target directories if they don't exist 116 if err := os.MkdirAll(mp, 0755); err != nil && !os.IsExist(err) { 117 return "", err 118 } 119 120 // Mount the device 121 if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil { 122 return "", err 123 } 124 125 rootFs := path.Join(mp, "rootfs") 126 if err := os.MkdirAll(rootFs, 0755); err != nil && !os.IsExist(err) { 127 d.DeviceSet.UnmountDevice(id) 128 return "", err 129 } 130 131 idFile := path.Join(mp, "id") 132 if _, err := os.Stat(idFile); err != nil && os.IsNotExist(err) { 133 // Create an "id" file with the container/image id in it to help reconscruct this in case 134 // of later problems 135 if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil { 136 d.DeviceSet.UnmountDevice(id) 137 return "", err 138 } 139 } 140 141 return rootFs, nil 142 } 143 144 func (d *Driver) Put(id string) { 145 if err := d.DeviceSet.UnmountDevice(id); err != nil { 146 log.Errorf("Warning: error unmounting device %s: %s", id, err) 147 } 148 } 149 150 func (d *Driver) Exists(id string) bool { 151 return d.DeviceSet.HasDevice(id) 152 }