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