Browse code

Move graphdrivers into runtime top level pkg Docker-DCO-1.1-Signed-off-by: Michael Crosby <michael@crosbymichael.com> (github: crosbymichael)

Michael Crosby authored on 2014/03/15 06:11:43
Showing 54 changed files
... ...
@@ -3,7 +3,7 @@ package main
3 3
 import (
4 4
 	"flag"
5 5
 	"fmt"
6
-	"github.com/dotcloud/docker/graphdriver/devmapper"
6
+	"github.com/dotcloud/docker/runtime/graphdriver/devmapper"
7 7
 	"os"
8 8
 	"path"
9 9
 	"sort"
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"fmt"
5 5
 	"github.com/dotcloud/docker/archive"
6 6
 	"github.com/dotcloud/docker/dockerversion"
7
-	"github.com/dotcloud/docker/graphdriver"
7
+	"github.com/dotcloud/docker/runtime/graphdriver"
8 8
 	"github.com/dotcloud/docker/image"
9 9
 	"github.com/dotcloud/docker/runconfig"
10 10
 	"github.com/dotcloud/docker/utils"
... ...
@@ -2,8 +2,8 @@ package graph
2 2
 
3 3
 import (
4 4
 	"bytes"
5
-	"github.com/dotcloud/docker/graphdriver"
6
-	_ "github.com/dotcloud/docker/graphdriver/vfs" // import the vfs driver so it is used in the tests
5
+	"github.com/dotcloud/docker/runtime/graphdriver"
6
+	_ "github.com/dotcloud/docker/runtime/graphdriver/vfs" // import the vfs driver so it is used in the tests
7 7
 	"github.com/dotcloud/docker/image"
8 8
 	"github.com/dotcloud/docker/utils"
9 9
 	"github.com/dotcloud/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
10 10
deleted file mode 100644
... ...
@@ -1,401 +0,0 @@
1
-/*
2
-
3
-aufs driver directory structure
4
-
5
-.
6
-├── layers // Metadata of layers
7
-│   ├── 1
8
-│   ├── 2
9
-│   └── 3
10
-├── diffs  // Content of the layer
11
-│   ├── 1  // Contains layers that need to be mounted for the id
12
-│   ├── 2
13
-│   └── 3
14
-└── mnt    // Mount points for the rw layers to be mounted
15
-    ├── 1
16
-    ├── 2
17
-    └── 3
18
-
19
-*/
20
-
21
-package aufs
22
-
23
-import (
24
-	"bufio"
25
-	"fmt"
26
-	"github.com/dotcloud/docker/archive"
27
-	"github.com/dotcloud/docker/graphdriver"
28
-	mountpk "github.com/dotcloud/docker/pkg/mount"
29
-	"github.com/dotcloud/docker/utils"
30
-	"os"
31
-	"os/exec"
32
-	"path"
33
-	"strings"
34
-	"sync"
35
-)
36
-
37
-var (
38
-	ErrAufsNotSupported = fmt.Errorf("AUFS was not found in /proc/filesystems")
39
-)
40
-
41
-func init() {
42
-	graphdriver.Register("aufs", Init)
43
-}
44
-
45
-type Driver struct {
46
-	root       string
47
-	sync.Mutex // Protects concurrent modification to active
48
-	active     map[string]int
49
-}
50
-
51
-// New returns a new AUFS driver.
52
-// An error is returned if AUFS is not supported.
53
-func Init(root string) (graphdriver.Driver, error) {
54
-	// Try to load the aufs kernel module
55
-	if err := supportsAufs(); err != nil {
56
-		return nil, err
57
-	}
58
-	paths := []string{
59
-		"mnt",
60
-		"diff",
61
-		"layers",
62
-	}
63
-
64
-	a := &Driver{
65
-		root:   root,
66
-		active: make(map[string]int),
67
-	}
68
-
69
-	// Create the root aufs driver dir and return
70
-	// if it already exists
71
-	// If not populate the dir structure
72
-	if err := os.MkdirAll(root, 0755); err != nil {
73
-		if os.IsExist(err) {
74
-			return a, nil
75
-		}
76
-		return nil, err
77
-	}
78
-
79
-	for _, p := range paths {
80
-		if err := os.MkdirAll(path.Join(root, p), 0755); err != nil {
81
-			return nil, err
82
-		}
83
-	}
84
-	return a, nil
85
-}
86
-
87
-// Return a nil error if the kernel supports aufs
88
-// We cannot modprobe because inside dind modprobe fails
89
-// to run
90
-func supportsAufs() error {
91
-	// We can try to modprobe aufs first before looking at
92
-	// proc/filesystems for when aufs is supported
93
-	exec.Command("modprobe", "aufs").Run()
94
-
95
-	f, err := os.Open("/proc/filesystems")
96
-	if err != nil {
97
-		return err
98
-	}
99
-	defer f.Close()
100
-
101
-	s := bufio.NewScanner(f)
102
-	for s.Scan() {
103
-		if strings.Contains(s.Text(), "aufs") {
104
-			return nil
105
-		}
106
-	}
107
-	return ErrAufsNotSupported
108
-}
109
-
110
-func (a Driver) rootPath() string {
111
-	return a.root
112
-}
113
-
114
-func (Driver) String() string {
115
-	return "aufs"
116
-}
117
-
118
-func (a Driver) Status() [][2]string {
119
-	ids, _ := loadIds(path.Join(a.rootPath(), "layers"))
120
-	return [][2]string{
121
-		{"Root Dir", a.rootPath()},
122
-		{"Dirs", fmt.Sprintf("%d", len(ids))},
123
-	}
124
-}
125
-
126
-// Exists returns true if the given id is registered with
127
-// this driver
128
-func (a Driver) Exists(id string) bool {
129
-	if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil {
130
-		return false
131
-	}
132
-	return true
133
-}
134
-
135
-// Three folders are created for each id
136
-// mnt, layers, and diff
137
-func (a *Driver) Create(id, parent string) error {
138
-	if err := a.createDirsFor(id); err != nil {
139
-		return err
140
-	}
141
-	// Write the layers metadata
142
-	f, err := os.Create(path.Join(a.rootPath(), "layers", id))
143
-	if err != nil {
144
-		return err
145
-	}
146
-	defer f.Close()
147
-
148
-	if parent != "" {
149
-		ids, err := getParentIds(a.rootPath(), parent)
150
-		if err != nil {
151
-			return err
152
-		}
153
-
154
-		if _, err := fmt.Fprintln(f, parent); err != nil {
155
-			return err
156
-		}
157
-		for _, i := range ids {
158
-			if _, err := fmt.Fprintln(f, i); err != nil {
159
-				return err
160
-			}
161
-		}
162
-	}
163
-	return nil
164
-}
165
-
166
-func (a *Driver) createDirsFor(id string) error {
167
-	paths := []string{
168
-		"mnt",
169
-		"diff",
170
-	}
171
-
172
-	for _, p := range paths {
173
-		if err := os.MkdirAll(path.Join(a.rootPath(), p, id), 0755); err != nil {
174
-			return err
175
-		}
176
-	}
177
-	return nil
178
-}
179
-
180
-// Unmount and remove the dir information
181
-func (a *Driver) Remove(id string) error {
182
-	// Protect the a.active from concurrent access
183
-	a.Lock()
184
-	defer a.Unlock()
185
-
186
-	if a.active[id] != 0 {
187
-		utils.Errorf("Warning: removing active id %s\n", id)
188
-	}
189
-
190
-	// Make sure the dir is umounted first
191
-	if err := a.unmount(id); err != nil {
192
-		return err
193
-	}
194
-	tmpDirs := []string{
195
-		"mnt",
196
-		"diff",
197
-	}
198
-
199
-	// Atomically remove each directory in turn by first moving it out of the
200
-	// way (so that docker doesn't find it anymore) before doing removal of
201
-	// the whole tree.
202
-	for _, p := range tmpDirs {
203
-
204
-		realPath := path.Join(a.rootPath(), p, id)
205
-		tmpPath := path.Join(a.rootPath(), p, fmt.Sprintf("%s-removing", id))
206
-		if err := os.Rename(realPath, tmpPath); err != nil && !os.IsNotExist(err) {
207
-			return err
208
-		}
209
-		defer os.RemoveAll(tmpPath)
210
-	}
211
-
212
-	// Remove the layers file for the id
213
-	if err := os.Remove(path.Join(a.rootPath(), "layers", id)); err != nil && !os.IsNotExist(err) {
214
-		return err
215
-	}
216
-	return nil
217
-}
218
-
219
-// Return the rootfs path for the id
220
-// This will mount the dir at it's given path
221
-func (a *Driver) Get(id string) (string, error) {
222
-	ids, err := getParentIds(a.rootPath(), id)
223
-	if err != nil {
224
-		if !os.IsNotExist(err) {
225
-			return "", err
226
-		}
227
-		ids = []string{}
228
-	}
229
-
230
-	// Protect the a.active from concurrent access
231
-	a.Lock()
232
-	defer a.Unlock()
233
-
234
-	count := a.active[id]
235
-
236
-	// If a dir does not have a parent ( no layers )do not try to mount
237
-	// just return the diff path to the data
238
-	out := path.Join(a.rootPath(), "diff", id)
239
-	if len(ids) > 0 {
240
-		out = path.Join(a.rootPath(), "mnt", id)
241
-
242
-		if count == 0 {
243
-			if err := a.mount(id); err != nil {
244
-				return "", err
245
-			}
246
-		}
247
-	}
248
-
249
-	a.active[id] = count + 1
250
-
251
-	return out, nil
252
-}
253
-
254
-func (a *Driver) Put(id string) {
255
-	// Protect the a.active from concurrent access
256
-	a.Lock()
257
-	defer a.Unlock()
258
-
259
-	if count := a.active[id]; count > 1 {
260
-		a.active[id] = count - 1
261
-	} else {
262
-		ids, _ := getParentIds(a.rootPath(), id)
263
-		// We only mounted if there are any parents
264
-		if ids != nil && len(ids) > 0 {
265
-			a.unmount(id)
266
-		}
267
-		delete(a.active, id)
268
-	}
269
-}
270
-
271
-// Returns an archive of the contents for the id
272
-func (a *Driver) Diff(id string) (archive.Archive, error) {
273
-	return archive.TarFilter(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
274
-		Compression: archive.Uncompressed,
275
-	})
276
-}
277
-
278
-func (a *Driver) ApplyDiff(id string, diff archive.ArchiveReader) error {
279
-	return archive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
280
-}
281
-
282
-// Returns the size of the contents for the id
283
-func (a *Driver) DiffSize(id string) (int64, error) {
284
-	return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
285
-}
286
-
287
-func (a *Driver) Changes(id string) ([]archive.Change, error) {
288
-	layers, err := a.getParentLayerPaths(id)
289
-	if err != nil {
290
-		return nil, err
291
-	}
292
-	return archive.Changes(layers, path.Join(a.rootPath(), "diff", id))
293
-}
294
-
295
-func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
296
-	parentIds, err := getParentIds(a.rootPath(), id)
297
-	if err != nil {
298
-		return nil, err
299
-	}
300
-	if len(parentIds) == 0 {
301
-		return nil, fmt.Errorf("Dir %s does not have any parent layers", id)
302
-	}
303
-	layers := make([]string, len(parentIds))
304
-
305
-	// Get the diff paths for all the parent ids
306
-	for i, p := range parentIds {
307
-		layers[i] = path.Join(a.rootPath(), "diff", p)
308
-	}
309
-	return layers, nil
310
-}
311
-
312
-func (a *Driver) mount(id string) error {
313
-	// If the id is mounted or we get an error return
314
-	if mounted, err := a.mounted(id); err != nil || mounted {
315
-		return err
316
-	}
317
-
318
-	var (
319
-		target = path.Join(a.rootPath(), "mnt", id)
320
-		rw     = path.Join(a.rootPath(), "diff", id)
321
-	)
322
-
323
-	layers, err := a.getParentLayerPaths(id)
324
-	if err != nil {
325
-		return err
326
-	}
327
-
328
-	if err := a.aufsMount(layers, rw, target); err != nil {
329
-		return err
330
-	}
331
-	return nil
332
-}
333
-
334
-func (a *Driver) unmount(id string) error {
335
-	if mounted, err := a.mounted(id); err != nil || !mounted {
336
-		return err
337
-	}
338
-	target := path.Join(a.rootPath(), "mnt", id)
339
-	return Unmount(target)
340
-}
341
-
342
-func (a *Driver) mounted(id string) (bool, error) {
343
-	target := path.Join(a.rootPath(), "mnt", id)
344
-	return mountpk.Mounted(target)
345
-}
346
-
347
-// During cleanup aufs needs to unmount all mountpoints
348
-func (a *Driver) Cleanup() error {
349
-	ids, err := loadIds(path.Join(a.rootPath(), "layers"))
350
-	if err != nil {
351
-		return err
352
-	}
353
-	for _, id := range ids {
354
-		if err := a.unmount(id); err != nil {
355
-			utils.Errorf("Unmounting %s: %s", utils.TruncateID(id), err)
356
-		}
357
-	}
358
-	return nil
359
-}
360
-
361
-func (a *Driver) aufsMount(ro []string, rw, target string) (err error) {
362
-	defer func() {
363
-		if err != nil {
364
-			Unmount(target)
365
-		}
366
-	}()
367
-
368
-	if err = a.tryMount(ro, rw, target); err != nil {
369
-		if err = a.mountRw(rw, target); err != nil {
370
-			return
371
-		}
372
-
373
-		for _, layer := range ro {
374
-			branch := fmt.Sprintf("append:%s=ro+wh", layer)
375
-			if err = mount("none", target, "aufs", MsRemount, branch); err != nil {
376
-				return
377
-			}
378
-		}
379
-	}
380
-	return
381
-}
382
-
383
-// Try to mount using the aufs fast path, if this fails then
384
-// append ro layers.
385
-func (a *Driver) tryMount(ro []string, rw, target string) (err error) {
386
-	var (
387
-		rwBranch   = fmt.Sprintf("%s=rw", rw)
388
-		roBranches = fmt.Sprintf("%s=ro+wh:", strings.Join(ro, "=ro+wh:"))
389
-	)
390
-	return mount("none", target, "aufs", 0, fmt.Sprintf("br:%v:%v,xino=/dev/shm/aufs.xino", rwBranch, roBranches))
391
-}
392
-
393
-func (a *Driver) mountRw(rw, target string) error {
394
-	return mount("none", target, "aufs", 0, fmt.Sprintf("br:%s,xino=/dev/shm/aufs.xino", rw))
395
-}
396
-
397
-func rollbackMount(target string, err error) {
398
-	if err != nil {
399
-		Unmount(target)
400
-	}
401
-}
402 1
deleted file mode 100644
... ...
@@ -1,697 +0,0 @@
1
-package aufs
2
-
3
-import (
4
-	"crypto/sha256"
5
-	"encoding/hex"
6
-	"fmt"
7
-	"github.com/dotcloud/docker/archive"
8
-	"github.com/dotcloud/docker/graphdriver"
9
-	"io/ioutil"
10
-	"os"
11
-	"path"
12
-	"testing"
13
-)
14
-
15
-var (
16
-	tmp = path.Join(os.TempDir(), "aufs-tests", "aufs")
17
-)
18
-
19
-func testInit(dir string, t *testing.T) graphdriver.Driver {
20
-	d, err := Init(dir)
21
-	if err != nil {
22
-		if err == ErrAufsNotSupported {
23
-			t.Skip(err)
24
-		} else {
25
-			t.Fatal(err)
26
-		}
27
-	}
28
-	return d
29
-}
30
-
31
-func newDriver(t *testing.T) *Driver {
32
-	if err := os.MkdirAll(tmp, 0755); err != nil {
33
-		t.Fatal(err)
34
-	}
35
-
36
-	d := testInit(tmp, t)
37
-	return d.(*Driver)
38
-}
39
-
40
-func TestNewDriver(t *testing.T) {
41
-	if err := os.MkdirAll(tmp, 0755); err != nil {
42
-		t.Fatal(err)
43
-	}
44
-
45
-	d := testInit(tmp, t)
46
-	defer os.RemoveAll(tmp)
47
-	if d == nil {
48
-		t.Fatalf("Driver should not be nil")
49
-	}
50
-}
51
-
52
-func TestAufsString(t *testing.T) {
53
-	d := newDriver(t)
54
-	defer os.RemoveAll(tmp)
55
-
56
-	if d.String() != "aufs" {
57
-		t.Fatalf("Expected aufs got %s", d.String())
58
-	}
59
-}
60
-
61
-func TestCreateDirStructure(t *testing.T) {
62
-	newDriver(t)
63
-	defer os.RemoveAll(tmp)
64
-
65
-	paths := []string{
66
-		"mnt",
67
-		"layers",
68
-		"diff",
69
-	}
70
-
71
-	for _, p := range paths {
72
-		if _, err := os.Stat(path.Join(tmp, p)); err != nil {
73
-			t.Fatal(err)
74
-		}
75
-	}
76
-}
77
-
78
-// We should be able to create two drivers with the same dir structure
79
-func TestNewDriverFromExistingDir(t *testing.T) {
80
-	if err := os.MkdirAll(tmp, 0755); err != nil {
81
-		t.Fatal(err)
82
-	}
83
-
84
-	testInit(tmp, t)
85
-	testInit(tmp, t)
86
-	os.RemoveAll(tmp)
87
-}
88
-
89
-func TestCreateNewDir(t *testing.T) {
90
-	d := newDriver(t)
91
-	defer os.RemoveAll(tmp)
92
-
93
-	if err := d.Create("1", ""); err != nil {
94
-		t.Fatal(err)
95
-	}
96
-}
97
-
98
-func TestCreateNewDirStructure(t *testing.T) {
99
-	d := newDriver(t)
100
-	defer os.RemoveAll(tmp)
101
-
102
-	if err := d.Create("1", ""); err != nil {
103
-		t.Fatal(err)
104
-	}
105
-
106
-	paths := []string{
107
-		"mnt",
108
-		"diff",
109
-		"layers",
110
-	}
111
-
112
-	for _, p := range paths {
113
-		if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil {
114
-			t.Fatal(err)
115
-		}
116
-	}
117
-}
118
-
119
-func TestRemoveImage(t *testing.T) {
120
-	d := newDriver(t)
121
-	defer os.RemoveAll(tmp)
122
-
123
-	if err := d.Create("1", ""); err != nil {
124
-		t.Fatal(err)
125
-	}
126
-
127
-	if err := d.Remove("1"); err != nil {
128
-		t.Fatal(err)
129
-	}
130
-
131
-	paths := []string{
132
-		"mnt",
133
-		"diff",
134
-		"layers",
135
-	}
136
-
137
-	for _, p := range paths {
138
-		if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil {
139
-			t.Fatalf("Error should not be nil because dirs with id 1 should be delted: %s", p)
140
-		}
141
-	}
142
-}
143
-
144
-func TestGetWithoutParent(t *testing.T) {
145
-	d := newDriver(t)
146
-	defer os.RemoveAll(tmp)
147
-
148
-	if err := d.Create("1", ""); err != nil {
149
-		t.Fatal(err)
150
-	}
151
-
152
-	diffPath, err := d.Get("1")
153
-	if err != nil {
154
-		t.Fatal(err)
155
-	}
156
-	expected := path.Join(tmp, "diff", "1")
157
-	if diffPath != expected {
158
-		t.Fatalf("Expected path %s got %s", expected, diffPath)
159
-	}
160
-}
161
-
162
-func TestCleanupWithNoDirs(t *testing.T) {
163
-	d := newDriver(t)
164
-	defer os.RemoveAll(tmp)
165
-
166
-	if err := d.Cleanup(); err != nil {
167
-		t.Fatal(err)
168
-	}
169
-}
170
-
171
-func TestCleanupWithDir(t *testing.T) {
172
-	d := newDriver(t)
173
-	defer os.RemoveAll(tmp)
174
-
175
-	if err := d.Create("1", ""); err != nil {
176
-		t.Fatal(err)
177
-	}
178
-
179
-	if err := d.Cleanup(); err != nil {
180
-		t.Fatal(err)
181
-	}
182
-}
183
-
184
-func TestMountedFalseResponse(t *testing.T) {
185
-	d := newDriver(t)
186
-	defer os.RemoveAll(tmp)
187
-
188
-	if err := d.Create("1", ""); err != nil {
189
-		t.Fatal(err)
190
-	}
191
-
192
-	response, err := d.mounted("1")
193
-	if err != nil {
194
-		t.Fatal(err)
195
-	}
196
-
197
-	if response != false {
198
-		t.Fatalf("Response if dir id 1 is mounted should be false")
199
-	}
200
-}
201
-
202
-func TestMountedTrueReponse(t *testing.T) {
203
-	d := newDriver(t)
204
-	defer os.RemoveAll(tmp)
205
-	defer d.Cleanup()
206
-
207
-	if err := d.Create("1", ""); err != nil {
208
-		t.Fatal(err)
209
-	}
210
-	if err := d.Create("2", "1"); err != nil {
211
-		t.Fatal(err)
212
-	}
213
-
214
-	_, err := d.Get("2")
215
-	if err != nil {
216
-		t.Fatal(err)
217
-	}
218
-
219
-	response, err := d.mounted("2")
220
-	if err != nil {
221
-		t.Fatal(err)
222
-	}
223
-
224
-	if response != true {
225
-		t.Fatalf("Response if dir id 2 is mounted should be true")
226
-	}
227
-}
228
-
229
-func TestMountWithParent(t *testing.T) {
230
-	d := newDriver(t)
231
-	defer os.RemoveAll(tmp)
232
-
233
-	if err := d.Create("1", ""); err != nil {
234
-		t.Fatal(err)
235
-	}
236
-	if err := d.Create("2", "1"); err != nil {
237
-		t.Fatal(err)
238
-	}
239
-
240
-	defer func() {
241
-		if err := d.Cleanup(); err != nil {
242
-			t.Fatal(err)
243
-		}
244
-	}()
245
-
246
-	mntPath, err := d.Get("2")
247
-	if err != nil {
248
-		t.Fatal(err)
249
-	}
250
-	if mntPath == "" {
251
-		t.Fatal("mntPath should not be empty string")
252
-	}
253
-
254
-	expected := path.Join(tmp, "mnt", "2")
255
-	if mntPath != expected {
256
-		t.Fatalf("Expected %s got %s", expected, mntPath)
257
-	}
258
-}
259
-
260
-func TestRemoveMountedDir(t *testing.T) {
261
-	d := newDriver(t)
262
-	defer os.RemoveAll(tmp)
263
-
264
-	if err := d.Create("1", ""); err != nil {
265
-		t.Fatal(err)
266
-	}
267
-	if err := d.Create("2", "1"); err != nil {
268
-		t.Fatal(err)
269
-	}
270
-
271
-	defer func() {
272
-		if err := d.Cleanup(); err != nil {
273
-			t.Fatal(err)
274
-		}
275
-	}()
276
-
277
-	mntPath, err := d.Get("2")
278
-	if err != nil {
279
-		t.Fatal(err)
280
-	}
281
-	if mntPath == "" {
282
-		t.Fatal("mntPath should not be empty string")
283
-	}
284
-
285
-	mounted, err := d.mounted("2")
286
-	if err != nil {
287
-		t.Fatal(err)
288
-	}
289
-
290
-	if !mounted {
291
-		t.Fatalf("Dir id 2 should be mounted")
292
-	}
293
-
294
-	if err := d.Remove("2"); err != nil {
295
-		t.Fatal(err)
296
-	}
297
-}
298
-
299
-func TestCreateWithInvalidParent(t *testing.T) {
300
-	d := newDriver(t)
301
-	defer os.RemoveAll(tmp)
302
-
303
-	if err := d.Create("1", "docker"); err == nil {
304
-		t.Fatalf("Error should not be nil with parent does not exist")
305
-	}
306
-}
307
-
308
-func TestGetDiff(t *testing.T) {
309
-	d := newDriver(t)
310
-	defer os.RemoveAll(tmp)
311
-
312
-	if err := d.Create("1", ""); err != nil {
313
-		t.Fatal(err)
314
-	}
315
-
316
-	diffPath, err := d.Get("1")
317
-	if err != nil {
318
-		t.Fatal(err)
319
-	}
320
-
321
-	// Add a file to the diff path with a fixed size
322
-	size := int64(1024)
323
-
324
-	f, err := os.Create(path.Join(diffPath, "test_file"))
325
-	if err != nil {
326
-		t.Fatal(err)
327
-	}
328
-	if err := f.Truncate(size); err != nil {
329
-		t.Fatal(err)
330
-	}
331
-	f.Close()
332
-
333
-	a, err := d.Diff("1")
334
-	if err != nil {
335
-		t.Fatal(err)
336
-	}
337
-	if a == nil {
338
-		t.Fatalf("Archive should not be nil")
339
-	}
340
-}
341
-
342
-func TestChanges(t *testing.T) {
343
-	d := newDriver(t)
344
-	defer os.RemoveAll(tmp)
345
-
346
-	if err := d.Create("1", ""); err != nil {
347
-		t.Fatal(err)
348
-	}
349
-	if err := d.Create("2", "1"); err != nil {
350
-		t.Fatal(err)
351
-	}
352
-
353
-	defer func() {
354
-		if err := d.Cleanup(); err != nil {
355
-			t.Fatal(err)
356
-		}
357
-	}()
358
-
359
-	mntPoint, err := d.Get("2")
360
-	if err != nil {
361
-		t.Fatal(err)
362
-	}
363
-
364
-	// Create a file to save in the mountpoint
365
-	f, err := os.Create(path.Join(mntPoint, "test.txt"))
366
-	if err != nil {
367
-		t.Fatal(err)
368
-	}
369
-
370
-	if _, err := f.WriteString("testline"); err != nil {
371
-		t.Fatal(err)
372
-	}
373
-	if err := f.Close(); err != nil {
374
-		t.Fatal(err)
375
-	}
376
-
377
-	changes, err := d.Changes("2")
378
-	if err != nil {
379
-		t.Fatal(err)
380
-	}
381
-	if len(changes) != 1 {
382
-		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
383
-	}
384
-	change := changes[0]
385
-
386
-	expectedPath := "/test.txt"
387
-	if change.Path != expectedPath {
388
-		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
389
-	}
390
-
391
-	if change.Kind != archive.ChangeAdd {
392
-		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
393
-	}
394
-
395
-	if err := d.Create("3", "2"); err != nil {
396
-		t.Fatal(err)
397
-	}
398
-	mntPoint, err = d.Get("3")
399
-	if err != nil {
400
-		t.Fatal(err)
401
-	}
402
-
403
-	// Create a file to save in the mountpoint
404
-	f, err = os.Create(path.Join(mntPoint, "test2.txt"))
405
-	if err != nil {
406
-		t.Fatal(err)
407
-	}
408
-
409
-	if _, err := f.WriteString("testline"); err != nil {
410
-		t.Fatal(err)
411
-	}
412
-	if err := f.Close(); err != nil {
413
-		t.Fatal(err)
414
-	}
415
-
416
-	changes, err = d.Changes("3")
417
-	if err != nil {
418
-		t.Fatal(err)
419
-	}
420
-
421
-	if len(changes) != 1 {
422
-		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
423
-	}
424
-	change = changes[0]
425
-
426
-	expectedPath = "/test2.txt"
427
-	if change.Path != expectedPath {
428
-		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
429
-	}
430
-
431
-	if change.Kind != archive.ChangeAdd {
432
-		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
433
-	}
434
-}
435
-
436
-func TestDiffSize(t *testing.T) {
437
-	d := newDriver(t)
438
-	defer os.RemoveAll(tmp)
439
-
440
-	if err := d.Create("1", ""); err != nil {
441
-		t.Fatal(err)
442
-	}
443
-
444
-	diffPath, err := d.Get("1")
445
-	if err != nil {
446
-		t.Fatal(err)
447
-	}
448
-
449
-	// Add a file to the diff path with a fixed size
450
-	size := int64(1024)
451
-
452
-	f, err := os.Create(path.Join(diffPath, "test_file"))
453
-	if err != nil {
454
-		t.Fatal(err)
455
-	}
456
-	if err := f.Truncate(size); err != nil {
457
-		t.Fatal(err)
458
-	}
459
-	s, err := f.Stat()
460
-	if err != nil {
461
-		t.Fatal(err)
462
-	}
463
-	size = s.Size()
464
-	if err := f.Close(); err != nil {
465
-		t.Fatal(err)
466
-	}
467
-
468
-	diffSize, err := d.DiffSize("1")
469
-	if err != nil {
470
-		t.Fatal(err)
471
-	}
472
-	if diffSize != size {
473
-		t.Fatalf("Expected size to be %d got %d", size, diffSize)
474
-	}
475
-}
476
-
477
-func TestChildDiffSize(t *testing.T) {
478
-	d := newDriver(t)
479
-	defer os.RemoveAll(tmp)
480
-	defer d.Cleanup()
481
-
482
-	if err := d.Create("1", ""); err != nil {
483
-		t.Fatal(err)
484
-	}
485
-
486
-	diffPath, err := d.Get("1")
487
-	if err != nil {
488
-		t.Fatal(err)
489
-	}
490
-
491
-	// Add a file to the diff path with a fixed size
492
-	size := int64(1024)
493
-
494
-	f, err := os.Create(path.Join(diffPath, "test_file"))
495
-	if err != nil {
496
-		t.Fatal(err)
497
-	}
498
-	if err := f.Truncate(size); err != nil {
499
-		t.Fatal(err)
500
-	}
501
-	s, err := f.Stat()
502
-	if err != nil {
503
-		t.Fatal(err)
504
-	}
505
-	size = s.Size()
506
-	if err := f.Close(); err != nil {
507
-		t.Fatal(err)
508
-	}
509
-
510
-	diffSize, err := d.DiffSize("1")
511
-	if err != nil {
512
-		t.Fatal(err)
513
-	}
514
-	if diffSize != size {
515
-		t.Fatalf("Expected size to be %d got %d", size, diffSize)
516
-	}
517
-
518
-	if err := d.Create("2", "1"); err != nil {
519
-		t.Fatal(err)
520
-	}
521
-
522
-	diffSize, err = d.DiffSize("2")
523
-	if err != nil {
524
-		t.Fatal(err)
525
-	}
526
-	// The diff size for the child should be zero
527
-	if diffSize != 0 {
528
-		t.Fatalf("Expected size to be %d got %d", 0, diffSize)
529
-	}
530
-}
531
-
532
-func TestExists(t *testing.T) {
533
-	d := newDriver(t)
534
-	defer os.RemoveAll(tmp)
535
-	defer d.Cleanup()
536
-
537
-	if err := d.Create("1", ""); err != nil {
538
-		t.Fatal(err)
539
-	}
540
-
541
-	if d.Exists("none") {
542
-		t.Fatal("id name should not exist in the driver")
543
-	}
544
-
545
-	if !d.Exists("1") {
546
-		t.Fatal("id 1 should exist in the driver")
547
-	}
548
-}
549
-
550
-func TestStatus(t *testing.T) {
551
-	d := newDriver(t)
552
-	defer os.RemoveAll(tmp)
553
-	defer d.Cleanup()
554
-
555
-	if err := d.Create("1", ""); err != nil {
556
-		t.Fatal(err)
557
-	}
558
-
559
-	status := d.Status()
560
-	if status == nil || len(status) == 0 {
561
-		t.Fatal("Status should not be nil or empty")
562
-	}
563
-	rootDir := status[0]
564
-	dirs := status[1]
565
-	if rootDir[0] != "Root Dir" {
566
-		t.Fatalf("Expected Root Dir got %s", rootDir[0])
567
-	}
568
-	if rootDir[1] != d.rootPath() {
569
-		t.Fatalf("Expected %s got %s", d.rootPath(), rootDir[1])
570
-	}
571
-	if dirs[0] != "Dirs" {
572
-		t.Fatalf("Expected Dirs got %s", dirs[0])
573
-	}
574
-	if dirs[1] != "1" {
575
-		t.Fatalf("Expected 1 got %s", dirs[1])
576
-	}
577
-}
578
-
579
-func TestApplyDiff(t *testing.T) {
580
-	d := newDriver(t)
581
-	defer os.RemoveAll(tmp)
582
-	defer d.Cleanup()
583
-
584
-	if err := d.Create("1", ""); err != nil {
585
-		t.Fatal(err)
586
-	}
587
-
588
-	diffPath, err := d.Get("1")
589
-	if err != nil {
590
-		t.Fatal(err)
591
-	}
592
-
593
-	// Add a file to the diff path with a fixed size
594
-	size := int64(1024)
595
-
596
-	f, err := os.Create(path.Join(diffPath, "test_file"))
597
-	if err != nil {
598
-		t.Fatal(err)
599
-	}
600
-	if err := f.Truncate(size); err != nil {
601
-		t.Fatal(err)
602
-	}
603
-	f.Close()
604
-
605
-	diff, err := d.Diff("1")
606
-	if err != nil {
607
-		t.Fatal(err)
608
-	}
609
-
610
-	if err := d.Create("2", ""); err != nil {
611
-		t.Fatal(err)
612
-	}
613
-	if err := d.Create("3", "2"); err != nil {
614
-		t.Fatal(err)
615
-	}
616
-
617
-	if err := d.ApplyDiff("3", diff); err != nil {
618
-		t.Fatal(err)
619
-	}
620
-
621
-	// Ensure that the file is in the mount point for id 3
622
-
623
-	mountPoint, err := d.Get("3")
624
-	if err != nil {
625
-		t.Fatal(err)
626
-	}
627
-	if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil {
628
-		t.Fatal(err)
629
-	}
630
-}
631
-
632
-func hash(c string) string {
633
-	h := sha256.New()
634
-	fmt.Fprint(h, c)
635
-	return hex.EncodeToString(h.Sum(nil))
636
-}
637
-
638
-func TestMountMoreThan42Layers(t *testing.T) {
639
-	d := newDriver(t)
640
-	defer os.RemoveAll(tmp)
641
-	defer d.Cleanup()
642
-	var last string
643
-	var expected int
644
-
645
-	for i := 1; i < 127; i++ {
646
-		expected++
647
-		var (
648
-			parent  = fmt.Sprintf("%d", i-1)
649
-			current = fmt.Sprintf("%d", i)
650
-		)
651
-
652
-		if parent == "0" {
653
-			parent = ""
654
-		} else {
655
-			parent = hash(parent)
656
-		}
657
-		current = hash(current)
658
-
659
-		if err := d.Create(current, parent); err != nil {
660
-			t.Logf("Current layer %d", i)
661
-			t.Fatal(err)
662
-		}
663
-		point, err := d.Get(current)
664
-		if err != nil {
665
-			t.Logf("Current layer %d", i)
666
-			t.Fatal(err)
667
-		}
668
-		f, err := os.Create(path.Join(point, current))
669
-		if err != nil {
670
-			t.Logf("Current layer %d", i)
671
-			t.Fatal(err)
672
-		}
673
-		f.Close()
674
-
675
-		if i%10 == 0 {
676
-			if err := os.Remove(path.Join(point, parent)); err != nil {
677
-				t.Logf("Current layer %d", i)
678
-				t.Fatal(err)
679
-			}
680
-			expected--
681
-		}
682
-		last = current
683
-	}
684
-
685
-	// Perform the actual mount for the top most image
686
-	point, err := d.Get(last)
687
-	if err != nil {
688
-		t.Fatal(err)
689
-	}
690
-	files, err := ioutil.ReadDir(point)
691
-	if err != nil {
692
-		t.Fatal(err)
693
-	}
694
-	if len(files) != expected {
695
-		t.Fatalf("Expected %d got %d", expected, len(files))
696
-	}
697
-}
698 1
deleted file mode 100644
... ...
@@ -1,46 +0,0 @@
1
-package aufs
2
-
3
-import (
4
-	"bufio"
5
-	"io/ioutil"
6
-	"os"
7
-	"path"
8
-)
9
-
10
-// Return all the directories
11
-func loadIds(root string) ([]string, error) {
12
-	dirs, err := ioutil.ReadDir(root)
13
-	if err != nil {
14
-		return nil, err
15
-	}
16
-	out := []string{}
17
-	for _, d := range dirs {
18
-		if !d.IsDir() {
19
-			out = append(out, d.Name())
20
-		}
21
-	}
22
-	return out, nil
23
-}
24
-
25
-// Read the layers file for the current id and return all the
26
-// layers represented by new lines in the file
27
-//
28
-// If there are no lines in the file then the id has no parent
29
-// and an empty slice is returned.
30
-func getParentIds(root, id string) ([]string, error) {
31
-	f, err := os.Open(path.Join(root, "layers", id))
32
-	if err != nil {
33
-		return nil, err
34
-	}
35
-	defer f.Close()
36
-
37
-	out := []string{}
38
-	s := bufio.NewScanner(f)
39
-
40
-	for s.Scan() {
41
-		if t := s.Text(); t != "" {
42
-			out = append(out, s.Text())
43
-		}
44
-	}
45
-	return out, s.Err()
46
-}
47 1
deleted file mode 100644
... ...
@@ -1,194 +0,0 @@
1
-package aufs
2
-
3
-import (
4
-	"encoding/json"
5
-	"fmt"
6
-	"io/ioutil"
7
-	"os"
8
-	"path"
9
-)
10
-
11
-type metadata struct {
12
-	ID       string `json:"id"`
13
-	ParentID string `json:"parent,omitempty"`
14
-	Image    string `json:"Image,omitempty"`
15
-
16
-	parent *metadata
17
-}
18
-
19
-func pathExists(pth string) bool {
20
-	if _, err := os.Stat(pth); err != nil {
21
-		return false
22
-	}
23
-	return true
24
-}
25
-
26
-// Migrate existing images and containers from docker < 0.7.x
27
-//
28
-// The format pre 0.7 is for docker to store the metadata and filesystem
29
-// content in the same directory.  For the migration to work we need to move Image layer
30
-// data from /var/lib/docker/graph/<id>/layers to the diff of the registered id.
31
-//
32
-// Next we need to migrate the container's rw layer to diff of the driver.  After the
33
-// contents are migrated we need to register the image and container ids with the
34
-// driver.
35
-//
36
-// For the migration we try to move the folder containing the layer files, if that
37
-// fails because the data is currently mounted we will fallback to creating a
38
-// symlink.
39
-func (a *Driver) Migrate(pth string, setupInit func(p string) error) error {
40
-	if pathExists(path.Join(pth, "graph")) {
41
-		if err := a.migrateRepositories(pth); err != nil {
42
-			return err
43
-		}
44
-		if err := a.migrateImages(path.Join(pth, "graph")); err != nil {
45
-			return err
46
-		}
47
-		return a.migrateContainers(path.Join(pth, "containers"), setupInit)
48
-	}
49
-	return nil
50
-}
51
-
52
-func (a *Driver) migrateRepositories(pth string) error {
53
-	name := path.Join(pth, "repositories")
54
-	if err := os.Rename(name, name+"-aufs"); err != nil && !os.IsNotExist(err) {
55
-		return err
56
-	}
57
-	return nil
58
-}
59
-
60
-func (a *Driver) migrateContainers(pth string, setupInit func(p string) error) error {
61
-	fis, err := ioutil.ReadDir(pth)
62
-	if err != nil {
63
-		return err
64
-	}
65
-
66
-	for _, fi := range fis {
67
-		if id := fi.Name(); fi.IsDir() && pathExists(path.Join(pth, id, "rw")) {
68
-			if err := tryRelocate(path.Join(pth, id, "rw"), path.Join(a.rootPath(), "diff", id)); err != nil {
69
-				return err
70
-			}
71
-
72
-			if !a.Exists(id) {
73
-
74
-				metadata, err := loadMetadata(path.Join(pth, id, "config.json"))
75
-				if err != nil {
76
-					return err
77
-				}
78
-
79
-				initID := fmt.Sprintf("%s-init", id)
80
-				if err := a.Create(initID, metadata.Image); err != nil {
81
-					return err
82
-				}
83
-
84
-				initPath, err := a.Get(initID)
85
-				if err != nil {
86
-					return err
87
-				}
88
-				// setup init layer
89
-				if err := setupInit(initPath); err != nil {
90
-					return err
91
-				}
92
-
93
-				if err := a.Create(id, initID); err != nil {
94
-					return err
95
-				}
96
-			}
97
-		}
98
-	}
99
-	return nil
100
-}
101
-
102
-func (a *Driver) migrateImages(pth string) error {
103
-	fis, err := ioutil.ReadDir(pth)
104
-	if err != nil {
105
-		return err
106
-	}
107
-	var (
108
-		m       = make(map[string]*metadata)
109
-		current *metadata
110
-		exists  bool
111
-	)
112
-
113
-	for _, fi := range fis {
114
-		if id := fi.Name(); fi.IsDir() && pathExists(path.Join(pth, id, "layer")) {
115
-			if current, exists = m[id]; !exists {
116
-				current, err = loadMetadata(path.Join(pth, id, "json"))
117
-				if err != nil {
118
-					return err
119
-				}
120
-				m[id] = current
121
-			}
122
-		}
123
-	}
124
-
125
-	for _, v := range m {
126
-		v.parent = m[v.ParentID]
127
-	}
128
-
129
-	migrated := make(map[string]bool)
130
-	for _, v := range m {
131
-		if err := a.migrateImage(v, pth, migrated); err != nil {
132
-			return err
133
-		}
134
-	}
135
-	return nil
136
-}
137
-
138
-func (a *Driver) migrateImage(m *metadata, pth string, migrated map[string]bool) error {
139
-	if !migrated[m.ID] {
140
-		if m.parent != nil {
141
-			a.migrateImage(m.parent, pth, migrated)
142
-		}
143
-		if err := tryRelocate(path.Join(pth, m.ID, "layer"), path.Join(a.rootPath(), "diff", m.ID)); err != nil {
144
-			return err
145
-		}
146
-		if !a.Exists(m.ID) {
147
-			if err := a.Create(m.ID, m.ParentID); err != nil {
148
-				return err
149
-			}
150
-		}
151
-		migrated[m.ID] = true
152
-	}
153
-	return nil
154
-}
155
-
156
-// tryRelocate will try to rename the old path to the new pack and if
157
-// the operation fails, it will fallback to a symlink
158
-func tryRelocate(oldPath, newPath string) error {
159
-	s, err := os.Lstat(newPath)
160
-	if err != nil && !os.IsNotExist(err) {
161
-		return err
162
-	}
163
-	// If the destination is a symlink then we already tried to relocate once before
164
-	// and it failed so we delete it and try to remove
165
-	if s != nil && s.Mode()&os.ModeSymlink == os.ModeSymlink {
166
-		if err := os.RemoveAll(newPath); err != nil {
167
-			return err
168
-		}
169
-	}
170
-	if err := os.Rename(oldPath, newPath); err != nil {
171
-		if sErr := os.Symlink(oldPath, newPath); sErr != nil {
172
-			return fmt.Errorf("Unable to relocate %s to %s: Rename err %s Symlink err %s", oldPath, newPath, err, sErr)
173
-		}
174
-	}
175
-	return nil
176
-}
177
-
178
-func loadMetadata(pth string) (*metadata, error) {
179
-	f, err := os.Open(pth)
180
-	if err != nil {
181
-		return nil, err
182
-	}
183
-	defer f.Close()
184
-
185
-	var (
186
-		out = &metadata{}
187
-		dec = json.NewDecoder(f)
188
-	)
189
-
190
-	if err := dec.Decode(out); err != nil {
191
-		return nil, err
192
-	}
193
-	return out, nil
194
-}
195 1
deleted file mode 100644
... ...
@@ -1,17 +0,0 @@
1
-package aufs
2
-
3
-import (
4
-	"github.com/dotcloud/docker/utils"
5
-	"os/exec"
6
-	"syscall"
7
-)
8
-
9
-func Unmount(target string) error {
10
-	if err := exec.Command("auplink", target, "flush").Run(); err != nil {
11
-		utils.Errorf("[warning]: couldn't run auplink before unmount: %s", err)
12
-	}
13
-	if err := syscall.Unmount(target, 0); err != nil {
14
-		return err
15
-	}
16
-	return nil
17
-}
18 1
deleted file mode 100644
... ...
@@ -1,11 +0,0 @@
1
-// +build amd64
2
-
3
-package aufs
4
-
5
-import "syscall"
6
-
7
-const MsRemount = syscall.MS_REMOUNT
8
-
9
-func mount(source string, target string, fstype string, flags uintptr, data string) error {
10
-	return syscall.Mount(source, target, fstype, flags, data)
11
-}
12 1
deleted file mode 100644
... ...
@@ -1,11 +0,0 @@
1
-// +build !linux !amd64
2
-
3
-package aufs
4
-
5
-import "errors"
6
-
7
-const MsRemount = 0
8
-
9
-func mount(source string, target string, fstype string, flags uintptr, data string) (err error) {
10
-	return errors.New("mount is not implemented on darwin")
11
-}
12 1
deleted file mode 100644
... ...
@@ -1,213 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package btrfs
4
-
5
-/*
6
-#include <stdlib.h>
7
-#include <dirent.h>
8
-#include <btrfs/ioctl.h>
9
-*/
10
-import "C"
11
-
12
-import (
13
-	"fmt"
14
-	"github.com/dotcloud/docker/graphdriver"
15
-	"os"
16
-	"path"
17
-	"syscall"
18
-	"unsafe"
19
-)
20
-
21
-func init() {
22
-	graphdriver.Register("btrfs", Init)
23
-}
24
-
25
-func Init(home string) (graphdriver.Driver, error) {
26
-	rootdir := path.Dir(home)
27
-
28
-	var buf syscall.Statfs_t
29
-	if err := syscall.Statfs(rootdir, &buf); err != nil {
30
-		return nil, err
31
-	}
32
-
33
-	if buf.Type != 0x9123683E {
34
-		return nil, fmt.Errorf("%s is not a btrfs filesystem", rootdir)
35
-	}
36
-
37
-	return &Driver{
38
-		home: home,
39
-	}, nil
40
-}
41
-
42
-type Driver struct {
43
-	home string
44
-}
45
-
46
-func (d *Driver) String() string {
47
-	return "btrfs"
48
-}
49
-
50
-func (d *Driver) Status() [][2]string {
51
-	return nil
52
-}
53
-
54
-func (d *Driver) Cleanup() error {
55
-	return nil
56
-}
57
-
58
-func free(p *C.char) {
59
-	C.free(unsafe.Pointer(p))
60
-}
61
-
62
-func openDir(path string) (*C.DIR, error) {
63
-	Cpath := C.CString(path)
64
-	defer free(Cpath)
65
-
66
-	dir := C.opendir(Cpath)
67
-	if dir == nil {
68
-		return nil, fmt.Errorf("Can't open dir")
69
-	}
70
-	return dir, nil
71
-}
72
-
73
-func closeDir(dir *C.DIR) {
74
-	if dir != nil {
75
-		C.closedir(dir)
76
-	}
77
-}
78
-
79
-func getDirFd(dir *C.DIR) uintptr {
80
-	return uintptr(C.dirfd(dir))
81
-}
82
-
83
-func subvolCreate(path, name string) error {
84
-	dir, err := openDir(path)
85
-	if err != nil {
86
-		return err
87
-	}
88
-	defer closeDir(dir)
89
-
90
-	var args C.struct_btrfs_ioctl_vol_args
91
-	for i, c := range []byte(name) {
92
-		args.name[i] = C.char(c)
93
-	}
94
-
95
-	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SUBVOL_CREATE,
96
-		uintptr(unsafe.Pointer(&args)))
97
-	if errno != 0 {
98
-		return fmt.Errorf("Failed to create btrfs subvolume: %v", errno.Error())
99
-	}
100
-	return nil
101
-}
102
-
103
-func subvolSnapshot(src, dest, name string) error {
104
-	srcDir, err := openDir(src)
105
-	if err != nil {
106
-		return err
107
-	}
108
-	defer closeDir(srcDir)
109
-
110
-	destDir, err := openDir(dest)
111
-	if err != nil {
112
-		return err
113
-	}
114
-	defer closeDir(destDir)
115
-
116
-	var args C.struct_btrfs_ioctl_vol_args_v2
117
-	args.fd = C.__s64(getDirFd(srcDir))
118
-	for i, c := range []byte(name) {
119
-		args.name[i] = C.char(c)
120
-	}
121
-
122
-	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(destDir), C.BTRFS_IOC_SNAP_CREATE_V2,
123
-		uintptr(unsafe.Pointer(&args)))
124
-	if errno != 0 {
125
-		return fmt.Errorf("Failed to create btrfs snapshot: %v", errno.Error())
126
-	}
127
-	return nil
128
-}
129
-
130
-func subvolDelete(path, name string) error {
131
-	dir, err := openDir(path)
132
-	if err != nil {
133
-		return err
134
-	}
135
-	defer closeDir(dir)
136
-
137
-	var args C.struct_btrfs_ioctl_vol_args
138
-	for i, c := range []byte(name) {
139
-		args.name[i] = C.char(c)
140
-	}
141
-
142
-	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SNAP_DESTROY,
143
-		uintptr(unsafe.Pointer(&args)))
144
-	if errno != 0 {
145
-		return fmt.Errorf("Failed to destroy btrfs snapshot: %v", errno.Error())
146
-	}
147
-	return nil
148
-}
149
-
150
-func (d *Driver) subvolumesDir() string {
151
-	return path.Join(d.home, "subvolumes")
152
-}
153
-
154
-func (d *Driver) subvolumesDirId(id string) string {
155
-	return path.Join(d.subvolumesDir(), id)
156
-}
157
-
158
-func (d *Driver) Create(id string, parent string) error {
159
-	subvolumes := path.Join(d.home, "subvolumes")
160
-	if err := os.MkdirAll(subvolumes, 0700); err != nil {
161
-		return err
162
-	}
163
-	if parent == "" {
164
-		if err := subvolCreate(subvolumes, id); err != nil {
165
-			return err
166
-		}
167
-	} else {
168
-		parentDir, err := d.Get(parent)
169
-		if err != nil {
170
-			return err
171
-		}
172
-		if err := subvolSnapshot(parentDir, subvolumes, id); err != nil {
173
-			return err
174
-		}
175
-	}
176
-	return nil
177
-}
178
-
179
-func (d *Driver) Remove(id string) error {
180
-	dir := d.subvolumesDirId(id)
181
-	if _, err := os.Stat(dir); err != nil {
182
-		return err
183
-	}
184
-	if err := subvolDelete(d.subvolumesDir(), id); err != nil {
185
-		return err
186
-	}
187
-	return os.RemoveAll(dir)
188
-}
189
-
190
-func (d *Driver) Get(id string) (string, error) {
191
-	dir := d.subvolumesDirId(id)
192
-	st, err := os.Stat(dir)
193
-	if err != nil {
194
-		return "", err
195
-	}
196
-
197
-	if !st.IsDir() {
198
-		return "", fmt.Errorf("%s: not a directory", dir)
199
-	}
200
-
201
-	return dir, nil
202
-}
203
-
204
-func (d *Driver) Put(id string) {
205
-	// Get() creates no runtime resources (like e.g. mounts)
206
-	// so this doesn't need to do anything.
207
-}
208
-
209
-func (d *Driver) Exists(id string) bool {
210
-	dir := d.subvolumesDirId(id)
211
-	_, err := os.Stat(dir)
212
-	return err == nil
213
-}
214 1
deleted file mode 100644
... ...
@@ -1,3 +0,0 @@
1
-// +build !linux !amd64
2
-
3
-package btrfs
4 1
deleted file mode 100644
... ...
@@ -1,126 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-import (
6
-	"fmt"
7
-	"github.com/dotcloud/docker/utils"
8
-)
9
-
10
-func stringToLoopName(src string) [LoNameSize]uint8 {
11
-	var dst [LoNameSize]uint8
12
-	copy(dst[:], src[:])
13
-	return dst
14
-}
15
-
16
-func getNextFreeLoopbackIndex() (int, error) {
17
-	f, err := osOpenFile("/dev/loop-control", osORdOnly, 0644)
18
-	if err != nil {
19
-		return 0, err
20
-	}
21
-	defer f.Close()
22
-
23
-	index, err := ioctlLoopCtlGetFree(f.Fd())
24
-	if index < 0 {
25
-		index = 0
26
-	}
27
-	return index, err
28
-}
29
-
30
-func openNextAvailableLoopback(index int, sparseFile *osFile) (loopFile *osFile, err error) {
31
-	// Start looking for a free /dev/loop
32
-	for {
33
-		target := fmt.Sprintf("/dev/loop%d", index)
34
-		index++
35
-
36
-		fi, err := osStat(target)
37
-		if err != nil {
38
-			if osIsNotExist(err) {
39
-				utils.Errorf("There are no more loopback device available.")
40
-			}
41
-			return nil, ErrAttachLoopbackDevice
42
-		}
43
-
44
-		if fi.Mode()&osModeDevice != osModeDevice {
45
-			utils.Errorf("Loopback device %s is not a block device.", target)
46
-			continue
47
-		}
48
-
49
-		// OpenFile adds O_CLOEXEC
50
-		loopFile, err = osOpenFile(target, osORdWr, 0644)
51
-		if err != nil {
52
-			utils.Errorf("Error openning loopback device: %s", err)
53
-			return nil, ErrAttachLoopbackDevice
54
-		}
55
-
56
-		// Try to attach to the loop file
57
-		if err := ioctlLoopSetFd(loopFile.Fd(), sparseFile.Fd()); err != nil {
58
-			loopFile.Close()
59
-
60
-			// If the error is EBUSY, then try the next loopback
61
-			if err != sysEBusy {
62
-				utils.Errorf("Cannot set up loopback device %s: %s", target, err)
63
-				return nil, ErrAttachLoopbackDevice
64
-			}
65
-
66
-			// Otherwise, we keep going with the loop
67
-			continue
68
-		}
69
-		// In case of success, we finished. Break the loop.
70
-		break
71
-	}
72
-
73
-	// This can't happen, but let's be sure
74
-	if loopFile == nil {
75
-		utils.Errorf("Unreachable code reached! Error attaching %s to a loopback device.", sparseFile.Name())
76
-		return nil, ErrAttachLoopbackDevice
77
-	}
78
-
79
-	return loopFile, nil
80
-}
81
-
82
-// attachLoopDevice attaches the given sparse file to the next
83
-// available loopback device. It returns an opened *osFile.
84
-func attachLoopDevice(sparseName string) (loop *osFile, err error) {
85
-
86
-	// Try to retrieve the next available loopback device via syscall.
87
-	// If it fails, we discard error and start loopking for a
88
-	// loopback from index 0.
89
-	startIndex, err := getNextFreeLoopbackIndex()
90
-	if err != nil {
91
-		utils.Debugf("Error retrieving the next available loopback: %s", err)
92
-	}
93
-
94
-	// OpenFile adds O_CLOEXEC
95
-	sparseFile, err := osOpenFile(sparseName, osORdWr, 0644)
96
-	if err != nil {
97
-		utils.Errorf("Error openning sparse file %s: %s", sparseName, err)
98
-		return nil, ErrAttachLoopbackDevice
99
-	}
100
-	defer sparseFile.Close()
101
-
102
-	loopFile, err := openNextAvailableLoopback(startIndex, sparseFile)
103
-	if err != nil {
104
-		return nil, err
105
-	}
106
-
107
-	// Set the status of the loopback device
108
-	loopInfo := &LoopInfo64{
109
-		loFileName: stringToLoopName(loopFile.Name()),
110
-		loOffset:   0,
111
-		loFlags:    LoFlagsAutoClear,
112
-	}
113
-
114
-	if err := ioctlLoopSetStatus64(loopFile.Fd(), loopInfo); err != nil {
115
-		utils.Errorf("Cannot set up loopback device info: %s", err)
116
-
117
-		// If the call failed, then free the loopback device
118
-		if err := ioctlLoopClrFd(loopFile.Fd()); err != nil {
119
-			utils.Errorf("Error while cleaning up the loopback device")
120
-		}
121
-		loopFile.Close()
122
-		return nil, ErrAttachLoopbackDevice
123
-	}
124
-
125
-	return loopFile, nil
126
-}
127 1
deleted file mode 100644
... ...
@@ -1,1088 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-import (
6
-	"encoding/json"
7
-	"errors"
8
-	"fmt"
9
-	"github.com/dotcloud/docker/utils"
10
-	"io"
11
-	"io/ioutil"
12
-	"path"
13
-	"path/filepath"
14
-	"strconv"
15
-	"strings"
16
-	"sync"
17
-	"time"
18
-)
19
-
20
-var (
21
-	DefaultDataLoopbackSize     int64  = 100 * 1024 * 1024 * 1024
22
-	DefaultMetaDataLoopbackSize int64  = 2 * 1024 * 1024 * 1024
23
-	DefaultBaseFsSize           uint64 = 10 * 1024 * 1024 * 1024
24
-)
25
-
26
-type DevInfo struct {
27
-	Hash          string     `json:"-"`
28
-	DeviceId      int        `json:"device_id"`
29
-	Size          uint64     `json:"size"`
30
-	TransactionId uint64     `json:"transaction_id"`
31
-	Initialized   bool       `json:"initialized"`
32
-	devices       *DeviceSet `json:"-"`
33
-
34
-	mountCount int    `json:"-"`
35
-	mountPath  string `json:"-"`
36
-	// A floating mount means one reference is not owned and
37
-	// will be stolen by the next mount. This allows us to
38
-	// avoid unmounting directly after creation before the
39
-	// first get (since we need to mount to set up the device
40
-	// a bit first).
41
-	floating bool `json:"-"`
42
-
43
-	// The global DeviceSet lock guarantees that we serialize all
44
-	// the calls to libdevmapper (which is not threadsafe), but we
45
-	// sometimes release that lock while sleeping. In that case
46
-	// this per-device lock is still held, protecting against
47
-	// other accesses to the device that we're doing the wait on.
48
-	lock sync.Mutex `json:"-"`
49
-}
50
-
51
-type MetaData struct {
52
-	Devices map[string]*DevInfo `json:devices`
53
-}
54
-
55
-type DeviceSet struct {
56
-	MetaData
57
-	sync.Mutex       // Protects Devices map and serializes calls into libdevmapper
58
-	root             string
59
-	devicePrefix     string
60
-	TransactionId    uint64
61
-	NewTransactionId uint64
62
-	nextFreeDevice   int
63
-	sawBusy          bool
64
-}
65
-
66
-type DiskUsage struct {
67
-	Used  uint64
68
-	Total uint64
69
-}
70
-
71
-type Status struct {
72
-	PoolName         string
73
-	DataLoopback     string
74
-	MetadataLoopback string
75
-	Data             DiskUsage
76
-	Metadata         DiskUsage
77
-	SectorSize       uint64
78
-}
79
-
80
-type DevStatus struct {
81
-	DeviceId            int
82
-	Size                uint64
83
-	TransactionId       uint64
84
-	SizeInSectors       uint64
85
-	MappedSectors       uint64
86
-	HighestMappedSector uint64
87
-}
88
-
89
-type UnmountMode int
90
-
91
-const (
92
-	UnmountRegular UnmountMode = iota
93
-	UnmountFloat
94
-	UnmountSink
95
-)
96
-
97
-func getDevName(name string) string {
98
-	return "/dev/mapper/" + name
99
-}
100
-
101
-func (info *DevInfo) Name() string {
102
-	hash := info.Hash
103
-	if hash == "" {
104
-		hash = "base"
105
-	}
106
-	return fmt.Sprintf("%s-%s", info.devices.devicePrefix, hash)
107
-}
108
-
109
-func (info *DevInfo) DevName() string {
110
-	return getDevName(info.Name())
111
-}
112
-
113
-func (devices *DeviceSet) loopbackDir() string {
114
-	return path.Join(devices.root, "devicemapper")
115
-}
116
-
117
-func (devices *DeviceSet) jsonFile() string {
118
-	return path.Join(devices.loopbackDir(), "json")
119
-}
120
-
121
-func (devices *DeviceSet) getPoolName() string {
122
-	return devices.devicePrefix + "-pool"
123
-}
124
-
125
-func (devices *DeviceSet) getPoolDevName() string {
126
-	return getDevName(devices.getPoolName())
127
-}
128
-
129
-func (devices *DeviceSet) hasImage(name string) bool {
130
-	dirname := devices.loopbackDir()
131
-	filename := path.Join(dirname, name)
132
-
133
-	_, err := osStat(filename)
134
-	return err == nil
135
-}
136
-
137
-// ensureImage creates a sparse file of <size> bytes at the path
138
-// <root>/devicemapper/<name>.
139
-// If the file already exists, it does nothing.
140
-// Either way it returns the full path.
141
-func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
142
-	dirname := devices.loopbackDir()
143
-	filename := path.Join(dirname, name)
144
-
145
-	if err := osMkdirAll(dirname, 0700); err != nil && !osIsExist(err) {
146
-		return "", err
147
-	}
148
-
149
-	if _, err := osStat(filename); err != nil {
150
-		if !osIsNotExist(err) {
151
-			return "", err
152
-		}
153
-		utils.Debugf("Creating loopback file %s for device-manage use", filename)
154
-		file, err := osOpenFile(filename, osORdWr|osOCreate, 0600)
155
-		if err != nil {
156
-			return "", err
157
-		}
158
-		defer file.Close()
159
-
160
-		if err = file.Truncate(size); err != nil {
161
-			return "", err
162
-		}
163
-	}
164
-	return filename, nil
165
-}
166
-
167
-func (devices *DeviceSet) allocateDeviceId() int {
168
-	// TODO: Add smarter reuse of deleted devices
169
-	id := devices.nextFreeDevice
170
-	devices.nextFreeDevice = devices.nextFreeDevice + 1
171
-	return id
172
-}
173
-
174
-func (devices *DeviceSet) allocateTransactionId() uint64 {
175
-	devices.NewTransactionId = devices.NewTransactionId + 1
176
-	return devices.NewTransactionId
177
-}
178
-
179
-func (devices *DeviceSet) saveMetadata() error {
180
-	jsonData, err := json.Marshal(devices.MetaData)
181
-	if err != nil {
182
-		return fmt.Errorf("Error encoding metadata to json: %s", err)
183
-	}
184
-	tmpFile, err := ioutil.TempFile(filepath.Dir(devices.jsonFile()), ".json")
185
-	if err != nil {
186
-		return fmt.Errorf("Error creating metadata file: %s", err)
187
-	}
188
-
189
-	n, err := tmpFile.Write(jsonData)
190
-	if err != nil {
191
-		return fmt.Errorf("Error writing metadata to %s: %s", tmpFile.Name(), err)
192
-	}
193
-	if n < len(jsonData) {
194
-		return io.ErrShortWrite
195
-	}
196
-	if err := tmpFile.Sync(); err != nil {
197
-		return fmt.Errorf("Error syncing metadata file %s: %s", tmpFile.Name(), err)
198
-	}
199
-	if err := tmpFile.Close(); err != nil {
200
-		return fmt.Errorf("Error closing metadata file %s: %s", tmpFile.Name(), err)
201
-	}
202
-	if err := osRename(tmpFile.Name(), devices.jsonFile()); err != nil {
203
-		return fmt.Errorf("Error committing metadata file %s: %s", tmpFile.Name(), err)
204
-	}
205
-
206
-	if devices.NewTransactionId != devices.TransactionId {
207
-		if err = setTransactionId(devices.getPoolDevName(), devices.TransactionId, devices.NewTransactionId); err != nil {
208
-			return fmt.Errorf("Error setting devmapper transition ID: %s", err)
209
-		}
210
-		devices.TransactionId = devices.NewTransactionId
211
-	}
212
-	return nil
213
-}
214
-
215
-func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*DevInfo, error) {
216
-	utils.Debugf("registerDevice(%v, %v)", id, hash)
217
-	info := &DevInfo{
218
-		Hash:          hash,
219
-		DeviceId:      id,
220
-		Size:          size,
221
-		TransactionId: devices.allocateTransactionId(),
222
-		Initialized:   false,
223
-		devices:       devices,
224
-	}
225
-
226
-	devices.Devices[hash] = info
227
-	if err := devices.saveMetadata(); err != nil {
228
-		// Try to remove unused device
229
-		delete(devices.Devices, hash)
230
-		return nil, err
231
-	}
232
-
233
-	return info, nil
234
-}
235
-
236
-func (devices *DeviceSet) activateDeviceIfNeeded(hash string) error {
237
-	utils.Debugf("activateDeviceIfNeeded(%v)", hash)
238
-	info := devices.Devices[hash]
239
-	if info == nil {
240
-		return fmt.Errorf("Unknown device %s", hash)
241
-	}
242
-
243
-	if devinfo, _ := getInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
244
-		return nil
245
-	}
246
-
247
-	return activateDevice(devices.getPoolDevName(), info.Name(), info.DeviceId, info.Size)
248
-}
249
-
250
-func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
251
-	devname := info.DevName()
252
-
253
-	err := execRun("mkfs.ext4", "-E", "discard,lazy_itable_init=0,lazy_journal_init=0", devname)
254
-	if err != nil {
255
-		err = execRun("mkfs.ext4", "-E", "discard,lazy_itable_init=0", devname)
256
-	}
257
-	if err != nil {
258
-		utils.Debugf("\n--->Err: %s\n", err)
259
-		return err
260
-	}
261
-	return nil
262
-}
263
-
264
-func (devices *DeviceSet) loadMetaData() error {
265
-	utils.Debugf("loadMetadata()")
266
-	defer utils.Debugf("loadMetadata END")
267
-	_, _, _, params, err := getStatus(devices.getPoolName())
268
-	if err != nil {
269
-		utils.Debugf("\n--->Err: %s\n", err)
270
-		return err
271
-	}
272
-
273
-	if _, err := fmt.Sscanf(params, "%d", &devices.TransactionId); err != nil {
274
-		utils.Debugf("\n--->Err: %s\n", err)
275
-		return err
276
-	}
277
-	devices.NewTransactionId = devices.TransactionId
278
-
279
-	jsonData, err := ioutil.ReadFile(devices.jsonFile())
280
-	if err != nil && !osIsNotExist(err) {
281
-		utils.Debugf("\n--->Err: %s\n", err)
282
-		return err
283
-	}
284
-
285
-	devices.MetaData.Devices = make(map[string]*DevInfo)
286
-	if jsonData != nil {
287
-		if err := json.Unmarshal(jsonData, &devices.MetaData); err != nil {
288
-			utils.Debugf("\n--->Err: %s\n", err)
289
-			return err
290
-		}
291
-	}
292
-
293
-	for hash, d := range devices.Devices {
294
-		d.Hash = hash
295
-		d.devices = devices
296
-
297
-		if d.DeviceId >= devices.nextFreeDevice {
298
-			devices.nextFreeDevice = d.DeviceId + 1
299
-		}
300
-
301
-		// If the transaction id is larger than the actual one we lost the device due to some crash
302
-		if d.TransactionId > devices.TransactionId {
303
-			utils.Debugf("Removing lost device %s with id %d", hash, d.TransactionId)
304
-			delete(devices.Devices, hash)
305
-		}
306
-	}
307
-	return nil
308
-}
309
-
310
-func (devices *DeviceSet) setupBaseImage() error {
311
-	oldInfo := devices.Devices[""]
312
-	if oldInfo != nil && oldInfo.Initialized {
313
-		return nil
314
-	}
315
-
316
-	if oldInfo != nil && !oldInfo.Initialized {
317
-		utils.Debugf("Removing uninitialized base image")
318
-		if err := devices.deleteDevice(""); err != nil {
319
-			utils.Debugf("\n--->Err: %s\n", err)
320
-			return err
321
-		}
322
-	}
323
-
324
-	utils.Debugf("Initializing base device-manager snapshot")
325
-
326
-	id := devices.allocateDeviceId()
327
-
328
-	// Create initial device
329
-	if err := createDevice(devices.getPoolDevName(), id); err != nil {
330
-		utils.Debugf("\n--->Err: %s\n", err)
331
-		return err
332
-	}
333
-
334
-	utils.Debugf("Registering base device (id %v) with FS size %v", id, DefaultBaseFsSize)
335
-	info, err := devices.registerDevice(id, "", DefaultBaseFsSize)
336
-	if err != nil {
337
-		_ = deleteDevice(devices.getPoolDevName(), id)
338
-		utils.Debugf("\n--->Err: %s\n", err)
339
-		return err
340
-	}
341
-
342
-	utils.Debugf("Creating filesystem on base device-manager snapshot")
343
-
344
-	if err = devices.activateDeviceIfNeeded(""); err != nil {
345
-		utils.Debugf("\n--->Err: %s\n", err)
346
-		return err
347
-	}
348
-
349
-	if err := devices.createFilesystem(info); err != nil {
350
-		utils.Debugf("\n--->Err: %s\n", err)
351
-		return err
352
-	}
353
-
354
-	info.Initialized = true
355
-	if err = devices.saveMetadata(); err != nil {
356
-		info.Initialized = false
357
-		utils.Debugf("\n--->Err: %s\n", err)
358
-		return err
359
-	}
360
-
361
-	return nil
362
-}
363
-
364
-func setCloseOnExec(name string) {
365
-	if fileInfos, _ := ioutil.ReadDir("/proc/self/fd"); fileInfos != nil {
366
-		for _, i := range fileInfos {
367
-			link, _ := osReadlink(filepath.Join("/proc/self/fd", i.Name()))
368
-			if link == name {
369
-				fd, err := strconv.Atoi(i.Name())
370
-				if err == nil {
371
-					sysCloseOnExec(fd)
372
-				}
373
-			}
374
-		}
375
-	}
376
-}
377
-
378
-func (devices *DeviceSet) log(level int, file string, line int, dmError int, message string) {
379
-	if level >= 7 {
380
-		return // Ignore _LOG_DEBUG
381
-	}
382
-
383
-	if strings.Contains(message, "busy") {
384
-		devices.sawBusy = true
385
-	}
386
-
387
-	utils.Debugf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message)
388
-}
389
-
390
-func major(device uint64) uint64 {
391
-	return (device >> 8) & 0xfff
392
-}
393
-
394
-func minor(device uint64) uint64 {
395
-	return (device & 0xff) | ((device >> 12) & 0xfff00)
396
-}
397
-
398
-func (devices *DeviceSet) ResizePool(size int64) error {
399
-	dirname := devices.loopbackDir()
400
-	datafilename := path.Join(dirname, "data")
401
-	metadatafilename := path.Join(dirname, "metadata")
402
-
403
-	datafile, err := osOpenFile(datafilename, osORdWr, 0)
404
-	if datafile == nil {
405
-		return err
406
-	}
407
-	defer datafile.Close()
408
-
409
-	fi, err := datafile.Stat()
410
-	if fi == nil {
411
-		return err
412
-	}
413
-
414
-	if fi.Size() > size {
415
-		return fmt.Errorf("Can't shrink file")
416
-	}
417
-
418
-	dataloopback := FindLoopDeviceFor(datafile)
419
-	if dataloopback == nil {
420
-		return fmt.Errorf("Unable to find loopback mount for: %s", datafilename)
421
-	}
422
-	defer dataloopback.Close()
423
-
424
-	metadatafile, err := osOpenFile(metadatafilename, osORdWr, 0)
425
-	if metadatafile == nil {
426
-		return err
427
-	}
428
-	defer metadatafile.Close()
429
-
430
-	metadataloopback := FindLoopDeviceFor(metadatafile)
431
-	if metadataloopback == nil {
432
-		return fmt.Errorf("Unable to find loopback mount for: %s", metadatafilename)
433
-	}
434
-	defer metadataloopback.Close()
435
-
436
-	// Grow loopback file
437
-	if err := datafile.Truncate(size); err != nil {
438
-		return fmt.Errorf("Unable to grow loopback file: %s", err)
439
-	}
440
-
441
-	// Reload size for loopback device
442
-	if err := LoopbackSetCapacity(dataloopback); err != nil {
443
-		return fmt.Errorf("Unable to update loopback capacity: %s", err)
444
-	}
445
-
446
-	// Suspend the pool
447
-	if err := suspendDevice(devices.getPoolName()); err != nil {
448
-		return fmt.Errorf("Unable to suspend pool: %s", err)
449
-	}
450
-
451
-	// Reload with the new block sizes
452
-	if err := reloadPool(devices.getPoolName(), dataloopback, metadataloopback); err != nil {
453
-		return fmt.Errorf("Unable to reload pool: %s", err)
454
-	}
455
-
456
-	// Resume the pool
457
-	if err := resumeDevice(devices.getPoolName()); err != nil {
458
-		return fmt.Errorf("Unable to resume pool: %s", err)
459
-	}
460
-
461
-	return nil
462
-}
463
-
464
-func (devices *DeviceSet) initDevmapper(doInit bool) error {
465
-	logInit(devices)
466
-
467
-	// Make sure the sparse images exist in <root>/devicemapper/data and
468
-	// <root>/devicemapper/metadata
469
-
470
-	hasData := devices.hasImage("data")
471
-	hasMetadata := devices.hasImage("metadata")
472
-
473
-	if !doInit && !hasData {
474
-		return errors.New("Loopback data file not found")
475
-	}
476
-
477
-	if !doInit && !hasMetadata {
478
-		return errors.New("Loopback metadata file not found")
479
-	}
480
-
481
-	createdLoopback := !hasData || !hasMetadata
482
-	data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
483
-	if err != nil {
484
-		utils.Debugf("Error device ensureImage (data): %s\n", err)
485
-		return err
486
-	}
487
-	metadata, err := devices.ensureImage("metadata", DefaultMetaDataLoopbackSize)
488
-	if err != nil {
489
-		utils.Debugf("Error device ensureImage (metadata): %s\n", err)
490
-		return err
491
-	}
492
-
493
-	// Set the device prefix from the device id and inode of the docker root dir
494
-
495
-	st, err := osStat(devices.root)
496
-	if err != nil {
497
-		return fmt.Errorf("Error looking up dir %s: %s", devices.root, err)
498
-	}
499
-	sysSt := toSysStatT(st.Sys())
500
-	// "reg-" stands for "regular file".
501
-	// In the future we might use "dev-" for "device file", etc.
502
-	// docker-maj,min[-inode] stands for:
503
-	//	- Managed by docker
504
-	//	- The target of this device is at major <maj> and minor <min>
505
-	//	- If <inode> is defined, use that file inside the device as a loopback image. Otherwise use the device itself.
506
-	devices.devicePrefix = fmt.Sprintf("docker-%d:%d-%d", major(sysSt.Dev), minor(sysSt.Dev), sysSt.Ino)
507
-	utils.Debugf("Generated prefix: %s", devices.devicePrefix)
508
-
509
-	// Check for the existence of the device <prefix>-pool
510
-	utils.Debugf("Checking for existence of the pool '%s'", devices.getPoolName())
511
-	info, err := getInfo(devices.getPoolName())
512
-	if info == nil {
513
-		utils.Debugf("Error device getInfo: %s", err)
514
-		return err
515
-	}
516
-
517
-	// It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files
518
-	// that are not Close-on-exec, and lxc-start will die if it inherits any unexpected files,
519
-	// so we add this badhack to make sure it closes itself
520
-	setCloseOnExec("/dev/mapper/control")
521
-
522
-	// If the pool doesn't exist, create it
523
-	if info.Exists == 0 {
524
-		utils.Debugf("Pool doesn't exist. Creating it.")
525
-
526
-		dataFile, err := attachLoopDevice(data)
527
-		if err != nil {
528
-			utils.Debugf("\n--->Err: %s\n", err)
529
-			return err
530
-		}
531
-		defer dataFile.Close()
532
-
533
-		metadataFile, err := attachLoopDevice(metadata)
534
-		if err != nil {
535
-			utils.Debugf("\n--->Err: %s\n", err)
536
-			return err
537
-		}
538
-		defer metadataFile.Close()
539
-
540
-		if err := createPool(devices.getPoolName(), dataFile, metadataFile); err != nil {
541
-			utils.Debugf("\n--->Err: %s\n", err)
542
-			return err
543
-		}
544
-	}
545
-
546
-	// If we didn't just create the data or metadata image, we need to
547
-	// load the metadata from the existing file.
548
-	if !createdLoopback {
549
-		if err = devices.loadMetaData(); err != nil {
550
-			utils.Debugf("\n--->Err: %s\n", err)
551
-			return err
552
-		}
553
-	}
554
-
555
-	// Setup the base image
556
-	if doInit {
557
-		if err := devices.setupBaseImage(); err != nil {
558
-			utils.Debugf("Error device setupBaseImage: %s\n", err)
559
-			return err
560
-		}
561
-	}
562
-
563
-	return nil
564
-}
565
-
566
-func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
567
-	devices.Lock()
568
-	defer devices.Unlock()
569
-
570
-	if devices.Devices[hash] != nil {
571
-		return fmt.Errorf("hash %s already exists", hash)
572
-	}
573
-
574
-	baseInfo := devices.Devices[baseHash]
575
-	if baseInfo == nil {
576
-		return fmt.Errorf("Error adding device for '%s': can't find device for parent '%s'", hash, baseHash)
577
-	}
578
-
579
-	baseInfo.lock.Lock()
580
-	defer baseInfo.lock.Unlock()
581
-
582
-	deviceId := devices.allocateDeviceId()
583
-
584
-	if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
585
-		utils.Debugf("Error creating snap device: %s\n", err)
586
-		return err
587
-	}
588
-
589
-	if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil {
590
-		deleteDevice(devices.getPoolDevName(), deviceId)
591
-		utils.Debugf("Error registering device: %s\n", err)
592
-		return err
593
-	}
594
-	return nil
595
-}
596
-
597
-func (devices *DeviceSet) deleteDevice(hash string) error {
598
-	info := devices.Devices[hash]
599
-	if info == nil {
600
-		return fmt.Errorf("hash %s doesn't exists", hash)
601
-	}
602
-
603
-	// This is a workaround for the kernel not discarding block so
604
-	// on the thin pool when we remove a thinp device, so we do it
605
-	// manually
606
-	if err := devices.activateDeviceIfNeeded(hash); err == nil {
607
-		if err := BlockDeviceDiscard(info.DevName()); err != nil {
608
-			utils.Debugf("Error discarding block on device: %s (ignoring)\n", err)
609
-		}
610
-	}
611
-
612
-	devinfo, _ := getInfo(info.Name())
613
-	if devinfo != nil && devinfo.Exists != 0 {
614
-		if err := devices.removeDeviceAndWait(info.Name()); err != nil {
615
-			utils.Debugf("Error removing device: %s\n", err)
616
-			return err
617
-		}
618
-	}
619
-
620
-	if info.Initialized {
621
-		info.Initialized = false
622
-		if err := devices.saveMetadata(); err != nil {
623
-			utils.Debugf("Error saving meta data: %s\n", err)
624
-			return err
625
-		}
626
-	}
627
-
628
-	if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
629
-		utils.Debugf("Error deleting device: %s\n", err)
630
-		return err
631
-	}
632
-
633
-	devices.allocateTransactionId()
634
-	delete(devices.Devices, info.Hash)
635
-
636
-	if err := devices.saveMetadata(); err != nil {
637
-		devices.Devices[info.Hash] = info
638
-		utils.Debugf("Error saving meta data: %s\n", err)
639
-		return err
640
-	}
641
-
642
-	return nil
643
-}
644
-
645
-func (devices *DeviceSet) DeleteDevice(hash string) error {
646
-	devices.Lock()
647
-	defer devices.Unlock()
648
-
649
-	info := devices.Devices[hash]
650
-	if info == nil {
651
-		return fmt.Errorf("Unknown device %s", hash)
652
-	}
653
-
654
-	info.lock.Lock()
655
-	defer info.lock.Unlock()
656
-
657
-	return devices.deleteDevice(hash)
658
-}
659
-
660
-func (devices *DeviceSet) deactivatePool() error {
661
-	utils.Debugf("[devmapper] deactivatePool()")
662
-	defer utils.Debugf("[devmapper] deactivatePool END")
663
-	devname := devices.getPoolDevName()
664
-	devinfo, err := getInfo(devname)
665
-	if err != nil {
666
-		utils.Debugf("\n--->Err: %s\n", err)
667
-		return err
668
-	}
669
-	if devinfo.Exists != 0 {
670
-		return removeDevice(devname)
671
-	}
672
-
673
-	return nil
674
-}
675
-
676
-func (devices *DeviceSet) deactivateDevice(hash string) error {
677
-	utils.Debugf("[devmapper] deactivateDevice(%s)", hash)
678
-	defer utils.Debugf("[devmapper] deactivateDevice END")
679
-
680
-	info := devices.Devices[hash]
681
-	if info == nil {
682
-		return fmt.Errorf("Unknown device %s", hash)
683
-	}
684
-	devinfo, err := getInfo(info.Name())
685
-	if err != nil {
686
-		utils.Debugf("\n--->Err: %s\n", err)
687
-		return err
688
-	}
689
-	if devinfo.Exists != 0 {
690
-		if err := devices.removeDeviceAndWait(info.Name()); err != nil {
691
-			utils.Debugf("\n--->Err: %s\n", err)
692
-			return err
693
-		}
694
-	}
695
-
696
-	return nil
697
-}
698
-
699
-// Issues the underlying dm remove operation and then waits
700
-// for it to finish.
701
-func (devices *DeviceSet) removeDeviceAndWait(devname string) error {
702
-	var err error
703
-
704
-	for i := 0; i < 1000; i++ {
705
-		devices.sawBusy = false
706
-		err = removeDevice(devname)
707
-		if err == nil {
708
-			break
709
-		}
710
-		if !devices.sawBusy {
711
-			return err
712
-		}
713
-
714
-		// If we see EBUSY it may be a transient error,
715
-		// sleep a bit a retry a few times.
716
-		devices.Unlock()
717
-		time.Sleep(10 * time.Millisecond)
718
-		devices.Lock()
719
-	}
720
-	if err != nil {
721
-		return err
722
-	}
723
-
724
-	if err := devices.waitRemove(devname); err != nil {
725
-		return err
726
-	}
727
-	return nil
728
-}
729
-
730
-// waitRemove blocks until either:
731
-// a) the device registered at <device_set_prefix>-<hash> is removed,
732
-// or b) the 1 second timeout expires.
733
-func (devices *DeviceSet) waitRemove(devname string) error {
734
-	utils.Debugf("[deviceset %s] waitRemove(%s)", devices.devicePrefix, devname)
735
-	defer utils.Debugf("[deviceset %s] waitRemove(%s) END", devices.devicePrefix, devname)
736
-	i := 0
737
-	for ; i < 1000; i += 1 {
738
-		devinfo, err := getInfo(devname)
739
-		if err != nil {
740
-			// If there is an error we assume the device doesn't exist.
741
-			// The error might actually be something else, but we can't differentiate.
742
-			return nil
743
-		}
744
-		if i%100 == 0 {
745
-			utils.Debugf("Waiting for removal of %s: exists=%d", devname, devinfo.Exists)
746
-		}
747
-		if devinfo.Exists == 0 {
748
-			break
749
-		}
750
-
751
-		devices.Unlock()
752
-		time.Sleep(10 * time.Millisecond)
753
-		devices.Lock()
754
-	}
755
-	if i == 1000 {
756
-		return fmt.Errorf("Timeout while waiting for device %s to be removed", devname)
757
-	}
758
-	return nil
759
-}
760
-
761
-// waitClose blocks until either:
762
-// a) the device registered at <device_set_prefix>-<hash> is closed,
763
-// or b) the 1 second timeout expires.
764
-func (devices *DeviceSet) waitClose(hash string) error {
765
-	info := devices.Devices[hash]
766
-	if info == nil {
767
-		return fmt.Errorf("Unknown device %s", hash)
768
-	}
769
-	i := 0
770
-	for ; i < 1000; i += 1 {
771
-		devinfo, err := getInfo(info.Name())
772
-		if err != nil {
773
-			return err
774
-		}
775
-		if i%100 == 0 {
776
-			utils.Debugf("Waiting for unmount of %s: opencount=%d", hash, devinfo.OpenCount)
777
-		}
778
-		if devinfo.OpenCount == 0 {
779
-			break
780
-		}
781
-		time.Sleep(1 * time.Millisecond)
782
-	}
783
-	if i == 1000 {
784
-		return fmt.Errorf("Timeout while waiting for device %s to close", hash)
785
-	}
786
-	return nil
787
-}
788
-
789
-func (devices *DeviceSet) Shutdown() error {
790
-	devices.Lock()
791
-	defer devices.Unlock()
792
-
793
-	utils.Debugf("[deviceset %s] shutdown()", devices.devicePrefix)
794
-	utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
795
-	defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
796
-
797
-	for _, info := range devices.Devices {
798
-		info.lock.Lock()
799
-		if info.mountCount > 0 {
800
-			if err := sysUnmount(info.mountPath, 0); err != nil {
801
-				utils.Debugf("Shutdown unmounting %s, error: %s\n", info.mountPath, err)
802
-			}
803
-		}
804
-		info.lock.Unlock()
805
-	}
806
-
807
-	for _, d := range devices.Devices {
808
-		d.lock.Lock()
809
-
810
-		if err := devices.waitClose(d.Hash); err != nil {
811
-			utils.Errorf("Warning: error waiting for device %s to unmount: %s\n", d.Hash, err)
812
-		}
813
-		if err := devices.deactivateDevice(d.Hash); err != nil {
814
-			utils.Debugf("Shutdown deactivate %s , error: %s\n", d.Hash, err)
815
-		}
816
-
817
-		d.lock.Unlock()
818
-	}
819
-
820
-	if err := devices.deactivatePool(); err != nil {
821
-		utils.Debugf("Shutdown deactivate pool , error: %s\n", err)
822
-	}
823
-
824
-	return nil
825
-}
826
-
827
-func (devices *DeviceSet) MountDevice(hash, path string) error {
828
-	devices.Lock()
829
-	defer devices.Unlock()
830
-
831
-	info := devices.Devices[hash]
832
-	if info == nil {
833
-		return fmt.Errorf("Unknown device %s", hash)
834
-	}
835
-
836
-	info.lock.Lock()
837
-	defer info.lock.Unlock()
838
-
839
-	if info.mountCount > 0 {
840
-		if path != info.mountPath {
841
-			return fmt.Errorf("Trying to mount devmapper device in multple places (%s, %s)", info.mountPath, path)
842
-		}
843
-
844
-		if info.floating {
845
-			// Steal floating ref
846
-			info.floating = false
847
-		} else {
848
-			info.mountCount++
849
-		}
850
-		return nil
851
-	}
852
-
853
-	if err := devices.activateDeviceIfNeeded(hash); err != nil {
854
-		return fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
855
-	}
856
-
857
-	var flags uintptr = sysMsMgcVal
858
-
859
-	err := sysMount(info.DevName(), path, "ext4", flags, "discard")
860
-	if err != nil && err == sysEInval {
861
-		err = sysMount(info.DevName(), path, "ext4", flags, "")
862
-	}
863
-	if err != nil {
864
-		return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err)
865
-	}
866
-
867
-	info.mountCount = 1
868
-	info.mountPath = path
869
-	info.floating = false
870
-
871
-	return devices.setInitialized(hash)
872
-}
873
-
874
-func (devices *DeviceSet) UnmountDevice(hash string, mode UnmountMode) error {
875
-	utils.Debugf("[devmapper] UnmountDevice(hash=%s, mode=%d)", hash, mode)
876
-	defer utils.Debugf("[devmapper] UnmountDevice END")
877
-	devices.Lock()
878
-	defer devices.Unlock()
879
-
880
-	info := devices.Devices[hash]
881
-	if info == nil {
882
-		return fmt.Errorf("UnmountDevice: no such device %s\n", hash)
883
-	}
884
-
885
-	info.lock.Lock()
886
-	defer info.lock.Unlock()
887
-
888
-	if mode == UnmountFloat {
889
-		if info.floating {
890
-			return fmt.Errorf("UnmountDevice: can't float floating reference %s\n", hash)
891
-		}
892
-
893
-		// Leave this reference floating
894
-		info.floating = true
895
-		return nil
896
-	}
897
-
898
-	if mode == UnmountSink {
899
-		if !info.floating {
900
-			// Someone already sunk this
901
-			return nil
902
-		}
903
-		// Otherwise, treat this as a regular unmount
904
-	}
905
-
906
-	if info.mountCount == 0 {
907
-		return fmt.Errorf("UnmountDevice: device not-mounted id %s\n", hash)
908
-	}
909
-
910
-	info.mountCount--
911
-	if info.mountCount > 0 {
912
-		return nil
913
-	}
914
-
915
-	utils.Debugf("[devmapper] Unmount(%s)", info.mountPath)
916
-	if err := sysUnmount(info.mountPath, 0); err != nil {
917
-		utils.Debugf("\n--->Err: %s\n", err)
918
-		return err
919
-	}
920
-	utils.Debugf("[devmapper] Unmount done")
921
-	// Wait for the unmount to be effective,
922
-	// by watching the value of Info.OpenCount for the device
923
-	if err := devices.waitClose(hash); err != nil {
924
-		return err
925
-	}
926
-
927
-	devices.deactivateDevice(hash)
928
-
929
-	info.mountPath = ""
930
-
931
-	return nil
932
-}
933
-
934
-func (devices *DeviceSet) HasDevice(hash string) bool {
935
-	devices.Lock()
936
-	defer devices.Unlock()
937
-
938
-	return devices.Devices[hash] != nil
939
-}
940
-
941
-func (devices *DeviceSet) HasInitializedDevice(hash string) bool {
942
-	devices.Lock()
943
-	defer devices.Unlock()
944
-
945
-	info := devices.Devices[hash]
946
-	return info != nil && info.Initialized
947
-}
948
-
949
-func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
950
-	devices.Lock()
951
-	defer devices.Unlock()
952
-
953
-	info := devices.Devices[hash]
954
-	if info == nil {
955
-		return false
956
-	}
957
-
958
-	info.lock.Lock()
959
-	defer info.lock.Unlock()
960
-
961
-	devinfo, _ := getInfo(info.Name())
962
-	return devinfo != nil && devinfo.Exists != 0
963
-}
964
-
965
-func (devices *DeviceSet) setInitialized(hash string) error {
966
-	info := devices.Devices[hash]
967
-	if info == nil {
968
-		return fmt.Errorf("Unknown device %s", hash)
969
-	}
970
-
971
-	info.Initialized = true
972
-	if err := devices.saveMetadata(); err != nil {
973
-		info.Initialized = false
974
-		utils.Debugf("\n--->Err: %s\n", err)
975
-		return err
976
-	}
977
-
978
-	return nil
979
-}
980
-
981
-func (devices *DeviceSet) List() []string {
982
-	devices.Lock()
983
-	defer devices.Unlock()
984
-
985
-	ids := make([]string, len(devices.Devices))
986
-	i := 0
987
-	for k := range devices.Devices {
988
-		ids[i] = k
989
-		i++
990
-	}
991
-	return ids
992
-}
993
-
994
-func (devices *DeviceSet) deviceStatus(devName string) (sizeInSectors, mappedSectors, highestMappedSector uint64, err error) {
995
-	var params string
996
-	_, sizeInSectors, _, params, err = getStatus(devName)
997
-	if err != nil {
998
-		return
999
-	}
1000
-	if _, err = fmt.Sscanf(params, "%d %d", &mappedSectors, &highestMappedSector); err == nil {
1001
-		return
1002
-	}
1003
-	return
1004
-}
1005
-
1006
-func (devices *DeviceSet) GetDeviceStatus(hash string) (*DevStatus, error) {
1007
-	devices.Lock()
1008
-	defer devices.Unlock()
1009
-
1010
-	info := devices.Devices[hash]
1011
-	if info == nil {
1012
-		return nil, fmt.Errorf("No device %s", hash)
1013
-	}
1014
-
1015
-	info.lock.Lock()
1016
-	defer info.lock.Unlock()
1017
-
1018
-	status := &DevStatus{
1019
-		DeviceId:      info.DeviceId,
1020
-		Size:          info.Size,
1021
-		TransactionId: info.TransactionId,
1022
-	}
1023
-
1024
-	if err := devices.activateDeviceIfNeeded(hash); err != nil {
1025
-		return nil, fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
1026
-	}
1027
-
1028
-	if sizeInSectors, mappedSectors, highestMappedSector, err := devices.deviceStatus(info.DevName()); err != nil {
1029
-		return nil, err
1030
-	} else {
1031
-		status.SizeInSectors = sizeInSectors
1032
-		status.MappedSectors = mappedSectors
1033
-		status.HighestMappedSector = highestMappedSector
1034
-	}
1035
-
1036
-	return status, nil
1037
-}
1038
-
1039
-func (devices *DeviceSet) poolStatus() (totalSizeInSectors, transactionId, dataUsed, dataTotal, metadataUsed, metadataTotal uint64, err error) {
1040
-	var params string
1041
-	if _, totalSizeInSectors, _, params, err = getStatus(devices.getPoolName()); err == nil {
1042
-		_, err = fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionId, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal)
1043
-	}
1044
-	return
1045
-}
1046
-
1047
-func (devices *DeviceSet) Status() *Status {
1048
-	devices.Lock()
1049
-	defer devices.Unlock()
1050
-
1051
-	status := &Status{}
1052
-
1053
-	status.PoolName = devices.getPoolName()
1054
-	status.DataLoopback = path.Join(devices.loopbackDir(), "data")
1055
-	status.MetadataLoopback = path.Join(devices.loopbackDir(), "metadata")
1056
-
1057
-	totalSizeInSectors, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus()
1058
-	if err == nil {
1059
-		// Convert from blocks to bytes
1060
-		blockSizeInSectors := totalSizeInSectors / dataTotal
1061
-
1062
-		status.Data.Used = dataUsed * blockSizeInSectors * 512
1063
-		status.Data.Total = dataTotal * blockSizeInSectors * 512
1064
-
1065
-		// metadata blocks are always 4k
1066
-		status.Metadata.Used = metadataUsed * 4096
1067
-		status.Metadata.Total = metadataTotal * 4096
1068
-
1069
-		status.SectorSize = blockSizeInSectors * 512
1070
-	}
1071
-
1072
-	return status
1073
-}
1074
-
1075
-func NewDeviceSet(root string, doInit bool) (*DeviceSet, error) {
1076
-	SetDevDir("/dev")
1077
-
1078
-	devices := &DeviceSet{
1079
-		root:     root,
1080
-		MetaData: MetaData{Devices: make(map[string]*DevInfo)},
1081
-	}
1082
-
1083
-	if err := devices.initDevmapper(doInit); err != nil {
1084
-		return nil, err
1085
-	}
1086
-
1087
-	return devices, nil
1088
-}
1089 1
deleted file mode 100644
... ...
@@ -1,595 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-import (
6
-	"errors"
7
-	"fmt"
8
-	"github.com/dotcloud/docker/utils"
9
-	"runtime"
10
-	"syscall"
11
-)
12
-
13
-type DevmapperLogger interface {
14
-	log(level int, file string, line int, dmError int, message string)
15
-}
16
-
17
-const (
18
-	DeviceCreate TaskType = iota
19
-	DeviceReload
20
-	DeviceRemove
21
-	DeviceRemoveAll
22
-	DeviceSuspend
23
-	DeviceResume
24
-	DeviceInfo
25
-	DeviceDeps
26
-	DeviceRename
27
-	DeviceVersion
28
-	DeviceStatus
29
-	DeviceTable
30
-	DeviceWaitevent
31
-	DeviceList
32
-	DeviceClear
33
-	DeviceMknodes
34
-	DeviceListVersions
35
-	DeviceTargetMsg
36
-	DeviceSetGeometry
37
-)
38
-
39
-const (
40
-	AddNodeOnResume AddNodeType = iota
41
-	AddNodeOnCreate
42
-)
43
-
44
-var (
45
-	ErrTaskRun                = errors.New("dm_task_run failed")
46
-	ErrTaskSetName            = errors.New("dm_task_set_name failed")
47
-	ErrTaskSetMessage         = errors.New("dm_task_set_message failed")
48
-	ErrTaskSetAddNode         = errors.New("dm_task_set_add_node failed")
49
-	ErrTaskSetRo              = errors.New("dm_task_set_ro failed")
50
-	ErrTaskAddTarget          = errors.New("dm_task_add_target failed")
51
-	ErrTaskSetSector          = errors.New("dm_task_set_sector failed")
52
-	ErrTaskGetInfo            = errors.New("dm_task_get_info failed")
53
-	ErrTaskSetCookie          = errors.New("dm_task_set_cookie failed")
54
-	ErrNilCookie              = errors.New("cookie ptr can't be nil")
55
-	ErrAttachLoopbackDevice   = errors.New("loopback mounting failed")
56
-	ErrGetBlockSize           = errors.New("Can't get block size")
57
-	ErrUdevWait               = errors.New("wait on udev cookie failed")
58
-	ErrSetDevDir              = errors.New("dm_set_dev_dir failed")
59
-	ErrGetLibraryVersion      = errors.New("dm_get_library_version failed")
60
-	ErrCreateRemoveTask       = errors.New("Can't create task of type DeviceRemove")
61
-	ErrRunRemoveDevice        = errors.New("running removeDevice failed")
62
-	ErrInvalidAddNode         = errors.New("Invalide AddNoce type")
63
-	ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
64
-	ErrLoopbackSetCapacity    = errors.New("Unable set loopback capacity")
65
-)
66
-
67
-type (
68
-	Task struct {
69
-		unmanaged *CDmTask
70
-	}
71
-	Info struct {
72
-		Exists        int
73
-		Suspended     int
74
-		LiveTable     int
75
-		InactiveTable int
76
-		OpenCount     int32
77
-		EventNr       uint32
78
-		Major         uint32
79
-		Minor         uint32
80
-		ReadOnly      int
81
-		TargetCount   int32
82
-	}
83
-	TaskType    int
84
-	AddNodeType int
85
-)
86
-
87
-func (t *Task) destroy() {
88
-	if t != nil {
89
-		DmTaskDestroy(t.unmanaged)
90
-		runtime.SetFinalizer(t, nil)
91
-	}
92
-}
93
-
94
-func TaskCreate(tasktype TaskType) *Task {
95
-	Ctask := DmTaskCreate(int(tasktype))
96
-	if Ctask == nil {
97
-		return nil
98
-	}
99
-	task := &Task{unmanaged: Ctask}
100
-	runtime.SetFinalizer(task, (*Task).destroy)
101
-	return task
102
-}
103
-
104
-func (t *Task) Run() error {
105
-	if res := DmTaskRun(t.unmanaged); res != 1 {
106
-		return ErrTaskRun
107
-	}
108
-	return nil
109
-}
110
-
111
-func (t *Task) SetName(name string) error {
112
-	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
113
-		return ErrTaskSetName
114
-	}
115
-	return nil
116
-}
117
-
118
-func (t *Task) SetMessage(message string) error {
119
-	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
120
-		return ErrTaskSetMessage
121
-	}
122
-	return nil
123
-}
124
-
125
-func (t *Task) SetSector(sector uint64) error {
126
-	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
127
-		return ErrTaskSetSector
128
-	}
129
-	return nil
130
-}
131
-
132
-func (t *Task) SetCookie(cookie *uint, flags uint16) error {
133
-	if cookie == nil {
134
-		return ErrNilCookie
135
-	}
136
-	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
137
-		return ErrTaskSetCookie
138
-	}
139
-	return nil
140
-}
141
-
142
-func (t *Task) SetAddNode(addNode AddNodeType) error {
143
-	if addNode != AddNodeOnResume && addNode != AddNodeOnCreate {
144
-		return ErrInvalidAddNode
145
-	}
146
-	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
147
-		return ErrTaskSetAddNode
148
-	}
149
-	return nil
150
-}
151
-
152
-func (t *Task) SetRo() error {
153
-	if res := DmTaskSetRo(t.unmanaged); res != 1 {
154
-		return ErrTaskSetRo
155
-	}
156
-	return nil
157
-}
158
-
159
-func (t *Task) AddTarget(start, size uint64, ttype, params string) error {
160
-	if res := DmTaskAddTarget(t.unmanaged, start, size,
161
-		ttype, params); res != 1 {
162
-		return ErrTaskAddTarget
163
-	}
164
-	return nil
165
-}
166
-
167
-func (t *Task) GetInfo() (*Info, error) {
168
-	info := &Info{}
169
-	if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
170
-		return nil, ErrTaskGetInfo
171
-	}
172
-	return info, nil
173
-}
174
-
175
-func (t *Task) GetNextTarget(next uintptr) (nextPtr uintptr, start uint64,
176
-	length uint64, targetType string, params string) {
177
-
178
-	return DmGetNextTarget(t.unmanaged, next, &start, &length,
179
-			&targetType, &params),
180
-		start, length, targetType, params
181
-}
182
-
183
-func getLoopbackBackingFile(file *osFile) (uint64, uint64, error) {
184
-	loopInfo, err := ioctlLoopGetStatus64(file.Fd())
185
-	if err != nil {
186
-		utils.Errorf("Error get loopback backing file: %s\n", err)
187
-		return 0, 0, ErrGetLoopbackBackingFile
188
-	}
189
-	return loopInfo.loDevice, loopInfo.loInode, nil
190
-}
191
-
192
-func LoopbackSetCapacity(file *osFile) error {
193
-	if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
194
-		utils.Errorf("Error loopbackSetCapacity: %s", err)
195
-		return ErrLoopbackSetCapacity
196
-	}
197
-	return nil
198
-}
199
-
200
-func FindLoopDeviceFor(file *osFile) *osFile {
201
-	stat, err := file.Stat()
202
-	if err != nil {
203
-		return nil
204
-	}
205
-	targetInode := stat.Sys().(*sysStatT).Ino
206
-	targetDevice := stat.Sys().(*sysStatT).Dev
207
-
208
-	for i := 0; true; i++ {
209
-		path := fmt.Sprintf("/dev/loop%d", i)
210
-
211
-		file, err := osOpenFile(path, osORdWr, 0)
212
-		if err != nil {
213
-			if osIsNotExist(err) {
214
-				return nil
215
-			}
216
-
217
-			// Ignore all errors until the first not-exist
218
-			// we want to continue looking for the file
219
-			continue
220
-		}
221
-
222
-		dev, inode, err := getLoopbackBackingFile(file)
223
-		if err == nil && dev == targetDevice && inode == targetInode {
224
-			return file
225
-		}
226
-		file.Close()
227
-	}
228
-
229
-	return nil
230
-}
231
-
232
-func UdevWait(cookie uint) error {
233
-	if res := DmUdevWait(cookie); res != 1 {
234
-		utils.Debugf("Failed to wait on udev cookie %d", cookie)
235
-		return ErrUdevWait
236
-	}
237
-	return nil
238
-}
239
-
240
-func LogInitVerbose(level int) {
241
-	DmLogInitVerbose(level)
242
-}
243
-
244
-var dmLogger DevmapperLogger = nil
245
-
246
-func logInit(logger DevmapperLogger) {
247
-	dmLogger = logger
248
-	LogWithErrnoInit()
249
-}
250
-
251
-func SetDevDir(dir string) error {
252
-	if res := DmSetDevDir(dir); res != 1 {
253
-		utils.Debugf("Error dm_set_dev_dir")
254
-		return ErrSetDevDir
255
-	}
256
-	return nil
257
-}
258
-
259
-func GetLibraryVersion() (string, error) {
260
-	var version string
261
-	if res := DmGetLibraryVersion(&version); res != 1 {
262
-		return "", ErrGetLibraryVersion
263
-	}
264
-	return version, nil
265
-}
266
-
267
-// Useful helper for cleanup
268
-func RemoveDevice(name string) error {
269
-	task := TaskCreate(DeviceRemove)
270
-	if task == nil {
271
-		return ErrCreateRemoveTask
272
-	}
273
-	if err := task.SetName(name); err != nil {
274
-		utils.Debugf("Can't set task name %s", name)
275
-		return err
276
-	}
277
-	if err := task.Run(); err != nil {
278
-		return ErrRunRemoveDevice
279
-	}
280
-	return nil
281
-}
282
-
283
-func GetBlockDeviceSize(file *osFile) (uint64, error) {
284
-	size, err := ioctlBlkGetSize64(file.Fd())
285
-	if err != nil {
286
-		utils.Errorf("Error getblockdevicesize: %s", err)
287
-		return 0, ErrGetBlockSize
288
-	}
289
-	return uint64(size), nil
290
-}
291
-
292
-func BlockDeviceDiscard(path string) error {
293
-	file, err := osOpenFile(path, osORdWr, 0)
294
-	if err != nil {
295
-		return err
296
-	}
297
-	defer file.Close()
298
-
299
-	size, err := GetBlockDeviceSize(file)
300
-	if err != nil {
301
-		return err
302
-	}
303
-
304
-	if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil {
305
-		return err
306
-	}
307
-
308
-	// Without this sometimes the remove of the device that happens after
309
-	// discard fails with EBUSY.
310
-	syscall.Sync()
311
-
312
-	return nil
313
-}
314
-
315
-// This is the programmatic example of "dmsetup create"
316
-func createPool(poolName string, dataFile, metadataFile *osFile) error {
317
-	task, err := createTask(DeviceCreate, poolName)
318
-	if task == nil {
319
-		return err
320
-	}
321
-
322
-	size, err := GetBlockDeviceSize(dataFile)
323
-	if err != nil {
324
-		return fmt.Errorf("Can't get data size")
325
-	}
326
-
327
-	params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768 1 skip_block_zeroing"
328
-	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
329
-		return fmt.Errorf("Can't add target")
330
-	}
331
-
332
-	var cookie uint = 0
333
-	if err := task.SetCookie(&cookie, 0); err != nil {
334
-		return fmt.Errorf("Can't set cookie")
335
-	}
336
-
337
-	if err := task.Run(); err != nil {
338
-		return fmt.Errorf("Error running DeviceCreate (createPool)")
339
-	}
340
-
341
-	UdevWait(cookie)
342
-
343
-	return nil
344
-}
345
-
346
-func reloadPool(poolName string, dataFile, metadataFile *osFile) error {
347
-	task, err := createTask(DeviceReload, poolName)
348
-	if task == nil {
349
-		return err
350
-	}
351
-
352
-	size, err := GetBlockDeviceSize(dataFile)
353
-	if err != nil {
354
-		return fmt.Errorf("Can't get data size")
355
-	}
356
-
357
-	params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
358
-	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
359
-		return fmt.Errorf("Can't add target")
360
-	}
361
-
362
-	if err := task.Run(); err != nil {
363
-		return fmt.Errorf("Error running DeviceCreate")
364
-	}
365
-
366
-	return nil
367
-}
368
-
369
-func createTask(t TaskType, name string) (*Task, error) {
370
-	task := TaskCreate(t)
371
-	if task == nil {
372
-		return nil, fmt.Errorf("Can't create task of type %d", int(t))
373
-	}
374
-	if err := task.SetName(name); err != nil {
375
-		return nil, fmt.Errorf("Can't set task name %s", name)
376
-	}
377
-	return task, nil
378
-}
379
-
380
-func getInfo(name string) (*Info, error) {
381
-	task, err := createTask(DeviceInfo, name)
382
-	if task == nil {
383
-		return nil, err
384
-	}
385
-	if err := task.Run(); err != nil {
386
-		return nil, err
387
-	}
388
-	return task.GetInfo()
389
-}
390
-
391
-func getStatus(name string) (uint64, uint64, string, string, error) {
392
-	task, err := createTask(DeviceStatus, name)
393
-	if task == nil {
394
-		utils.Debugf("getStatus: Error createTask: %s", err)
395
-		return 0, 0, "", "", err
396
-	}
397
-	if err := task.Run(); err != nil {
398
-		utils.Debugf("getStatus: Error Run: %s", err)
399
-		return 0, 0, "", "", err
400
-	}
401
-
402
-	devinfo, err := task.GetInfo()
403
-	if err != nil {
404
-		utils.Debugf("getStatus: Error GetInfo: %s", err)
405
-		return 0, 0, "", "", err
406
-	}
407
-	if devinfo.Exists == 0 {
408
-		utils.Debugf("getStatus: Non existing device %s", name)
409
-		return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
410
-	}
411
-
412
-	_, start, length, targetType, params := task.GetNextTarget(0)
413
-	return start, length, targetType, params, nil
414
-}
415
-
416
-func setTransactionId(poolName string, oldId uint64, newId uint64) error {
417
-	task, err := createTask(DeviceTargetMsg, poolName)
418
-	if task == nil {
419
-		return err
420
-	}
421
-
422
-	if err := task.SetSector(0); err != nil {
423
-		return fmt.Errorf("Can't set sector")
424
-	}
425
-
426
-	if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
427
-		return fmt.Errorf("Can't set message")
428
-	}
429
-
430
-	if err := task.Run(); err != nil {
431
-		return fmt.Errorf("Error running setTransactionId")
432
-	}
433
-	return nil
434
-}
435
-
436
-func suspendDevice(name string) error {
437
-	task, err := createTask(DeviceSuspend, name)
438
-	if task == nil {
439
-		return err
440
-	}
441
-	if err := task.Run(); err != nil {
442
-		return fmt.Errorf("Error running DeviceSuspend: %s", err)
443
-	}
444
-	return nil
445
-}
446
-
447
-func resumeDevice(name string) error {
448
-	task, err := createTask(DeviceResume, name)
449
-	if task == nil {
450
-		return err
451
-	}
452
-
453
-	var cookie uint = 0
454
-	if err := task.SetCookie(&cookie, 0); err != nil {
455
-		return fmt.Errorf("Can't set cookie")
456
-	}
457
-
458
-	if err := task.Run(); err != nil {
459
-		return fmt.Errorf("Error running DeviceResume")
460
-	}
461
-
462
-	UdevWait(cookie)
463
-
464
-	return nil
465
-}
466
-
467
-func createDevice(poolName string, deviceId int) error {
468
-	utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
469
-	task, err := createTask(DeviceTargetMsg, poolName)
470
-	if task == nil {
471
-		return err
472
-	}
473
-
474
-	if err := task.SetSector(0); err != nil {
475
-		return fmt.Errorf("Can't set sector")
476
-	}
477
-
478
-	if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
479
-		return fmt.Errorf("Can't set message")
480
-	}
481
-
482
-	if err := task.Run(); err != nil {
483
-		return fmt.Errorf("Error running createDevice")
484
-	}
485
-	return nil
486
-}
487
-
488
-func deleteDevice(poolName string, deviceId int) error {
489
-	task, err := createTask(DeviceTargetMsg, poolName)
490
-	if task == nil {
491
-		return err
492
-	}
493
-
494
-	if err := task.SetSector(0); err != nil {
495
-		return fmt.Errorf("Can't set sector")
496
-	}
497
-
498
-	if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
499
-		return fmt.Errorf("Can't set message")
500
-	}
501
-
502
-	if err := task.Run(); err != nil {
503
-		return fmt.Errorf("Error running deleteDevice")
504
-	}
505
-	return nil
506
-}
507
-
508
-func removeDevice(name string) error {
509
-	utils.Debugf("[devmapper] removeDevice START")
510
-	defer utils.Debugf("[devmapper] removeDevice END")
511
-	task, err := createTask(DeviceRemove, name)
512
-	if task == nil {
513
-		return err
514
-	}
515
-	if err = task.Run(); err != nil {
516
-		return fmt.Errorf("Error running removeDevice")
517
-	}
518
-	return nil
519
-}
520
-
521
-func activateDevice(poolName string, name string, deviceId int, size uint64) error {
522
-	task, err := createTask(DeviceCreate, name)
523
-	if task == nil {
524
-		return err
525
-	}
526
-
527
-	params := fmt.Sprintf("%s %d", poolName, deviceId)
528
-	if err := task.AddTarget(0, size/512, "thin", params); err != nil {
529
-		return fmt.Errorf("Can't add target")
530
-	}
531
-	if err := task.SetAddNode(AddNodeOnCreate); err != nil {
532
-		return fmt.Errorf("Can't add node")
533
-	}
534
-
535
-	var cookie uint = 0
536
-	if err := task.SetCookie(&cookie, 0); err != nil {
537
-		return fmt.Errorf("Can't set cookie")
538
-	}
539
-
540
-	if err := task.Run(); err != nil {
541
-		return fmt.Errorf("Error running DeviceCreate (activateDevice)")
542
-	}
543
-
544
-	UdevWait(cookie)
545
-
546
-	return nil
547
-}
548
-
549
-func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
550
-	devinfo, _ := getInfo(baseName)
551
-	doSuspend := devinfo != nil && devinfo.Exists != 0
552
-
553
-	if doSuspend {
554
-		if err := suspendDevice(baseName); err != nil {
555
-			return err
556
-		}
557
-	}
558
-
559
-	task, err := createTask(DeviceTargetMsg, poolName)
560
-	if task == nil {
561
-		if doSuspend {
562
-			resumeDevice(baseName)
563
-		}
564
-		return err
565
-	}
566
-
567
-	if err := task.SetSector(0); err != nil {
568
-		if doSuspend {
569
-			resumeDevice(baseName)
570
-		}
571
-		return fmt.Errorf("Can't set sector")
572
-	}
573
-
574
-	if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
575
-		if doSuspend {
576
-			resumeDevice(baseName)
577
-		}
578
-		return fmt.Errorf("Can't set message")
579
-	}
580
-
581
-	if err := task.Run(); err != nil {
582
-		if doSuspend {
583
-			resumeDevice(baseName)
584
-		}
585
-		return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
586
-	}
587
-
588
-	if doSuspend {
589
-		if err := resumeDevice(baseName); err != nil {
590
-			return err
591
-		}
592
-	}
593
-
594
-	return nil
595
-}
596 1
deleted file mode 100644
... ...
@@ -1,106 +0,0 @@
1
-package devmapper
2
-
3
-// Definition of struct dm_task and sub structures (from lvm2)
4
-//
5
-// struct dm_ioctl {
6
-// 	/*
7
-// 	 * The version number is made up of three parts:
8
-// 	 * major - no backward or forward compatibility,
9
-// 	 * minor - only backwards compatible,
10
-// 	 * patch - both backwards and forwards compatible.
11
-// 	 *
12
-// 	 * All clients of the ioctl interface should fill in the
13
-// 	 * version number of the interface that they were
14
-// 	 * compiled with.
15
-// 	 *
16
-// 	 * All recognised ioctl commands (ie. those that don't
17
-// 	 * return -ENOTTY) fill out this field, even if the
18
-// 	 * command failed.
19
-// 	 */
20
-// 	uint32_t version[3];	/* in/out */
21
-// 	uint32_t data_size;	/* total size of data passed in
22
-// 				 * including this struct */
23
-
24
-// 	uint32_t data_start;	/* offset to start of data
25
-// 				 * relative to start of this struct */
26
-
27
-// 	uint32_t target_count;	/* in/out */
28
-// 	int32_t open_count;	/* out */
29
-// 	uint32_t flags;		/* in/out */
30
-
31
-// 	/*
32
-// 	 * event_nr holds either the event number (input and output) or the
33
-// 	 * udev cookie value (input only).
34
-// 	 * The DM_DEV_WAIT ioctl takes an event number as input.
35
-// 	 * The DM_SUSPEND, DM_DEV_REMOVE and DM_DEV_RENAME ioctls
36
-// 	 * use the field as a cookie to return in the DM_COOKIE
37
-// 	 * variable with the uevents they issue.
38
-// 	 * For output, the ioctls return the event number, not the cookie.
39
-// 	 */
40
-// 	uint32_t event_nr;      	/* in/out */
41
-// 	uint32_t padding;
42
-
43
-// 	uint64_t dev;		/* in/out */
44
-
45
-// 	char name[DM_NAME_LEN];	/* device name */
46
-// 	char uuid[DM_UUID_LEN];	/* unique identifier for
47
-// 				 * the block device */
48
-// 	char data[7];		/* padding or data */
49
-// };
50
-
51
-// struct target {
52
-// 	uint64_t start;
53
-// 	uint64_t length;
54
-// 	char *type;
55
-// 	char *params;
56
-
57
-// 	struct target *next;
58
-// };
59
-
60
-// typedef enum {
61
-// 	DM_ADD_NODE_ON_RESUME, /* add /dev/mapper node with dmsetup resume */
62
-// 	DM_ADD_NODE_ON_CREATE  /* add /dev/mapper node with dmsetup create */
63
-// } dm_add_node_t;
64
-
65
-// struct dm_task {
66
-// 	int type;
67
-// 	char *dev_name;
68
-// 	char *mangled_dev_name;
69
-
70
-// 	struct target *head, *tail;
71
-
72
-// 	int read_only;
73
-// 	uint32_t event_nr;
74
-// 	int major;
75
-// 	int minor;
76
-// 	int allow_default_major_fallback;
77
-// 	uid_t uid;
78
-// 	gid_t gid;
79
-// 	mode_t mode;
80
-// 	uint32_t read_ahead;
81
-// 	uint32_t read_ahead_flags;
82
-// 	union {
83
-// 		struct dm_ioctl *v4;
84
-// 	} dmi;
85
-// 	char *newname;
86
-// 	char *message;
87
-// 	char *geometry;
88
-// 	uint64_t sector;
89
-// 	int no_flush;
90
-// 	int no_open_count;
91
-// 	int skip_lockfs;
92
-// 	int query_inactive_table;
93
-// 	int suppress_identical_reload;
94
-// 	dm_add_node_t add_node;
95
-// 	uint64_t existing_table_size;
96
-// 	int cookie_set;
97
-// 	int new_uuid;
98
-// 	int secure_data;
99
-// 	int retry_remove;
100
-// 	int enable_checks;
101
-// 	int expected_errno;
102
-
103
-// 	char *uuid;
104
-// 	char *mangled_uuid;
105
-// };
106
-//
107 1
deleted file mode 100644
... ...
@@ -1,15 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-import "C"
6
-
7
-// Due to the way cgo works this has to be in a separate file, as devmapper.go has
8
-// definitions in the cgo block, which is incompatible with using "//export"
9
-
10
-//export DevmapperLogCallback
11
-func DevmapperLogCallback(level C.int, file *C.char, line C.int, dm_errno_or_class C.int, message *C.char) {
12
-	if dmLogger != nil {
13
-		dmLogger.log(int(level), C.GoString(file), int(line), int(dm_errno_or_class), C.GoString(message))
14
-	}
15
-}
16 1
deleted file mode 100644
... ...
@@ -1,287 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-import (
6
-	"testing"
7
-)
8
-
9
-func TestTaskCreate(t *testing.T) {
10
-	t.Skip("FIXME: not a unit test")
11
-	// Test success
12
-	taskCreate(t, DeviceInfo)
13
-
14
-	// Test Failure
15
-	DmTaskCreate = dmTaskCreateFail
16
-	defer func() { DmTaskCreate = dmTaskCreateFct }()
17
-	if task := TaskCreate(-1); task != nil {
18
-		t.Fatalf("An error should have occured while creating an invalid task.")
19
-	}
20
-}
21
-
22
-func TestTaskRun(t *testing.T) {
23
-	t.Skip("FIXME: not a unit test")
24
-	task := taskCreate(t, DeviceInfo)
25
-
26
-	// Test success
27
-	// Perform the RUN
28
-	if err := task.Run(); err != nil {
29
-		t.Fatal(err)
30
-	}
31
-	// Make sure we don't have error with GetInfo
32
-	if _, err := task.GetInfo(); err != nil {
33
-		t.Fatal(err)
34
-	}
35
-
36
-	// Test failure
37
-	DmTaskRun = dmTaskRunFail
38
-	defer func() { DmTaskRun = dmTaskRunFct }()
39
-
40
-	task = taskCreate(t, DeviceInfo)
41
-	// Perform the RUN
42
-	if err := task.Run(); err != ErrTaskRun {
43
-		t.Fatalf("An error should have occured while running task.")
44
-	}
45
-	// Make sure GetInfo also fails
46
-	if _, err := task.GetInfo(); err != ErrTaskGetInfo {
47
-		t.Fatalf("GetInfo should fail if task.Run() failed.")
48
-	}
49
-}
50
-
51
-func TestTaskSetName(t *testing.T) {
52
-	t.Skip("FIXME: not a unit test")
53
-	task := taskCreate(t, DeviceInfo)
54
-
55
-	// Test success
56
-	if err := task.SetName("test"); err != nil {
57
-		t.Fatal(err)
58
-	}
59
-
60
-	// Test failure
61
-	DmTaskSetName = dmTaskSetNameFail
62
-	defer func() { DmTaskSetName = dmTaskSetNameFct }()
63
-
64
-	if err := task.SetName("test"); err != ErrTaskSetName {
65
-		t.Fatalf("An error should have occured while runnign SetName.")
66
-	}
67
-}
68
-
69
-func TestTaskSetMessage(t *testing.T) {
70
-	t.Skip("FIXME: not a unit test")
71
-	task := taskCreate(t, DeviceInfo)
72
-
73
-	// Test success
74
-	if err := task.SetMessage("test"); err != nil {
75
-		t.Fatal(err)
76
-	}
77
-
78
-	// Test failure
79
-	DmTaskSetMessage = dmTaskSetMessageFail
80
-	defer func() { DmTaskSetMessage = dmTaskSetMessageFct }()
81
-
82
-	if err := task.SetMessage("test"); err != ErrTaskSetMessage {
83
-		t.Fatalf("An error should have occured while runnign SetMessage.")
84
-	}
85
-}
86
-
87
-func TestTaskSetSector(t *testing.T) {
88
-	t.Skip("FIXME: not a unit test")
89
-	task := taskCreate(t, DeviceInfo)
90
-
91
-	// Test success
92
-	if err := task.SetSector(128); err != nil {
93
-		t.Fatal(err)
94
-	}
95
-
96
-	DmTaskSetSector = dmTaskSetSectorFail
97
-	defer func() { DmTaskSetSector = dmTaskSetSectorFct }()
98
-
99
-	// Test failure
100
-	if err := task.SetSector(0); err != ErrTaskSetSector {
101
-		t.Fatalf("An error should have occured while running SetSector.")
102
-	}
103
-}
104
-
105
-func TestTaskSetCookie(t *testing.T) {
106
-	t.Skip("FIXME: not a unit test")
107
-	var (
108
-		cookie uint = 0
109
-		task        = taskCreate(t, DeviceInfo)
110
-	)
111
-
112
-	// Test success
113
-	if err := task.SetCookie(&cookie, 0); err != nil {
114
-		t.Fatal(err)
115
-	}
116
-
117
-	// Test failure
118
-	if err := task.SetCookie(nil, 0); err != ErrNilCookie {
119
-		t.Fatalf("An error should have occured while running SetCookie with nil cookie.")
120
-	}
121
-
122
-	DmTaskSetCookie = dmTaskSetCookieFail
123
-	defer func() { DmTaskSetCookie = dmTaskSetCookieFct }()
124
-
125
-	if err := task.SetCookie(&cookie, 0); err != ErrTaskSetCookie {
126
-		t.Fatalf("An error should have occured while running SetCookie.")
127
-	}
128
-}
129
-
130
-func TestTaskSetAddNode(t *testing.T) {
131
-	t.Skip("FIXME: not a unit test")
132
-	task := taskCreate(t, DeviceInfo)
133
-
134
-	// Test success
135
-	if err := task.SetAddNode(0); err != nil {
136
-		t.Fatal(err)
137
-	}
138
-
139
-	// Test failure
140
-	if err := task.SetAddNode(-1); err != ErrInvalidAddNode {
141
-		t.Fatalf("An error should have occured running SetAddNode with wrong node.")
142
-	}
143
-
144
-	DmTaskSetAddNode = dmTaskSetAddNodeFail
145
-	defer func() { DmTaskSetAddNode = dmTaskSetAddNodeFct }()
146
-
147
-	if err := task.SetAddNode(0); err != ErrTaskSetAddNode {
148
-		t.Fatalf("An error should have occured running SetAddNode.")
149
-	}
150
-}
151
-
152
-func TestTaskSetRo(t *testing.T) {
153
-	t.Skip("FIXME: not a unit test")
154
-	task := taskCreate(t, DeviceInfo)
155
-
156
-	// Test success
157
-	if err := task.SetRo(); err != nil {
158
-		t.Fatal(err)
159
-	}
160
-
161
-	// Test failure
162
-	DmTaskSetRo = dmTaskSetRoFail
163
-	defer func() { DmTaskSetRo = dmTaskSetRoFct }()
164
-
165
-	if err := task.SetRo(); err != ErrTaskSetRo {
166
-		t.Fatalf("An error should have occured running SetRo.")
167
-	}
168
-}
169
-
170
-func TestTaskAddTarget(t *testing.T) {
171
-	t.Skip("FIXME: not a unit test")
172
-	task := taskCreate(t, DeviceInfo)
173
-
174
-	// Test success
175
-	if err := task.AddTarget(0, 128, "thinp", ""); err != nil {
176
-		t.Fatal(err)
177
-	}
178
-
179
-	// Test failure
180
-	DmTaskAddTarget = dmTaskAddTargetFail
181
-	defer func() { DmTaskAddTarget = dmTaskAddTargetFct }()
182
-
183
-	if err := task.AddTarget(0, 128, "thinp", ""); err != ErrTaskAddTarget {
184
-		t.Fatalf("An error should have occured running AddTarget.")
185
-	}
186
-}
187
-
188
-// func TestTaskGetInfo(t *testing.T) {
189
-// 	task := taskCreate(t, DeviceInfo)
190
-
191
-// 	// Test success
192
-// 	if _, err := task.GetInfo(); err != nil {
193
-// 		t.Fatal(err)
194
-// 	}
195
-
196
-// 	// Test failure
197
-// 	DmTaskGetInfo = dmTaskGetInfoFail
198
-// 	defer func() { DmTaskGetInfo = dmTaskGetInfoFct }()
199
-
200
-// 	if _, err := task.GetInfo(); err != ErrTaskGetInfo {
201
-// 		t.Fatalf("An error should have occured running GetInfo.")
202
-// 	}
203
-// }
204
-
205
-// func TestTaskGetNextTarget(t *testing.T) {
206
-// 	task := taskCreate(t, DeviceInfo)
207
-
208
-// 	if next, _, _, _, _ := task.GetNextTarget(0); next == 0 {
209
-// 		t.Fatalf("The next target should not be 0.")
210
-// 	}
211
-// }
212
-
213
-/// Utils
214
-func taskCreate(t *testing.T, taskType TaskType) *Task {
215
-	task := TaskCreate(taskType)
216
-	if task == nil {
217
-		t.Fatalf("Error creating task")
218
-	}
219
-	return task
220
-}
221
-
222
-/// Failure function replacement
223
-func dmTaskCreateFail(t int) *CDmTask {
224
-	return nil
225
-}
226
-
227
-func dmTaskRunFail(task *CDmTask) int {
228
-	return -1
229
-}
230
-
231
-func dmTaskSetNameFail(task *CDmTask, name string) int {
232
-	return -1
233
-}
234
-
235
-func dmTaskSetMessageFail(task *CDmTask, message string) int {
236
-	return -1
237
-}
238
-
239
-func dmTaskSetSectorFail(task *CDmTask, sector uint64) int {
240
-	return -1
241
-}
242
-
243
-func dmTaskSetCookieFail(task *CDmTask, cookie *uint, flags uint16) int {
244
-	return -1
245
-}
246
-
247
-func dmTaskSetAddNodeFail(task *CDmTask, addNode AddNodeType) int {
248
-	return -1
249
-}
250
-
251
-func dmTaskSetRoFail(task *CDmTask) int {
252
-	return -1
253
-}
254
-
255
-func dmTaskAddTargetFail(task *CDmTask,
256
-	start, size uint64, ttype, params string) int {
257
-	return -1
258
-}
259
-
260
-func dmTaskGetInfoFail(task *CDmTask, info *Info) int {
261
-	return -1
262
-}
263
-
264
-func dmGetNextTargetFail(task *CDmTask, next uintptr, start, length *uint64,
265
-	target, params *string) uintptr {
266
-	return 0
267
-}
268
-
269
-func dmAttachLoopDeviceFail(filename string, fd *int) string {
270
-	return ""
271
-}
272
-
273
-func sysGetBlockSizeFail(fd uintptr, size *uint64) sysErrno {
274
-	return 1
275
-}
276
-
277
-func dmUdevWaitFail(cookie uint) int {
278
-	return -1
279
-}
280
-
281
-func dmSetDevDirFail(dir string) int {
282
-	return -1
283
-}
284
-
285
-func dmGetLibraryVersionFail(version *string) int {
286
-	return -1
287
-}
288 1
deleted file mode 100644
... ...
@@ -1,229 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-/*
6
-#cgo LDFLAGS: -L. -ldevmapper
7
-#include <libdevmapper.h>
8
-#include <linux/loop.h> // FIXME: present only for defines, maybe we can remove it?
9
-#include <linux/fs.h>   // FIXME: present only for BLKGETSIZE64, maybe we can remove it?
10
-
11
-#ifndef LOOP_CTL_GET_FREE
12
-  #define LOOP_CTL_GET_FREE 0x4C82
13
-#endif
14
-
15
-#ifndef LO_FLAGS_PARTSCAN
16
-  #define LO_FLAGS_PARTSCAN 8
17
-#endif
18
-
19
-// FIXME: Can't we find a way to do the logging in pure Go?
20
-extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
21
-
22
-static void	log_cb(int level, const char *file, int line, int dm_errno_or_class, const char *f, ...)
23
-{
24
-  char buffer[256];
25
-  va_list ap;
26
-
27
-  va_start(ap, f);
28
-  vsnprintf(buffer, 256, f, ap);
29
-  va_end(ap);
30
-
31
-  DevmapperLogCallback(level, (char *)file, line, dm_errno_or_class, buffer);
32
-}
33
-
34
-static void	log_with_errno_init()
35
-{
36
-  dm_log_with_errno_init(log_cb);
37
-}
38
-*/
39
-import "C"
40
-
41
-import (
42
-	"unsafe"
43
-)
44
-
45
-type (
46
-	CDmTask C.struct_dm_task
47
-
48
-	CLoopInfo64 C.struct_loop_info64
49
-	LoopInfo64  struct {
50
-		loDevice           uint64 /* ioctl r/o */
51
-		loInode            uint64 /* ioctl r/o */
52
-		loRdevice          uint64 /* ioctl r/o */
53
-		loOffset           uint64
54
-		loSizelimit        uint64 /* bytes, 0 == max available */
55
-		loNumber           uint32 /* ioctl r/o */
56
-		loEncrypt_type     uint32
57
-		loEncrypt_key_size uint32 /* ioctl w/o */
58
-		loFlags            uint32 /* ioctl r/o */
59
-		loFileName         [LoNameSize]uint8
60
-		loCryptName        [LoNameSize]uint8
61
-		loEncryptKey       [LoKeySize]uint8 /* ioctl w/o */
62
-		loInit             [2]uint64
63
-	}
64
-)
65
-
66
-// IOCTL consts
67
-const (
68
-	BlkGetSize64 = C.BLKGETSIZE64
69
-	BlkDiscard   = C.BLKDISCARD
70
-
71
-	LoopSetFd       = C.LOOP_SET_FD
72
-	LoopCtlGetFree  = C.LOOP_CTL_GET_FREE
73
-	LoopGetStatus64 = C.LOOP_GET_STATUS64
74
-	LoopSetStatus64 = C.LOOP_SET_STATUS64
75
-	LoopClrFd       = C.LOOP_CLR_FD
76
-	LoopSetCapacity = C.LOOP_SET_CAPACITY
77
-)
78
-
79
-const (
80
-	LoFlagsAutoClear = C.LO_FLAGS_AUTOCLEAR
81
-	LoFlagsReadOnly  = C.LO_FLAGS_READ_ONLY
82
-	LoFlagsPartScan  = C.LO_FLAGS_PARTSCAN
83
-	LoKeySize        = C.LO_KEY_SIZE
84
-	LoNameSize       = C.LO_NAME_SIZE
85
-)
86
-
87
-var (
88
-	DmGetLibraryVersion = dmGetLibraryVersionFct
89
-	DmGetNextTarget     = dmGetNextTargetFct
90
-	DmLogInitVerbose    = dmLogInitVerboseFct
91
-	DmSetDevDir         = dmSetDevDirFct
92
-	DmTaskAddTarget     = dmTaskAddTargetFct
93
-	DmTaskCreate        = dmTaskCreateFct
94
-	DmTaskDestroy       = dmTaskDestroyFct
95
-	DmTaskGetInfo       = dmTaskGetInfoFct
96
-	DmTaskRun           = dmTaskRunFct
97
-	DmTaskSetAddNode    = dmTaskSetAddNodeFct
98
-	DmTaskSetCookie     = dmTaskSetCookieFct
99
-	DmTaskSetMessage    = dmTaskSetMessageFct
100
-	DmTaskSetName       = dmTaskSetNameFct
101
-	DmTaskSetRo         = dmTaskSetRoFct
102
-	DmTaskSetSector     = dmTaskSetSectorFct
103
-	DmUdevWait          = dmUdevWaitFct
104
-	LogWithErrnoInit    = logWithErrnoInitFct
105
-)
106
-
107
-func free(p *C.char) {
108
-	C.free(unsafe.Pointer(p))
109
-}
110
-
111
-func dmTaskDestroyFct(task *CDmTask) {
112
-	C.dm_task_destroy((*C.struct_dm_task)(task))
113
-}
114
-
115
-func dmTaskCreateFct(taskType int) *CDmTask {
116
-	return (*CDmTask)(C.dm_task_create(C.int(taskType)))
117
-}
118
-
119
-func dmTaskRunFct(task *CDmTask) int {
120
-	ret, _ := C.dm_task_run((*C.struct_dm_task)(task))
121
-	return int(ret)
122
-}
123
-
124
-func dmTaskSetNameFct(task *CDmTask, name string) int {
125
-	Cname := C.CString(name)
126
-	defer free(Cname)
127
-
128
-	return int(C.dm_task_set_name((*C.struct_dm_task)(task), Cname))
129
-}
130
-
131
-func dmTaskSetMessageFct(task *CDmTask, message string) int {
132
-	Cmessage := C.CString(message)
133
-	defer free(Cmessage)
134
-
135
-	return int(C.dm_task_set_message((*C.struct_dm_task)(task), Cmessage))
136
-}
137
-
138
-func dmTaskSetSectorFct(task *CDmTask, sector uint64) int {
139
-	return int(C.dm_task_set_sector((*C.struct_dm_task)(task), C.uint64_t(sector)))
140
-}
141
-
142
-func dmTaskSetCookieFct(task *CDmTask, cookie *uint, flags uint16) int {
143
-	cCookie := C.uint32_t(*cookie)
144
-	defer func() {
145
-		*cookie = uint(cCookie)
146
-	}()
147
-	return int(C.dm_task_set_cookie((*C.struct_dm_task)(task), &cCookie, C.uint16_t(flags)))
148
-}
149
-
150
-func dmTaskSetAddNodeFct(task *CDmTask, addNode AddNodeType) int {
151
-	return int(C.dm_task_set_add_node((*C.struct_dm_task)(task), C.dm_add_node_t(addNode)))
152
-}
153
-
154
-func dmTaskSetRoFct(task *CDmTask) int {
155
-	return int(C.dm_task_set_ro((*C.struct_dm_task)(task)))
156
-}
157
-
158
-func dmTaskAddTargetFct(task *CDmTask,
159
-	start, size uint64, ttype, params string) int {
160
-
161
-	Cttype := C.CString(ttype)
162
-	defer free(Cttype)
163
-
164
-	Cparams := C.CString(params)
165
-	defer free(Cparams)
166
-
167
-	return int(C.dm_task_add_target((*C.struct_dm_task)(task), C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
168
-}
169
-
170
-func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
171
-	Cinfo := C.struct_dm_info{}
172
-	defer func() {
173
-		info.Exists = int(Cinfo.exists)
174
-		info.Suspended = int(Cinfo.suspended)
175
-		info.LiveTable = int(Cinfo.live_table)
176
-		info.InactiveTable = int(Cinfo.inactive_table)
177
-		info.OpenCount = int32(Cinfo.open_count)
178
-		info.EventNr = uint32(Cinfo.event_nr)
179
-		info.Major = uint32(Cinfo.major)
180
-		info.Minor = uint32(Cinfo.minor)
181
-		info.ReadOnly = int(Cinfo.read_only)
182
-		info.TargetCount = int32(Cinfo.target_count)
183
-	}()
184
-	return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
185
-}
186
-
187
-func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64, target, params *string) uintptr {
188
-	var (
189
-		Cstart, Clength      C.uint64_t
190
-		CtargetType, Cparams *C.char
191
-	)
192
-	defer func() {
193
-		*start = uint64(Cstart)
194
-		*length = uint64(Clength)
195
-		*target = C.GoString(CtargetType)
196
-		*params = C.GoString(Cparams)
197
-	}()
198
-
199
-	nextp := C.dm_get_next_target((*C.struct_dm_task)(task), unsafe.Pointer(next), &Cstart, &Clength, &CtargetType, &Cparams)
200
-	return uintptr(nextp)
201
-}
202
-
203
-func dmUdevWaitFct(cookie uint) int {
204
-	return int(C.dm_udev_wait(C.uint32_t(cookie)))
205
-}
206
-
207
-func dmLogInitVerboseFct(level int) {
208
-	C.dm_log_init_verbose(C.int(level))
209
-}
210
-
211
-func logWithErrnoInitFct() {
212
-	C.log_with_errno_init()
213
-}
214
-
215
-func dmSetDevDirFct(dir string) int {
216
-	Cdir := C.CString(dir)
217
-	defer free(Cdir)
218
-
219
-	return int(C.dm_set_dev_dir(Cdir))
220
-}
221
-
222
-func dmGetLibraryVersionFct(version *string) int {
223
-	buffer := C.CString(string(make([]byte, 128)))
224
-	defer free(buffer)
225
-	defer func() {
226
-		*version = C.GoString(buffer)
227
-	}()
228
-	return int(C.dm_get_library_version(buffer, 128))
229
-}
230 1
deleted file mode 100644
... ...
@@ -1,143 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-import (
6
-	"fmt"
7
-	"github.com/dotcloud/docker/graphdriver"
8
-	"github.com/dotcloud/docker/utils"
9
-	"io/ioutil"
10
-	"os"
11
-	"path"
12
-)
13
-
14
-func init() {
15
-	graphdriver.Register("devicemapper", Init)
16
-}
17
-
18
-// Placeholder interfaces, to be replaced
19
-// at integration.
20
-
21
-// End of placeholder interfaces.
22
-
23
-type Driver struct {
24
-	*DeviceSet
25
-	home string
26
-}
27
-
28
-var Init = func(home string) (graphdriver.Driver, error) {
29
-	deviceSet, err := NewDeviceSet(home, true)
30
-	if err != nil {
31
-		return nil, err
32
-	}
33
-	d := &Driver{
34
-		DeviceSet: deviceSet,
35
-		home:      home,
36
-	}
37
-	return d, nil
38
-}
39
-
40
-func (d *Driver) String() string {
41
-	return "devicemapper"
42
-}
43
-
44
-func (d *Driver) Status() [][2]string {
45
-	s := d.DeviceSet.Status()
46
-
47
-	status := [][2]string{
48
-		{"Pool Name", s.PoolName},
49
-		{"Data file", s.DataLoopback},
50
-		{"Metadata file", s.MetadataLoopback},
51
-		{"Data Space Used", fmt.Sprintf("%.1f Mb", float64(s.Data.Used)/(1024*1024))},
52
-		{"Data Space Total", fmt.Sprintf("%.1f Mb", float64(s.Data.Total)/(1024*1024))},
53
-		{"Metadata Space Used", fmt.Sprintf("%.1f Mb", float64(s.Metadata.Used)/(1024*1024))},
54
-		{"Metadata Space Total", fmt.Sprintf("%.1f Mb", float64(s.Metadata.Total)/(1024*1024))},
55
-	}
56
-	return status
57
-}
58
-
59
-func (d *Driver) Cleanup() error {
60
-	return d.DeviceSet.Shutdown()
61
-}
62
-
63
-func (d *Driver) Create(id, parent string) error {
64
-	if err := d.DeviceSet.AddDevice(id, parent); err != nil {
65
-		return err
66
-	}
67
-
68
-	mp := path.Join(d.home, "mnt", id)
69
-	if err := d.mount(id, mp); err != nil {
70
-		return err
71
-	}
72
-
73
-	if err := osMkdirAll(path.Join(mp, "rootfs"), 0755); err != nil && !osIsExist(err) {
74
-		return err
75
-	}
76
-
77
-	// Create an "id" file with the container/image id in it to help reconscruct this in case
78
-	// of later problems
79
-	if err := ioutil.WriteFile(path.Join(mp, "id"), []byte(id), 0600); err != nil {
80
-		return err
81
-	}
82
-
83
-	// We float this reference so that the next Get call can
84
-	// steal it, so we don't have to unmount
85
-	if err := d.DeviceSet.UnmountDevice(id, UnmountFloat); err != nil {
86
-		return err
87
-	}
88
-
89
-	return nil
90
-}
91
-
92
-func (d *Driver) Remove(id string) error {
93
-	if !d.DeviceSet.HasDevice(id) {
94
-		// Consider removing a non-existing device a no-op
95
-		// This is useful to be able to progress on container removal
96
-		// if the underlying device has gone away due to earlier errors
97
-		return nil
98
-	}
99
-
100
-	// Sink the float from create in case no Get() call was made
101
-	if err := d.DeviceSet.UnmountDevice(id, UnmountSink); err != nil {
102
-		return err
103
-	}
104
-	// This assumes the device has been properly Get/Put:ed and thus is unmounted
105
-	if err := d.DeviceSet.DeleteDevice(id); err != nil {
106
-		return err
107
-	}
108
-
109
-	mp := path.Join(d.home, "mnt", id)
110
-	if err := os.RemoveAll(mp); err != nil && !os.IsNotExist(err) {
111
-		return err
112
-	}
113
-
114
-	return nil
115
-}
116
-
117
-func (d *Driver) Get(id string) (string, error) {
118
-	mp := path.Join(d.home, "mnt", id)
119
-	if err := d.mount(id, mp); err != nil {
120
-		return "", err
121
-	}
122
-
123
-	return path.Join(mp, "rootfs"), nil
124
-}
125
-
126
-func (d *Driver) Put(id string) {
127
-	if err := d.DeviceSet.UnmountDevice(id, UnmountRegular); err != nil {
128
-		utils.Errorf("Warning: error unmounting device %s: %s\n", id, err)
129
-	}
130
-}
131
-
132
-func (d *Driver) mount(id, mountPoint string) error {
133
-	// Create the target directories if they don't exist
134
-	if err := osMkdirAll(mountPoint, 0755); err != nil && !osIsExist(err) {
135
-		return err
136
-	}
137
-	// Mount the device
138
-	return d.DeviceSet.MountDevice(id, mountPoint)
139
-}
140
-
141
-func (d *Driver) Exists(id string) bool {
142
-	return d.Devices[id] != nil
143
-}
144 1
deleted file mode 100644
... ...
@@ -1,886 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-import (
6
-	"fmt"
7
-	"github.com/dotcloud/docker/graphdriver"
8
-	"io/ioutil"
9
-	"path"
10
-	"runtime"
11
-	"strings"
12
-	"syscall"
13
-	"testing"
14
-)
15
-
16
-func init() {
17
-	// Reduce the size the the base fs and loopback for the tests
18
-	DefaultDataLoopbackSize = 300 * 1024 * 1024
19
-	DefaultMetaDataLoopbackSize = 200 * 1024 * 1024
20
-	DefaultBaseFsSize = 300 * 1024 * 1024
21
-}
22
-
23
-// denyAllDevmapper mocks all calls to libdevmapper in the unit tests, and denies them by default
24
-func denyAllDevmapper() {
25
-	// Hijack all calls to libdevmapper with default panics.
26
-	// Authorized calls are selectively hijacked in each tests.
27
-	DmTaskCreate = func(t int) *CDmTask {
28
-		panic("DmTaskCreate: this method should not be called here")
29
-	}
30
-	DmTaskRun = func(task *CDmTask) int {
31
-		panic("DmTaskRun: this method should not be called here")
32
-	}
33
-	DmTaskSetName = func(task *CDmTask, name string) int {
34
-		panic("DmTaskSetName: this method should not be called here")
35
-	}
36
-	DmTaskSetMessage = func(task *CDmTask, message string) int {
37
-		panic("DmTaskSetMessage: this method should not be called here")
38
-	}
39
-	DmTaskSetSector = func(task *CDmTask, sector uint64) int {
40
-		panic("DmTaskSetSector: this method should not be called here")
41
-	}
42
-	DmTaskSetCookie = func(task *CDmTask, cookie *uint, flags uint16) int {
43
-		panic("DmTaskSetCookie: this method should not be called here")
44
-	}
45
-	DmTaskSetAddNode = func(task *CDmTask, addNode AddNodeType) int {
46
-		panic("DmTaskSetAddNode: this method should not be called here")
47
-	}
48
-	DmTaskSetRo = func(task *CDmTask) int {
49
-		panic("DmTaskSetRo: this method should not be called here")
50
-	}
51
-	DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
52
-		panic("DmTaskAddTarget: this method should not be called here")
53
-	}
54
-	DmTaskGetInfo = func(task *CDmTask, info *Info) int {
55
-		panic("DmTaskGetInfo: this method should not be called here")
56
-	}
57
-	DmGetNextTarget = func(task *CDmTask, next uintptr, start, length *uint64, target, params *string) uintptr {
58
-		panic("DmGetNextTarget: this method should not be called here")
59
-	}
60
-	DmUdevWait = func(cookie uint) int {
61
-		panic("DmUdevWait: this method should not be called here")
62
-	}
63
-	DmSetDevDir = func(dir string) int {
64
-		panic("DmSetDevDir: this method should not be called here")
65
-	}
66
-	DmGetLibraryVersion = func(version *string) int {
67
-		panic("DmGetLibraryVersion: this method should not be called here")
68
-	}
69
-	DmLogInitVerbose = func(level int) {
70
-		panic("DmLogInitVerbose: this method should not be called here")
71
-	}
72
-	DmTaskDestroy = func(task *CDmTask) {
73
-		panic("DmTaskDestroy: this method should not be called here")
74
-	}
75
-	LogWithErrnoInit = func() {
76
-		panic("LogWithErrnoInit: this method should not be called here")
77
-	}
78
-}
79
-
80
-func denyAllSyscall() {
81
-	sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
82
-		panic("sysMount: this method should not be called here")
83
-	}
84
-	sysUnmount = func(target string, flags int) (err error) {
85
-		panic("sysUnmount: this method should not be called here")
86
-	}
87
-	sysCloseOnExec = func(fd int) {
88
-		panic("sysCloseOnExec: this method should not be called here")
89
-	}
90
-	sysSyscall = func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
91
-		panic("sysSyscall: this method should not be called here")
92
-	}
93
-	// Not a syscall, but forbidding it here anyway
94
-	Mounted = func(mnt string) (bool, error) {
95
-		panic("devmapper.Mounted: this method should not be called here")
96
-	}
97
-	// osOpenFile = os.OpenFile
98
-	// osNewFile = os.NewFile
99
-	// osCreate = os.Create
100
-	// osStat = os.Stat
101
-	// osIsNotExist = os.IsNotExist
102
-	// osIsExist = os.IsExist
103
-	// osMkdirAll = os.MkdirAll
104
-	// osRemoveAll = os.RemoveAll
105
-	// osRename = os.Rename
106
-	// osReadlink = os.Readlink
107
-
108
-	// execRun = func(name string, args ...string) error {
109
-	// 	return exec.Command(name, args...).Run()
110
-	// }
111
-}
112
-
113
-func mkTestDirectory(t *testing.T) string {
114
-	dir, err := ioutil.TempDir("", "docker-test-devmapper-")
115
-	if err != nil {
116
-		t.Fatal(err)
117
-	}
118
-	return dir
119
-}
120
-
121
-func newDriver(t *testing.T) *Driver {
122
-	home := mkTestDirectory(t)
123
-	d, err := Init(home)
124
-	if err != nil {
125
-		t.Fatal(err)
126
-	}
127
-	return d.(*Driver)
128
-}
129
-
130
-func cleanup(d *Driver) {
131
-	d.Cleanup()
132
-	osRemoveAll(d.home)
133
-}
134
-
135
-type Set map[string]bool
136
-
137
-func (r Set) Assert(t *testing.T, names ...string) {
138
-	for _, key := range names {
139
-		required := true
140
-		if strings.HasPrefix(key, "?") {
141
-			key = key[1:]
142
-			required = false
143
-		}
144
-		if _, exists := r[key]; !exists && required {
145
-			t.Fatalf("Key not set: %s", key)
146
-		}
147
-		delete(r, key)
148
-	}
149
-	if len(r) != 0 {
150
-		t.Fatalf("Unexpected keys: %v", r)
151
-	}
152
-}
153
-
154
-func TestInit(t *testing.T) {
155
-	var (
156
-		calls        = make(Set)
157
-		taskMessages = make(Set)
158
-		taskTypes    = make(Set)
159
-		home         = mkTestDirectory(t)
160
-	)
161
-	defer osRemoveAll(home)
162
-
163
-	func() {
164
-		denyAllDevmapper()
165
-		DmSetDevDir = func(dir string) int {
166
-			calls["DmSetDevDir"] = true
167
-			expectedDir := "/dev"
168
-			if dir != expectedDir {
169
-				t.Fatalf("Wrong libdevmapper call\nExpected: DmSetDevDir(%v)\nReceived: DmSetDevDir(%v)\n", expectedDir, dir)
170
-			}
171
-			return 0
172
-		}
173
-		LogWithErrnoInit = func() {
174
-			calls["DmLogWithErrnoInit"] = true
175
-		}
176
-		var task1 CDmTask
177
-		DmTaskCreate = func(taskType int) *CDmTask {
178
-			calls["DmTaskCreate"] = true
179
-			taskTypes[fmt.Sprintf("%d", taskType)] = true
180
-			return &task1
181
-		}
182
-		DmTaskSetName = func(task *CDmTask, name string) int {
183
-			calls["DmTaskSetName"] = true
184
-			expectedTask := &task1
185
-			if task != expectedTask {
186
-				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetName(%v)\nReceived: DmTaskSetName(%v)\n", expectedTask, task)
187
-			}
188
-			// FIXME: use Set.AssertRegexp()
189
-			if !strings.HasPrefix(name, "docker-") && !strings.HasPrefix(name, "/dev/mapper/docker-") ||
190
-				!strings.HasSuffix(name, "-pool") && !strings.HasSuffix(name, "-base") {
191
-				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetName(%v)\nReceived: DmTaskSetName(%v)\n", "docker-...-pool", name)
192
-			}
193
-			return 1
194
-		}
195
-		DmTaskRun = func(task *CDmTask) int {
196
-			calls["DmTaskRun"] = true
197
-			expectedTask := &task1
198
-			if task != expectedTask {
199
-				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskRun(%v)\nReceived: DmTaskRun(%v)\n", expectedTask, task)
200
-			}
201
-			return 1
202
-		}
203
-		DmTaskGetInfo = func(task *CDmTask, info *Info) int {
204
-			calls["DmTaskGetInfo"] = true
205
-			expectedTask := &task1
206
-			if task != expectedTask {
207
-				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskGetInfo(%v)\nReceived: DmTaskGetInfo(%v)\n", expectedTask, task)
208
-			}
209
-			// This will crash if info is not dereferenceable
210
-			info.Exists = 0
211
-			return 1
212
-		}
213
-		DmTaskSetSector = func(task *CDmTask, sector uint64) int {
214
-			calls["DmTaskSetSector"] = true
215
-			expectedTask := &task1
216
-			if task != expectedTask {
217
-				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetSector(%v)\nReceived: DmTaskSetSector(%v)\n", expectedTask, task)
218
-			}
219
-			if expectedSector := uint64(0); sector != expectedSector {
220
-				t.Fatalf("Wrong libdevmapper call to DmTaskSetSector\nExpected: %v\nReceived: %v\n", expectedSector, sector)
221
-			}
222
-			return 1
223
-		}
224
-		DmTaskSetMessage = func(task *CDmTask, message string) int {
225
-			calls["DmTaskSetMessage"] = true
226
-			expectedTask := &task1
227
-			if task != expectedTask {
228
-				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetSector(%v)\nReceived: DmTaskSetSector(%v)\n", expectedTask, task)
229
-			}
230
-			taskMessages[message] = true
231
-			return 1
232
-		}
233
-		DmTaskDestroy = func(task *CDmTask) {
234
-			calls["DmTaskDestroy"] = true
235
-			expectedTask := &task1
236
-			if task != expectedTask {
237
-				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
238
-			}
239
-		}
240
-		DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
241
-			calls["DmTaskSetTarget"] = true
242
-			expectedTask := &task1
243
-			if task != expectedTask {
244
-				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
245
-			}
246
-			if start != 0 {
247
-				t.Fatalf("Wrong start: %d != %d", start, 0)
248
-			}
249
-			if ttype != "thin" && ttype != "thin-pool" {
250
-				t.Fatalf("Wrong ttype: %s", ttype)
251
-			}
252
-			// Quick smoke test
253
-			if params == "" {
254
-				t.Fatalf("Params should not be empty")
255
-			}
256
-			return 1
257
-		}
258
-		fakeCookie := uint(4321)
259
-		DmTaskSetCookie = func(task *CDmTask, cookie *uint, flags uint16) int {
260
-			calls["DmTaskSetCookie"] = true
261
-			expectedTask := &task1
262
-			if task != expectedTask {
263
-				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
264
-			}
265
-			if flags != 0 {
266
-				t.Fatalf("Cookie flags should be 0 (not %x)", flags)
267
-			}
268
-			*cookie = fakeCookie
269
-			return 1
270
-		}
271
-		DmUdevWait = func(cookie uint) int {
272
-			calls["DmUdevWait"] = true
273
-			if cookie != fakeCookie {
274
-				t.Fatalf("Wrong cookie: %d != %d", cookie, fakeCookie)
275
-			}
276
-			return 1
277
-		}
278
-		DmTaskSetAddNode = func(task *CDmTask, addNode AddNodeType) int {
279
-			if addNode != AddNodeOnCreate {
280
-				t.Fatalf("Wrong AddNoteType: %v (expected %v)", addNode, AddNodeOnCreate)
281
-			}
282
-			calls["DmTaskSetAddNode"] = true
283
-			return 1
284
-		}
285
-		execRun = func(name string, args ...string) error {
286
-			calls["execRun"] = true
287
-			if name != "mkfs.ext4" {
288
-				t.Fatalf("Expected %s to be executed, not %s", "mkfs.ext4", name)
289
-			}
290
-			return nil
291
-		}
292
-		driver, err := Init(home)
293
-		if err != nil {
294
-			t.Fatal(err)
295
-		}
296
-		defer func() {
297
-			if err := driver.Cleanup(); err != nil {
298
-				t.Fatal(err)
299
-			}
300
-		}()
301
-	}()
302
-	// Put all tests in a function to make sure the garbage collection will
303
-	// occur.
304
-
305
-	// Call GC to cleanup runtime.Finalizers
306
-	runtime.GC()
307
-
308
-	calls.Assert(t,
309
-		"DmSetDevDir",
310
-		"DmLogWithErrnoInit",
311
-		"DmTaskSetName",
312
-		"DmTaskRun",
313
-		"DmTaskGetInfo",
314
-		"DmTaskDestroy",
315
-		"execRun",
316
-		"DmTaskCreate",
317
-		"DmTaskSetTarget",
318
-		"DmTaskSetCookie",
319
-		"DmUdevWait",
320
-		"DmTaskSetSector",
321
-		"DmTaskSetMessage",
322
-		"DmTaskSetAddNode",
323
-	)
324
-	taskTypes.Assert(t, "0", "6", "17")
325
-	taskMessages.Assert(t, "create_thin 0", "set_transaction_id 0 1")
326
-}
327
-
328
-func fakeInit() func(home string) (graphdriver.Driver, error) {
329
-	oldInit := Init
330
-	Init = func(home string) (graphdriver.Driver, error) {
331
-		return &Driver{
332
-			home: home,
333
-		}, nil
334
-	}
335
-	return oldInit
336
-}
337
-
338
-func restoreInit(init func(home string) (graphdriver.Driver, error)) {
339
-	Init = init
340
-}
341
-
342
-func mockAllDevmapper(calls Set) {
343
-	DmSetDevDir = func(dir string) int {
344
-		calls["DmSetDevDir"] = true
345
-		return 0
346
-	}
347
-	LogWithErrnoInit = func() {
348
-		calls["DmLogWithErrnoInit"] = true
349
-	}
350
-	DmTaskCreate = func(taskType int) *CDmTask {
351
-		calls["DmTaskCreate"] = true
352
-		return &CDmTask{}
353
-	}
354
-	DmTaskSetName = func(task *CDmTask, name string) int {
355
-		calls["DmTaskSetName"] = true
356
-		return 1
357
-	}
358
-	DmTaskRun = func(task *CDmTask) int {
359
-		calls["DmTaskRun"] = true
360
-		return 1
361
-	}
362
-	DmTaskGetInfo = func(task *CDmTask, info *Info) int {
363
-		calls["DmTaskGetInfo"] = true
364
-		return 1
365
-	}
366
-	DmTaskSetSector = func(task *CDmTask, sector uint64) int {
367
-		calls["DmTaskSetSector"] = true
368
-		return 1
369
-	}
370
-	DmTaskSetMessage = func(task *CDmTask, message string) int {
371
-		calls["DmTaskSetMessage"] = true
372
-		return 1
373
-	}
374
-	DmTaskDestroy = func(task *CDmTask) {
375
-		calls["DmTaskDestroy"] = true
376
-	}
377
-	DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
378
-		calls["DmTaskSetTarget"] = true
379
-		return 1
380
-	}
381
-	DmTaskSetCookie = func(task *CDmTask, cookie *uint, flags uint16) int {
382
-		calls["DmTaskSetCookie"] = true
383
-		return 1
384
-	}
385
-	DmUdevWait = func(cookie uint) int {
386
-		calls["DmUdevWait"] = true
387
-		return 1
388
-	}
389
-	DmTaskSetAddNode = func(task *CDmTask, addNode AddNodeType) int {
390
-		calls["DmTaskSetAddNode"] = true
391
-		return 1
392
-	}
393
-	execRun = func(name string, args ...string) error {
394
-		calls["execRun"] = true
395
-		return nil
396
-	}
397
-}
398
-
399
-func TestDriverName(t *testing.T) {
400
-	denyAllDevmapper()
401
-	defer denyAllDevmapper()
402
-
403
-	oldInit := fakeInit()
404
-	defer restoreInit(oldInit)
405
-
406
-	d := newDriver(t)
407
-	if d.String() != "devicemapper" {
408
-		t.Fatalf("Expected driver name to be devicemapper got %s", d.String())
409
-	}
410
-}
411
-
412
-func TestDriverCreate(t *testing.T) {
413
-	denyAllDevmapper()
414
-	denyAllSyscall()
415
-	defer denyAllSyscall()
416
-	defer denyAllDevmapper()
417
-
418
-	calls := make(Set)
419
-	mockAllDevmapper(calls)
420
-
421
-	sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
422
-		calls["sysMount"] = true
423
-		// FIXME: compare the exact source and target strings (inodes + devname)
424
-		if expectedSource := "/dev/mapper/docker-"; !strings.HasPrefix(source, expectedSource) {
425
-			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedSource, source)
426
-		}
427
-		if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
428
-			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
429
-		}
430
-		if expectedFstype := "ext4"; fstype != expectedFstype {
431
-			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFstype, fstype)
432
-		}
433
-		if expectedFlags := uintptr(3236757504); flags != expectedFlags {
434
-			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
435
-		}
436
-		return nil
437
-	}
438
-
439
-	Mounted = func(mnt string) (bool, error) {
440
-		calls["Mounted"] = true
441
-		if !strings.HasPrefix(mnt, "/tmp/docker-test-devmapper-") || !strings.HasSuffix(mnt, "/mnt/1") {
442
-			t.Fatalf("Wrong mounted call\nExpected: Mounted(%v)\nReceived: Mounted(%v)\n", "/tmp/docker-test-devmapper-.../mnt/1", mnt)
443
-		}
444
-		return false, nil
445
-	}
446
-
447
-	sysSyscall = func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
448
-		calls["sysSyscall"] = true
449
-		if trap != sysSysIoctl {
450
-			t.Fatalf("Unexpected syscall. Expecting SYS_IOCTL, received: %d", trap)
451
-		}
452
-		switch a2 {
453
-		case LoopSetFd:
454
-			calls["ioctl.loopsetfd"] = true
455
-		case LoopCtlGetFree:
456
-			calls["ioctl.loopctlgetfree"] = true
457
-		case LoopGetStatus64:
458
-			calls["ioctl.loopgetstatus"] = true
459
-		case LoopSetStatus64:
460
-			calls["ioctl.loopsetstatus"] = true
461
-		case LoopClrFd:
462
-			calls["ioctl.loopclrfd"] = true
463
-		case LoopSetCapacity:
464
-			calls["ioctl.loopsetcapacity"] = true
465
-		case BlkGetSize64:
466
-			calls["ioctl.blkgetsize"] = true
467
-		default:
468
-			t.Fatalf("Unexpected IOCTL. Received %d", a2)
469
-		}
470
-		return 0, 0, 0
471
-	}
472
-
473
-	func() {
474
-		d := newDriver(t)
475
-
476
-		calls.Assert(t,
477
-			"DmSetDevDir",
478
-			"DmLogWithErrnoInit",
479
-			"DmTaskSetName",
480
-			"DmTaskRun",
481
-			"DmTaskGetInfo",
482
-			"execRun",
483
-			"DmTaskCreate",
484
-			"DmTaskSetTarget",
485
-			"DmTaskSetCookie",
486
-			"DmUdevWait",
487
-			"DmTaskSetSector",
488
-			"DmTaskSetMessage",
489
-			"DmTaskSetAddNode",
490
-			"sysSyscall",
491
-			"ioctl.blkgetsize",
492
-			"ioctl.loopsetfd",
493
-			"ioctl.loopsetstatus",
494
-			"?ioctl.loopctlgetfree",
495
-		)
496
-
497
-		if err := d.Create("1", ""); err != nil {
498
-			t.Fatal(err)
499
-		}
500
-		calls.Assert(t,
501
-			"DmTaskCreate",
502
-			"DmTaskGetInfo",
503
-			"sysMount",
504
-			"DmTaskRun",
505
-			"DmTaskSetTarget",
506
-			"DmTaskSetSector",
507
-			"DmTaskSetCookie",
508
-			"DmUdevWait",
509
-			"DmTaskSetName",
510
-			"DmTaskSetMessage",
511
-			"DmTaskSetAddNode",
512
-		)
513
-
514
-	}()
515
-
516
-	runtime.GC()
517
-
518
-	calls.Assert(t,
519
-		"DmTaskDestroy",
520
-	)
521
-}
522
-
523
-func TestDriverRemove(t *testing.T) {
524
-	denyAllDevmapper()
525
-	denyAllSyscall()
526
-	defer denyAllSyscall()
527
-	defer denyAllDevmapper()
528
-
529
-	calls := make(Set)
530
-	mockAllDevmapper(calls)
531
-
532
-	sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
533
-		calls["sysMount"] = true
534
-		// FIXME: compare the exact source and target strings (inodes + devname)
535
-		if expectedSource := "/dev/mapper/docker-"; !strings.HasPrefix(source, expectedSource) {
536
-			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedSource, source)
537
-		}
538
-		if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
539
-			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
540
-		}
541
-		if expectedFstype := "ext4"; fstype != expectedFstype {
542
-			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFstype, fstype)
543
-		}
544
-		if expectedFlags := uintptr(3236757504); flags != expectedFlags {
545
-			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
546
-		}
547
-		return nil
548
-	}
549
-	sysUnmount = func(target string, flags int) (err error) {
550
-		calls["sysUnmount"] = true
551
-		// FIXME: compare the exact source and target strings (inodes + devname)
552
-		if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
553
-			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
554
-		}
555
-		if expectedFlags := 0; flags != expectedFlags {
556
-			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
557
-		}
558
-		return nil
559
-	}
560
-	Mounted = func(mnt string) (bool, error) {
561
-		calls["Mounted"] = true
562
-		return false, nil
563
-	}
564
-
565
-	sysSyscall = func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
566
-		calls["sysSyscall"] = true
567
-		if trap != sysSysIoctl {
568
-			t.Fatalf("Unexpected syscall. Expecting SYS_IOCTL, received: %d", trap)
569
-		}
570
-		switch a2 {
571
-		case LoopSetFd:
572
-			calls["ioctl.loopsetfd"] = true
573
-		case LoopCtlGetFree:
574
-			calls["ioctl.loopctlgetfree"] = true
575
-		case LoopGetStatus64:
576
-			calls["ioctl.loopgetstatus"] = true
577
-		case LoopSetStatus64:
578
-			calls["ioctl.loopsetstatus"] = true
579
-		case LoopClrFd:
580
-			calls["ioctl.loopclrfd"] = true
581
-		case LoopSetCapacity:
582
-			calls["ioctl.loopsetcapacity"] = true
583
-		case BlkGetSize64:
584
-			calls["ioctl.blkgetsize"] = true
585
-		default:
586
-			t.Fatalf("Unexpected IOCTL. Received %d", a2)
587
-		}
588
-		return 0, 0, 0
589
-	}
590
-
591
-	func() {
592
-		d := newDriver(t)
593
-
594
-		calls.Assert(t,
595
-			"DmSetDevDir",
596
-			"DmLogWithErrnoInit",
597
-			"DmTaskSetName",
598
-			"DmTaskRun",
599
-			"DmTaskGetInfo",
600
-			"execRun",
601
-			"DmTaskCreate",
602
-			"DmTaskSetTarget",
603
-			"DmTaskSetCookie",
604
-			"DmUdevWait",
605
-			"DmTaskSetSector",
606
-			"DmTaskSetMessage",
607
-			"DmTaskSetAddNode",
608
-			"sysSyscall",
609
-			"ioctl.blkgetsize",
610
-			"ioctl.loopsetfd",
611
-			"ioctl.loopsetstatus",
612
-			"?ioctl.loopctlgetfree",
613
-		)
614
-
615
-		if err := d.Create("1", ""); err != nil {
616
-			t.Fatal(err)
617
-		}
618
-
619
-		calls.Assert(t,
620
-			"DmTaskCreate",
621
-			"DmTaskGetInfo",
622
-			"sysMount",
623
-			"DmTaskRun",
624
-			"DmTaskSetTarget",
625
-			"DmTaskSetSector",
626
-			"DmTaskSetCookie",
627
-			"DmUdevWait",
628
-			"DmTaskSetName",
629
-			"DmTaskSetMessage",
630
-			"DmTaskSetAddNode",
631
-		)
632
-
633
-		Mounted = func(mnt string) (bool, error) {
634
-			calls["Mounted"] = true
635
-			return true, nil
636
-		}
637
-
638
-		if err := d.Remove("1"); err != nil {
639
-			t.Fatal(err)
640
-		}
641
-
642
-		calls.Assert(t,
643
-			"DmTaskRun",
644
-			"DmTaskSetSector",
645
-			"DmTaskSetName",
646
-			"DmTaskSetMessage",
647
-			"DmTaskCreate",
648
-			"DmTaskGetInfo",
649
-			"DmTaskSetCookie",
650
-			"DmTaskSetTarget",
651
-			"DmTaskSetAddNode",
652
-			"DmUdevWait",
653
-			"sysUnmount",
654
-		)
655
-	}()
656
-	runtime.GC()
657
-
658
-	calls.Assert(t,
659
-		"DmTaskDestroy",
660
-	)
661
-}
662
-
663
-func TestCleanup(t *testing.T) {
664
-	t.Skip("FIXME: not a unit test")
665
-	t.Skip("Unimplemented")
666
-	d := newDriver(t)
667
-	defer osRemoveAll(d.home)
668
-
669
-	mountPoints := make([]string, 2)
670
-
671
-	if err := d.Create("1", ""); err != nil {
672
-		t.Fatal(err)
673
-	}
674
-	// Mount the id
675
-	p, err := d.Get("1")
676
-	if err != nil {
677
-		t.Fatal(err)
678
-	}
679
-	mountPoints[0] = p
680
-
681
-	if err := d.Create("2", "1"); err != nil {
682
-		t.Fatal(err)
683
-	}
684
-
685
-	p, err = d.Get("2")
686
-	if err != nil {
687
-		t.Fatal(err)
688
-	}
689
-	mountPoints[1] = p
690
-
691
-	// Ensure that all the mount points are currently mounted
692
-	for _, p := range mountPoints {
693
-		if mounted, err := Mounted(p); err != nil {
694
-			t.Fatal(err)
695
-		} else if !mounted {
696
-			t.Fatalf("Expected %s to be mounted", p)
697
-		}
698
-	}
699
-
700
-	// Ensure that devices are active
701
-	for _, p := range []string{"1", "2"} {
702
-		if !d.HasActivatedDevice(p) {
703
-			t.Fatalf("Expected %s to have an active device", p)
704
-		}
705
-	}
706
-
707
-	if err := d.Cleanup(); err != nil {
708
-		t.Fatal(err)
709
-	}
710
-
711
-	// Ensure that all the mount points are no longer mounted
712
-	for _, p := range mountPoints {
713
-		if mounted, err := Mounted(p); err != nil {
714
-			t.Fatal(err)
715
-		} else if mounted {
716
-			t.Fatalf("Expected %s to not be mounted", p)
717
-		}
718
-	}
719
-
720
-	// Ensure that devices are no longer activated
721
-	for _, p := range []string{"1", "2"} {
722
-		if d.HasActivatedDevice(p) {
723
-			t.Fatalf("Expected %s not be an active device", p)
724
-		}
725
-	}
726
-}
727
-
728
-func TestNotMounted(t *testing.T) {
729
-	t.Skip("FIXME: not a unit test")
730
-	t.Skip("Not implemented")
731
-	d := newDriver(t)
732
-	defer cleanup(d)
733
-
734
-	if err := d.Create("1", ""); err != nil {
735
-		t.Fatal(err)
736
-	}
737
-
738
-	mounted, err := Mounted(path.Join(d.home, "mnt", "1"))
739
-	if err != nil {
740
-		t.Fatal(err)
741
-	}
742
-	if mounted {
743
-		t.Fatal("Id 1 should not be mounted")
744
-	}
745
-}
746
-
747
-func TestMounted(t *testing.T) {
748
-	t.Skip("FIXME: not a unit test")
749
-	d := newDriver(t)
750
-	defer cleanup(d)
751
-
752
-	if err := d.Create("1", ""); err != nil {
753
-		t.Fatal(err)
754
-	}
755
-	if _, err := d.Get("1"); err != nil {
756
-		t.Fatal(err)
757
-	}
758
-
759
-	mounted, err := Mounted(path.Join(d.home, "mnt", "1"))
760
-	if err != nil {
761
-		t.Fatal(err)
762
-	}
763
-	if !mounted {
764
-		t.Fatal("Id 1 should be mounted")
765
-	}
766
-}
767
-
768
-func TestInitCleanedDriver(t *testing.T) {
769
-	t.Skip("FIXME: not a unit test")
770
-	d := newDriver(t)
771
-
772
-	if err := d.Create("1", ""); err != nil {
773
-		t.Fatal(err)
774
-	}
775
-	if _, err := d.Get("1"); err != nil {
776
-		t.Fatal(err)
777
-	}
778
-
779
-	if err := d.Cleanup(); err != nil {
780
-		t.Fatal(err)
781
-	}
782
-
783
-	driver, err := Init(d.home)
784
-	if err != nil {
785
-		t.Fatal(err)
786
-	}
787
-	d = driver.(*Driver)
788
-	defer cleanup(d)
789
-
790
-	if _, err := d.Get("1"); err != nil {
791
-		t.Fatal(err)
792
-	}
793
-}
794
-
795
-func TestMountMountedDriver(t *testing.T) {
796
-	t.Skip("FIXME: not a unit test")
797
-	d := newDriver(t)
798
-	defer cleanup(d)
799
-
800
-	if err := d.Create("1", ""); err != nil {
801
-		t.Fatal(err)
802
-	}
803
-
804
-	// Perform get on same id to ensure that it will
805
-	// not be mounted twice
806
-	if _, err := d.Get("1"); err != nil {
807
-		t.Fatal(err)
808
-	}
809
-	if _, err := d.Get("1"); err != nil {
810
-		t.Fatal(err)
811
-	}
812
-}
813
-
814
-func TestGetReturnsValidDevice(t *testing.T) {
815
-	t.Skip("FIXME: not a unit test")
816
-	d := newDriver(t)
817
-	defer cleanup(d)
818
-
819
-	if err := d.Create("1", ""); err != nil {
820
-		t.Fatal(err)
821
-	}
822
-
823
-	if !d.HasDevice("1") {
824
-		t.Fatalf("Expected id 1 to be in device set")
825
-	}
826
-
827
-	if _, err := d.Get("1"); err != nil {
828
-		t.Fatal(err)
829
-	}
830
-
831
-	if !d.HasActivatedDevice("1") {
832
-		t.Fatalf("Expected id 1 to be activated")
833
-	}
834
-
835
-	if !d.HasInitializedDevice("1") {
836
-		t.Fatalf("Expected id 1 to be initialized")
837
-	}
838
-}
839
-
840
-func TestDriverGetSize(t *testing.T) {
841
-	t.Skip("FIXME: not a unit test")
842
-	t.Skipf("Size is currently not implemented")
843
-
844
-	d := newDriver(t)
845
-	defer cleanup(d)
846
-
847
-	if err := d.Create("1", ""); err != nil {
848
-		t.Fatal(err)
849
-	}
850
-
851
-	mountPoint, err := d.Get("1")
852
-	if err != nil {
853
-		t.Fatal(err)
854
-	}
855
-
856
-	size := int64(1024)
857
-
858
-	f, err := osCreate(path.Join(mountPoint, "test_file"))
859
-	if err != nil {
860
-		t.Fatal(err)
861
-	}
862
-	if err := f.Truncate(size); err != nil {
863
-		t.Fatal(err)
864
-	}
865
-	f.Close()
866
-
867
-	// diffSize, err := d.DiffSize("1")
868
-	// if err != nil {
869
-	// 	t.Fatal(err)
870
-	// }
871
-	// if diffSize != size {
872
-	// 	t.Fatalf("Expected size %d got %d", size, diffSize)
873
-	// }
874
-}
875
-
876
-func assertMap(t *testing.T, m map[string]bool, keys ...string) {
877
-	for _, key := range keys {
878
-		if _, exists := m[key]; !exists {
879
-			t.Fatalf("Key not set: %s", key)
880
-		}
881
-		delete(m, key)
882
-	}
883
-	if len(m) != 0 {
884
-		t.Fatalf("Unexpected keys: %v", m)
885
-	}
886
-}
887 1
deleted file mode 100644
... ...
@@ -1,71 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-import (
6
-	"unsafe"
7
-)
8
-
9
-func ioctlLoopCtlGetFree(fd uintptr) (int, error) {
10
-	index, _, err := sysSyscall(sysSysIoctl, fd, LoopCtlGetFree, 0)
11
-	if err != 0 {
12
-		return 0, err
13
-	}
14
-	return int(index), nil
15
-}
16
-
17
-func ioctlLoopSetFd(loopFd, sparseFd uintptr) error {
18
-	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetFd, sparseFd); err != 0 {
19
-		return err
20
-	}
21
-	return nil
22
-}
23
-
24
-func ioctlLoopSetStatus64(loopFd uintptr, loopInfo *LoopInfo64) error {
25
-	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
26
-		return err
27
-	}
28
-	return nil
29
-}
30
-
31
-func ioctlLoopClrFd(loopFd uintptr) error {
32
-	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopClrFd, 0); err != 0 {
33
-		return err
34
-	}
35
-	return nil
36
-}
37
-
38
-func ioctlLoopGetStatus64(loopFd uintptr) (*LoopInfo64, error) {
39
-	loopInfo := &LoopInfo64{}
40
-
41
-	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopGetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
42
-		return nil, err
43
-	}
44
-	return loopInfo, nil
45
-}
46
-
47
-func ioctlLoopSetCapacity(loopFd uintptr, value int) error {
48
-	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetCapacity, uintptr(value)); err != 0 {
49
-		return err
50
-	}
51
-	return nil
52
-}
53
-
54
-func ioctlBlkGetSize64(fd uintptr) (int64, error) {
55
-	var size int64
56
-	if _, _, err := sysSyscall(sysSysIoctl, fd, BlkGetSize64, uintptr(unsafe.Pointer(&size))); err != 0 {
57
-		return 0, err
58
-	}
59
-	return size, nil
60
-}
61
-
62
-func ioctlBlkDiscard(fd uintptr, offset, length uint64) error {
63
-	var r [2]uint64
64
-	r[0] = offset
65
-	r[1] = length
66
-
67
-	if _, _, err := sysSyscall(sysSysIoctl, fd, BlkDiscard, uintptr(unsafe.Pointer(&r[0]))); err != 0 {
68
-		return err
69
-	}
70
-	return nil
71
-}
72 1
deleted file mode 100644
... ...
@@ -1,27 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-import (
6
-	"path/filepath"
7
-)
8
-
9
-// FIXME: this is copy-pasted from the aufs driver.
10
-// It should be moved into the core.
11
-
12
-var Mounted = func(mountpoint string) (bool, error) {
13
-	mntpoint, err := osStat(mountpoint)
14
-	if err != nil {
15
-		if osIsNotExist(err) {
16
-			return false, nil
17
-		}
18
-		return false, err
19
-	}
20
-	parent, err := osStat(filepath.Join(mountpoint, ".."))
21
-	if err != nil {
22
-		return false, err
23
-	}
24
-	mntpointSt := toSysStatT(mntpoint.Sys())
25
-	parentSt := toSysStatT(parent.Sys())
26
-	return mntpointSt.Dev != parentSt.Dev, nil
27
-}
28 1
deleted file mode 100644
... ...
@@ -1,57 +0,0 @@
1
-// +build linux,amd64
2
-
3
-package devmapper
4
-
5
-import (
6
-	"os"
7
-	"os/exec"
8
-	"syscall"
9
-)
10
-
11
-type (
12
-	sysStatT syscall.Stat_t
13
-	sysErrno syscall.Errno
14
-
15
-	osFile struct{ *os.File }
16
-)
17
-
18
-var (
19
-	sysMount       = syscall.Mount
20
-	sysUnmount     = syscall.Unmount
21
-	sysCloseOnExec = syscall.CloseOnExec
22
-	sysSyscall     = syscall.Syscall
23
-
24
-	osOpenFile = func(name string, flag int, perm os.FileMode) (*osFile, error) {
25
-		f, err := os.OpenFile(name, flag, perm)
26
-		return &osFile{File: f}, err
27
-	}
28
-	osOpen       = func(name string) (*osFile, error) { f, err := os.Open(name); return &osFile{File: f}, err }
29
-	osNewFile    = os.NewFile
30
-	osCreate     = os.Create
31
-	osStat       = os.Stat
32
-	osIsNotExist = os.IsNotExist
33
-	osIsExist    = os.IsExist
34
-	osMkdirAll   = os.MkdirAll
35
-	osRemoveAll  = os.RemoveAll
36
-	osRename     = os.Rename
37
-	osReadlink   = os.Readlink
38
-
39
-	execRun = func(name string, args ...string) error { return exec.Command(name, args...).Run() }
40
-)
41
-
42
-const (
43
-	sysMsMgcVal = syscall.MS_MGC_VAL
44
-	sysMsRdOnly = syscall.MS_RDONLY
45
-	sysEInval   = syscall.EINVAL
46
-	sysSysIoctl = syscall.SYS_IOCTL
47
-	sysEBusy    = syscall.EBUSY
48
-
49
-	osORdOnly    = os.O_RDONLY
50
-	osORdWr      = os.O_RDWR
51
-	osOCreate    = os.O_CREATE
52
-	osModeDevice = os.ModeDevice
53
-)
54
-
55
-func toSysStatT(i interface{}) *sysStatT {
56
-	return (*sysStatT)(i.(*syscall.Stat_t))
57
-}
58 1
deleted file mode 100644
... ...
@@ -1,93 +0,0 @@
1
-package graphdriver
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/archive"
6
-	"github.com/dotcloud/docker/utils"
7
-	"os"
8
-	"path"
9
-)
10
-
11
-type InitFunc func(root string) (Driver, error)
12
-
13
-type Driver interface {
14
-	String() string
15
-
16
-	Create(id, parent string) error
17
-	Remove(id string) error
18
-
19
-	Get(id string) (dir string, err error)
20
-	Put(id string)
21
-	Exists(id string) bool
22
-
23
-	Status() [][2]string
24
-
25
-	Cleanup() error
26
-}
27
-
28
-type Differ interface {
29
-	Diff(id string) (archive.Archive, error)
30
-	Changes(id string) ([]archive.Change, error)
31
-	ApplyDiff(id string, diff archive.ArchiveReader) error
32
-	DiffSize(id string) (bytes int64, err error)
33
-}
34
-
35
-var (
36
-	DefaultDriver string
37
-	// All registred drivers
38
-	drivers map[string]InitFunc
39
-	// Slice of drivers that should be used in an order
40
-	priority = []string{
41
-		"aufs",
42
-		"devicemapper",
43
-		"vfs",
44
-		// experimental, has to be enabled manually for now
45
-		"btrfs",
46
-	}
47
-)
48
-
49
-func init() {
50
-	drivers = make(map[string]InitFunc)
51
-}
52
-
53
-func Register(name string, initFunc InitFunc) error {
54
-	if _, exists := drivers[name]; exists {
55
-		return fmt.Errorf("Name already registered %s", name)
56
-	}
57
-	drivers[name] = initFunc
58
-
59
-	return nil
60
-}
61
-
62
-func GetDriver(name, home string) (Driver, error) {
63
-	if initFunc, exists := drivers[name]; exists {
64
-		return initFunc(path.Join(home, name))
65
-	}
66
-	return nil, fmt.Errorf("No such driver: %s", name)
67
-}
68
-
69
-func New(root string) (driver Driver, err error) {
70
-	for _, name := range []string{os.Getenv("DOCKER_DRIVER"), DefaultDriver} {
71
-		if name != "" {
72
-			return GetDriver(name, root)
73
-		}
74
-	}
75
-
76
-	// Check for priority drivers first
77
-	for _, name := range priority {
78
-		if driver, err = GetDriver(name, root); err != nil {
79
-			utils.Debugf("Error loading driver %s: %s", name, err)
80
-			continue
81
-		}
82
-		return driver, nil
83
-	}
84
-
85
-	// Check all registered drivers if no priority driver is found
86
-	for _, initFunc := range drivers {
87
-		if driver, err = initFunc(root); err != nil {
88
-			continue
89
-		}
90
-		return driver, nil
91
-	}
92
-	return nil, err
93
-}
94 1
deleted file mode 100644
... ...
@@ -1,95 +0,0 @@
1
-package vfs
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/graphdriver"
6
-	"os"
7
-	"os/exec"
8
-	"path"
9
-)
10
-
11
-func init() {
12
-	graphdriver.Register("vfs", Init)
13
-}
14
-
15
-func Init(home string) (graphdriver.Driver, error) {
16
-	d := &Driver{
17
-		home: home,
18
-	}
19
-	return d, nil
20
-}
21
-
22
-type Driver struct {
23
-	home string
24
-}
25
-
26
-func (d *Driver) String() string {
27
-	return "vfs"
28
-}
29
-
30
-func (d *Driver) Status() [][2]string {
31
-	return nil
32
-}
33
-
34
-func (d *Driver) Cleanup() error {
35
-	return nil
36
-}
37
-
38
-func copyDir(src, dst string) error {
39
-	if output, err := exec.Command("cp", "-aT", "--reflink=auto", src, dst).CombinedOutput(); err != nil {
40
-		return fmt.Errorf("Error VFS copying directory: %s (%s)", err, output)
41
-	}
42
-	return nil
43
-}
44
-
45
-func (d *Driver) Create(id string, parent string) error {
46
-	dir := d.dir(id)
47
-	if err := os.MkdirAll(path.Dir(dir), 0700); err != nil {
48
-		return err
49
-	}
50
-	if err := os.Mkdir(dir, 0700); err != nil {
51
-		return err
52
-	}
53
-	if parent == "" {
54
-		return nil
55
-	}
56
-	parentDir, err := d.Get(parent)
57
-	if err != nil {
58
-		return fmt.Errorf("%s: %s", parent, err)
59
-	}
60
-	if err := copyDir(parentDir, dir); err != nil {
61
-		return err
62
-	}
63
-	return nil
64
-}
65
-
66
-func (d *Driver) dir(id string) string {
67
-	return path.Join(d.home, "dir", path.Base(id))
68
-}
69
-
70
-func (d *Driver) Remove(id string) error {
71
-	if _, err := os.Stat(d.dir(id)); err != nil {
72
-		return err
73
-	}
74
-	return os.RemoveAll(d.dir(id))
75
-}
76
-
77
-func (d *Driver) Get(id string) (string, error) {
78
-	dir := d.dir(id)
79
-	if st, err := os.Stat(dir); err != nil {
80
-		return "", err
81
-	} else if !st.IsDir() {
82
-		return "", fmt.Errorf("%s: not a directory", dir)
83
-	}
84
-	return dir, nil
85
-}
86
-
87
-func (d *Driver) Put(id string) {
88
-	// The vfs driver has no runtime resources (e.g. mounts)
89
-	// to clean up, so we don't need anything here
90
-}
91
-
92
-func (d *Driver) Exists(id string) bool {
93
-	_, err := os.Stat(d.dir(id))
94
-	return err == nil
95
-}
... ...
@@ -1,7 +1,7 @@
1 1
 package image
2 2
 
3 3
 import (
4
-	"github.com/dotcloud/docker/graphdriver"
4
+	"github.com/dotcloud/docker/runtime/graphdriver"
5 5
 )
6 6
 
7 7
 type Graph interface {
... ...
@@ -4,7 +4,7 @@ import (
4 4
 	"encoding/json"
5 5
 	"fmt"
6 6
 	"github.com/dotcloud/docker/archive"
7
-	"github.com/dotcloud/docker/graphdriver"
7
+	"github.com/dotcloud/docker/runtime/graphdriver"
8 8
 	"github.com/dotcloud/docker/runconfig"
9 9
 	"github.com/dotcloud/docker/utils"
10 10
 	"io/ioutil"
... ...
@@ -5,7 +5,7 @@ import (
5 5
 	"github.com/dotcloud/docker/archive"
6 6
 	"github.com/dotcloud/docker/dockerversion"
7 7
 	"github.com/dotcloud/docker/graph"
8
-	"github.com/dotcloud/docker/graphdriver"
8
+	"github.com/dotcloud/docker/runtime/graphdriver"
9 9
 	"github.com/dotcloud/docker/image"
10 10
 	"github.com/dotcloud/docker/utils"
11 11
 	"io"
... ...
@@ -7,7 +7,7 @@ import (
7 7
 	"github.com/dotcloud/docker/archive"
8 8
 	"github.com/dotcloud/docker/engine"
9 9
 	"github.com/dotcloud/docker/runtime/execdriver"
10
-	"github.com/dotcloud/docker/graphdriver"
10
+	"github.com/dotcloud/docker/runtime/graphdriver"
11 11
 	"github.com/dotcloud/docker/image"
12 12
 	"github.com/dotcloud/docker/links"
13 13
 	"github.com/dotcloud/docker/nat"
14 14
new file mode 100644
... ...
@@ -0,0 +1,401 @@
0
+/*
1
+
2
+aufs driver directory structure
3
+
4
+.
5
+├── layers // Metadata of layers
6
+│   ├── 1
7
+│   ├── 2
8
+│   └── 3
9
+├── diffs  // Content of the layer
10
+│   ├── 1  // Contains layers that need to be mounted for the id
11
+│   ├── 2
12
+│   └── 3
13
+└── mnt    // Mount points for the rw layers to be mounted
14
+    ├── 1
15
+    ├── 2
16
+    └── 3
17
+
18
+*/
19
+
20
+package aufs
21
+
22
+import (
23
+	"bufio"
24
+	"fmt"
25
+	"github.com/dotcloud/docker/archive"
26
+	"github.com/dotcloud/docker/runtime/graphdriver"
27
+	mountpk "github.com/dotcloud/docker/pkg/mount"
28
+	"github.com/dotcloud/docker/utils"
29
+	"os"
30
+	"os/exec"
31
+	"path"
32
+	"strings"
33
+	"sync"
34
+)
35
+
36
+var (
37
+	ErrAufsNotSupported = fmt.Errorf("AUFS was not found in /proc/filesystems")
38
+)
39
+
40
+func init() {
41
+	graphdriver.Register("aufs", Init)
42
+}
43
+
44
+type Driver struct {
45
+	root       string
46
+	sync.Mutex // Protects concurrent modification to active
47
+	active     map[string]int
48
+}
49
+
50
+// New returns a new AUFS driver.
51
+// An error is returned if AUFS is not supported.
52
+func Init(root string) (graphdriver.Driver, error) {
53
+	// Try to load the aufs kernel module
54
+	if err := supportsAufs(); err != nil {
55
+		return nil, err
56
+	}
57
+	paths := []string{
58
+		"mnt",
59
+		"diff",
60
+		"layers",
61
+	}
62
+
63
+	a := &Driver{
64
+		root:   root,
65
+		active: make(map[string]int),
66
+	}
67
+
68
+	// Create the root aufs driver dir and return
69
+	// if it already exists
70
+	// If not populate the dir structure
71
+	if err := os.MkdirAll(root, 0755); err != nil {
72
+		if os.IsExist(err) {
73
+			return a, nil
74
+		}
75
+		return nil, err
76
+	}
77
+
78
+	for _, p := range paths {
79
+		if err := os.MkdirAll(path.Join(root, p), 0755); err != nil {
80
+			return nil, err
81
+		}
82
+	}
83
+	return a, nil
84
+}
85
+
86
+// Return a nil error if the kernel supports aufs
87
+// We cannot modprobe because inside dind modprobe fails
88
+// to run
89
+func supportsAufs() error {
90
+	// We can try to modprobe aufs first before looking at
91
+	// proc/filesystems for when aufs is supported
92
+	exec.Command("modprobe", "aufs").Run()
93
+
94
+	f, err := os.Open("/proc/filesystems")
95
+	if err != nil {
96
+		return err
97
+	}
98
+	defer f.Close()
99
+
100
+	s := bufio.NewScanner(f)
101
+	for s.Scan() {
102
+		if strings.Contains(s.Text(), "aufs") {
103
+			return nil
104
+		}
105
+	}
106
+	return ErrAufsNotSupported
107
+}
108
+
109
+func (a Driver) rootPath() string {
110
+	return a.root
111
+}
112
+
113
+func (Driver) String() string {
114
+	return "aufs"
115
+}
116
+
117
+func (a Driver) Status() [][2]string {
118
+	ids, _ := loadIds(path.Join(a.rootPath(), "layers"))
119
+	return [][2]string{
120
+		{"Root Dir", a.rootPath()},
121
+		{"Dirs", fmt.Sprintf("%d", len(ids))},
122
+	}
123
+}
124
+
125
+// Exists returns true if the given id is registered with
126
+// this driver
127
+func (a Driver) Exists(id string) bool {
128
+	if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil {
129
+		return false
130
+	}
131
+	return true
132
+}
133
+
134
+// Three folders are created for each id
135
+// mnt, layers, and diff
136
+func (a *Driver) Create(id, parent string) error {
137
+	if err := a.createDirsFor(id); err != nil {
138
+		return err
139
+	}
140
+	// Write the layers metadata
141
+	f, err := os.Create(path.Join(a.rootPath(), "layers", id))
142
+	if err != nil {
143
+		return err
144
+	}
145
+	defer f.Close()
146
+
147
+	if parent != "" {
148
+		ids, err := getParentIds(a.rootPath(), parent)
149
+		if err != nil {
150
+			return err
151
+		}
152
+
153
+		if _, err := fmt.Fprintln(f, parent); err != nil {
154
+			return err
155
+		}
156
+		for _, i := range ids {
157
+			if _, err := fmt.Fprintln(f, i); err != nil {
158
+				return err
159
+			}
160
+		}
161
+	}
162
+	return nil
163
+}
164
+
165
+func (a *Driver) createDirsFor(id string) error {
166
+	paths := []string{
167
+		"mnt",
168
+		"diff",
169
+	}
170
+
171
+	for _, p := range paths {
172
+		if err := os.MkdirAll(path.Join(a.rootPath(), p, id), 0755); err != nil {
173
+			return err
174
+		}
175
+	}
176
+	return nil
177
+}
178
+
179
+// Unmount and remove the dir information
180
+func (a *Driver) Remove(id string) error {
181
+	// Protect the a.active from concurrent access
182
+	a.Lock()
183
+	defer a.Unlock()
184
+
185
+	if a.active[id] != 0 {
186
+		utils.Errorf("Warning: removing active id %s\n", id)
187
+	}
188
+
189
+	// Make sure the dir is umounted first
190
+	if err := a.unmount(id); err != nil {
191
+		return err
192
+	}
193
+	tmpDirs := []string{
194
+		"mnt",
195
+		"diff",
196
+	}
197
+
198
+	// Atomically remove each directory in turn by first moving it out of the
199
+	// way (so that docker doesn't find it anymore) before doing removal of
200
+	// the whole tree.
201
+	for _, p := range tmpDirs {
202
+
203
+		realPath := path.Join(a.rootPath(), p, id)
204
+		tmpPath := path.Join(a.rootPath(), p, fmt.Sprintf("%s-removing", id))
205
+		if err := os.Rename(realPath, tmpPath); err != nil && !os.IsNotExist(err) {
206
+			return err
207
+		}
208
+		defer os.RemoveAll(tmpPath)
209
+	}
210
+
211
+	// Remove the layers file for the id
212
+	if err := os.Remove(path.Join(a.rootPath(), "layers", id)); err != nil && !os.IsNotExist(err) {
213
+		return err
214
+	}
215
+	return nil
216
+}
217
+
218
+// Return the rootfs path for the id
219
+// This will mount the dir at it's given path
220
+func (a *Driver) Get(id string) (string, error) {
221
+	ids, err := getParentIds(a.rootPath(), id)
222
+	if err != nil {
223
+		if !os.IsNotExist(err) {
224
+			return "", err
225
+		}
226
+		ids = []string{}
227
+	}
228
+
229
+	// Protect the a.active from concurrent access
230
+	a.Lock()
231
+	defer a.Unlock()
232
+
233
+	count := a.active[id]
234
+
235
+	// If a dir does not have a parent ( no layers )do not try to mount
236
+	// just return the diff path to the data
237
+	out := path.Join(a.rootPath(), "diff", id)
238
+	if len(ids) > 0 {
239
+		out = path.Join(a.rootPath(), "mnt", id)
240
+
241
+		if count == 0 {
242
+			if err := a.mount(id); err != nil {
243
+				return "", err
244
+			}
245
+		}
246
+	}
247
+
248
+	a.active[id] = count + 1
249
+
250
+	return out, nil
251
+}
252
+
253
+func (a *Driver) Put(id string) {
254
+	// Protect the a.active from concurrent access
255
+	a.Lock()
256
+	defer a.Unlock()
257
+
258
+	if count := a.active[id]; count > 1 {
259
+		a.active[id] = count - 1
260
+	} else {
261
+		ids, _ := getParentIds(a.rootPath(), id)
262
+		// We only mounted if there are any parents
263
+		if ids != nil && len(ids) > 0 {
264
+			a.unmount(id)
265
+		}
266
+		delete(a.active, id)
267
+	}
268
+}
269
+
270
+// Returns an archive of the contents for the id
271
+func (a *Driver) Diff(id string) (archive.Archive, error) {
272
+	return archive.TarFilter(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
273
+		Compression: archive.Uncompressed,
274
+	})
275
+}
276
+
277
+func (a *Driver) ApplyDiff(id string, diff archive.ArchiveReader) error {
278
+	return archive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
279
+}
280
+
281
+// Returns the size of the contents for the id
282
+func (a *Driver) DiffSize(id string) (int64, error) {
283
+	return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
284
+}
285
+
286
+func (a *Driver) Changes(id string) ([]archive.Change, error) {
287
+	layers, err := a.getParentLayerPaths(id)
288
+	if err != nil {
289
+		return nil, err
290
+	}
291
+	return archive.Changes(layers, path.Join(a.rootPath(), "diff", id))
292
+}
293
+
294
+func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
295
+	parentIds, err := getParentIds(a.rootPath(), id)
296
+	if err != nil {
297
+		return nil, err
298
+	}
299
+	if len(parentIds) == 0 {
300
+		return nil, fmt.Errorf("Dir %s does not have any parent layers", id)
301
+	}
302
+	layers := make([]string, len(parentIds))
303
+
304
+	// Get the diff paths for all the parent ids
305
+	for i, p := range parentIds {
306
+		layers[i] = path.Join(a.rootPath(), "diff", p)
307
+	}
308
+	return layers, nil
309
+}
310
+
311
+func (a *Driver) mount(id string) error {
312
+	// If the id is mounted or we get an error return
313
+	if mounted, err := a.mounted(id); err != nil || mounted {
314
+		return err
315
+	}
316
+
317
+	var (
318
+		target = path.Join(a.rootPath(), "mnt", id)
319
+		rw     = path.Join(a.rootPath(), "diff", id)
320
+	)
321
+
322
+	layers, err := a.getParentLayerPaths(id)
323
+	if err != nil {
324
+		return err
325
+	}
326
+
327
+	if err := a.aufsMount(layers, rw, target); err != nil {
328
+		return err
329
+	}
330
+	return nil
331
+}
332
+
333
+func (a *Driver) unmount(id string) error {
334
+	if mounted, err := a.mounted(id); err != nil || !mounted {
335
+		return err
336
+	}
337
+	target := path.Join(a.rootPath(), "mnt", id)
338
+	return Unmount(target)
339
+}
340
+
341
+func (a *Driver) mounted(id string) (bool, error) {
342
+	target := path.Join(a.rootPath(), "mnt", id)
343
+	return mountpk.Mounted(target)
344
+}
345
+
346
+// During cleanup aufs needs to unmount all mountpoints
347
+func (a *Driver) Cleanup() error {
348
+	ids, err := loadIds(path.Join(a.rootPath(), "layers"))
349
+	if err != nil {
350
+		return err
351
+	}
352
+	for _, id := range ids {
353
+		if err := a.unmount(id); err != nil {
354
+			utils.Errorf("Unmounting %s: %s", utils.TruncateID(id), err)
355
+		}
356
+	}
357
+	return nil
358
+}
359
+
360
+func (a *Driver) aufsMount(ro []string, rw, target string) (err error) {
361
+	defer func() {
362
+		if err != nil {
363
+			Unmount(target)
364
+		}
365
+	}()
366
+
367
+	if err = a.tryMount(ro, rw, target); err != nil {
368
+		if err = a.mountRw(rw, target); err != nil {
369
+			return
370
+		}
371
+
372
+		for _, layer := range ro {
373
+			branch := fmt.Sprintf("append:%s=ro+wh", layer)
374
+			if err = mount("none", target, "aufs", MsRemount, branch); err != nil {
375
+				return
376
+			}
377
+		}
378
+	}
379
+	return
380
+}
381
+
382
+// Try to mount using the aufs fast path, if this fails then
383
+// append ro layers.
384
+func (a *Driver) tryMount(ro []string, rw, target string) (err error) {
385
+	var (
386
+		rwBranch   = fmt.Sprintf("%s=rw", rw)
387
+		roBranches = fmt.Sprintf("%s=ro+wh:", strings.Join(ro, "=ro+wh:"))
388
+	)
389
+	return mount("none", target, "aufs", 0, fmt.Sprintf("br:%v:%v,xino=/dev/shm/aufs.xino", rwBranch, roBranches))
390
+}
391
+
392
+func (a *Driver) mountRw(rw, target string) error {
393
+	return mount("none", target, "aufs", 0, fmt.Sprintf("br:%s,xino=/dev/shm/aufs.xino", rw))
394
+}
395
+
396
+func rollbackMount(target string, err error) {
397
+	if err != nil {
398
+		Unmount(target)
399
+	}
400
+}
0 401
new file mode 100644
... ...
@@ -0,0 +1,697 @@
0
+package aufs
1
+
2
+import (
3
+	"crypto/sha256"
4
+	"encoding/hex"
5
+	"fmt"
6
+	"github.com/dotcloud/docker/archive"
7
+	"github.com/dotcloud/docker/runtime/graphdriver"
8
+	"io/ioutil"
9
+	"os"
10
+	"path"
11
+	"testing"
12
+)
13
+
14
+var (
15
+	tmp = path.Join(os.TempDir(), "aufs-tests", "aufs")
16
+)
17
+
18
+func testInit(dir string, t *testing.T) graphdriver.Driver {
19
+	d, err := Init(dir)
20
+	if err != nil {
21
+		if err == ErrAufsNotSupported {
22
+			t.Skip(err)
23
+		} else {
24
+			t.Fatal(err)
25
+		}
26
+	}
27
+	return d
28
+}
29
+
30
+func newDriver(t *testing.T) *Driver {
31
+	if err := os.MkdirAll(tmp, 0755); err != nil {
32
+		t.Fatal(err)
33
+	}
34
+
35
+	d := testInit(tmp, t)
36
+	return d.(*Driver)
37
+}
38
+
39
+func TestNewDriver(t *testing.T) {
40
+	if err := os.MkdirAll(tmp, 0755); err != nil {
41
+		t.Fatal(err)
42
+	}
43
+
44
+	d := testInit(tmp, t)
45
+	defer os.RemoveAll(tmp)
46
+	if d == nil {
47
+		t.Fatalf("Driver should not be nil")
48
+	}
49
+}
50
+
51
+func TestAufsString(t *testing.T) {
52
+	d := newDriver(t)
53
+	defer os.RemoveAll(tmp)
54
+
55
+	if d.String() != "aufs" {
56
+		t.Fatalf("Expected aufs got %s", d.String())
57
+	}
58
+}
59
+
60
+func TestCreateDirStructure(t *testing.T) {
61
+	newDriver(t)
62
+	defer os.RemoveAll(tmp)
63
+
64
+	paths := []string{
65
+		"mnt",
66
+		"layers",
67
+		"diff",
68
+	}
69
+
70
+	for _, p := range paths {
71
+		if _, err := os.Stat(path.Join(tmp, p)); err != nil {
72
+			t.Fatal(err)
73
+		}
74
+	}
75
+}
76
+
77
+// We should be able to create two drivers with the same dir structure
78
+func TestNewDriverFromExistingDir(t *testing.T) {
79
+	if err := os.MkdirAll(tmp, 0755); err != nil {
80
+		t.Fatal(err)
81
+	}
82
+
83
+	testInit(tmp, t)
84
+	testInit(tmp, t)
85
+	os.RemoveAll(tmp)
86
+}
87
+
88
+func TestCreateNewDir(t *testing.T) {
89
+	d := newDriver(t)
90
+	defer os.RemoveAll(tmp)
91
+
92
+	if err := d.Create("1", ""); err != nil {
93
+		t.Fatal(err)
94
+	}
95
+}
96
+
97
+func TestCreateNewDirStructure(t *testing.T) {
98
+	d := newDriver(t)
99
+	defer os.RemoveAll(tmp)
100
+
101
+	if err := d.Create("1", ""); err != nil {
102
+		t.Fatal(err)
103
+	}
104
+
105
+	paths := []string{
106
+		"mnt",
107
+		"diff",
108
+		"layers",
109
+	}
110
+
111
+	for _, p := range paths {
112
+		if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil {
113
+			t.Fatal(err)
114
+		}
115
+	}
116
+}
117
+
118
+func TestRemoveImage(t *testing.T) {
119
+	d := newDriver(t)
120
+	defer os.RemoveAll(tmp)
121
+
122
+	if err := d.Create("1", ""); err != nil {
123
+		t.Fatal(err)
124
+	}
125
+
126
+	if err := d.Remove("1"); err != nil {
127
+		t.Fatal(err)
128
+	}
129
+
130
+	paths := []string{
131
+		"mnt",
132
+		"diff",
133
+		"layers",
134
+	}
135
+
136
+	for _, p := range paths {
137
+		if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil {
138
+			t.Fatalf("Error should not be nil because dirs with id 1 should be delted: %s", p)
139
+		}
140
+	}
141
+}
142
+
143
+func TestGetWithoutParent(t *testing.T) {
144
+	d := newDriver(t)
145
+	defer os.RemoveAll(tmp)
146
+
147
+	if err := d.Create("1", ""); err != nil {
148
+		t.Fatal(err)
149
+	}
150
+
151
+	diffPath, err := d.Get("1")
152
+	if err != nil {
153
+		t.Fatal(err)
154
+	}
155
+	expected := path.Join(tmp, "diff", "1")
156
+	if diffPath != expected {
157
+		t.Fatalf("Expected path %s got %s", expected, diffPath)
158
+	}
159
+}
160
+
161
+func TestCleanupWithNoDirs(t *testing.T) {
162
+	d := newDriver(t)
163
+	defer os.RemoveAll(tmp)
164
+
165
+	if err := d.Cleanup(); err != nil {
166
+		t.Fatal(err)
167
+	}
168
+}
169
+
170
+func TestCleanupWithDir(t *testing.T) {
171
+	d := newDriver(t)
172
+	defer os.RemoveAll(tmp)
173
+
174
+	if err := d.Create("1", ""); err != nil {
175
+		t.Fatal(err)
176
+	}
177
+
178
+	if err := d.Cleanup(); err != nil {
179
+		t.Fatal(err)
180
+	}
181
+}
182
+
183
+func TestMountedFalseResponse(t *testing.T) {
184
+	d := newDriver(t)
185
+	defer os.RemoveAll(tmp)
186
+
187
+	if err := d.Create("1", ""); err != nil {
188
+		t.Fatal(err)
189
+	}
190
+
191
+	response, err := d.mounted("1")
192
+	if err != nil {
193
+		t.Fatal(err)
194
+	}
195
+
196
+	if response != false {
197
+		t.Fatalf("Response if dir id 1 is mounted should be false")
198
+	}
199
+}
200
+
201
+func TestMountedTrueReponse(t *testing.T) {
202
+	d := newDriver(t)
203
+	defer os.RemoveAll(tmp)
204
+	defer d.Cleanup()
205
+
206
+	if err := d.Create("1", ""); err != nil {
207
+		t.Fatal(err)
208
+	}
209
+	if err := d.Create("2", "1"); err != nil {
210
+		t.Fatal(err)
211
+	}
212
+
213
+	_, err := d.Get("2")
214
+	if err != nil {
215
+		t.Fatal(err)
216
+	}
217
+
218
+	response, err := d.mounted("2")
219
+	if err != nil {
220
+		t.Fatal(err)
221
+	}
222
+
223
+	if response != true {
224
+		t.Fatalf("Response if dir id 2 is mounted should be true")
225
+	}
226
+}
227
+
228
+func TestMountWithParent(t *testing.T) {
229
+	d := newDriver(t)
230
+	defer os.RemoveAll(tmp)
231
+
232
+	if err := d.Create("1", ""); err != nil {
233
+		t.Fatal(err)
234
+	}
235
+	if err := d.Create("2", "1"); err != nil {
236
+		t.Fatal(err)
237
+	}
238
+
239
+	defer func() {
240
+		if err := d.Cleanup(); err != nil {
241
+			t.Fatal(err)
242
+		}
243
+	}()
244
+
245
+	mntPath, err := d.Get("2")
246
+	if err != nil {
247
+		t.Fatal(err)
248
+	}
249
+	if mntPath == "" {
250
+		t.Fatal("mntPath should not be empty string")
251
+	}
252
+
253
+	expected := path.Join(tmp, "mnt", "2")
254
+	if mntPath != expected {
255
+		t.Fatalf("Expected %s got %s", expected, mntPath)
256
+	}
257
+}
258
+
259
+func TestRemoveMountedDir(t *testing.T) {
260
+	d := newDriver(t)
261
+	defer os.RemoveAll(tmp)
262
+
263
+	if err := d.Create("1", ""); err != nil {
264
+		t.Fatal(err)
265
+	}
266
+	if err := d.Create("2", "1"); err != nil {
267
+		t.Fatal(err)
268
+	}
269
+
270
+	defer func() {
271
+		if err := d.Cleanup(); err != nil {
272
+			t.Fatal(err)
273
+		}
274
+	}()
275
+
276
+	mntPath, err := d.Get("2")
277
+	if err != nil {
278
+		t.Fatal(err)
279
+	}
280
+	if mntPath == "" {
281
+		t.Fatal("mntPath should not be empty string")
282
+	}
283
+
284
+	mounted, err := d.mounted("2")
285
+	if err != nil {
286
+		t.Fatal(err)
287
+	}
288
+
289
+	if !mounted {
290
+		t.Fatalf("Dir id 2 should be mounted")
291
+	}
292
+
293
+	if err := d.Remove("2"); err != nil {
294
+		t.Fatal(err)
295
+	}
296
+}
297
+
298
+func TestCreateWithInvalidParent(t *testing.T) {
299
+	d := newDriver(t)
300
+	defer os.RemoveAll(tmp)
301
+
302
+	if err := d.Create("1", "docker"); err == nil {
303
+		t.Fatalf("Error should not be nil with parent does not exist")
304
+	}
305
+}
306
+
307
+func TestGetDiff(t *testing.T) {
308
+	d := newDriver(t)
309
+	defer os.RemoveAll(tmp)
310
+
311
+	if err := d.Create("1", ""); err != nil {
312
+		t.Fatal(err)
313
+	}
314
+
315
+	diffPath, err := d.Get("1")
316
+	if err != nil {
317
+		t.Fatal(err)
318
+	}
319
+
320
+	// Add a file to the diff path with a fixed size
321
+	size := int64(1024)
322
+
323
+	f, err := os.Create(path.Join(diffPath, "test_file"))
324
+	if err != nil {
325
+		t.Fatal(err)
326
+	}
327
+	if err := f.Truncate(size); err != nil {
328
+		t.Fatal(err)
329
+	}
330
+	f.Close()
331
+
332
+	a, err := d.Diff("1")
333
+	if err != nil {
334
+		t.Fatal(err)
335
+	}
336
+	if a == nil {
337
+		t.Fatalf("Archive should not be nil")
338
+	}
339
+}
340
+
341
+func TestChanges(t *testing.T) {
342
+	d := newDriver(t)
343
+	defer os.RemoveAll(tmp)
344
+
345
+	if err := d.Create("1", ""); err != nil {
346
+		t.Fatal(err)
347
+	}
348
+	if err := d.Create("2", "1"); err != nil {
349
+		t.Fatal(err)
350
+	}
351
+
352
+	defer func() {
353
+		if err := d.Cleanup(); err != nil {
354
+			t.Fatal(err)
355
+		}
356
+	}()
357
+
358
+	mntPoint, err := d.Get("2")
359
+	if err != nil {
360
+		t.Fatal(err)
361
+	}
362
+
363
+	// Create a file to save in the mountpoint
364
+	f, err := os.Create(path.Join(mntPoint, "test.txt"))
365
+	if err != nil {
366
+		t.Fatal(err)
367
+	}
368
+
369
+	if _, err := f.WriteString("testline"); err != nil {
370
+		t.Fatal(err)
371
+	}
372
+	if err := f.Close(); err != nil {
373
+		t.Fatal(err)
374
+	}
375
+
376
+	changes, err := d.Changes("2")
377
+	if err != nil {
378
+		t.Fatal(err)
379
+	}
380
+	if len(changes) != 1 {
381
+		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
382
+	}
383
+	change := changes[0]
384
+
385
+	expectedPath := "/test.txt"
386
+	if change.Path != expectedPath {
387
+		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
388
+	}
389
+
390
+	if change.Kind != archive.ChangeAdd {
391
+		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
392
+	}
393
+
394
+	if err := d.Create("3", "2"); err != nil {
395
+		t.Fatal(err)
396
+	}
397
+	mntPoint, err = d.Get("3")
398
+	if err != nil {
399
+		t.Fatal(err)
400
+	}
401
+
402
+	// Create a file to save in the mountpoint
403
+	f, err = os.Create(path.Join(mntPoint, "test2.txt"))
404
+	if err != nil {
405
+		t.Fatal(err)
406
+	}
407
+
408
+	if _, err := f.WriteString("testline"); err != nil {
409
+		t.Fatal(err)
410
+	}
411
+	if err := f.Close(); err != nil {
412
+		t.Fatal(err)
413
+	}
414
+
415
+	changes, err = d.Changes("3")
416
+	if err != nil {
417
+		t.Fatal(err)
418
+	}
419
+
420
+	if len(changes) != 1 {
421
+		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
422
+	}
423
+	change = changes[0]
424
+
425
+	expectedPath = "/test2.txt"
426
+	if change.Path != expectedPath {
427
+		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
428
+	}
429
+
430
+	if change.Kind != archive.ChangeAdd {
431
+		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
432
+	}
433
+}
434
+
435
+func TestDiffSize(t *testing.T) {
436
+	d := newDriver(t)
437
+	defer os.RemoveAll(tmp)
438
+
439
+	if err := d.Create("1", ""); err != nil {
440
+		t.Fatal(err)
441
+	}
442
+
443
+	diffPath, err := d.Get("1")
444
+	if err != nil {
445
+		t.Fatal(err)
446
+	}
447
+
448
+	// Add a file to the diff path with a fixed size
449
+	size := int64(1024)
450
+
451
+	f, err := os.Create(path.Join(diffPath, "test_file"))
452
+	if err != nil {
453
+		t.Fatal(err)
454
+	}
455
+	if err := f.Truncate(size); err != nil {
456
+		t.Fatal(err)
457
+	}
458
+	s, err := f.Stat()
459
+	if err != nil {
460
+		t.Fatal(err)
461
+	}
462
+	size = s.Size()
463
+	if err := f.Close(); err != nil {
464
+		t.Fatal(err)
465
+	}
466
+
467
+	diffSize, err := d.DiffSize("1")
468
+	if err != nil {
469
+		t.Fatal(err)
470
+	}
471
+	if diffSize != size {
472
+		t.Fatalf("Expected size to be %d got %d", size, diffSize)
473
+	}
474
+}
475
+
476
+func TestChildDiffSize(t *testing.T) {
477
+	d := newDriver(t)
478
+	defer os.RemoveAll(tmp)
479
+	defer d.Cleanup()
480
+
481
+	if err := d.Create("1", ""); err != nil {
482
+		t.Fatal(err)
483
+	}
484
+
485
+	diffPath, err := d.Get("1")
486
+	if err != nil {
487
+		t.Fatal(err)
488
+	}
489
+
490
+	// Add a file to the diff path with a fixed size
491
+	size := int64(1024)
492
+
493
+	f, err := os.Create(path.Join(diffPath, "test_file"))
494
+	if err != nil {
495
+		t.Fatal(err)
496
+	}
497
+	if err := f.Truncate(size); err != nil {
498
+		t.Fatal(err)
499
+	}
500
+	s, err := f.Stat()
501
+	if err != nil {
502
+		t.Fatal(err)
503
+	}
504
+	size = s.Size()
505
+	if err := f.Close(); err != nil {
506
+		t.Fatal(err)
507
+	}
508
+
509
+	diffSize, err := d.DiffSize("1")
510
+	if err != nil {
511
+		t.Fatal(err)
512
+	}
513
+	if diffSize != size {
514
+		t.Fatalf("Expected size to be %d got %d", size, diffSize)
515
+	}
516
+
517
+	if err := d.Create("2", "1"); err != nil {
518
+		t.Fatal(err)
519
+	}
520
+
521
+	diffSize, err = d.DiffSize("2")
522
+	if err != nil {
523
+		t.Fatal(err)
524
+	}
525
+	// The diff size for the child should be zero
526
+	if diffSize != 0 {
527
+		t.Fatalf("Expected size to be %d got %d", 0, diffSize)
528
+	}
529
+}
530
+
531
+func TestExists(t *testing.T) {
532
+	d := newDriver(t)
533
+	defer os.RemoveAll(tmp)
534
+	defer d.Cleanup()
535
+
536
+	if err := d.Create("1", ""); err != nil {
537
+		t.Fatal(err)
538
+	}
539
+
540
+	if d.Exists("none") {
541
+		t.Fatal("id name should not exist in the driver")
542
+	}
543
+
544
+	if !d.Exists("1") {
545
+		t.Fatal("id 1 should exist in the driver")
546
+	}
547
+}
548
+
549
+func TestStatus(t *testing.T) {
550
+	d := newDriver(t)
551
+	defer os.RemoveAll(tmp)
552
+	defer d.Cleanup()
553
+
554
+	if err := d.Create("1", ""); err != nil {
555
+		t.Fatal(err)
556
+	}
557
+
558
+	status := d.Status()
559
+	if status == nil || len(status) == 0 {
560
+		t.Fatal("Status should not be nil or empty")
561
+	}
562
+	rootDir := status[0]
563
+	dirs := status[1]
564
+	if rootDir[0] != "Root Dir" {
565
+		t.Fatalf("Expected Root Dir got %s", rootDir[0])
566
+	}
567
+	if rootDir[1] != d.rootPath() {
568
+		t.Fatalf("Expected %s got %s", d.rootPath(), rootDir[1])
569
+	}
570
+	if dirs[0] != "Dirs" {
571
+		t.Fatalf("Expected Dirs got %s", dirs[0])
572
+	}
573
+	if dirs[1] != "1" {
574
+		t.Fatalf("Expected 1 got %s", dirs[1])
575
+	}
576
+}
577
+
578
+func TestApplyDiff(t *testing.T) {
579
+	d := newDriver(t)
580
+	defer os.RemoveAll(tmp)
581
+	defer d.Cleanup()
582
+
583
+	if err := d.Create("1", ""); err != nil {
584
+		t.Fatal(err)
585
+	}
586
+
587
+	diffPath, err := d.Get("1")
588
+	if err != nil {
589
+		t.Fatal(err)
590
+	}
591
+
592
+	// Add a file to the diff path with a fixed size
593
+	size := int64(1024)
594
+
595
+	f, err := os.Create(path.Join(diffPath, "test_file"))
596
+	if err != nil {
597
+		t.Fatal(err)
598
+	}
599
+	if err := f.Truncate(size); err != nil {
600
+		t.Fatal(err)
601
+	}
602
+	f.Close()
603
+
604
+	diff, err := d.Diff("1")
605
+	if err != nil {
606
+		t.Fatal(err)
607
+	}
608
+
609
+	if err := d.Create("2", ""); err != nil {
610
+		t.Fatal(err)
611
+	}
612
+	if err := d.Create("3", "2"); err != nil {
613
+		t.Fatal(err)
614
+	}
615
+
616
+	if err := d.ApplyDiff("3", diff); err != nil {
617
+		t.Fatal(err)
618
+	}
619
+
620
+	// Ensure that the file is in the mount point for id 3
621
+
622
+	mountPoint, err := d.Get("3")
623
+	if err != nil {
624
+		t.Fatal(err)
625
+	}
626
+	if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil {
627
+		t.Fatal(err)
628
+	}
629
+}
630
+
631
+func hash(c string) string {
632
+	h := sha256.New()
633
+	fmt.Fprint(h, c)
634
+	return hex.EncodeToString(h.Sum(nil))
635
+}
636
+
637
+func TestMountMoreThan42Layers(t *testing.T) {
638
+	d := newDriver(t)
639
+	defer os.RemoveAll(tmp)
640
+	defer d.Cleanup()
641
+	var last string
642
+	var expected int
643
+
644
+	for i := 1; i < 127; i++ {
645
+		expected++
646
+		var (
647
+			parent  = fmt.Sprintf("%d", i-1)
648
+			current = fmt.Sprintf("%d", i)
649
+		)
650
+
651
+		if parent == "0" {
652
+			parent = ""
653
+		} else {
654
+			parent = hash(parent)
655
+		}
656
+		current = hash(current)
657
+
658
+		if err := d.Create(current, parent); err != nil {
659
+			t.Logf("Current layer %d", i)
660
+			t.Fatal(err)
661
+		}
662
+		point, err := d.Get(current)
663
+		if err != nil {
664
+			t.Logf("Current layer %d", i)
665
+			t.Fatal(err)
666
+		}
667
+		f, err := os.Create(path.Join(point, current))
668
+		if err != nil {
669
+			t.Logf("Current layer %d", i)
670
+			t.Fatal(err)
671
+		}
672
+		f.Close()
673
+
674
+		if i%10 == 0 {
675
+			if err := os.Remove(path.Join(point, parent)); err != nil {
676
+				t.Logf("Current layer %d", i)
677
+				t.Fatal(err)
678
+			}
679
+			expected--
680
+		}
681
+		last = current
682
+	}
683
+
684
+	// Perform the actual mount for the top most image
685
+	point, err := d.Get(last)
686
+	if err != nil {
687
+		t.Fatal(err)
688
+	}
689
+	files, err := ioutil.ReadDir(point)
690
+	if err != nil {
691
+		t.Fatal(err)
692
+	}
693
+	if len(files) != expected {
694
+		t.Fatalf("Expected %d got %d", expected, len(files))
695
+	}
696
+}
0 697
new file mode 100644
... ...
@@ -0,0 +1,46 @@
0
+package aufs
1
+
2
+import (
3
+	"bufio"
4
+	"io/ioutil"
5
+	"os"
6
+	"path"
7
+)
8
+
9
+// Return all the directories
10
+func loadIds(root string) ([]string, error) {
11
+	dirs, err := ioutil.ReadDir(root)
12
+	if err != nil {
13
+		return nil, err
14
+	}
15
+	out := []string{}
16
+	for _, d := range dirs {
17
+		if !d.IsDir() {
18
+			out = append(out, d.Name())
19
+		}
20
+	}
21
+	return out, nil
22
+}
23
+
24
+// Read the layers file for the current id and return all the
25
+// layers represented by new lines in the file
26
+//
27
+// If there are no lines in the file then the id has no parent
28
+// and an empty slice is returned.
29
+func getParentIds(root, id string) ([]string, error) {
30
+	f, err := os.Open(path.Join(root, "layers", id))
31
+	if err != nil {
32
+		return nil, err
33
+	}
34
+	defer f.Close()
35
+
36
+	out := []string{}
37
+	s := bufio.NewScanner(f)
38
+
39
+	for s.Scan() {
40
+		if t := s.Text(); t != "" {
41
+			out = append(out, s.Text())
42
+		}
43
+	}
44
+	return out, s.Err()
45
+}
0 46
new file mode 100644
... ...
@@ -0,0 +1,194 @@
0
+package aufs
1
+
2
+import (
3
+	"encoding/json"
4
+	"fmt"
5
+	"io/ioutil"
6
+	"os"
7
+	"path"
8
+)
9
+
10
+type metadata struct {
11
+	ID       string `json:"id"`
12
+	ParentID string `json:"parent,omitempty"`
13
+	Image    string `json:"Image,omitempty"`
14
+
15
+	parent *metadata
16
+}
17
+
18
+func pathExists(pth string) bool {
19
+	if _, err := os.Stat(pth); err != nil {
20
+		return false
21
+	}
22
+	return true
23
+}
24
+
25
+// Migrate existing images and containers from docker < 0.7.x
26
+//
27
+// The format pre 0.7 is for docker to store the metadata and filesystem
28
+// content in the same directory.  For the migration to work we need to move Image layer
29
+// data from /var/lib/docker/graph/<id>/layers to the diff of the registered id.
30
+//
31
+// Next we need to migrate the container's rw layer to diff of the driver.  After the
32
+// contents are migrated we need to register the image and container ids with the
33
+// driver.
34
+//
35
+// For the migration we try to move the folder containing the layer files, if that
36
+// fails because the data is currently mounted we will fallback to creating a
37
+// symlink.
38
+func (a *Driver) Migrate(pth string, setupInit func(p string) error) error {
39
+	if pathExists(path.Join(pth, "graph")) {
40
+		if err := a.migrateRepositories(pth); err != nil {
41
+			return err
42
+		}
43
+		if err := a.migrateImages(path.Join(pth, "graph")); err != nil {
44
+			return err
45
+		}
46
+		return a.migrateContainers(path.Join(pth, "containers"), setupInit)
47
+	}
48
+	return nil
49
+}
50
+
51
+func (a *Driver) migrateRepositories(pth string) error {
52
+	name := path.Join(pth, "repositories")
53
+	if err := os.Rename(name, name+"-aufs"); err != nil && !os.IsNotExist(err) {
54
+		return err
55
+	}
56
+	return nil
57
+}
58
+
59
+func (a *Driver) migrateContainers(pth string, setupInit func(p string) error) error {
60
+	fis, err := ioutil.ReadDir(pth)
61
+	if err != nil {
62
+		return err
63
+	}
64
+
65
+	for _, fi := range fis {
66
+		if id := fi.Name(); fi.IsDir() && pathExists(path.Join(pth, id, "rw")) {
67
+			if err := tryRelocate(path.Join(pth, id, "rw"), path.Join(a.rootPath(), "diff", id)); err != nil {
68
+				return err
69
+			}
70
+
71
+			if !a.Exists(id) {
72
+
73
+				metadata, err := loadMetadata(path.Join(pth, id, "config.json"))
74
+				if err != nil {
75
+					return err
76
+				}
77
+
78
+				initID := fmt.Sprintf("%s-init", id)
79
+				if err := a.Create(initID, metadata.Image); err != nil {
80
+					return err
81
+				}
82
+
83
+				initPath, err := a.Get(initID)
84
+				if err != nil {
85
+					return err
86
+				}
87
+				// setup init layer
88
+				if err := setupInit(initPath); err != nil {
89
+					return err
90
+				}
91
+
92
+				if err := a.Create(id, initID); err != nil {
93
+					return err
94
+				}
95
+			}
96
+		}
97
+	}
98
+	return nil
99
+}
100
+
101
+func (a *Driver) migrateImages(pth string) error {
102
+	fis, err := ioutil.ReadDir(pth)
103
+	if err != nil {
104
+		return err
105
+	}
106
+	var (
107
+		m       = make(map[string]*metadata)
108
+		current *metadata
109
+		exists  bool
110
+	)
111
+
112
+	for _, fi := range fis {
113
+		if id := fi.Name(); fi.IsDir() && pathExists(path.Join(pth, id, "layer")) {
114
+			if current, exists = m[id]; !exists {
115
+				current, err = loadMetadata(path.Join(pth, id, "json"))
116
+				if err != nil {
117
+					return err
118
+				}
119
+				m[id] = current
120
+			}
121
+		}
122
+	}
123
+
124
+	for _, v := range m {
125
+		v.parent = m[v.ParentID]
126
+	}
127
+
128
+	migrated := make(map[string]bool)
129
+	for _, v := range m {
130
+		if err := a.migrateImage(v, pth, migrated); err != nil {
131
+			return err
132
+		}
133
+	}
134
+	return nil
135
+}
136
+
137
+func (a *Driver) migrateImage(m *metadata, pth string, migrated map[string]bool) error {
138
+	if !migrated[m.ID] {
139
+		if m.parent != nil {
140
+			a.migrateImage(m.parent, pth, migrated)
141
+		}
142
+		if err := tryRelocate(path.Join(pth, m.ID, "layer"), path.Join(a.rootPath(), "diff", m.ID)); err != nil {
143
+			return err
144
+		}
145
+		if !a.Exists(m.ID) {
146
+			if err := a.Create(m.ID, m.ParentID); err != nil {
147
+				return err
148
+			}
149
+		}
150
+		migrated[m.ID] = true
151
+	}
152
+	return nil
153
+}
154
+
155
+// tryRelocate will try to rename the old path to the new pack and if
156
+// the operation fails, it will fallback to a symlink
157
+func tryRelocate(oldPath, newPath string) error {
158
+	s, err := os.Lstat(newPath)
159
+	if err != nil && !os.IsNotExist(err) {
160
+		return err
161
+	}
162
+	// If the destination is a symlink then we already tried to relocate once before
163
+	// and it failed so we delete it and try to remove
164
+	if s != nil && s.Mode()&os.ModeSymlink == os.ModeSymlink {
165
+		if err := os.RemoveAll(newPath); err != nil {
166
+			return err
167
+		}
168
+	}
169
+	if err := os.Rename(oldPath, newPath); err != nil {
170
+		if sErr := os.Symlink(oldPath, newPath); sErr != nil {
171
+			return fmt.Errorf("Unable to relocate %s to %s: Rename err %s Symlink err %s", oldPath, newPath, err, sErr)
172
+		}
173
+	}
174
+	return nil
175
+}
176
+
177
+func loadMetadata(pth string) (*metadata, error) {
178
+	f, err := os.Open(pth)
179
+	if err != nil {
180
+		return nil, err
181
+	}
182
+	defer f.Close()
183
+
184
+	var (
185
+		out = &metadata{}
186
+		dec = json.NewDecoder(f)
187
+	)
188
+
189
+	if err := dec.Decode(out); err != nil {
190
+		return nil, err
191
+	}
192
+	return out, nil
193
+}
0 194
new file mode 100644
... ...
@@ -0,0 +1,17 @@
0
+package aufs
1
+
2
+import (
3
+	"github.com/dotcloud/docker/utils"
4
+	"os/exec"
5
+	"syscall"
6
+)
7
+
8
+func Unmount(target string) error {
9
+	if err := exec.Command("auplink", target, "flush").Run(); err != nil {
10
+		utils.Errorf("[warning]: couldn't run auplink before unmount: %s", err)
11
+	}
12
+	if err := syscall.Unmount(target, 0); err != nil {
13
+		return err
14
+	}
15
+	return nil
16
+}
0 17
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+// +build amd64
1
+
2
+package aufs
3
+
4
+import "syscall"
5
+
6
+const MsRemount = syscall.MS_REMOUNT
7
+
8
+func mount(source string, target string, fstype string, flags uintptr, data string) error {
9
+	return syscall.Mount(source, target, fstype, flags, data)
10
+}
0 11
new file mode 100644
... ...
@@ -0,0 +1,11 @@
0
+// +build !linux !amd64
1
+
2
+package aufs
3
+
4
+import "errors"
5
+
6
+const MsRemount = 0
7
+
8
+func mount(source string, target string, fstype string, flags uintptr, data string) (err error) {
9
+	return errors.New("mount is not implemented on darwin")
10
+}
0 11
new file mode 100644
... ...
@@ -0,0 +1,213 @@
0
+// +build linux,amd64
1
+
2
+package btrfs
3
+
4
+/*
5
+#include <stdlib.h>
6
+#include <dirent.h>
7
+#include <btrfs/ioctl.h>
8
+*/
9
+import "C"
10
+
11
+import (
12
+	"fmt"
13
+	"github.com/dotcloud/docker/runtime/graphdriver"
14
+	"os"
15
+	"path"
16
+	"syscall"
17
+	"unsafe"
18
+)
19
+
20
+func init() {
21
+	graphdriver.Register("btrfs", Init)
22
+}
23
+
24
+func Init(home string) (graphdriver.Driver, error) {
25
+	rootdir := path.Dir(home)
26
+
27
+	var buf syscall.Statfs_t
28
+	if err := syscall.Statfs(rootdir, &buf); err != nil {
29
+		return nil, err
30
+	}
31
+
32
+	if buf.Type != 0x9123683E {
33
+		return nil, fmt.Errorf("%s is not a btrfs filesystem", rootdir)
34
+	}
35
+
36
+	return &Driver{
37
+		home: home,
38
+	}, nil
39
+}
40
+
41
+type Driver struct {
42
+	home string
43
+}
44
+
45
+func (d *Driver) String() string {
46
+	return "btrfs"
47
+}
48
+
49
+func (d *Driver) Status() [][2]string {
50
+	return nil
51
+}
52
+
53
+func (d *Driver) Cleanup() error {
54
+	return nil
55
+}
56
+
57
+func free(p *C.char) {
58
+	C.free(unsafe.Pointer(p))
59
+}
60
+
61
+func openDir(path string) (*C.DIR, error) {
62
+	Cpath := C.CString(path)
63
+	defer free(Cpath)
64
+
65
+	dir := C.opendir(Cpath)
66
+	if dir == nil {
67
+		return nil, fmt.Errorf("Can't open dir")
68
+	}
69
+	return dir, nil
70
+}
71
+
72
+func closeDir(dir *C.DIR) {
73
+	if dir != nil {
74
+		C.closedir(dir)
75
+	}
76
+}
77
+
78
+func getDirFd(dir *C.DIR) uintptr {
79
+	return uintptr(C.dirfd(dir))
80
+}
81
+
82
+func subvolCreate(path, name string) error {
83
+	dir, err := openDir(path)
84
+	if err != nil {
85
+		return err
86
+	}
87
+	defer closeDir(dir)
88
+
89
+	var args C.struct_btrfs_ioctl_vol_args
90
+	for i, c := range []byte(name) {
91
+		args.name[i] = C.char(c)
92
+	}
93
+
94
+	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SUBVOL_CREATE,
95
+		uintptr(unsafe.Pointer(&args)))
96
+	if errno != 0 {
97
+		return fmt.Errorf("Failed to create btrfs subvolume: %v", errno.Error())
98
+	}
99
+	return nil
100
+}
101
+
102
+func subvolSnapshot(src, dest, name string) error {
103
+	srcDir, err := openDir(src)
104
+	if err != nil {
105
+		return err
106
+	}
107
+	defer closeDir(srcDir)
108
+
109
+	destDir, err := openDir(dest)
110
+	if err != nil {
111
+		return err
112
+	}
113
+	defer closeDir(destDir)
114
+
115
+	var args C.struct_btrfs_ioctl_vol_args_v2
116
+	args.fd = C.__s64(getDirFd(srcDir))
117
+	for i, c := range []byte(name) {
118
+		args.name[i] = C.char(c)
119
+	}
120
+
121
+	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(destDir), C.BTRFS_IOC_SNAP_CREATE_V2,
122
+		uintptr(unsafe.Pointer(&args)))
123
+	if errno != 0 {
124
+		return fmt.Errorf("Failed to create btrfs snapshot: %v", errno.Error())
125
+	}
126
+	return nil
127
+}
128
+
129
+func subvolDelete(path, name string) error {
130
+	dir, err := openDir(path)
131
+	if err != nil {
132
+		return err
133
+	}
134
+	defer closeDir(dir)
135
+
136
+	var args C.struct_btrfs_ioctl_vol_args
137
+	for i, c := range []byte(name) {
138
+		args.name[i] = C.char(c)
139
+	}
140
+
141
+	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, getDirFd(dir), C.BTRFS_IOC_SNAP_DESTROY,
142
+		uintptr(unsafe.Pointer(&args)))
143
+	if errno != 0 {
144
+		return fmt.Errorf("Failed to destroy btrfs snapshot: %v", errno.Error())
145
+	}
146
+	return nil
147
+}
148
+
149
+func (d *Driver) subvolumesDir() string {
150
+	return path.Join(d.home, "subvolumes")
151
+}
152
+
153
+func (d *Driver) subvolumesDirId(id string) string {
154
+	return path.Join(d.subvolumesDir(), id)
155
+}
156
+
157
+func (d *Driver) Create(id string, parent string) error {
158
+	subvolumes := path.Join(d.home, "subvolumes")
159
+	if err := os.MkdirAll(subvolumes, 0700); err != nil {
160
+		return err
161
+	}
162
+	if parent == "" {
163
+		if err := subvolCreate(subvolumes, id); err != nil {
164
+			return err
165
+		}
166
+	} else {
167
+		parentDir, err := d.Get(parent)
168
+		if err != nil {
169
+			return err
170
+		}
171
+		if err := subvolSnapshot(parentDir, subvolumes, id); err != nil {
172
+			return err
173
+		}
174
+	}
175
+	return nil
176
+}
177
+
178
+func (d *Driver) Remove(id string) error {
179
+	dir := d.subvolumesDirId(id)
180
+	if _, err := os.Stat(dir); err != nil {
181
+		return err
182
+	}
183
+	if err := subvolDelete(d.subvolumesDir(), id); err != nil {
184
+		return err
185
+	}
186
+	return os.RemoveAll(dir)
187
+}
188
+
189
+func (d *Driver) Get(id string) (string, error) {
190
+	dir := d.subvolumesDirId(id)
191
+	st, err := os.Stat(dir)
192
+	if err != nil {
193
+		return "", err
194
+	}
195
+
196
+	if !st.IsDir() {
197
+		return "", fmt.Errorf("%s: not a directory", dir)
198
+	}
199
+
200
+	return dir, nil
201
+}
202
+
203
+func (d *Driver) Put(id string) {
204
+	// Get() creates no runtime resources (like e.g. mounts)
205
+	// so this doesn't need to do anything.
206
+}
207
+
208
+func (d *Driver) Exists(id string) bool {
209
+	dir := d.subvolumesDirId(id)
210
+	_, err := os.Stat(dir)
211
+	return err == nil
212
+}
0 213
new file mode 100644
... ...
@@ -0,0 +1,3 @@
0
+// +build !linux !amd64
1
+
2
+package btrfs
0 3
new file mode 100644
... ...
@@ -0,0 +1,126 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+import (
5
+	"fmt"
6
+	"github.com/dotcloud/docker/utils"
7
+)
8
+
9
+func stringToLoopName(src string) [LoNameSize]uint8 {
10
+	var dst [LoNameSize]uint8
11
+	copy(dst[:], src[:])
12
+	return dst
13
+}
14
+
15
+func getNextFreeLoopbackIndex() (int, error) {
16
+	f, err := osOpenFile("/dev/loop-control", osORdOnly, 0644)
17
+	if err != nil {
18
+		return 0, err
19
+	}
20
+	defer f.Close()
21
+
22
+	index, err := ioctlLoopCtlGetFree(f.Fd())
23
+	if index < 0 {
24
+		index = 0
25
+	}
26
+	return index, err
27
+}
28
+
29
+func openNextAvailableLoopback(index int, sparseFile *osFile) (loopFile *osFile, err error) {
30
+	// Start looking for a free /dev/loop
31
+	for {
32
+		target := fmt.Sprintf("/dev/loop%d", index)
33
+		index++
34
+
35
+		fi, err := osStat(target)
36
+		if err != nil {
37
+			if osIsNotExist(err) {
38
+				utils.Errorf("There are no more loopback device available.")
39
+			}
40
+			return nil, ErrAttachLoopbackDevice
41
+		}
42
+
43
+		if fi.Mode()&osModeDevice != osModeDevice {
44
+			utils.Errorf("Loopback device %s is not a block device.", target)
45
+			continue
46
+		}
47
+
48
+		// OpenFile adds O_CLOEXEC
49
+		loopFile, err = osOpenFile(target, osORdWr, 0644)
50
+		if err != nil {
51
+			utils.Errorf("Error openning loopback device: %s", err)
52
+			return nil, ErrAttachLoopbackDevice
53
+		}
54
+
55
+		// Try to attach to the loop file
56
+		if err := ioctlLoopSetFd(loopFile.Fd(), sparseFile.Fd()); err != nil {
57
+			loopFile.Close()
58
+
59
+			// If the error is EBUSY, then try the next loopback
60
+			if err != sysEBusy {
61
+				utils.Errorf("Cannot set up loopback device %s: %s", target, err)
62
+				return nil, ErrAttachLoopbackDevice
63
+			}
64
+
65
+			// Otherwise, we keep going with the loop
66
+			continue
67
+		}
68
+		// In case of success, we finished. Break the loop.
69
+		break
70
+	}
71
+
72
+	// This can't happen, but let's be sure
73
+	if loopFile == nil {
74
+		utils.Errorf("Unreachable code reached! Error attaching %s to a loopback device.", sparseFile.Name())
75
+		return nil, ErrAttachLoopbackDevice
76
+	}
77
+
78
+	return loopFile, nil
79
+}
80
+
81
+// attachLoopDevice attaches the given sparse file to the next
82
+// available loopback device. It returns an opened *osFile.
83
+func attachLoopDevice(sparseName string) (loop *osFile, err error) {
84
+
85
+	// Try to retrieve the next available loopback device via syscall.
86
+	// If it fails, we discard error and start loopking for a
87
+	// loopback from index 0.
88
+	startIndex, err := getNextFreeLoopbackIndex()
89
+	if err != nil {
90
+		utils.Debugf("Error retrieving the next available loopback: %s", err)
91
+	}
92
+
93
+	// OpenFile adds O_CLOEXEC
94
+	sparseFile, err := osOpenFile(sparseName, osORdWr, 0644)
95
+	if err != nil {
96
+		utils.Errorf("Error openning sparse file %s: %s", sparseName, err)
97
+		return nil, ErrAttachLoopbackDevice
98
+	}
99
+	defer sparseFile.Close()
100
+
101
+	loopFile, err := openNextAvailableLoopback(startIndex, sparseFile)
102
+	if err != nil {
103
+		return nil, err
104
+	}
105
+
106
+	// Set the status of the loopback device
107
+	loopInfo := &LoopInfo64{
108
+		loFileName: stringToLoopName(loopFile.Name()),
109
+		loOffset:   0,
110
+		loFlags:    LoFlagsAutoClear,
111
+	}
112
+
113
+	if err := ioctlLoopSetStatus64(loopFile.Fd(), loopInfo); err != nil {
114
+		utils.Errorf("Cannot set up loopback device info: %s", err)
115
+
116
+		// If the call failed, then free the loopback device
117
+		if err := ioctlLoopClrFd(loopFile.Fd()); err != nil {
118
+			utils.Errorf("Error while cleaning up the loopback device")
119
+		}
120
+		loopFile.Close()
121
+		return nil, ErrAttachLoopbackDevice
122
+	}
123
+
124
+	return loopFile, nil
125
+}
0 126
new file mode 100644
... ...
@@ -0,0 +1,1088 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+import (
5
+	"encoding/json"
6
+	"errors"
7
+	"fmt"
8
+	"github.com/dotcloud/docker/utils"
9
+	"io"
10
+	"io/ioutil"
11
+	"path"
12
+	"path/filepath"
13
+	"strconv"
14
+	"strings"
15
+	"sync"
16
+	"time"
17
+)
18
+
19
+var (
20
+	DefaultDataLoopbackSize     int64  = 100 * 1024 * 1024 * 1024
21
+	DefaultMetaDataLoopbackSize int64  = 2 * 1024 * 1024 * 1024
22
+	DefaultBaseFsSize           uint64 = 10 * 1024 * 1024 * 1024
23
+)
24
+
25
+type DevInfo struct {
26
+	Hash          string     `json:"-"`
27
+	DeviceId      int        `json:"device_id"`
28
+	Size          uint64     `json:"size"`
29
+	TransactionId uint64     `json:"transaction_id"`
30
+	Initialized   bool       `json:"initialized"`
31
+	devices       *DeviceSet `json:"-"`
32
+
33
+	mountCount int    `json:"-"`
34
+	mountPath  string `json:"-"`
35
+	// A floating mount means one reference is not owned and
36
+	// will be stolen by the next mount. This allows us to
37
+	// avoid unmounting directly after creation before the
38
+	// first get (since we need to mount to set up the device
39
+	// a bit first).
40
+	floating bool `json:"-"`
41
+
42
+	// The global DeviceSet lock guarantees that we serialize all
43
+	// the calls to libdevmapper (which is not threadsafe), but we
44
+	// sometimes release that lock while sleeping. In that case
45
+	// this per-device lock is still held, protecting against
46
+	// other accesses to the device that we're doing the wait on.
47
+	lock sync.Mutex `json:"-"`
48
+}
49
+
50
+type MetaData struct {
51
+	Devices map[string]*DevInfo `json:devices`
52
+}
53
+
54
+type DeviceSet struct {
55
+	MetaData
56
+	sync.Mutex       // Protects Devices map and serializes calls into libdevmapper
57
+	root             string
58
+	devicePrefix     string
59
+	TransactionId    uint64
60
+	NewTransactionId uint64
61
+	nextFreeDevice   int
62
+	sawBusy          bool
63
+}
64
+
65
+type DiskUsage struct {
66
+	Used  uint64
67
+	Total uint64
68
+}
69
+
70
+type Status struct {
71
+	PoolName         string
72
+	DataLoopback     string
73
+	MetadataLoopback string
74
+	Data             DiskUsage
75
+	Metadata         DiskUsage
76
+	SectorSize       uint64
77
+}
78
+
79
+type DevStatus struct {
80
+	DeviceId            int
81
+	Size                uint64
82
+	TransactionId       uint64
83
+	SizeInSectors       uint64
84
+	MappedSectors       uint64
85
+	HighestMappedSector uint64
86
+}
87
+
88
+type UnmountMode int
89
+
90
+const (
91
+	UnmountRegular UnmountMode = iota
92
+	UnmountFloat
93
+	UnmountSink
94
+)
95
+
96
+func getDevName(name string) string {
97
+	return "/dev/mapper/" + name
98
+}
99
+
100
+func (info *DevInfo) Name() string {
101
+	hash := info.Hash
102
+	if hash == "" {
103
+		hash = "base"
104
+	}
105
+	return fmt.Sprintf("%s-%s", info.devices.devicePrefix, hash)
106
+}
107
+
108
+func (info *DevInfo) DevName() string {
109
+	return getDevName(info.Name())
110
+}
111
+
112
+func (devices *DeviceSet) loopbackDir() string {
113
+	return path.Join(devices.root, "devicemapper")
114
+}
115
+
116
+func (devices *DeviceSet) jsonFile() string {
117
+	return path.Join(devices.loopbackDir(), "json")
118
+}
119
+
120
+func (devices *DeviceSet) getPoolName() string {
121
+	return devices.devicePrefix + "-pool"
122
+}
123
+
124
+func (devices *DeviceSet) getPoolDevName() string {
125
+	return getDevName(devices.getPoolName())
126
+}
127
+
128
+func (devices *DeviceSet) hasImage(name string) bool {
129
+	dirname := devices.loopbackDir()
130
+	filename := path.Join(dirname, name)
131
+
132
+	_, err := osStat(filename)
133
+	return err == nil
134
+}
135
+
136
+// ensureImage creates a sparse file of <size> bytes at the path
137
+// <root>/devicemapper/<name>.
138
+// If the file already exists, it does nothing.
139
+// Either way it returns the full path.
140
+func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
141
+	dirname := devices.loopbackDir()
142
+	filename := path.Join(dirname, name)
143
+
144
+	if err := osMkdirAll(dirname, 0700); err != nil && !osIsExist(err) {
145
+		return "", err
146
+	}
147
+
148
+	if _, err := osStat(filename); err != nil {
149
+		if !osIsNotExist(err) {
150
+			return "", err
151
+		}
152
+		utils.Debugf("Creating loopback file %s for device-manage use", filename)
153
+		file, err := osOpenFile(filename, osORdWr|osOCreate, 0600)
154
+		if err != nil {
155
+			return "", err
156
+		}
157
+		defer file.Close()
158
+
159
+		if err = file.Truncate(size); err != nil {
160
+			return "", err
161
+		}
162
+	}
163
+	return filename, nil
164
+}
165
+
166
+func (devices *DeviceSet) allocateDeviceId() int {
167
+	// TODO: Add smarter reuse of deleted devices
168
+	id := devices.nextFreeDevice
169
+	devices.nextFreeDevice = devices.nextFreeDevice + 1
170
+	return id
171
+}
172
+
173
+func (devices *DeviceSet) allocateTransactionId() uint64 {
174
+	devices.NewTransactionId = devices.NewTransactionId + 1
175
+	return devices.NewTransactionId
176
+}
177
+
178
+func (devices *DeviceSet) saveMetadata() error {
179
+	jsonData, err := json.Marshal(devices.MetaData)
180
+	if err != nil {
181
+		return fmt.Errorf("Error encoding metadata to json: %s", err)
182
+	}
183
+	tmpFile, err := ioutil.TempFile(filepath.Dir(devices.jsonFile()), ".json")
184
+	if err != nil {
185
+		return fmt.Errorf("Error creating metadata file: %s", err)
186
+	}
187
+
188
+	n, err := tmpFile.Write(jsonData)
189
+	if err != nil {
190
+		return fmt.Errorf("Error writing metadata to %s: %s", tmpFile.Name(), err)
191
+	}
192
+	if n < len(jsonData) {
193
+		return io.ErrShortWrite
194
+	}
195
+	if err := tmpFile.Sync(); err != nil {
196
+		return fmt.Errorf("Error syncing metadata file %s: %s", tmpFile.Name(), err)
197
+	}
198
+	if err := tmpFile.Close(); err != nil {
199
+		return fmt.Errorf("Error closing metadata file %s: %s", tmpFile.Name(), err)
200
+	}
201
+	if err := osRename(tmpFile.Name(), devices.jsonFile()); err != nil {
202
+		return fmt.Errorf("Error committing metadata file %s: %s", tmpFile.Name(), err)
203
+	}
204
+
205
+	if devices.NewTransactionId != devices.TransactionId {
206
+		if err = setTransactionId(devices.getPoolDevName(), devices.TransactionId, devices.NewTransactionId); err != nil {
207
+			return fmt.Errorf("Error setting devmapper transition ID: %s", err)
208
+		}
209
+		devices.TransactionId = devices.NewTransactionId
210
+	}
211
+	return nil
212
+}
213
+
214
+func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*DevInfo, error) {
215
+	utils.Debugf("registerDevice(%v, %v)", id, hash)
216
+	info := &DevInfo{
217
+		Hash:          hash,
218
+		DeviceId:      id,
219
+		Size:          size,
220
+		TransactionId: devices.allocateTransactionId(),
221
+		Initialized:   false,
222
+		devices:       devices,
223
+	}
224
+
225
+	devices.Devices[hash] = info
226
+	if err := devices.saveMetadata(); err != nil {
227
+		// Try to remove unused device
228
+		delete(devices.Devices, hash)
229
+		return nil, err
230
+	}
231
+
232
+	return info, nil
233
+}
234
+
235
+func (devices *DeviceSet) activateDeviceIfNeeded(hash string) error {
236
+	utils.Debugf("activateDeviceIfNeeded(%v)", hash)
237
+	info := devices.Devices[hash]
238
+	if info == nil {
239
+		return fmt.Errorf("Unknown device %s", hash)
240
+	}
241
+
242
+	if devinfo, _ := getInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
243
+		return nil
244
+	}
245
+
246
+	return activateDevice(devices.getPoolDevName(), info.Name(), info.DeviceId, info.Size)
247
+}
248
+
249
+func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
250
+	devname := info.DevName()
251
+
252
+	err := execRun("mkfs.ext4", "-E", "discard,lazy_itable_init=0,lazy_journal_init=0", devname)
253
+	if err != nil {
254
+		err = execRun("mkfs.ext4", "-E", "discard,lazy_itable_init=0", devname)
255
+	}
256
+	if err != nil {
257
+		utils.Debugf("\n--->Err: %s\n", err)
258
+		return err
259
+	}
260
+	return nil
261
+}
262
+
263
+func (devices *DeviceSet) loadMetaData() error {
264
+	utils.Debugf("loadMetadata()")
265
+	defer utils.Debugf("loadMetadata END")
266
+	_, _, _, params, err := getStatus(devices.getPoolName())
267
+	if err != nil {
268
+		utils.Debugf("\n--->Err: %s\n", err)
269
+		return err
270
+	}
271
+
272
+	if _, err := fmt.Sscanf(params, "%d", &devices.TransactionId); err != nil {
273
+		utils.Debugf("\n--->Err: %s\n", err)
274
+		return err
275
+	}
276
+	devices.NewTransactionId = devices.TransactionId
277
+
278
+	jsonData, err := ioutil.ReadFile(devices.jsonFile())
279
+	if err != nil && !osIsNotExist(err) {
280
+		utils.Debugf("\n--->Err: %s\n", err)
281
+		return err
282
+	}
283
+
284
+	devices.MetaData.Devices = make(map[string]*DevInfo)
285
+	if jsonData != nil {
286
+		if err := json.Unmarshal(jsonData, &devices.MetaData); err != nil {
287
+			utils.Debugf("\n--->Err: %s\n", err)
288
+			return err
289
+		}
290
+	}
291
+
292
+	for hash, d := range devices.Devices {
293
+		d.Hash = hash
294
+		d.devices = devices
295
+
296
+		if d.DeviceId >= devices.nextFreeDevice {
297
+			devices.nextFreeDevice = d.DeviceId + 1
298
+		}
299
+
300
+		// If the transaction id is larger than the actual one we lost the device due to some crash
301
+		if d.TransactionId > devices.TransactionId {
302
+			utils.Debugf("Removing lost device %s with id %d", hash, d.TransactionId)
303
+			delete(devices.Devices, hash)
304
+		}
305
+	}
306
+	return nil
307
+}
308
+
309
+func (devices *DeviceSet) setupBaseImage() error {
310
+	oldInfo := devices.Devices[""]
311
+	if oldInfo != nil && oldInfo.Initialized {
312
+		return nil
313
+	}
314
+
315
+	if oldInfo != nil && !oldInfo.Initialized {
316
+		utils.Debugf("Removing uninitialized base image")
317
+		if err := devices.deleteDevice(""); err != nil {
318
+			utils.Debugf("\n--->Err: %s\n", err)
319
+			return err
320
+		}
321
+	}
322
+
323
+	utils.Debugf("Initializing base device-manager snapshot")
324
+
325
+	id := devices.allocateDeviceId()
326
+
327
+	// Create initial device
328
+	if err := createDevice(devices.getPoolDevName(), id); err != nil {
329
+		utils.Debugf("\n--->Err: %s\n", err)
330
+		return err
331
+	}
332
+
333
+	utils.Debugf("Registering base device (id %v) with FS size %v", id, DefaultBaseFsSize)
334
+	info, err := devices.registerDevice(id, "", DefaultBaseFsSize)
335
+	if err != nil {
336
+		_ = deleteDevice(devices.getPoolDevName(), id)
337
+		utils.Debugf("\n--->Err: %s\n", err)
338
+		return err
339
+	}
340
+
341
+	utils.Debugf("Creating filesystem on base device-manager snapshot")
342
+
343
+	if err = devices.activateDeviceIfNeeded(""); err != nil {
344
+		utils.Debugf("\n--->Err: %s\n", err)
345
+		return err
346
+	}
347
+
348
+	if err := devices.createFilesystem(info); err != nil {
349
+		utils.Debugf("\n--->Err: %s\n", err)
350
+		return err
351
+	}
352
+
353
+	info.Initialized = true
354
+	if err = devices.saveMetadata(); err != nil {
355
+		info.Initialized = false
356
+		utils.Debugf("\n--->Err: %s\n", err)
357
+		return err
358
+	}
359
+
360
+	return nil
361
+}
362
+
363
+func setCloseOnExec(name string) {
364
+	if fileInfos, _ := ioutil.ReadDir("/proc/self/fd"); fileInfos != nil {
365
+		for _, i := range fileInfos {
366
+			link, _ := osReadlink(filepath.Join("/proc/self/fd", i.Name()))
367
+			if link == name {
368
+				fd, err := strconv.Atoi(i.Name())
369
+				if err == nil {
370
+					sysCloseOnExec(fd)
371
+				}
372
+			}
373
+		}
374
+	}
375
+}
376
+
377
+func (devices *DeviceSet) log(level int, file string, line int, dmError int, message string) {
378
+	if level >= 7 {
379
+		return // Ignore _LOG_DEBUG
380
+	}
381
+
382
+	if strings.Contains(message, "busy") {
383
+		devices.sawBusy = true
384
+	}
385
+
386
+	utils.Debugf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message)
387
+}
388
+
389
+func major(device uint64) uint64 {
390
+	return (device >> 8) & 0xfff
391
+}
392
+
393
+func minor(device uint64) uint64 {
394
+	return (device & 0xff) | ((device >> 12) & 0xfff00)
395
+}
396
+
397
+func (devices *DeviceSet) ResizePool(size int64) error {
398
+	dirname := devices.loopbackDir()
399
+	datafilename := path.Join(dirname, "data")
400
+	metadatafilename := path.Join(dirname, "metadata")
401
+
402
+	datafile, err := osOpenFile(datafilename, osORdWr, 0)
403
+	if datafile == nil {
404
+		return err
405
+	}
406
+	defer datafile.Close()
407
+
408
+	fi, err := datafile.Stat()
409
+	if fi == nil {
410
+		return err
411
+	}
412
+
413
+	if fi.Size() > size {
414
+		return fmt.Errorf("Can't shrink file")
415
+	}
416
+
417
+	dataloopback := FindLoopDeviceFor(datafile)
418
+	if dataloopback == nil {
419
+		return fmt.Errorf("Unable to find loopback mount for: %s", datafilename)
420
+	}
421
+	defer dataloopback.Close()
422
+
423
+	metadatafile, err := osOpenFile(metadatafilename, osORdWr, 0)
424
+	if metadatafile == nil {
425
+		return err
426
+	}
427
+	defer metadatafile.Close()
428
+
429
+	metadataloopback := FindLoopDeviceFor(metadatafile)
430
+	if metadataloopback == nil {
431
+		return fmt.Errorf("Unable to find loopback mount for: %s", metadatafilename)
432
+	}
433
+	defer metadataloopback.Close()
434
+
435
+	// Grow loopback file
436
+	if err := datafile.Truncate(size); err != nil {
437
+		return fmt.Errorf("Unable to grow loopback file: %s", err)
438
+	}
439
+
440
+	// Reload size for loopback device
441
+	if err := LoopbackSetCapacity(dataloopback); err != nil {
442
+		return fmt.Errorf("Unable to update loopback capacity: %s", err)
443
+	}
444
+
445
+	// Suspend the pool
446
+	if err := suspendDevice(devices.getPoolName()); err != nil {
447
+		return fmt.Errorf("Unable to suspend pool: %s", err)
448
+	}
449
+
450
+	// Reload with the new block sizes
451
+	if err := reloadPool(devices.getPoolName(), dataloopback, metadataloopback); err != nil {
452
+		return fmt.Errorf("Unable to reload pool: %s", err)
453
+	}
454
+
455
+	// Resume the pool
456
+	if err := resumeDevice(devices.getPoolName()); err != nil {
457
+		return fmt.Errorf("Unable to resume pool: %s", err)
458
+	}
459
+
460
+	return nil
461
+}
462
+
463
+func (devices *DeviceSet) initDevmapper(doInit bool) error {
464
+	logInit(devices)
465
+
466
+	// Make sure the sparse images exist in <root>/devicemapper/data and
467
+	// <root>/devicemapper/metadata
468
+
469
+	hasData := devices.hasImage("data")
470
+	hasMetadata := devices.hasImage("metadata")
471
+
472
+	if !doInit && !hasData {
473
+		return errors.New("Loopback data file not found")
474
+	}
475
+
476
+	if !doInit && !hasMetadata {
477
+		return errors.New("Loopback metadata file not found")
478
+	}
479
+
480
+	createdLoopback := !hasData || !hasMetadata
481
+	data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
482
+	if err != nil {
483
+		utils.Debugf("Error device ensureImage (data): %s\n", err)
484
+		return err
485
+	}
486
+	metadata, err := devices.ensureImage("metadata", DefaultMetaDataLoopbackSize)
487
+	if err != nil {
488
+		utils.Debugf("Error device ensureImage (metadata): %s\n", err)
489
+		return err
490
+	}
491
+
492
+	// Set the device prefix from the device id and inode of the docker root dir
493
+
494
+	st, err := osStat(devices.root)
495
+	if err != nil {
496
+		return fmt.Errorf("Error looking up dir %s: %s", devices.root, err)
497
+	}
498
+	sysSt := toSysStatT(st.Sys())
499
+	// "reg-" stands for "regular file".
500
+	// In the future we might use "dev-" for "device file", etc.
501
+	// docker-maj,min[-inode] stands for:
502
+	//	- Managed by docker
503
+	//	- The target of this device is at major <maj> and minor <min>
504
+	//	- If <inode> is defined, use that file inside the device as a loopback image. Otherwise use the device itself.
505
+	devices.devicePrefix = fmt.Sprintf("docker-%d:%d-%d", major(sysSt.Dev), minor(sysSt.Dev), sysSt.Ino)
506
+	utils.Debugf("Generated prefix: %s", devices.devicePrefix)
507
+
508
+	// Check for the existence of the device <prefix>-pool
509
+	utils.Debugf("Checking for existence of the pool '%s'", devices.getPoolName())
510
+	info, err := getInfo(devices.getPoolName())
511
+	if info == nil {
512
+		utils.Debugf("Error device getInfo: %s", err)
513
+		return err
514
+	}
515
+
516
+	// It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files
517
+	// that are not Close-on-exec, and lxc-start will die if it inherits any unexpected files,
518
+	// so we add this badhack to make sure it closes itself
519
+	setCloseOnExec("/dev/mapper/control")
520
+
521
+	// If the pool doesn't exist, create it
522
+	if info.Exists == 0 {
523
+		utils.Debugf("Pool doesn't exist. Creating it.")
524
+
525
+		dataFile, err := attachLoopDevice(data)
526
+		if err != nil {
527
+			utils.Debugf("\n--->Err: %s\n", err)
528
+			return err
529
+		}
530
+		defer dataFile.Close()
531
+
532
+		metadataFile, err := attachLoopDevice(metadata)
533
+		if err != nil {
534
+			utils.Debugf("\n--->Err: %s\n", err)
535
+			return err
536
+		}
537
+		defer metadataFile.Close()
538
+
539
+		if err := createPool(devices.getPoolName(), dataFile, metadataFile); err != nil {
540
+			utils.Debugf("\n--->Err: %s\n", err)
541
+			return err
542
+		}
543
+	}
544
+
545
+	// If we didn't just create the data or metadata image, we need to
546
+	// load the metadata from the existing file.
547
+	if !createdLoopback {
548
+		if err = devices.loadMetaData(); err != nil {
549
+			utils.Debugf("\n--->Err: %s\n", err)
550
+			return err
551
+		}
552
+	}
553
+
554
+	// Setup the base image
555
+	if doInit {
556
+		if err := devices.setupBaseImage(); err != nil {
557
+			utils.Debugf("Error device setupBaseImage: %s\n", err)
558
+			return err
559
+		}
560
+	}
561
+
562
+	return nil
563
+}
564
+
565
+func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
566
+	devices.Lock()
567
+	defer devices.Unlock()
568
+
569
+	if devices.Devices[hash] != nil {
570
+		return fmt.Errorf("hash %s already exists", hash)
571
+	}
572
+
573
+	baseInfo := devices.Devices[baseHash]
574
+	if baseInfo == nil {
575
+		return fmt.Errorf("Error adding device for '%s': can't find device for parent '%s'", hash, baseHash)
576
+	}
577
+
578
+	baseInfo.lock.Lock()
579
+	defer baseInfo.lock.Unlock()
580
+
581
+	deviceId := devices.allocateDeviceId()
582
+
583
+	if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
584
+		utils.Debugf("Error creating snap device: %s\n", err)
585
+		return err
586
+	}
587
+
588
+	if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil {
589
+		deleteDevice(devices.getPoolDevName(), deviceId)
590
+		utils.Debugf("Error registering device: %s\n", err)
591
+		return err
592
+	}
593
+	return nil
594
+}
595
+
596
+func (devices *DeviceSet) deleteDevice(hash string) error {
597
+	info := devices.Devices[hash]
598
+	if info == nil {
599
+		return fmt.Errorf("hash %s doesn't exists", hash)
600
+	}
601
+
602
+	// This is a workaround for the kernel not discarding block so
603
+	// on the thin pool when we remove a thinp device, so we do it
604
+	// manually
605
+	if err := devices.activateDeviceIfNeeded(hash); err == nil {
606
+		if err := BlockDeviceDiscard(info.DevName()); err != nil {
607
+			utils.Debugf("Error discarding block on device: %s (ignoring)\n", err)
608
+		}
609
+	}
610
+
611
+	devinfo, _ := getInfo(info.Name())
612
+	if devinfo != nil && devinfo.Exists != 0 {
613
+		if err := devices.removeDeviceAndWait(info.Name()); err != nil {
614
+			utils.Debugf("Error removing device: %s\n", err)
615
+			return err
616
+		}
617
+	}
618
+
619
+	if info.Initialized {
620
+		info.Initialized = false
621
+		if err := devices.saveMetadata(); err != nil {
622
+			utils.Debugf("Error saving meta data: %s\n", err)
623
+			return err
624
+		}
625
+	}
626
+
627
+	if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
628
+		utils.Debugf("Error deleting device: %s\n", err)
629
+		return err
630
+	}
631
+
632
+	devices.allocateTransactionId()
633
+	delete(devices.Devices, info.Hash)
634
+
635
+	if err := devices.saveMetadata(); err != nil {
636
+		devices.Devices[info.Hash] = info
637
+		utils.Debugf("Error saving meta data: %s\n", err)
638
+		return err
639
+	}
640
+
641
+	return nil
642
+}
643
+
644
+func (devices *DeviceSet) DeleteDevice(hash string) error {
645
+	devices.Lock()
646
+	defer devices.Unlock()
647
+
648
+	info := devices.Devices[hash]
649
+	if info == nil {
650
+		return fmt.Errorf("Unknown device %s", hash)
651
+	}
652
+
653
+	info.lock.Lock()
654
+	defer info.lock.Unlock()
655
+
656
+	return devices.deleteDevice(hash)
657
+}
658
+
659
+func (devices *DeviceSet) deactivatePool() error {
660
+	utils.Debugf("[devmapper] deactivatePool()")
661
+	defer utils.Debugf("[devmapper] deactivatePool END")
662
+	devname := devices.getPoolDevName()
663
+	devinfo, err := getInfo(devname)
664
+	if err != nil {
665
+		utils.Debugf("\n--->Err: %s\n", err)
666
+		return err
667
+	}
668
+	if devinfo.Exists != 0 {
669
+		return removeDevice(devname)
670
+	}
671
+
672
+	return nil
673
+}
674
+
675
+func (devices *DeviceSet) deactivateDevice(hash string) error {
676
+	utils.Debugf("[devmapper] deactivateDevice(%s)", hash)
677
+	defer utils.Debugf("[devmapper] deactivateDevice END")
678
+
679
+	info := devices.Devices[hash]
680
+	if info == nil {
681
+		return fmt.Errorf("Unknown device %s", hash)
682
+	}
683
+	devinfo, err := getInfo(info.Name())
684
+	if err != nil {
685
+		utils.Debugf("\n--->Err: %s\n", err)
686
+		return err
687
+	}
688
+	if devinfo.Exists != 0 {
689
+		if err := devices.removeDeviceAndWait(info.Name()); err != nil {
690
+			utils.Debugf("\n--->Err: %s\n", err)
691
+			return err
692
+		}
693
+	}
694
+
695
+	return nil
696
+}
697
+
698
+// Issues the underlying dm remove operation and then waits
699
+// for it to finish.
700
+func (devices *DeviceSet) removeDeviceAndWait(devname string) error {
701
+	var err error
702
+
703
+	for i := 0; i < 1000; i++ {
704
+		devices.sawBusy = false
705
+		err = removeDevice(devname)
706
+		if err == nil {
707
+			break
708
+		}
709
+		if !devices.sawBusy {
710
+			return err
711
+		}
712
+
713
+		// If we see EBUSY it may be a transient error,
714
+		// sleep a bit a retry a few times.
715
+		devices.Unlock()
716
+		time.Sleep(10 * time.Millisecond)
717
+		devices.Lock()
718
+	}
719
+	if err != nil {
720
+		return err
721
+	}
722
+
723
+	if err := devices.waitRemove(devname); err != nil {
724
+		return err
725
+	}
726
+	return nil
727
+}
728
+
729
+// waitRemove blocks until either:
730
+// a) the device registered at <device_set_prefix>-<hash> is removed,
731
+// or b) the 1 second timeout expires.
732
+func (devices *DeviceSet) waitRemove(devname string) error {
733
+	utils.Debugf("[deviceset %s] waitRemove(%s)", devices.devicePrefix, devname)
734
+	defer utils.Debugf("[deviceset %s] waitRemove(%s) END", devices.devicePrefix, devname)
735
+	i := 0
736
+	for ; i < 1000; i += 1 {
737
+		devinfo, err := getInfo(devname)
738
+		if err != nil {
739
+			// If there is an error we assume the device doesn't exist.
740
+			// The error might actually be something else, but we can't differentiate.
741
+			return nil
742
+		}
743
+		if i%100 == 0 {
744
+			utils.Debugf("Waiting for removal of %s: exists=%d", devname, devinfo.Exists)
745
+		}
746
+		if devinfo.Exists == 0 {
747
+			break
748
+		}
749
+
750
+		devices.Unlock()
751
+		time.Sleep(10 * time.Millisecond)
752
+		devices.Lock()
753
+	}
754
+	if i == 1000 {
755
+		return fmt.Errorf("Timeout while waiting for device %s to be removed", devname)
756
+	}
757
+	return nil
758
+}
759
+
760
+// waitClose blocks until either:
761
+// a) the device registered at <device_set_prefix>-<hash> is closed,
762
+// or b) the 1 second timeout expires.
763
+func (devices *DeviceSet) waitClose(hash string) error {
764
+	info := devices.Devices[hash]
765
+	if info == nil {
766
+		return fmt.Errorf("Unknown device %s", hash)
767
+	}
768
+	i := 0
769
+	for ; i < 1000; i += 1 {
770
+		devinfo, err := getInfo(info.Name())
771
+		if err != nil {
772
+			return err
773
+		}
774
+		if i%100 == 0 {
775
+			utils.Debugf("Waiting for unmount of %s: opencount=%d", hash, devinfo.OpenCount)
776
+		}
777
+		if devinfo.OpenCount == 0 {
778
+			break
779
+		}
780
+		time.Sleep(1 * time.Millisecond)
781
+	}
782
+	if i == 1000 {
783
+		return fmt.Errorf("Timeout while waiting for device %s to close", hash)
784
+	}
785
+	return nil
786
+}
787
+
788
+func (devices *DeviceSet) Shutdown() error {
789
+	devices.Lock()
790
+	defer devices.Unlock()
791
+
792
+	utils.Debugf("[deviceset %s] shutdown()", devices.devicePrefix)
793
+	utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
794
+	defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
795
+
796
+	for _, info := range devices.Devices {
797
+		info.lock.Lock()
798
+		if info.mountCount > 0 {
799
+			if err := sysUnmount(info.mountPath, 0); err != nil {
800
+				utils.Debugf("Shutdown unmounting %s, error: %s\n", info.mountPath, err)
801
+			}
802
+		}
803
+		info.lock.Unlock()
804
+	}
805
+
806
+	for _, d := range devices.Devices {
807
+		d.lock.Lock()
808
+
809
+		if err := devices.waitClose(d.Hash); err != nil {
810
+			utils.Errorf("Warning: error waiting for device %s to unmount: %s\n", d.Hash, err)
811
+		}
812
+		if err := devices.deactivateDevice(d.Hash); err != nil {
813
+			utils.Debugf("Shutdown deactivate %s , error: %s\n", d.Hash, err)
814
+		}
815
+
816
+		d.lock.Unlock()
817
+	}
818
+
819
+	if err := devices.deactivatePool(); err != nil {
820
+		utils.Debugf("Shutdown deactivate pool , error: %s\n", err)
821
+	}
822
+
823
+	return nil
824
+}
825
+
826
+func (devices *DeviceSet) MountDevice(hash, path string) error {
827
+	devices.Lock()
828
+	defer devices.Unlock()
829
+
830
+	info := devices.Devices[hash]
831
+	if info == nil {
832
+		return fmt.Errorf("Unknown device %s", hash)
833
+	}
834
+
835
+	info.lock.Lock()
836
+	defer info.lock.Unlock()
837
+
838
+	if info.mountCount > 0 {
839
+		if path != info.mountPath {
840
+			return fmt.Errorf("Trying to mount devmapper device in multple places (%s, %s)", info.mountPath, path)
841
+		}
842
+
843
+		if info.floating {
844
+			// Steal floating ref
845
+			info.floating = false
846
+		} else {
847
+			info.mountCount++
848
+		}
849
+		return nil
850
+	}
851
+
852
+	if err := devices.activateDeviceIfNeeded(hash); err != nil {
853
+		return fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
854
+	}
855
+
856
+	var flags uintptr = sysMsMgcVal
857
+
858
+	err := sysMount(info.DevName(), path, "ext4", flags, "discard")
859
+	if err != nil && err == sysEInval {
860
+		err = sysMount(info.DevName(), path, "ext4", flags, "")
861
+	}
862
+	if err != nil {
863
+		return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err)
864
+	}
865
+
866
+	info.mountCount = 1
867
+	info.mountPath = path
868
+	info.floating = false
869
+
870
+	return devices.setInitialized(hash)
871
+}
872
+
873
+func (devices *DeviceSet) UnmountDevice(hash string, mode UnmountMode) error {
874
+	utils.Debugf("[devmapper] UnmountDevice(hash=%s, mode=%d)", hash, mode)
875
+	defer utils.Debugf("[devmapper] UnmountDevice END")
876
+	devices.Lock()
877
+	defer devices.Unlock()
878
+
879
+	info := devices.Devices[hash]
880
+	if info == nil {
881
+		return fmt.Errorf("UnmountDevice: no such device %s\n", hash)
882
+	}
883
+
884
+	info.lock.Lock()
885
+	defer info.lock.Unlock()
886
+
887
+	if mode == UnmountFloat {
888
+		if info.floating {
889
+			return fmt.Errorf("UnmountDevice: can't float floating reference %s\n", hash)
890
+		}
891
+
892
+		// Leave this reference floating
893
+		info.floating = true
894
+		return nil
895
+	}
896
+
897
+	if mode == UnmountSink {
898
+		if !info.floating {
899
+			// Someone already sunk this
900
+			return nil
901
+		}
902
+		// Otherwise, treat this as a regular unmount
903
+	}
904
+
905
+	if info.mountCount == 0 {
906
+		return fmt.Errorf("UnmountDevice: device not-mounted id %s\n", hash)
907
+	}
908
+
909
+	info.mountCount--
910
+	if info.mountCount > 0 {
911
+		return nil
912
+	}
913
+
914
+	utils.Debugf("[devmapper] Unmount(%s)", info.mountPath)
915
+	if err := sysUnmount(info.mountPath, 0); err != nil {
916
+		utils.Debugf("\n--->Err: %s\n", err)
917
+		return err
918
+	}
919
+	utils.Debugf("[devmapper] Unmount done")
920
+	// Wait for the unmount to be effective,
921
+	// by watching the value of Info.OpenCount for the device
922
+	if err := devices.waitClose(hash); err != nil {
923
+		return err
924
+	}
925
+
926
+	devices.deactivateDevice(hash)
927
+
928
+	info.mountPath = ""
929
+
930
+	return nil
931
+}
932
+
933
+func (devices *DeviceSet) HasDevice(hash string) bool {
934
+	devices.Lock()
935
+	defer devices.Unlock()
936
+
937
+	return devices.Devices[hash] != nil
938
+}
939
+
940
+func (devices *DeviceSet) HasInitializedDevice(hash string) bool {
941
+	devices.Lock()
942
+	defer devices.Unlock()
943
+
944
+	info := devices.Devices[hash]
945
+	return info != nil && info.Initialized
946
+}
947
+
948
+func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
949
+	devices.Lock()
950
+	defer devices.Unlock()
951
+
952
+	info := devices.Devices[hash]
953
+	if info == nil {
954
+		return false
955
+	}
956
+
957
+	info.lock.Lock()
958
+	defer info.lock.Unlock()
959
+
960
+	devinfo, _ := getInfo(info.Name())
961
+	return devinfo != nil && devinfo.Exists != 0
962
+}
963
+
964
+func (devices *DeviceSet) setInitialized(hash string) error {
965
+	info := devices.Devices[hash]
966
+	if info == nil {
967
+		return fmt.Errorf("Unknown device %s", hash)
968
+	}
969
+
970
+	info.Initialized = true
971
+	if err := devices.saveMetadata(); err != nil {
972
+		info.Initialized = false
973
+		utils.Debugf("\n--->Err: %s\n", err)
974
+		return err
975
+	}
976
+
977
+	return nil
978
+}
979
+
980
+func (devices *DeviceSet) List() []string {
981
+	devices.Lock()
982
+	defer devices.Unlock()
983
+
984
+	ids := make([]string, len(devices.Devices))
985
+	i := 0
986
+	for k := range devices.Devices {
987
+		ids[i] = k
988
+		i++
989
+	}
990
+	return ids
991
+}
992
+
993
+func (devices *DeviceSet) deviceStatus(devName string) (sizeInSectors, mappedSectors, highestMappedSector uint64, err error) {
994
+	var params string
995
+	_, sizeInSectors, _, params, err = getStatus(devName)
996
+	if err != nil {
997
+		return
998
+	}
999
+	if _, err = fmt.Sscanf(params, "%d %d", &mappedSectors, &highestMappedSector); err == nil {
1000
+		return
1001
+	}
1002
+	return
1003
+}
1004
+
1005
+func (devices *DeviceSet) GetDeviceStatus(hash string) (*DevStatus, error) {
1006
+	devices.Lock()
1007
+	defer devices.Unlock()
1008
+
1009
+	info := devices.Devices[hash]
1010
+	if info == nil {
1011
+		return nil, fmt.Errorf("No device %s", hash)
1012
+	}
1013
+
1014
+	info.lock.Lock()
1015
+	defer info.lock.Unlock()
1016
+
1017
+	status := &DevStatus{
1018
+		DeviceId:      info.DeviceId,
1019
+		Size:          info.Size,
1020
+		TransactionId: info.TransactionId,
1021
+	}
1022
+
1023
+	if err := devices.activateDeviceIfNeeded(hash); err != nil {
1024
+		return nil, fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
1025
+	}
1026
+
1027
+	if sizeInSectors, mappedSectors, highestMappedSector, err := devices.deviceStatus(info.DevName()); err != nil {
1028
+		return nil, err
1029
+	} else {
1030
+		status.SizeInSectors = sizeInSectors
1031
+		status.MappedSectors = mappedSectors
1032
+		status.HighestMappedSector = highestMappedSector
1033
+	}
1034
+
1035
+	return status, nil
1036
+}
1037
+
1038
+func (devices *DeviceSet) poolStatus() (totalSizeInSectors, transactionId, dataUsed, dataTotal, metadataUsed, metadataTotal uint64, err error) {
1039
+	var params string
1040
+	if _, totalSizeInSectors, _, params, err = getStatus(devices.getPoolName()); err == nil {
1041
+		_, err = fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionId, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal)
1042
+	}
1043
+	return
1044
+}
1045
+
1046
+func (devices *DeviceSet) Status() *Status {
1047
+	devices.Lock()
1048
+	defer devices.Unlock()
1049
+
1050
+	status := &Status{}
1051
+
1052
+	status.PoolName = devices.getPoolName()
1053
+	status.DataLoopback = path.Join(devices.loopbackDir(), "data")
1054
+	status.MetadataLoopback = path.Join(devices.loopbackDir(), "metadata")
1055
+
1056
+	totalSizeInSectors, _, dataUsed, dataTotal, metadataUsed, metadataTotal, err := devices.poolStatus()
1057
+	if err == nil {
1058
+		// Convert from blocks to bytes
1059
+		blockSizeInSectors := totalSizeInSectors / dataTotal
1060
+
1061
+		status.Data.Used = dataUsed * blockSizeInSectors * 512
1062
+		status.Data.Total = dataTotal * blockSizeInSectors * 512
1063
+
1064
+		// metadata blocks are always 4k
1065
+		status.Metadata.Used = metadataUsed * 4096
1066
+		status.Metadata.Total = metadataTotal * 4096
1067
+
1068
+		status.SectorSize = blockSizeInSectors * 512
1069
+	}
1070
+
1071
+	return status
1072
+}
1073
+
1074
+func NewDeviceSet(root string, doInit bool) (*DeviceSet, error) {
1075
+	SetDevDir("/dev")
1076
+
1077
+	devices := &DeviceSet{
1078
+		root:     root,
1079
+		MetaData: MetaData{Devices: make(map[string]*DevInfo)},
1080
+	}
1081
+
1082
+	if err := devices.initDevmapper(doInit); err != nil {
1083
+		return nil, err
1084
+	}
1085
+
1086
+	return devices, nil
1087
+}
0 1088
new file mode 100644
... ...
@@ -0,0 +1,595 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+import (
5
+	"errors"
6
+	"fmt"
7
+	"github.com/dotcloud/docker/utils"
8
+	"runtime"
9
+	"syscall"
10
+)
11
+
12
+type DevmapperLogger interface {
13
+	log(level int, file string, line int, dmError int, message string)
14
+}
15
+
16
+const (
17
+	DeviceCreate TaskType = iota
18
+	DeviceReload
19
+	DeviceRemove
20
+	DeviceRemoveAll
21
+	DeviceSuspend
22
+	DeviceResume
23
+	DeviceInfo
24
+	DeviceDeps
25
+	DeviceRename
26
+	DeviceVersion
27
+	DeviceStatus
28
+	DeviceTable
29
+	DeviceWaitevent
30
+	DeviceList
31
+	DeviceClear
32
+	DeviceMknodes
33
+	DeviceListVersions
34
+	DeviceTargetMsg
35
+	DeviceSetGeometry
36
+)
37
+
38
+const (
39
+	AddNodeOnResume AddNodeType = iota
40
+	AddNodeOnCreate
41
+)
42
+
43
+var (
44
+	ErrTaskRun                = errors.New("dm_task_run failed")
45
+	ErrTaskSetName            = errors.New("dm_task_set_name failed")
46
+	ErrTaskSetMessage         = errors.New("dm_task_set_message failed")
47
+	ErrTaskSetAddNode         = errors.New("dm_task_set_add_node failed")
48
+	ErrTaskSetRo              = errors.New("dm_task_set_ro failed")
49
+	ErrTaskAddTarget          = errors.New("dm_task_add_target failed")
50
+	ErrTaskSetSector          = errors.New("dm_task_set_sector failed")
51
+	ErrTaskGetInfo            = errors.New("dm_task_get_info failed")
52
+	ErrTaskSetCookie          = errors.New("dm_task_set_cookie failed")
53
+	ErrNilCookie              = errors.New("cookie ptr can't be nil")
54
+	ErrAttachLoopbackDevice   = errors.New("loopback mounting failed")
55
+	ErrGetBlockSize           = errors.New("Can't get block size")
56
+	ErrUdevWait               = errors.New("wait on udev cookie failed")
57
+	ErrSetDevDir              = errors.New("dm_set_dev_dir failed")
58
+	ErrGetLibraryVersion      = errors.New("dm_get_library_version failed")
59
+	ErrCreateRemoveTask       = errors.New("Can't create task of type DeviceRemove")
60
+	ErrRunRemoveDevice        = errors.New("running removeDevice failed")
61
+	ErrInvalidAddNode         = errors.New("Invalide AddNoce type")
62
+	ErrGetLoopbackBackingFile = errors.New("Unable to get loopback backing file")
63
+	ErrLoopbackSetCapacity    = errors.New("Unable set loopback capacity")
64
+)
65
+
66
+type (
67
+	Task struct {
68
+		unmanaged *CDmTask
69
+	}
70
+	Info struct {
71
+		Exists        int
72
+		Suspended     int
73
+		LiveTable     int
74
+		InactiveTable int
75
+		OpenCount     int32
76
+		EventNr       uint32
77
+		Major         uint32
78
+		Minor         uint32
79
+		ReadOnly      int
80
+		TargetCount   int32
81
+	}
82
+	TaskType    int
83
+	AddNodeType int
84
+)
85
+
86
+func (t *Task) destroy() {
87
+	if t != nil {
88
+		DmTaskDestroy(t.unmanaged)
89
+		runtime.SetFinalizer(t, nil)
90
+	}
91
+}
92
+
93
+func TaskCreate(tasktype TaskType) *Task {
94
+	Ctask := DmTaskCreate(int(tasktype))
95
+	if Ctask == nil {
96
+		return nil
97
+	}
98
+	task := &Task{unmanaged: Ctask}
99
+	runtime.SetFinalizer(task, (*Task).destroy)
100
+	return task
101
+}
102
+
103
+func (t *Task) Run() error {
104
+	if res := DmTaskRun(t.unmanaged); res != 1 {
105
+		return ErrTaskRun
106
+	}
107
+	return nil
108
+}
109
+
110
+func (t *Task) SetName(name string) error {
111
+	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
112
+		return ErrTaskSetName
113
+	}
114
+	return nil
115
+}
116
+
117
+func (t *Task) SetMessage(message string) error {
118
+	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
119
+		return ErrTaskSetMessage
120
+	}
121
+	return nil
122
+}
123
+
124
+func (t *Task) SetSector(sector uint64) error {
125
+	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
126
+		return ErrTaskSetSector
127
+	}
128
+	return nil
129
+}
130
+
131
+func (t *Task) SetCookie(cookie *uint, flags uint16) error {
132
+	if cookie == nil {
133
+		return ErrNilCookie
134
+	}
135
+	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
136
+		return ErrTaskSetCookie
137
+	}
138
+	return nil
139
+}
140
+
141
+func (t *Task) SetAddNode(addNode AddNodeType) error {
142
+	if addNode != AddNodeOnResume && addNode != AddNodeOnCreate {
143
+		return ErrInvalidAddNode
144
+	}
145
+	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
146
+		return ErrTaskSetAddNode
147
+	}
148
+	return nil
149
+}
150
+
151
+func (t *Task) SetRo() error {
152
+	if res := DmTaskSetRo(t.unmanaged); res != 1 {
153
+		return ErrTaskSetRo
154
+	}
155
+	return nil
156
+}
157
+
158
+func (t *Task) AddTarget(start, size uint64, ttype, params string) error {
159
+	if res := DmTaskAddTarget(t.unmanaged, start, size,
160
+		ttype, params); res != 1 {
161
+		return ErrTaskAddTarget
162
+	}
163
+	return nil
164
+}
165
+
166
+func (t *Task) GetInfo() (*Info, error) {
167
+	info := &Info{}
168
+	if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
169
+		return nil, ErrTaskGetInfo
170
+	}
171
+	return info, nil
172
+}
173
+
174
+func (t *Task) GetNextTarget(next uintptr) (nextPtr uintptr, start uint64,
175
+	length uint64, targetType string, params string) {
176
+
177
+	return DmGetNextTarget(t.unmanaged, next, &start, &length,
178
+			&targetType, &params),
179
+		start, length, targetType, params
180
+}
181
+
182
+func getLoopbackBackingFile(file *osFile) (uint64, uint64, error) {
183
+	loopInfo, err := ioctlLoopGetStatus64(file.Fd())
184
+	if err != nil {
185
+		utils.Errorf("Error get loopback backing file: %s\n", err)
186
+		return 0, 0, ErrGetLoopbackBackingFile
187
+	}
188
+	return loopInfo.loDevice, loopInfo.loInode, nil
189
+}
190
+
191
+func LoopbackSetCapacity(file *osFile) error {
192
+	if err := ioctlLoopSetCapacity(file.Fd(), 0); err != nil {
193
+		utils.Errorf("Error loopbackSetCapacity: %s", err)
194
+		return ErrLoopbackSetCapacity
195
+	}
196
+	return nil
197
+}
198
+
199
+func FindLoopDeviceFor(file *osFile) *osFile {
200
+	stat, err := file.Stat()
201
+	if err != nil {
202
+		return nil
203
+	}
204
+	targetInode := stat.Sys().(*sysStatT).Ino
205
+	targetDevice := stat.Sys().(*sysStatT).Dev
206
+
207
+	for i := 0; true; i++ {
208
+		path := fmt.Sprintf("/dev/loop%d", i)
209
+
210
+		file, err := osOpenFile(path, osORdWr, 0)
211
+		if err != nil {
212
+			if osIsNotExist(err) {
213
+				return nil
214
+			}
215
+
216
+			// Ignore all errors until the first not-exist
217
+			// we want to continue looking for the file
218
+			continue
219
+		}
220
+
221
+		dev, inode, err := getLoopbackBackingFile(file)
222
+		if err == nil && dev == targetDevice && inode == targetInode {
223
+			return file
224
+		}
225
+		file.Close()
226
+	}
227
+
228
+	return nil
229
+}
230
+
231
+func UdevWait(cookie uint) error {
232
+	if res := DmUdevWait(cookie); res != 1 {
233
+		utils.Debugf("Failed to wait on udev cookie %d", cookie)
234
+		return ErrUdevWait
235
+	}
236
+	return nil
237
+}
238
+
239
+func LogInitVerbose(level int) {
240
+	DmLogInitVerbose(level)
241
+}
242
+
243
+var dmLogger DevmapperLogger = nil
244
+
245
+func logInit(logger DevmapperLogger) {
246
+	dmLogger = logger
247
+	LogWithErrnoInit()
248
+}
249
+
250
+func SetDevDir(dir string) error {
251
+	if res := DmSetDevDir(dir); res != 1 {
252
+		utils.Debugf("Error dm_set_dev_dir")
253
+		return ErrSetDevDir
254
+	}
255
+	return nil
256
+}
257
+
258
+func GetLibraryVersion() (string, error) {
259
+	var version string
260
+	if res := DmGetLibraryVersion(&version); res != 1 {
261
+		return "", ErrGetLibraryVersion
262
+	}
263
+	return version, nil
264
+}
265
+
266
+// Useful helper for cleanup
267
+func RemoveDevice(name string) error {
268
+	task := TaskCreate(DeviceRemove)
269
+	if task == nil {
270
+		return ErrCreateRemoveTask
271
+	}
272
+	if err := task.SetName(name); err != nil {
273
+		utils.Debugf("Can't set task name %s", name)
274
+		return err
275
+	}
276
+	if err := task.Run(); err != nil {
277
+		return ErrRunRemoveDevice
278
+	}
279
+	return nil
280
+}
281
+
282
+func GetBlockDeviceSize(file *osFile) (uint64, error) {
283
+	size, err := ioctlBlkGetSize64(file.Fd())
284
+	if err != nil {
285
+		utils.Errorf("Error getblockdevicesize: %s", err)
286
+		return 0, ErrGetBlockSize
287
+	}
288
+	return uint64(size), nil
289
+}
290
+
291
+func BlockDeviceDiscard(path string) error {
292
+	file, err := osOpenFile(path, osORdWr, 0)
293
+	if err != nil {
294
+		return err
295
+	}
296
+	defer file.Close()
297
+
298
+	size, err := GetBlockDeviceSize(file)
299
+	if err != nil {
300
+		return err
301
+	}
302
+
303
+	if err := ioctlBlkDiscard(file.Fd(), 0, size); err != nil {
304
+		return err
305
+	}
306
+
307
+	// Without this sometimes the remove of the device that happens after
308
+	// discard fails with EBUSY.
309
+	syscall.Sync()
310
+
311
+	return nil
312
+}
313
+
314
+// This is the programmatic example of "dmsetup create"
315
+func createPool(poolName string, dataFile, metadataFile *osFile) error {
316
+	task, err := createTask(DeviceCreate, poolName)
317
+	if task == nil {
318
+		return err
319
+	}
320
+
321
+	size, err := GetBlockDeviceSize(dataFile)
322
+	if err != nil {
323
+		return fmt.Errorf("Can't get data size")
324
+	}
325
+
326
+	params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768 1 skip_block_zeroing"
327
+	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
328
+		return fmt.Errorf("Can't add target")
329
+	}
330
+
331
+	var cookie uint = 0
332
+	if err := task.SetCookie(&cookie, 0); err != nil {
333
+		return fmt.Errorf("Can't set cookie")
334
+	}
335
+
336
+	if err := task.Run(); err != nil {
337
+		return fmt.Errorf("Error running DeviceCreate (createPool)")
338
+	}
339
+
340
+	UdevWait(cookie)
341
+
342
+	return nil
343
+}
344
+
345
+func reloadPool(poolName string, dataFile, metadataFile *osFile) error {
346
+	task, err := createTask(DeviceReload, poolName)
347
+	if task == nil {
348
+		return err
349
+	}
350
+
351
+	size, err := GetBlockDeviceSize(dataFile)
352
+	if err != nil {
353
+		return fmt.Errorf("Can't get data size")
354
+	}
355
+
356
+	params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
357
+	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
358
+		return fmt.Errorf("Can't add target")
359
+	}
360
+
361
+	if err := task.Run(); err != nil {
362
+		return fmt.Errorf("Error running DeviceCreate")
363
+	}
364
+
365
+	return nil
366
+}
367
+
368
+func createTask(t TaskType, name string) (*Task, error) {
369
+	task := TaskCreate(t)
370
+	if task == nil {
371
+		return nil, fmt.Errorf("Can't create task of type %d", int(t))
372
+	}
373
+	if err := task.SetName(name); err != nil {
374
+		return nil, fmt.Errorf("Can't set task name %s", name)
375
+	}
376
+	return task, nil
377
+}
378
+
379
+func getInfo(name string) (*Info, error) {
380
+	task, err := createTask(DeviceInfo, name)
381
+	if task == nil {
382
+		return nil, err
383
+	}
384
+	if err := task.Run(); err != nil {
385
+		return nil, err
386
+	}
387
+	return task.GetInfo()
388
+}
389
+
390
+func getStatus(name string) (uint64, uint64, string, string, error) {
391
+	task, err := createTask(DeviceStatus, name)
392
+	if task == nil {
393
+		utils.Debugf("getStatus: Error createTask: %s", err)
394
+		return 0, 0, "", "", err
395
+	}
396
+	if err := task.Run(); err != nil {
397
+		utils.Debugf("getStatus: Error Run: %s", err)
398
+		return 0, 0, "", "", err
399
+	}
400
+
401
+	devinfo, err := task.GetInfo()
402
+	if err != nil {
403
+		utils.Debugf("getStatus: Error GetInfo: %s", err)
404
+		return 0, 0, "", "", err
405
+	}
406
+	if devinfo.Exists == 0 {
407
+		utils.Debugf("getStatus: Non existing device %s", name)
408
+		return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
409
+	}
410
+
411
+	_, start, length, targetType, params := task.GetNextTarget(0)
412
+	return start, length, targetType, params, nil
413
+}
414
+
415
+func setTransactionId(poolName string, oldId uint64, newId uint64) error {
416
+	task, err := createTask(DeviceTargetMsg, poolName)
417
+	if task == nil {
418
+		return err
419
+	}
420
+
421
+	if err := task.SetSector(0); err != nil {
422
+		return fmt.Errorf("Can't set sector")
423
+	}
424
+
425
+	if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
426
+		return fmt.Errorf("Can't set message")
427
+	}
428
+
429
+	if err := task.Run(); err != nil {
430
+		return fmt.Errorf("Error running setTransactionId")
431
+	}
432
+	return nil
433
+}
434
+
435
+func suspendDevice(name string) error {
436
+	task, err := createTask(DeviceSuspend, name)
437
+	if task == nil {
438
+		return err
439
+	}
440
+	if err := task.Run(); err != nil {
441
+		return fmt.Errorf("Error running DeviceSuspend: %s", err)
442
+	}
443
+	return nil
444
+}
445
+
446
+func resumeDevice(name string) error {
447
+	task, err := createTask(DeviceResume, name)
448
+	if task == nil {
449
+		return err
450
+	}
451
+
452
+	var cookie uint = 0
453
+	if err := task.SetCookie(&cookie, 0); err != nil {
454
+		return fmt.Errorf("Can't set cookie")
455
+	}
456
+
457
+	if err := task.Run(); err != nil {
458
+		return fmt.Errorf("Error running DeviceResume")
459
+	}
460
+
461
+	UdevWait(cookie)
462
+
463
+	return nil
464
+}
465
+
466
+func createDevice(poolName string, deviceId int) error {
467
+	utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
468
+	task, err := createTask(DeviceTargetMsg, poolName)
469
+	if task == nil {
470
+		return err
471
+	}
472
+
473
+	if err := task.SetSector(0); err != nil {
474
+		return fmt.Errorf("Can't set sector")
475
+	}
476
+
477
+	if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
478
+		return fmt.Errorf("Can't set message")
479
+	}
480
+
481
+	if err := task.Run(); err != nil {
482
+		return fmt.Errorf("Error running createDevice")
483
+	}
484
+	return nil
485
+}
486
+
487
+func deleteDevice(poolName string, deviceId int) error {
488
+	task, err := createTask(DeviceTargetMsg, poolName)
489
+	if task == nil {
490
+		return err
491
+	}
492
+
493
+	if err := task.SetSector(0); err != nil {
494
+		return fmt.Errorf("Can't set sector")
495
+	}
496
+
497
+	if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
498
+		return fmt.Errorf("Can't set message")
499
+	}
500
+
501
+	if err := task.Run(); err != nil {
502
+		return fmt.Errorf("Error running deleteDevice")
503
+	}
504
+	return nil
505
+}
506
+
507
+func removeDevice(name string) error {
508
+	utils.Debugf("[devmapper] removeDevice START")
509
+	defer utils.Debugf("[devmapper] removeDevice END")
510
+	task, err := createTask(DeviceRemove, name)
511
+	if task == nil {
512
+		return err
513
+	}
514
+	if err = task.Run(); err != nil {
515
+		return fmt.Errorf("Error running removeDevice")
516
+	}
517
+	return nil
518
+}
519
+
520
+func activateDevice(poolName string, name string, deviceId int, size uint64) error {
521
+	task, err := createTask(DeviceCreate, name)
522
+	if task == nil {
523
+		return err
524
+	}
525
+
526
+	params := fmt.Sprintf("%s %d", poolName, deviceId)
527
+	if err := task.AddTarget(0, size/512, "thin", params); err != nil {
528
+		return fmt.Errorf("Can't add target")
529
+	}
530
+	if err := task.SetAddNode(AddNodeOnCreate); err != nil {
531
+		return fmt.Errorf("Can't add node")
532
+	}
533
+
534
+	var cookie uint = 0
535
+	if err := task.SetCookie(&cookie, 0); err != nil {
536
+		return fmt.Errorf("Can't set cookie")
537
+	}
538
+
539
+	if err := task.Run(); err != nil {
540
+		return fmt.Errorf("Error running DeviceCreate (activateDevice)")
541
+	}
542
+
543
+	UdevWait(cookie)
544
+
545
+	return nil
546
+}
547
+
548
+func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
549
+	devinfo, _ := getInfo(baseName)
550
+	doSuspend := devinfo != nil && devinfo.Exists != 0
551
+
552
+	if doSuspend {
553
+		if err := suspendDevice(baseName); err != nil {
554
+			return err
555
+		}
556
+	}
557
+
558
+	task, err := createTask(DeviceTargetMsg, poolName)
559
+	if task == nil {
560
+		if doSuspend {
561
+			resumeDevice(baseName)
562
+		}
563
+		return err
564
+	}
565
+
566
+	if err := task.SetSector(0); err != nil {
567
+		if doSuspend {
568
+			resumeDevice(baseName)
569
+		}
570
+		return fmt.Errorf("Can't set sector")
571
+	}
572
+
573
+	if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
574
+		if doSuspend {
575
+			resumeDevice(baseName)
576
+		}
577
+		return fmt.Errorf("Can't set message")
578
+	}
579
+
580
+	if err := task.Run(); err != nil {
581
+		if doSuspend {
582
+			resumeDevice(baseName)
583
+		}
584
+		return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
585
+	}
586
+
587
+	if doSuspend {
588
+		if err := resumeDevice(baseName); err != nil {
589
+			return err
590
+		}
591
+	}
592
+
593
+	return nil
594
+}
0 595
new file mode 100644
... ...
@@ -0,0 +1,106 @@
0
+package devmapper
1
+
2
+// Definition of struct dm_task and sub structures (from lvm2)
3
+//
4
+// struct dm_ioctl {
5
+// 	/*
6
+// 	 * The version number is made up of three parts:
7
+// 	 * major - no backward or forward compatibility,
8
+// 	 * minor - only backwards compatible,
9
+// 	 * patch - both backwards and forwards compatible.
10
+// 	 *
11
+// 	 * All clients of the ioctl interface should fill in the
12
+// 	 * version number of the interface that they were
13
+// 	 * compiled with.
14
+// 	 *
15
+// 	 * All recognised ioctl commands (ie. those that don't
16
+// 	 * return -ENOTTY) fill out this field, even if the
17
+// 	 * command failed.
18
+// 	 */
19
+// 	uint32_t version[3];	/* in/out */
20
+// 	uint32_t data_size;	/* total size of data passed in
21
+// 				 * including this struct */
22
+
23
+// 	uint32_t data_start;	/* offset to start of data
24
+// 				 * relative to start of this struct */
25
+
26
+// 	uint32_t target_count;	/* in/out */
27
+// 	int32_t open_count;	/* out */
28
+// 	uint32_t flags;		/* in/out */
29
+
30
+// 	/*
31
+// 	 * event_nr holds either the event number (input and output) or the
32
+// 	 * udev cookie value (input only).
33
+// 	 * The DM_DEV_WAIT ioctl takes an event number as input.
34
+// 	 * The DM_SUSPEND, DM_DEV_REMOVE and DM_DEV_RENAME ioctls
35
+// 	 * use the field as a cookie to return in the DM_COOKIE
36
+// 	 * variable with the uevents they issue.
37
+// 	 * For output, the ioctls return the event number, not the cookie.
38
+// 	 */
39
+// 	uint32_t event_nr;      	/* in/out */
40
+// 	uint32_t padding;
41
+
42
+// 	uint64_t dev;		/* in/out */
43
+
44
+// 	char name[DM_NAME_LEN];	/* device name */
45
+// 	char uuid[DM_UUID_LEN];	/* unique identifier for
46
+// 				 * the block device */
47
+// 	char data[7];		/* padding or data */
48
+// };
49
+
50
+// struct target {
51
+// 	uint64_t start;
52
+// 	uint64_t length;
53
+// 	char *type;
54
+// 	char *params;
55
+
56
+// 	struct target *next;
57
+// };
58
+
59
+// typedef enum {
60
+// 	DM_ADD_NODE_ON_RESUME, /* add /dev/mapper node with dmsetup resume */
61
+// 	DM_ADD_NODE_ON_CREATE  /* add /dev/mapper node with dmsetup create */
62
+// } dm_add_node_t;
63
+
64
+// struct dm_task {
65
+// 	int type;
66
+// 	char *dev_name;
67
+// 	char *mangled_dev_name;
68
+
69
+// 	struct target *head, *tail;
70
+
71
+// 	int read_only;
72
+// 	uint32_t event_nr;
73
+// 	int major;
74
+// 	int minor;
75
+// 	int allow_default_major_fallback;
76
+// 	uid_t uid;
77
+// 	gid_t gid;
78
+// 	mode_t mode;
79
+// 	uint32_t read_ahead;
80
+// 	uint32_t read_ahead_flags;
81
+// 	union {
82
+// 		struct dm_ioctl *v4;
83
+// 	} dmi;
84
+// 	char *newname;
85
+// 	char *message;
86
+// 	char *geometry;
87
+// 	uint64_t sector;
88
+// 	int no_flush;
89
+// 	int no_open_count;
90
+// 	int skip_lockfs;
91
+// 	int query_inactive_table;
92
+// 	int suppress_identical_reload;
93
+// 	dm_add_node_t add_node;
94
+// 	uint64_t existing_table_size;
95
+// 	int cookie_set;
96
+// 	int new_uuid;
97
+// 	int secure_data;
98
+// 	int retry_remove;
99
+// 	int enable_checks;
100
+// 	int expected_errno;
101
+
102
+// 	char *uuid;
103
+// 	char *mangled_uuid;
104
+// };
105
+//
0 106
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+import "C"
5
+
6
+// Due to the way cgo works this has to be in a separate file, as devmapper.go has
7
+// definitions in the cgo block, which is incompatible with using "//export"
8
+
9
+//export DevmapperLogCallback
10
+func DevmapperLogCallback(level C.int, file *C.char, line C.int, dm_errno_or_class C.int, message *C.char) {
11
+	if dmLogger != nil {
12
+		dmLogger.log(int(level), C.GoString(file), int(line), int(dm_errno_or_class), C.GoString(message))
13
+	}
14
+}
0 15
new file mode 100644
... ...
@@ -0,0 +1,287 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+import (
5
+	"testing"
6
+)
7
+
8
+func TestTaskCreate(t *testing.T) {
9
+	t.Skip("FIXME: not a unit test")
10
+	// Test success
11
+	taskCreate(t, DeviceInfo)
12
+
13
+	// Test Failure
14
+	DmTaskCreate = dmTaskCreateFail
15
+	defer func() { DmTaskCreate = dmTaskCreateFct }()
16
+	if task := TaskCreate(-1); task != nil {
17
+		t.Fatalf("An error should have occured while creating an invalid task.")
18
+	}
19
+}
20
+
21
+func TestTaskRun(t *testing.T) {
22
+	t.Skip("FIXME: not a unit test")
23
+	task := taskCreate(t, DeviceInfo)
24
+
25
+	// Test success
26
+	// Perform the RUN
27
+	if err := task.Run(); err != nil {
28
+		t.Fatal(err)
29
+	}
30
+	// Make sure we don't have error with GetInfo
31
+	if _, err := task.GetInfo(); err != nil {
32
+		t.Fatal(err)
33
+	}
34
+
35
+	// Test failure
36
+	DmTaskRun = dmTaskRunFail
37
+	defer func() { DmTaskRun = dmTaskRunFct }()
38
+
39
+	task = taskCreate(t, DeviceInfo)
40
+	// Perform the RUN
41
+	if err := task.Run(); err != ErrTaskRun {
42
+		t.Fatalf("An error should have occured while running task.")
43
+	}
44
+	// Make sure GetInfo also fails
45
+	if _, err := task.GetInfo(); err != ErrTaskGetInfo {
46
+		t.Fatalf("GetInfo should fail if task.Run() failed.")
47
+	}
48
+}
49
+
50
+func TestTaskSetName(t *testing.T) {
51
+	t.Skip("FIXME: not a unit test")
52
+	task := taskCreate(t, DeviceInfo)
53
+
54
+	// Test success
55
+	if err := task.SetName("test"); err != nil {
56
+		t.Fatal(err)
57
+	}
58
+
59
+	// Test failure
60
+	DmTaskSetName = dmTaskSetNameFail
61
+	defer func() { DmTaskSetName = dmTaskSetNameFct }()
62
+
63
+	if err := task.SetName("test"); err != ErrTaskSetName {
64
+		t.Fatalf("An error should have occured while runnign SetName.")
65
+	}
66
+}
67
+
68
+func TestTaskSetMessage(t *testing.T) {
69
+	t.Skip("FIXME: not a unit test")
70
+	task := taskCreate(t, DeviceInfo)
71
+
72
+	// Test success
73
+	if err := task.SetMessage("test"); err != nil {
74
+		t.Fatal(err)
75
+	}
76
+
77
+	// Test failure
78
+	DmTaskSetMessage = dmTaskSetMessageFail
79
+	defer func() { DmTaskSetMessage = dmTaskSetMessageFct }()
80
+
81
+	if err := task.SetMessage("test"); err != ErrTaskSetMessage {
82
+		t.Fatalf("An error should have occured while runnign SetMessage.")
83
+	}
84
+}
85
+
86
+func TestTaskSetSector(t *testing.T) {
87
+	t.Skip("FIXME: not a unit test")
88
+	task := taskCreate(t, DeviceInfo)
89
+
90
+	// Test success
91
+	if err := task.SetSector(128); err != nil {
92
+		t.Fatal(err)
93
+	}
94
+
95
+	DmTaskSetSector = dmTaskSetSectorFail
96
+	defer func() { DmTaskSetSector = dmTaskSetSectorFct }()
97
+
98
+	// Test failure
99
+	if err := task.SetSector(0); err != ErrTaskSetSector {
100
+		t.Fatalf("An error should have occured while running SetSector.")
101
+	}
102
+}
103
+
104
+func TestTaskSetCookie(t *testing.T) {
105
+	t.Skip("FIXME: not a unit test")
106
+	var (
107
+		cookie uint = 0
108
+		task        = taskCreate(t, DeviceInfo)
109
+	)
110
+
111
+	// Test success
112
+	if err := task.SetCookie(&cookie, 0); err != nil {
113
+		t.Fatal(err)
114
+	}
115
+
116
+	// Test failure
117
+	if err := task.SetCookie(nil, 0); err != ErrNilCookie {
118
+		t.Fatalf("An error should have occured while running SetCookie with nil cookie.")
119
+	}
120
+
121
+	DmTaskSetCookie = dmTaskSetCookieFail
122
+	defer func() { DmTaskSetCookie = dmTaskSetCookieFct }()
123
+
124
+	if err := task.SetCookie(&cookie, 0); err != ErrTaskSetCookie {
125
+		t.Fatalf("An error should have occured while running SetCookie.")
126
+	}
127
+}
128
+
129
+func TestTaskSetAddNode(t *testing.T) {
130
+	t.Skip("FIXME: not a unit test")
131
+	task := taskCreate(t, DeviceInfo)
132
+
133
+	// Test success
134
+	if err := task.SetAddNode(0); err != nil {
135
+		t.Fatal(err)
136
+	}
137
+
138
+	// Test failure
139
+	if err := task.SetAddNode(-1); err != ErrInvalidAddNode {
140
+		t.Fatalf("An error should have occured running SetAddNode with wrong node.")
141
+	}
142
+
143
+	DmTaskSetAddNode = dmTaskSetAddNodeFail
144
+	defer func() { DmTaskSetAddNode = dmTaskSetAddNodeFct }()
145
+
146
+	if err := task.SetAddNode(0); err != ErrTaskSetAddNode {
147
+		t.Fatalf("An error should have occured running SetAddNode.")
148
+	}
149
+}
150
+
151
+func TestTaskSetRo(t *testing.T) {
152
+	t.Skip("FIXME: not a unit test")
153
+	task := taskCreate(t, DeviceInfo)
154
+
155
+	// Test success
156
+	if err := task.SetRo(); err != nil {
157
+		t.Fatal(err)
158
+	}
159
+
160
+	// Test failure
161
+	DmTaskSetRo = dmTaskSetRoFail
162
+	defer func() { DmTaskSetRo = dmTaskSetRoFct }()
163
+
164
+	if err := task.SetRo(); err != ErrTaskSetRo {
165
+		t.Fatalf("An error should have occured running SetRo.")
166
+	}
167
+}
168
+
169
+func TestTaskAddTarget(t *testing.T) {
170
+	t.Skip("FIXME: not a unit test")
171
+	task := taskCreate(t, DeviceInfo)
172
+
173
+	// Test success
174
+	if err := task.AddTarget(0, 128, "thinp", ""); err != nil {
175
+		t.Fatal(err)
176
+	}
177
+
178
+	// Test failure
179
+	DmTaskAddTarget = dmTaskAddTargetFail
180
+	defer func() { DmTaskAddTarget = dmTaskAddTargetFct }()
181
+
182
+	if err := task.AddTarget(0, 128, "thinp", ""); err != ErrTaskAddTarget {
183
+		t.Fatalf("An error should have occured running AddTarget.")
184
+	}
185
+}
186
+
187
+// func TestTaskGetInfo(t *testing.T) {
188
+// 	task := taskCreate(t, DeviceInfo)
189
+
190
+// 	// Test success
191
+// 	if _, err := task.GetInfo(); err != nil {
192
+// 		t.Fatal(err)
193
+// 	}
194
+
195
+// 	// Test failure
196
+// 	DmTaskGetInfo = dmTaskGetInfoFail
197
+// 	defer func() { DmTaskGetInfo = dmTaskGetInfoFct }()
198
+
199
+// 	if _, err := task.GetInfo(); err != ErrTaskGetInfo {
200
+// 		t.Fatalf("An error should have occured running GetInfo.")
201
+// 	}
202
+// }
203
+
204
+// func TestTaskGetNextTarget(t *testing.T) {
205
+// 	task := taskCreate(t, DeviceInfo)
206
+
207
+// 	if next, _, _, _, _ := task.GetNextTarget(0); next == 0 {
208
+// 		t.Fatalf("The next target should not be 0.")
209
+// 	}
210
+// }
211
+
212
+/// Utils
213
+func taskCreate(t *testing.T, taskType TaskType) *Task {
214
+	task := TaskCreate(taskType)
215
+	if task == nil {
216
+		t.Fatalf("Error creating task")
217
+	}
218
+	return task
219
+}
220
+
221
+/// Failure function replacement
222
+func dmTaskCreateFail(t int) *CDmTask {
223
+	return nil
224
+}
225
+
226
+func dmTaskRunFail(task *CDmTask) int {
227
+	return -1
228
+}
229
+
230
+func dmTaskSetNameFail(task *CDmTask, name string) int {
231
+	return -1
232
+}
233
+
234
+func dmTaskSetMessageFail(task *CDmTask, message string) int {
235
+	return -1
236
+}
237
+
238
+func dmTaskSetSectorFail(task *CDmTask, sector uint64) int {
239
+	return -1
240
+}
241
+
242
+func dmTaskSetCookieFail(task *CDmTask, cookie *uint, flags uint16) int {
243
+	return -1
244
+}
245
+
246
+func dmTaskSetAddNodeFail(task *CDmTask, addNode AddNodeType) int {
247
+	return -1
248
+}
249
+
250
+func dmTaskSetRoFail(task *CDmTask) int {
251
+	return -1
252
+}
253
+
254
+func dmTaskAddTargetFail(task *CDmTask,
255
+	start, size uint64, ttype, params string) int {
256
+	return -1
257
+}
258
+
259
+func dmTaskGetInfoFail(task *CDmTask, info *Info) int {
260
+	return -1
261
+}
262
+
263
+func dmGetNextTargetFail(task *CDmTask, next uintptr, start, length *uint64,
264
+	target, params *string) uintptr {
265
+	return 0
266
+}
267
+
268
+func dmAttachLoopDeviceFail(filename string, fd *int) string {
269
+	return ""
270
+}
271
+
272
+func sysGetBlockSizeFail(fd uintptr, size *uint64) sysErrno {
273
+	return 1
274
+}
275
+
276
+func dmUdevWaitFail(cookie uint) int {
277
+	return -1
278
+}
279
+
280
+func dmSetDevDirFail(dir string) int {
281
+	return -1
282
+}
283
+
284
+func dmGetLibraryVersionFail(version *string) int {
285
+	return -1
286
+}
0 287
new file mode 100644
... ...
@@ -0,0 +1,229 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+/*
5
+#cgo LDFLAGS: -L. -ldevmapper
6
+#include <libdevmapper.h>
7
+#include <linux/loop.h> // FIXME: present only for defines, maybe we can remove it?
8
+#include <linux/fs.h>   // FIXME: present only for BLKGETSIZE64, maybe we can remove it?
9
+
10
+#ifndef LOOP_CTL_GET_FREE
11
+  #define LOOP_CTL_GET_FREE 0x4C82
12
+#endif
13
+
14
+#ifndef LO_FLAGS_PARTSCAN
15
+  #define LO_FLAGS_PARTSCAN 8
16
+#endif
17
+
18
+// FIXME: Can't we find a way to do the logging in pure Go?
19
+extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
20
+
21
+static void	log_cb(int level, const char *file, int line, int dm_errno_or_class, const char *f, ...)
22
+{
23
+  char buffer[256];
24
+  va_list ap;
25
+
26
+  va_start(ap, f);
27
+  vsnprintf(buffer, 256, f, ap);
28
+  va_end(ap);
29
+
30
+  DevmapperLogCallback(level, (char *)file, line, dm_errno_or_class, buffer);
31
+}
32
+
33
+static void	log_with_errno_init()
34
+{
35
+  dm_log_with_errno_init(log_cb);
36
+}
37
+*/
38
+import "C"
39
+
40
+import (
41
+	"unsafe"
42
+)
43
+
44
+type (
45
+	CDmTask C.struct_dm_task
46
+
47
+	CLoopInfo64 C.struct_loop_info64
48
+	LoopInfo64  struct {
49
+		loDevice           uint64 /* ioctl r/o */
50
+		loInode            uint64 /* ioctl r/o */
51
+		loRdevice          uint64 /* ioctl r/o */
52
+		loOffset           uint64
53
+		loSizelimit        uint64 /* bytes, 0 == max available */
54
+		loNumber           uint32 /* ioctl r/o */
55
+		loEncrypt_type     uint32
56
+		loEncrypt_key_size uint32 /* ioctl w/o */
57
+		loFlags            uint32 /* ioctl r/o */
58
+		loFileName         [LoNameSize]uint8
59
+		loCryptName        [LoNameSize]uint8
60
+		loEncryptKey       [LoKeySize]uint8 /* ioctl w/o */
61
+		loInit             [2]uint64
62
+	}
63
+)
64
+
65
+// IOCTL consts
66
+const (
67
+	BlkGetSize64 = C.BLKGETSIZE64
68
+	BlkDiscard   = C.BLKDISCARD
69
+
70
+	LoopSetFd       = C.LOOP_SET_FD
71
+	LoopCtlGetFree  = C.LOOP_CTL_GET_FREE
72
+	LoopGetStatus64 = C.LOOP_GET_STATUS64
73
+	LoopSetStatus64 = C.LOOP_SET_STATUS64
74
+	LoopClrFd       = C.LOOP_CLR_FD
75
+	LoopSetCapacity = C.LOOP_SET_CAPACITY
76
+)
77
+
78
+const (
79
+	LoFlagsAutoClear = C.LO_FLAGS_AUTOCLEAR
80
+	LoFlagsReadOnly  = C.LO_FLAGS_READ_ONLY
81
+	LoFlagsPartScan  = C.LO_FLAGS_PARTSCAN
82
+	LoKeySize        = C.LO_KEY_SIZE
83
+	LoNameSize       = C.LO_NAME_SIZE
84
+)
85
+
86
+var (
87
+	DmGetLibraryVersion = dmGetLibraryVersionFct
88
+	DmGetNextTarget     = dmGetNextTargetFct
89
+	DmLogInitVerbose    = dmLogInitVerboseFct
90
+	DmSetDevDir         = dmSetDevDirFct
91
+	DmTaskAddTarget     = dmTaskAddTargetFct
92
+	DmTaskCreate        = dmTaskCreateFct
93
+	DmTaskDestroy       = dmTaskDestroyFct
94
+	DmTaskGetInfo       = dmTaskGetInfoFct
95
+	DmTaskRun           = dmTaskRunFct
96
+	DmTaskSetAddNode    = dmTaskSetAddNodeFct
97
+	DmTaskSetCookie     = dmTaskSetCookieFct
98
+	DmTaskSetMessage    = dmTaskSetMessageFct
99
+	DmTaskSetName       = dmTaskSetNameFct
100
+	DmTaskSetRo         = dmTaskSetRoFct
101
+	DmTaskSetSector     = dmTaskSetSectorFct
102
+	DmUdevWait          = dmUdevWaitFct
103
+	LogWithErrnoInit    = logWithErrnoInitFct
104
+)
105
+
106
+func free(p *C.char) {
107
+	C.free(unsafe.Pointer(p))
108
+}
109
+
110
+func dmTaskDestroyFct(task *CDmTask) {
111
+	C.dm_task_destroy((*C.struct_dm_task)(task))
112
+}
113
+
114
+func dmTaskCreateFct(taskType int) *CDmTask {
115
+	return (*CDmTask)(C.dm_task_create(C.int(taskType)))
116
+}
117
+
118
+func dmTaskRunFct(task *CDmTask) int {
119
+	ret, _ := C.dm_task_run((*C.struct_dm_task)(task))
120
+	return int(ret)
121
+}
122
+
123
+func dmTaskSetNameFct(task *CDmTask, name string) int {
124
+	Cname := C.CString(name)
125
+	defer free(Cname)
126
+
127
+	return int(C.dm_task_set_name((*C.struct_dm_task)(task), Cname))
128
+}
129
+
130
+func dmTaskSetMessageFct(task *CDmTask, message string) int {
131
+	Cmessage := C.CString(message)
132
+	defer free(Cmessage)
133
+
134
+	return int(C.dm_task_set_message((*C.struct_dm_task)(task), Cmessage))
135
+}
136
+
137
+func dmTaskSetSectorFct(task *CDmTask, sector uint64) int {
138
+	return int(C.dm_task_set_sector((*C.struct_dm_task)(task), C.uint64_t(sector)))
139
+}
140
+
141
+func dmTaskSetCookieFct(task *CDmTask, cookie *uint, flags uint16) int {
142
+	cCookie := C.uint32_t(*cookie)
143
+	defer func() {
144
+		*cookie = uint(cCookie)
145
+	}()
146
+	return int(C.dm_task_set_cookie((*C.struct_dm_task)(task), &cCookie, C.uint16_t(flags)))
147
+}
148
+
149
+func dmTaskSetAddNodeFct(task *CDmTask, addNode AddNodeType) int {
150
+	return int(C.dm_task_set_add_node((*C.struct_dm_task)(task), C.dm_add_node_t(addNode)))
151
+}
152
+
153
+func dmTaskSetRoFct(task *CDmTask) int {
154
+	return int(C.dm_task_set_ro((*C.struct_dm_task)(task)))
155
+}
156
+
157
+func dmTaskAddTargetFct(task *CDmTask,
158
+	start, size uint64, ttype, params string) int {
159
+
160
+	Cttype := C.CString(ttype)
161
+	defer free(Cttype)
162
+
163
+	Cparams := C.CString(params)
164
+	defer free(Cparams)
165
+
166
+	return int(C.dm_task_add_target((*C.struct_dm_task)(task), C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
167
+}
168
+
169
+func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
170
+	Cinfo := C.struct_dm_info{}
171
+	defer func() {
172
+		info.Exists = int(Cinfo.exists)
173
+		info.Suspended = int(Cinfo.suspended)
174
+		info.LiveTable = int(Cinfo.live_table)
175
+		info.InactiveTable = int(Cinfo.inactive_table)
176
+		info.OpenCount = int32(Cinfo.open_count)
177
+		info.EventNr = uint32(Cinfo.event_nr)
178
+		info.Major = uint32(Cinfo.major)
179
+		info.Minor = uint32(Cinfo.minor)
180
+		info.ReadOnly = int(Cinfo.read_only)
181
+		info.TargetCount = int32(Cinfo.target_count)
182
+	}()
183
+	return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
184
+}
185
+
186
+func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64, target, params *string) uintptr {
187
+	var (
188
+		Cstart, Clength      C.uint64_t
189
+		CtargetType, Cparams *C.char
190
+	)
191
+	defer func() {
192
+		*start = uint64(Cstart)
193
+		*length = uint64(Clength)
194
+		*target = C.GoString(CtargetType)
195
+		*params = C.GoString(Cparams)
196
+	}()
197
+
198
+	nextp := C.dm_get_next_target((*C.struct_dm_task)(task), unsafe.Pointer(next), &Cstart, &Clength, &CtargetType, &Cparams)
199
+	return uintptr(nextp)
200
+}
201
+
202
+func dmUdevWaitFct(cookie uint) int {
203
+	return int(C.dm_udev_wait(C.uint32_t(cookie)))
204
+}
205
+
206
+func dmLogInitVerboseFct(level int) {
207
+	C.dm_log_init_verbose(C.int(level))
208
+}
209
+
210
+func logWithErrnoInitFct() {
211
+	C.log_with_errno_init()
212
+}
213
+
214
+func dmSetDevDirFct(dir string) int {
215
+	Cdir := C.CString(dir)
216
+	defer free(Cdir)
217
+
218
+	return int(C.dm_set_dev_dir(Cdir))
219
+}
220
+
221
+func dmGetLibraryVersionFct(version *string) int {
222
+	buffer := C.CString(string(make([]byte, 128)))
223
+	defer free(buffer)
224
+	defer func() {
225
+		*version = C.GoString(buffer)
226
+	}()
227
+	return int(C.dm_get_library_version(buffer, 128))
228
+}
0 229
new file mode 100644
... ...
@@ -0,0 +1,143 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+import (
5
+	"fmt"
6
+	"github.com/dotcloud/docker/runtime/graphdriver"
7
+	"github.com/dotcloud/docker/utils"
8
+	"io/ioutil"
9
+	"os"
10
+	"path"
11
+)
12
+
13
+func init() {
14
+	graphdriver.Register("devicemapper", Init)
15
+}
16
+
17
+// Placeholder interfaces, to be replaced
18
+// at integration.
19
+
20
+// End of placeholder interfaces.
21
+
22
+type Driver struct {
23
+	*DeviceSet
24
+	home string
25
+}
26
+
27
+var Init = func(home string) (graphdriver.Driver, error) {
28
+	deviceSet, err := NewDeviceSet(home, true)
29
+	if err != nil {
30
+		return nil, err
31
+	}
32
+	d := &Driver{
33
+		DeviceSet: deviceSet,
34
+		home:      home,
35
+	}
36
+	return d, nil
37
+}
38
+
39
+func (d *Driver) String() string {
40
+	return "devicemapper"
41
+}
42
+
43
+func (d *Driver) Status() [][2]string {
44
+	s := d.DeviceSet.Status()
45
+
46
+	status := [][2]string{
47
+		{"Pool Name", s.PoolName},
48
+		{"Data file", s.DataLoopback},
49
+		{"Metadata file", s.MetadataLoopback},
50
+		{"Data Space Used", fmt.Sprintf("%.1f Mb", float64(s.Data.Used)/(1024*1024))},
51
+		{"Data Space Total", fmt.Sprintf("%.1f Mb", float64(s.Data.Total)/(1024*1024))},
52
+		{"Metadata Space Used", fmt.Sprintf("%.1f Mb", float64(s.Metadata.Used)/(1024*1024))},
53
+		{"Metadata Space Total", fmt.Sprintf("%.1f Mb", float64(s.Metadata.Total)/(1024*1024))},
54
+	}
55
+	return status
56
+}
57
+
58
+func (d *Driver) Cleanup() error {
59
+	return d.DeviceSet.Shutdown()
60
+}
61
+
62
+func (d *Driver) Create(id, parent string) error {
63
+	if err := d.DeviceSet.AddDevice(id, parent); err != nil {
64
+		return err
65
+	}
66
+
67
+	mp := path.Join(d.home, "mnt", id)
68
+	if err := d.mount(id, mp); err != nil {
69
+		return err
70
+	}
71
+
72
+	if err := osMkdirAll(path.Join(mp, "rootfs"), 0755); err != nil && !osIsExist(err) {
73
+		return err
74
+	}
75
+
76
+	// Create an "id" file with the container/image id in it to help reconscruct this in case
77
+	// of later problems
78
+	if err := ioutil.WriteFile(path.Join(mp, "id"), []byte(id), 0600); err != nil {
79
+		return err
80
+	}
81
+
82
+	// We float this reference so that the next Get call can
83
+	// steal it, so we don't have to unmount
84
+	if err := d.DeviceSet.UnmountDevice(id, UnmountFloat); 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
+	// Sink the float from create in case no Get() call was made
100
+	if err := d.DeviceSet.UnmountDevice(id, UnmountSink); err != nil {
101
+		return err
102
+	}
103
+	// This assumes the device has been properly Get/Put:ed and thus is unmounted
104
+	if err := d.DeviceSet.DeleteDevice(id); err != nil {
105
+		return err
106
+	}
107
+
108
+	mp := path.Join(d.home, "mnt", id)
109
+	if err := os.RemoveAll(mp); err != nil && !os.IsNotExist(err) {
110
+		return err
111
+	}
112
+
113
+	return nil
114
+}
115
+
116
+func (d *Driver) Get(id string) (string, error) {
117
+	mp := path.Join(d.home, "mnt", id)
118
+	if err := d.mount(id, mp); err != nil {
119
+		return "", err
120
+	}
121
+
122
+	return path.Join(mp, "rootfs"), nil
123
+}
124
+
125
+func (d *Driver) Put(id string) {
126
+	if err := d.DeviceSet.UnmountDevice(id, UnmountRegular); err != nil {
127
+		utils.Errorf("Warning: error unmounting device %s: %s\n", id, err)
128
+	}
129
+}
130
+
131
+func (d *Driver) mount(id, mountPoint string) error {
132
+	// Create the target directories if they don't exist
133
+	if err := osMkdirAll(mountPoint, 0755); err != nil && !osIsExist(err) {
134
+		return err
135
+	}
136
+	// Mount the device
137
+	return d.DeviceSet.MountDevice(id, mountPoint)
138
+}
139
+
140
+func (d *Driver) Exists(id string) bool {
141
+	return d.Devices[id] != nil
142
+}
0 143
new file mode 100644
... ...
@@ -0,0 +1,886 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+import (
5
+	"fmt"
6
+	"github.com/dotcloud/docker/runtime/graphdriver"
7
+	"io/ioutil"
8
+	"path"
9
+	"runtime"
10
+	"strings"
11
+	"syscall"
12
+	"testing"
13
+)
14
+
15
+func init() {
16
+	// Reduce the size the the base fs and loopback for the tests
17
+	DefaultDataLoopbackSize = 300 * 1024 * 1024
18
+	DefaultMetaDataLoopbackSize = 200 * 1024 * 1024
19
+	DefaultBaseFsSize = 300 * 1024 * 1024
20
+}
21
+
22
+// denyAllDevmapper mocks all calls to libdevmapper in the unit tests, and denies them by default
23
+func denyAllDevmapper() {
24
+	// Hijack all calls to libdevmapper with default panics.
25
+	// Authorized calls are selectively hijacked in each tests.
26
+	DmTaskCreate = func(t int) *CDmTask {
27
+		panic("DmTaskCreate: this method should not be called here")
28
+	}
29
+	DmTaskRun = func(task *CDmTask) int {
30
+		panic("DmTaskRun: this method should not be called here")
31
+	}
32
+	DmTaskSetName = func(task *CDmTask, name string) int {
33
+		panic("DmTaskSetName: this method should not be called here")
34
+	}
35
+	DmTaskSetMessage = func(task *CDmTask, message string) int {
36
+		panic("DmTaskSetMessage: this method should not be called here")
37
+	}
38
+	DmTaskSetSector = func(task *CDmTask, sector uint64) int {
39
+		panic("DmTaskSetSector: this method should not be called here")
40
+	}
41
+	DmTaskSetCookie = func(task *CDmTask, cookie *uint, flags uint16) int {
42
+		panic("DmTaskSetCookie: this method should not be called here")
43
+	}
44
+	DmTaskSetAddNode = func(task *CDmTask, addNode AddNodeType) int {
45
+		panic("DmTaskSetAddNode: this method should not be called here")
46
+	}
47
+	DmTaskSetRo = func(task *CDmTask) int {
48
+		panic("DmTaskSetRo: this method should not be called here")
49
+	}
50
+	DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
51
+		panic("DmTaskAddTarget: this method should not be called here")
52
+	}
53
+	DmTaskGetInfo = func(task *CDmTask, info *Info) int {
54
+		panic("DmTaskGetInfo: this method should not be called here")
55
+	}
56
+	DmGetNextTarget = func(task *CDmTask, next uintptr, start, length *uint64, target, params *string) uintptr {
57
+		panic("DmGetNextTarget: this method should not be called here")
58
+	}
59
+	DmUdevWait = func(cookie uint) int {
60
+		panic("DmUdevWait: this method should not be called here")
61
+	}
62
+	DmSetDevDir = func(dir string) int {
63
+		panic("DmSetDevDir: this method should not be called here")
64
+	}
65
+	DmGetLibraryVersion = func(version *string) int {
66
+		panic("DmGetLibraryVersion: this method should not be called here")
67
+	}
68
+	DmLogInitVerbose = func(level int) {
69
+		panic("DmLogInitVerbose: this method should not be called here")
70
+	}
71
+	DmTaskDestroy = func(task *CDmTask) {
72
+		panic("DmTaskDestroy: this method should not be called here")
73
+	}
74
+	LogWithErrnoInit = func() {
75
+		panic("LogWithErrnoInit: this method should not be called here")
76
+	}
77
+}
78
+
79
+func denyAllSyscall() {
80
+	sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
81
+		panic("sysMount: this method should not be called here")
82
+	}
83
+	sysUnmount = func(target string, flags int) (err error) {
84
+		panic("sysUnmount: this method should not be called here")
85
+	}
86
+	sysCloseOnExec = func(fd int) {
87
+		panic("sysCloseOnExec: this method should not be called here")
88
+	}
89
+	sysSyscall = func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
90
+		panic("sysSyscall: this method should not be called here")
91
+	}
92
+	// Not a syscall, but forbidding it here anyway
93
+	Mounted = func(mnt string) (bool, error) {
94
+		panic("devmapper.Mounted: this method should not be called here")
95
+	}
96
+	// osOpenFile = os.OpenFile
97
+	// osNewFile = os.NewFile
98
+	// osCreate = os.Create
99
+	// osStat = os.Stat
100
+	// osIsNotExist = os.IsNotExist
101
+	// osIsExist = os.IsExist
102
+	// osMkdirAll = os.MkdirAll
103
+	// osRemoveAll = os.RemoveAll
104
+	// osRename = os.Rename
105
+	// osReadlink = os.Readlink
106
+
107
+	// execRun = func(name string, args ...string) error {
108
+	// 	return exec.Command(name, args...).Run()
109
+	// }
110
+}
111
+
112
+func mkTestDirectory(t *testing.T) string {
113
+	dir, err := ioutil.TempDir("", "docker-test-devmapper-")
114
+	if err != nil {
115
+		t.Fatal(err)
116
+	}
117
+	return dir
118
+}
119
+
120
+func newDriver(t *testing.T) *Driver {
121
+	home := mkTestDirectory(t)
122
+	d, err := Init(home)
123
+	if err != nil {
124
+		t.Fatal(err)
125
+	}
126
+	return d.(*Driver)
127
+}
128
+
129
+func cleanup(d *Driver) {
130
+	d.Cleanup()
131
+	osRemoveAll(d.home)
132
+}
133
+
134
+type Set map[string]bool
135
+
136
+func (r Set) Assert(t *testing.T, names ...string) {
137
+	for _, key := range names {
138
+		required := true
139
+		if strings.HasPrefix(key, "?") {
140
+			key = key[1:]
141
+			required = false
142
+		}
143
+		if _, exists := r[key]; !exists && required {
144
+			t.Fatalf("Key not set: %s", key)
145
+		}
146
+		delete(r, key)
147
+	}
148
+	if len(r) != 0 {
149
+		t.Fatalf("Unexpected keys: %v", r)
150
+	}
151
+}
152
+
153
+func TestInit(t *testing.T) {
154
+	var (
155
+		calls        = make(Set)
156
+		taskMessages = make(Set)
157
+		taskTypes    = make(Set)
158
+		home         = mkTestDirectory(t)
159
+	)
160
+	defer osRemoveAll(home)
161
+
162
+	func() {
163
+		denyAllDevmapper()
164
+		DmSetDevDir = func(dir string) int {
165
+			calls["DmSetDevDir"] = true
166
+			expectedDir := "/dev"
167
+			if dir != expectedDir {
168
+				t.Fatalf("Wrong libdevmapper call\nExpected: DmSetDevDir(%v)\nReceived: DmSetDevDir(%v)\n", expectedDir, dir)
169
+			}
170
+			return 0
171
+		}
172
+		LogWithErrnoInit = func() {
173
+			calls["DmLogWithErrnoInit"] = true
174
+		}
175
+		var task1 CDmTask
176
+		DmTaskCreate = func(taskType int) *CDmTask {
177
+			calls["DmTaskCreate"] = true
178
+			taskTypes[fmt.Sprintf("%d", taskType)] = true
179
+			return &task1
180
+		}
181
+		DmTaskSetName = func(task *CDmTask, name string) int {
182
+			calls["DmTaskSetName"] = true
183
+			expectedTask := &task1
184
+			if task != expectedTask {
185
+				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetName(%v)\nReceived: DmTaskSetName(%v)\n", expectedTask, task)
186
+			}
187
+			// FIXME: use Set.AssertRegexp()
188
+			if !strings.HasPrefix(name, "docker-") && !strings.HasPrefix(name, "/dev/mapper/docker-") ||
189
+				!strings.HasSuffix(name, "-pool") && !strings.HasSuffix(name, "-base") {
190
+				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetName(%v)\nReceived: DmTaskSetName(%v)\n", "docker-...-pool", name)
191
+			}
192
+			return 1
193
+		}
194
+		DmTaskRun = func(task *CDmTask) int {
195
+			calls["DmTaskRun"] = true
196
+			expectedTask := &task1
197
+			if task != expectedTask {
198
+				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskRun(%v)\nReceived: DmTaskRun(%v)\n", expectedTask, task)
199
+			}
200
+			return 1
201
+		}
202
+		DmTaskGetInfo = func(task *CDmTask, info *Info) int {
203
+			calls["DmTaskGetInfo"] = true
204
+			expectedTask := &task1
205
+			if task != expectedTask {
206
+				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskGetInfo(%v)\nReceived: DmTaskGetInfo(%v)\n", expectedTask, task)
207
+			}
208
+			// This will crash if info is not dereferenceable
209
+			info.Exists = 0
210
+			return 1
211
+		}
212
+		DmTaskSetSector = func(task *CDmTask, sector uint64) int {
213
+			calls["DmTaskSetSector"] = true
214
+			expectedTask := &task1
215
+			if task != expectedTask {
216
+				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetSector(%v)\nReceived: DmTaskSetSector(%v)\n", expectedTask, task)
217
+			}
218
+			if expectedSector := uint64(0); sector != expectedSector {
219
+				t.Fatalf("Wrong libdevmapper call to DmTaskSetSector\nExpected: %v\nReceived: %v\n", expectedSector, sector)
220
+			}
221
+			return 1
222
+		}
223
+		DmTaskSetMessage = func(task *CDmTask, message string) int {
224
+			calls["DmTaskSetMessage"] = true
225
+			expectedTask := &task1
226
+			if task != expectedTask {
227
+				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskSetSector(%v)\nReceived: DmTaskSetSector(%v)\n", expectedTask, task)
228
+			}
229
+			taskMessages[message] = true
230
+			return 1
231
+		}
232
+		DmTaskDestroy = func(task *CDmTask) {
233
+			calls["DmTaskDestroy"] = true
234
+			expectedTask := &task1
235
+			if task != expectedTask {
236
+				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
237
+			}
238
+		}
239
+		DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
240
+			calls["DmTaskSetTarget"] = true
241
+			expectedTask := &task1
242
+			if task != expectedTask {
243
+				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
244
+			}
245
+			if start != 0 {
246
+				t.Fatalf("Wrong start: %d != %d", start, 0)
247
+			}
248
+			if ttype != "thin" && ttype != "thin-pool" {
249
+				t.Fatalf("Wrong ttype: %s", ttype)
250
+			}
251
+			// Quick smoke test
252
+			if params == "" {
253
+				t.Fatalf("Params should not be empty")
254
+			}
255
+			return 1
256
+		}
257
+		fakeCookie := uint(4321)
258
+		DmTaskSetCookie = func(task *CDmTask, cookie *uint, flags uint16) int {
259
+			calls["DmTaskSetCookie"] = true
260
+			expectedTask := &task1
261
+			if task != expectedTask {
262
+				t.Fatalf("Wrong libdevmapper call\nExpected: DmTaskDestroy(%v)\nReceived: DmTaskDestroy(%v)\n", expectedTask, task)
263
+			}
264
+			if flags != 0 {
265
+				t.Fatalf("Cookie flags should be 0 (not %x)", flags)
266
+			}
267
+			*cookie = fakeCookie
268
+			return 1
269
+		}
270
+		DmUdevWait = func(cookie uint) int {
271
+			calls["DmUdevWait"] = true
272
+			if cookie != fakeCookie {
273
+				t.Fatalf("Wrong cookie: %d != %d", cookie, fakeCookie)
274
+			}
275
+			return 1
276
+		}
277
+		DmTaskSetAddNode = func(task *CDmTask, addNode AddNodeType) int {
278
+			if addNode != AddNodeOnCreate {
279
+				t.Fatalf("Wrong AddNoteType: %v (expected %v)", addNode, AddNodeOnCreate)
280
+			}
281
+			calls["DmTaskSetAddNode"] = true
282
+			return 1
283
+		}
284
+		execRun = func(name string, args ...string) error {
285
+			calls["execRun"] = true
286
+			if name != "mkfs.ext4" {
287
+				t.Fatalf("Expected %s to be executed, not %s", "mkfs.ext4", name)
288
+			}
289
+			return nil
290
+		}
291
+		driver, err := Init(home)
292
+		if err != nil {
293
+			t.Fatal(err)
294
+		}
295
+		defer func() {
296
+			if err := driver.Cleanup(); err != nil {
297
+				t.Fatal(err)
298
+			}
299
+		}()
300
+	}()
301
+	// Put all tests in a function to make sure the garbage collection will
302
+	// occur.
303
+
304
+	// Call GC to cleanup runtime.Finalizers
305
+	runtime.GC()
306
+
307
+	calls.Assert(t,
308
+		"DmSetDevDir",
309
+		"DmLogWithErrnoInit",
310
+		"DmTaskSetName",
311
+		"DmTaskRun",
312
+		"DmTaskGetInfo",
313
+		"DmTaskDestroy",
314
+		"execRun",
315
+		"DmTaskCreate",
316
+		"DmTaskSetTarget",
317
+		"DmTaskSetCookie",
318
+		"DmUdevWait",
319
+		"DmTaskSetSector",
320
+		"DmTaskSetMessage",
321
+		"DmTaskSetAddNode",
322
+	)
323
+	taskTypes.Assert(t, "0", "6", "17")
324
+	taskMessages.Assert(t, "create_thin 0", "set_transaction_id 0 1")
325
+}
326
+
327
+func fakeInit() func(home string) (graphdriver.Driver, error) {
328
+	oldInit := Init
329
+	Init = func(home string) (graphdriver.Driver, error) {
330
+		return &Driver{
331
+			home: home,
332
+		}, nil
333
+	}
334
+	return oldInit
335
+}
336
+
337
+func restoreInit(init func(home string) (graphdriver.Driver, error)) {
338
+	Init = init
339
+}
340
+
341
+func mockAllDevmapper(calls Set) {
342
+	DmSetDevDir = func(dir string) int {
343
+		calls["DmSetDevDir"] = true
344
+		return 0
345
+	}
346
+	LogWithErrnoInit = func() {
347
+		calls["DmLogWithErrnoInit"] = true
348
+	}
349
+	DmTaskCreate = func(taskType int) *CDmTask {
350
+		calls["DmTaskCreate"] = true
351
+		return &CDmTask{}
352
+	}
353
+	DmTaskSetName = func(task *CDmTask, name string) int {
354
+		calls["DmTaskSetName"] = true
355
+		return 1
356
+	}
357
+	DmTaskRun = func(task *CDmTask) int {
358
+		calls["DmTaskRun"] = true
359
+		return 1
360
+	}
361
+	DmTaskGetInfo = func(task *CDmTask, info *Info) int {
362
+		calls["DmTaskGetInfo"] = true
363
+		return 1
364
+	}
365
+	DmTaskSetSector = func(task *CDmTask, sector uint64) int {
366
+		calls["DmTaskSetSector"] = true
367
+		return 1
368
+	}
369
+	DmTaskSetMessage = func(task *CDmTask, message string) int {
370
+		calls["DmTaskSetMessage"] = true
371
+		return 1
372
+	}
373
+	DmTaskDestroy = func(task *CDmTask) {
374
+		calls["DmTaskDestroy"] = true
375
+	}
376
+	DmTaskAddTarget = func(task *CDmTask, start, size uint64, ttype, params string) int {
377
+		calls["DmTaskSetTarget"] = true
378
+		return 1
379
+	}
380
+	DmTaskSetCookie = func(task *CDmTask, cookie *uint, flags uint16) int {
381
+		calls["DmTaskSetCookie"] = true
382
+		return 1
383
+	}
384
+	DmUdevWait = func(cookie uint) int {
385
+		calls["DmUdevWait"] = true
386
+		return 1
387
+	}
388
+	DmTaskSetAddNode = func(task *CDmTask, addNode AddNodeType) int {
389
+		calls["DmTaskSetAddNode"] = true
390
+		return 1
391
+	}
392
+	execRun = func(name string, args ...string) error {
393
+		calls["execRun"] = true
394
+		return nil
395
+	}
396
+}
397
+
398
+func TestDriverName(t *testing.T) {
399
+	denyAllDevmapper()
400
+	defer denyAllDevmapper()
401
+
402
+	oldInit := fakeInit()
403
+	defer restoreInit(oldInit)
404
+
405
+	d := newDriver(t)
406
+	if d.String() != "devicemapper" {
407
+		t.Fatalf("Expected driver name to be devicemapper got %s", d.String())
408
+	}
409
+}
410
+
411
+func TestDriverCreate(t *testing.T) {
412
+	denyAllDevmapper()
413
+	denyAllSyscall()
414
+	defer denyAllSyscall()
415
+	defer denyAllDevmapper()
416
+
417
+	calls := make(Set)
418
+	mockAllDevmapper(calls)
419
+
420
+	sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
421
+		calls["sysMount"] = true
422
+		// FIXME: compare the exact source and target strings (inodes + devname)
423
+		if expectedSource := "/dev/mapper/docker-"; !strings.HasPrefix(source, expectedSource) {
424
+			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedSource, source)
425
+		}
426
+		if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
427
+			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
428
+		}
429
+		if expectedFstype := "ext4"; fstype != expectedFstype {
430
+			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFstype, fstype)
431
+		}
432
+		if expectedFlags := uintptr(3236757504); flags != expectedFlags {
433
+			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
434
+		}
435
+		return nil
436
+	}
437
+
438
+	Mounted = func(mnt string) (bool, error) {
439
+		calls["Mounted"] = true
440
+		if !strings.HasPrefix(mnt, "/tmp/docker-test-devmapper-") || !strings.HasSuffix(mnt, "/mnt/1") {
441
+			t.Fatalf("Wrong mounted call\nExpected: Mounted(%v)\nReceived: Mounted(%v)\n", "/tmp/docker-test-devmapper-.../mnt/1", mnt)
442
+		}
443
+		return false, nil
444
+	}
445
+
446
+	sysSyscall = func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
447
+		calls["sysSyscall"] = true
448
+		if trap != sysSysIoctl {
449
+			t.Fatalf("Unexpected syscall. Expecting SYS_IOCTL, received: %d", trap)
450
+		}
451
+		switch a2 {
452
+		case LoopSetFd:
453
+			calls["ioctl.loopsetfd"] = true
454
+		case LoopCtlGetFree:
455
+			calls["ioctl.loopctlgetfree"] = true
456
+		case LoopGetStatus64:
457
+			calls["ioctl.loopgetstatus"] = true
458
+		case LoopSetStatus64:
459
+			calls["ioctl.loopsetstatus"] = true
460
+		case LoopClrFd:
461
+			calls["ioctl.loopclrfd"] = true
462
+		case LoopSetCapacity:
463
+			calls["ioctl.loopsetcapacity"] = true
464
+		case BlkGetSize64:
465
+			calls["ioctl.blkgetsize"] = true
466
+		default:
467
+			t.Fatalf("Unexpected IOCTL. Received %d", a2)
468
+		}
469
+		return 0, 0, 0
470
+	}
471
+
472
+	func() {
473
+		d := newDriver(t)
474
+
475
+		calls.Assert(t,
476
+			"DmSetDevDir",
477
+			"DmLogWithErrnoInit",
478
+			"DmTaskSetName",
479
+			"DmTaskRun",
480
+			"DmTaskGetInfo",
481
+			"execRun",
482
+			"DmTaskCreate",
483
+			"DmTaskSetTarget",
484
+			"DmTaskSetCookie",
485
+			"DmUdevWait",
486
+			"DmTaskSetSector",
487
+			"DmTaskSetMessage",
488
+			"DmTaskSetAddNode",
489
+			"sysSyscall",
490
+			"ioctl.blkgetsize",
491
+			"ioctl.loopsetfd",
492
+			"ioctl.loopsetstatus",
493
+			"?ioctl.loopctlgetfree",
494
+		)
495
+
496
+		if err := d.Create("1", ""); err != nil {
497
+			t.Fatal(err)
498
+		}
499
+		calls.Assert(t,
500
+			"DmTaskCreate",
501
+			"DmTaskGetInfo",
502
+			"sysMount",
503
+			"DmTaskRun",
504
+			"DmTaskSetTarget",
505
+			"DmTaskSetSector",
506
+			"DmTaskSetCookie",
507
+			"DmUdevWait",
508
+			"DmTaskSetName",
509
+			"DmTaskSetMessage",
510
+			"DmTaskSetAddNode",
511
+		)
512
+
513
+	}()
514
+
515
+	runtime.GC()
516
+
517
+	calls.Assert(t,
518
+		"DmTaskDestroy",
519
+	)
520
+}
521
+
522
+func TestDriverRemove(t *testing.T) {
523
+	denyAllDevmapper()
524
+	denyAllSyscall()
525
+	defer denyAllSyscall()
526
+	defer denyAllDevmapper()
527
+
528
+	calls := make(Set)
529
+	mockAllDevmapper(calls)
530
+
531
+	sysMount = func(source, target, fstype string, flags uintptr, data string) (err error) {
532
+		calls["sysMount"] = true
533
+		// FIXME: compare the exact source and target strings (inodes + devname)
534
+		if expectedSource := "/dev/mapper/docker-"; !strings.HasPrefix(source, expectedSource) {
535
+			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedSource, source)
536
+		}
537
+		if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
538
+			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
539
+		}
540
+		if expectedFstype := "ext4"; fstype != expectedFstype {
541
+			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFstype, fstype)
542
+		}
543
+		if expectedFlags := uintptr(3236757504); flags != expectedFlags {
544
+			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
545
+		}
546
+		return nil
547
+	}
548
+	sysUnmount = func(target string, flags int) (err error) {
549
+		calls["sysUnmount"] = true
550
+		// FIXME: compare the exact source and target strings (inodes + devname)
551
+		if expectedTarget := "/tmp/docker-test-devmapper-"; !strings.HasPrefix(target, expectedTarget) {
552
+			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedTarget, target)
553
+		}
554
+		if expectedFlags := 0; flags != expectedFlags {
555
+			t.Fatalf("Wrong syscall call\nExpected: Mount(%v)\nReceived: Mount(%v)\n", expectedFlags, flags)
556
+		}
557
+		return nil
558
+	}
559
+	Mounted = func(mnt string) (bool, error) {
560
+		calls["Mounted"] = true
561
+		return false, nil
562
+	}
563
+
564
+	sysSyscall = func(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.Errno) {
565
+		calls["sysSyscall"] = true
566
+		if trap != sysSysIoctl {
567
+			t.Fatalf("Unexpected syscall. Expecting SYS_IOCTL, received: %d", trap)
568
+		}
569
+		switch a2 {
570
+		case LoopSetFd:
571
+			calls["ioctl.loopsetfd"] = true
572
+		case LoopCtlGetFree:
573
+			calls["ioctl.loopctlgetfree"] = true
574
+		case LoopGetStatus64:
575
+			calls["ioctl.loopgetstatus"] = true
576
+		case LoopSetStatus64:
577
+			calls["ioctl.loopsetstatus"] = true
578
+		case LoopClrFd:
579
+			calls["ioctl.loopclrfd"] = true
580
+		case LoopSetCapacity:
581
+			calls["ioctl.loopsetcapacity"] = true
582
+		case BlkGetSize64:
583
+			calls["ioctl.blkgetsize"] = true
584
+		default:
585
+			t.Fatalf("Unexpected IOCTL. Received %d", a2)
586
+		}
587
+		return 0, 0, 0
588
+	}
589
+
590
+	func() {
591
+		d := newDriver(t)
592
+
593
+		calls.Assert(t,
594
+			"DmSetDevDir",
595
+			"DmLogWithErrnoInit",
596
+			"DmTaskSetName",
597
+			"DmTaskRun",
598
+			"DmTaskGetInfo",
599
+			"execRun",
600
+			"DmTaskCreate",
601
+			"DmTaskSetTarget",
602
+			"DmTaskSetCookie",
603
+			"DmUdevWait",
604
+			"DmTaskSetSector",
605
+			"DmTaskSetMessage",
606
+			"DmTaskSetAddNode",
607
+			"sysSyscall",
608
+			"ioctl.blkgetsize",
609
+			"ioctl.loopsetfd",
610
+			"ioctl.loopsetstatus",
611
+			"?ioctl.loopctlgetfree",
612
+		)
613
+
614
+		if err := d.Create("1", ""); err != nil {
615
+			t.Fatal(err)
616
+		}
617
+
618
+		calls.Assert(t,
619
+			"DmTaskCreate",
620
+			"DmTaskGetInfo",
621
+			"sysMount",
622
+			"DmTaskRun",
623
+			"DmTaskSetTarget",
624
+			"DmTaskSetSector",
625
+			"DmTaskSetCookie",
626
+			"DmUdevWait",
627
+			"DmTaskSetName",
628
+			"DmTaskSetMessage",
629
+			"DmTaskSetAddNode",
630
+		)
631
+
632
+		Mounted = func(mnt string) (bool, error) {
633
+			calls["Mounted"] = true
634
+			return true, nil
635
+		}
636
+
637
+		if err := d.Remove("1"); err != nil {
638
+			t.Fatal(err)
639
+		}
640
+
641
+		calls.Assert(t,
642
+			"DmTaskRun",
643
+			"DmTaskSetSector",
644
+			"DmTaskSetName",
645
+			"DmTaskSetMessage",
646
+			"DmTaskCreate",
647
+			"DmTaskGetInfo",
648
+			"DmTaskSetCookie",
649
+			"DmTaskSetTarget",
650
+			"DmTaskSetAddNode",
651
+			"DmUdevWait",
652
+			"sysUnmount",
653
+		)
654
+	}()
655
+	runtime.GC()
656
+
657
+	calls.Assert(t,
658
+		"DmTaskDestroy",
659
+	)
660
+}
661
+
662
+func TestCleanup(t *testing.T) {
663
+	t.Skip("FIXME: not a unit test")
664
+	t.Skip("Unimplemented")
665
+	d := newDriver(t)
666
+	defer osRemoveAll(d.home)
667
+
668
+	mountPoints := make([]string, 2)
669
+
670
+	if err := d.Create("1", ""); err != nil {
671
+		t.Fatal(err)
672
+	}
673
+	// Mount the id
674
+	p, err := d.Get("1")
675
+	if err != nil {
676
+		t.Fatal(err)
677
+	}
678
+	mountPoints[0] = p
679
+
680
+	if err := d.Create("2", "1"); err != nil {
681
+		t.Fatal(err)
682
+	}
683
+
684
+	p, err = d.Get("2")
685
+	if err != nil {
686
+		t.Fatal(err)
687
+	}
688
+	mountPoints[1] = p
689
+
690
+	// Ensure that all the mount points are currently mounted
691
+	for _, p := range mountPoints {
692
+		if mounted, err := Mounted(p); err != nil {
693
+			t.Fatal(err)
694
+		} else if !mounted {
695
+			t.Fatalf("Expected %s to be mounted", p)
696
+		}
697
+	}
698
+
699
+	// Ensure that devices are active
700
+	for _, p := range []string{"1", "2"} {
701
+		if !d.HasActivatedDevice(p) {
702
+			t.Fatalf("Expected %s to have an active device", p)
703
+		}
704
+	}
705
+
706
+	if err := d.Cleanup(); err != nil {
707
+		t.Fatal(err)
708
+	}
709
+
710
+	// Ensure that all the mount points are no longer mounted
711
+	for _, p := range mountPoints {
712
+		if mounted, err := Mounted(p); err != nil {
713
+			t.Fatal(err)
714
+		} else if mounted {
715
+			t.Fatalf("Expected %s to not be mounted", p)
716
+		}
717
+	}
718
+
719
+	// Ensure that devices are no longer activated
720
+	for _, p := range []string{"1", "2"} {
721
+		if d.HasActivatedDevice(p) {
722
+			t.Fatalf("Expected %s not be an active device", p)
723
+		}
724
+	}
725
+}
726
+
727
+func TestNotMounted(t *testing.T) {
728
+	t.Skip("FIXME: not a unit test")
729
+	t.Skip("Not implemented")
730
+	d := newDriver(t)
731
+	defer cleanup(d)
732
+
733
+	if err := d.Create("1", ""); err != nil {
734
+		t.Fatal(err)
735
+	}
736
+
737
+	mounted, err := Mounted(path.Join(d.home, "mnt", "1"))
738
+	if err != nil {
739
+		t.Fatal(err)
740
+	}
741
+	if mounted {
742
+		t.Fatal("Id 1 should not be mounted")
743
+	}
744
+}
745
+
746
+func TestMounted(t *testing.T) {
747
+	t.Skip("FIXME: not a unit test")
748
+	d := newDriver(t)
749
+	defer cleanup(d)
750
+
751
+	if err := d.Create("1", ""); err != nil {
752
+		t.Fatal(err)
753
+	}
754
+	if _, err := d.Get("1"); err != nil {
755
+		t.Fatal(err)
756
+	}
757
+
758
+	mounted, err := Mounted(path.Join(d.home, "mnt", "1"))
759
+	if err != nil {
760
+		t.Fatal(err)
761
+	}
762
+	if !mounted {
763
+		t.Fatal("Id 1 should be mounted")
764
+	}
765
+}
766
+
767
+func TestInitCleanedDriver(t *testing.T) {
768
+	t.Skip("FIXME: not a unit test")
769
+	d := newDriver(t)
770
+
771
+	if err := d.Create("1", ""); err != nil {
772
+		t.Fatal(err)
773
+	}
774
+	if _, err := d.Get("1"); err != nil {
775
+		t.Fatal(err)
776
+	}
777
+
778
+	if err := d.Cleanup(); err != nil {
779
+		t.Fatal(err)
780
+	}
781
+
782
+	driver, err := Init(d.home)
783
+	if err != nil {
784
+		t.Fatal(err)
785
+	}
786
+	d = driver.(*Driver)
787
+	defer cleanup(d)
788
+
789
+	if _, err := d.Get("1"); err != nil {
790
+		t.Fatal(err)
791
+	}
792
+}
793
+
794
+func TestMountMountedDriver(t *testing.T) {
795
+	t.Skip("FIXME: not a unit test")
796
+	d := newDriver(t)
797
+	defer cleanup(d)
798
+
799
+	if err := d.Create("1", ""); err != nil {
800
+		t.Fatal(err)
801
+	}
802
+
803
+	// Perform get on same id to ensure that it will
804
+	// not be mounted twice
805
+	if _, err := d.Get("1"); err != nil {
806
+		t.Fatal(err)
807
+	}
808
+	if _, err := d.Get("1"); err != nil {
809
+		t.Fatal(err)
810
+	}
811
+}
812
+
813
+func TestGetReturnsValidDevice(t *testing.T) {
814
+	t.Skip("FIXME: not a unit test")
815
+	d := newDriver(t)
816
+	defer cleanup(d)
817
+
818
+	if err := d.Create("1", ""); err != nil {
819
+		t.Fatal(err)
820
+	}
821
+
822
+	if !d.HasDevice("1") {
823
+		t.Fatalf("Expected id 1 to be in device set")
824
+	}
825
+
826
+	if _, err := d.Get("1"); err != nil {
827
+		t.Fatal(err)
828
+	}
829
+
830
+	if !d.HasActivatedDevice("1") {
831
+		t.Fatalf("Expected id 1 to be activated")
832
+	}
833
+
834
+	if !d.HasInitializedDevice("1") {
835
+		t.Fatalf("Expected id 1 to be initialized")
836
+	}
837
+}
838
+
839
+func TestDriverGetSize(t *testing.T) {
840
+	t.Skip("FIXME: not a unit test")
841
+	t.Skipf("Size is currently not implemented")
842
+
843
+	d := newDriver(t)
844
+	defer cleanup(d)
845
+
846
+	if err := d.Create("1", ""); err != nil {
847
+		t.Fatal(err)
848
+	}
849
+
850
+	mountPoint, err := d.Get("1")
851
+	if err != nil {
852
+		t.Fatal(err)
853
+	}
854
+
855
+	size := int64(1024)
856
+
857
+	f, err := osCreate(path.Join(mountPoint, "test_file"))
858
+	if err != nil {
859
+		t.Fatal(err)
860
+	}
861
+	if err := f.Truncate(size); err != nil {
862
+		t.Fatal(err)
863
+	}
864
+	f.Close()
865
+
866
+	// diffSize, err := d.DiffSize("1")
867
+	// if err != nil {
868
+	// 	t.Fatal(err)
869
+	// }
870
+	// if diffSize != size {
871
+	// 	t.Fatalf("Expected size %d got %d", size, diffSize)
872
+	// }
873
+}
874
+
875
+func assertMap(t *testing.T, m map[string]bool, keys ...string) {
876
+	for _, key := range keys {
877
+		if _, exists := m[key]; !exists {
878
+			t.Fatalf("Key not set: %s", key)
879
+		}
880
+		delete(m, key)
881
+	}
882
+	if len(m) != 0 {
883
+		t.Fatalf("Unexpected keys: %v", m)
884
+	}
885
+}
0 886
new file mode 100644
... ...
@@ -0,0 +1,71 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+import (
5
+	"unsafe"
6
+)
7
+
8
+func ioctlLoopCtlGetFree(fd uintptr) (int, error) {
9
+	index, _, err := sysSyscall(sysSysIoctl, fd, LoopCtlGetFree, 0)
10
+	if err != 0 {
11
+		return 0, err
12
+	}
13
+	return int(index), nil
14
+}
15
+
16
+func ioctlLoopSetFd(loopFd, sparseFd uintptr) error {
17
+	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetFd, sparseFd); err != 0 {
18
+		return err
19
+	}
20
+	return nil
21
+}
22
+
23
+func ioctlLoopSetStatus64(loopFd uintptr, loopInfo *LoopInfo64) error {
24
+	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
25
+		return err
26
+	}
27
+	return nil
28
+}
29
+
30
+func ioctlLoopClrFd(loopFd uintptr) error {
31
+	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopClrFd, 0); err != 0 {
32
+		return err
33
+	}
34
+	return nil
35
+}
36
+
37
+func ioctlLoopGetStatus64(loopFd uintptr) (*LoopInfo64, error) {
38
+	loopInfo := &LoopInfo64{}
39
+
40
+	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopGetStatus64, uintptr(unsafe.Pointer(loopInfo))); err != 0 {
41
+		return nil, err
42
+	}
43
+	return loopInfo, nil
44
+}
45
+
46
+func ioctlLoopSetCapacity(loopFd uintptr, value int) error {
47
+	if _, _, err := sysSyscall(sysSysIoctl, loopFd, LoopSetCapacity, uintptr(value)); err != 0 {
48
+		return err
49
+	}
50
+	return nil
51
+}
52
+
53
+func ioctlBlkGetSize64(fd uintptr) (int64, error) {
54
+	var size int64
55
+	if _, _, err := sysSyscall(sysSysIoctl, fd, BlkGetSize64, uintptr(unsafe.Pointer(&size))); err != 0 {
56
+		return 0, err
57
+	}
58
+	return size, nil
59
+}
60
+
61
+func ioctlBlkDiscard(fd uintptr, offset, length uint64) error {
62
+	var r [2]uint64
63
+	r[0] = offset
64
+	r[1] = length
65
+
66
+	if _, _, err := sysSyscall(sysSysIoctl, fd, BlkDiscard, uintptr(unsafe.Pointer(&r[0]))); err != 0 {
67
+		return err
68
+	}
69
+	return nil
70
+}
0 71
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+import (
5
+	"path/filepath"
6
+)
7
+
8
+// FIXME: this is copy-pasted from the aufs driver.
9
+// It should be moved into the core.
10
+
11
+var Mounted = func(mountpoint string) (bool, error) {
12
+	mntpoint, err := osStat(mountpoint)
13
+	if err != nil {
14
+		if osIsNotExist(err) {
15
+			return false, nil
16
+		}
17
+		return false, err
18
+	}
19
+	parent, err := osStat(filepath.Join(mountpoint, ".."))
20
+	if err != nil {
21
+		return false, err
22
+	}
23
+	mntpointSt := toSysStatT(mntpoint.Sys())
24
+	parentSt := toSysStatT(parent.Sys())
25
+	return mntpointSt.Dev != parentSt.Dev, nil
26
+}
0 27
new file mode 100644
... ...
@@ -0,0 +1,57 @@
0
+// +build linux,amd64
1
+
2
+package devmapper
3
+
4
+import (
5
+	"os"
6
+	"os/exec"
7
+	"syscall"
8
+)
9
+
10
+type (
11
+	sysStatT syscall.Stat_t
12
+	sysErrno syscall.Errno
13
+
14
+	osFile struct{ *os.File }
15
+)
16
+
17
+var (
18
+	sysMount       = syscall.Mount
19
+	sysUnmount     = syscall.Unmount
20
+	sysCloseOnExec = syscall.CloseOnExec
21
+	sysSyscall     = syscall.Syscall
22
+
23
+	osOpenFile = func(name string, flag int, perm os.FileMode) (*osFile, error) {
24
+		f, err := os.OpenFile(name, flag, perm)
25
+		return &osFile{File: f}, err
26
+	}
27
+	osOpen       = func(name string) (*osFile, error) { f, err := os.Open(name); return &osFile{File: f}, err }
28
+	osNewFile    = os.NewFile
29
+	osCreate     = os.Create
30
+	osStat       = os.Stat
31
+	osIsNotExist = os.IsNotExist
32
+	osIsExist    = os.IsExist
33
+	osMkdirAll   = os.MkdirAll
34
+	osRemoveAll  = os.RemoveAll
35
+	osRename     = os.Rename
36
+	osReadlink   = os.Readlink
37
+
38
+	execRun = func(name string, args ...string) error { return exec.Command(name, args...).Run() }
39
+)
40
+
41
+const (
42
+	sysMsMgcVal = syscall.MS_MGC_VAL
43
+	sysMsRdOnly = syscall.MS_RDONLY
44
+	sysEInval   = syscall.EINVAL
45
+	sysSysIoctl = syscall.SYS_IOCTL
46
+	sysEBusy    = syscall.EBUSY
47
+
48
+	osORdOnly    = os.O_RDONLY
49
+	osORdWr      = os.O_RDWR
50
+	osOCreate    = os.O_CREATE
51
+	osModeDevice = os.ModeDevice
52
+)
53
+
54
+func toSysStatT(i interface{}) *sysStatT {
55
+	return (*sysStatT)(i.(*syscall.Stat_t))
56
+}
0 57
new file mode 100644
... ...
@@ -0,0 +1,93 @@
0
+package graphdriver
1
+
2
+import (
3
+	"fmt"
4
+	"github.com/dotcloud/docker/archive"
5
+	"github.com/dotcloud/docker/utils"
6
+	"os"
7
+	"path"
8
+)
9
+
10
+type InitFunc func(root string) (Driver, error)
11
+
12
+type Driver interface {
13
+	String() string
14
+
15
+	Create(id, parent string) error
16
+	Remove(id string) error
17
+
18
+	Get(id string) (dir string, err error)
19
+	Put(id string)
20
+	Exists(id string) bool
21
+
22
+	Status() [][2]string
23
+
24
+	Cleanup() error
25
+}
26
+
27
+type Differ interface {
28
+	Diff(id string) (archive.Archive, error)
29
+	Changes(id string) ([]archive.Change, error)
30
+	ApplyDiff(id string, diff archive.ArchiveReader) error
31
+	DiffSize(id string) (bytes int64, err error)
32
+}
33
+
34
+var (
35
+	DefaultDriver string
36
+	// All registred drivers
37
+	drivers map[string]InitFunc
38
+	// Slice of drivers that should be used in an order
39
+	priority = []string{
40
+		"aufs",
41
+		"devicemapper",
42
+		"vfs",
43
+		// experimental, has to be enabled manually for now
44
+		"btrfs",
45
+	}
46
+)
47
+
48
+func init() {
49
+	drivers = make(map[string]InitFunc)
50
+}
51
+
52
+func Register(name string, initFunc InitFunc) error {
53
+	if _, exists := drivers[name]; exists {
54
+		return fmt.Errorf("Name already registered %s", name)
55
+	}
56
+	drivers[name] = initFunc
57
+
58
+	return nil
59
+}
60
+
61
+func GetDriver(name, home string) (Driver, error) {
62
+	if initFunc, exists := drivers[name]; exists {
63
+		return initFunc(path.Join(home, name))
64
+	}
65
+	return nil, fmt.Errorf("No such driver: %s", name)
66
+}
67
+
68
+func New(root string) (driver Driver, err error) {
69
+	for _, name := range []string{os.Getenv("DOCKER_DRIVER"), DefaultDriver} {
70
+		if name != "" {
71
+			return GetDriver(name, root)
72
+		}
73
+	}
74
+
75
+	// Check for priority drivers first
76
+	for _, name := range priority {
77
+		if driver, err = GetDriver(name, root); err != nil {
78
+			utils.Debugf("Error loading driver %s: %s", name, err)
79
+			continue
80
+		}
81
+		return driver, nil
82
+	}
83
+
84
+	// Check all registered drivers if no priority driver is found
85
+	for _, initFunc := range drivers {
86
+		if driver, err = initFunc(root); err != nil {
87
+			continue
88
+		}
89
+		return driver, nil
90
+	}
91
+	return nil, err
92
+}
0 93
new file mode 100644
... ...
@@ -0,0 +1,95 @@
0
+package vfs
1
+
2
+import (
3
+	"fmt"
4
+	"github.com/dotcloud/docker/runtime/graphdriver"
5
+	"os"
6
+	"os/exec"
7
+	"path"
8
+)
9
+
10
+func init() {
11
+	graphdriver.Register("vfs", Init)
12
+}
13
+
14
+func Init(home string) (graphdriver.Driver, error) {
15
+	d := &Driver{
16
+		home: home,
17
+	}
18
+	return d, nil
19
+}
20
+
21
+type Driver struct {
22
+	home string
23
+}
24
+
25
+func (d *Driver) String() string {
26
+	return "vfs"
27
+}
28
+
29
+func (d *Driver) Status() [][2]string {
30
+	return nil
31
+}
32
+
33
+func (d *Driver) Cleanup() error {
34
+	return nil
35
+}
36
+
37
+func copyDir(src, dst string) error {
38
+	if output, err := exec.Command("cp", "-aT", "--reflink=auto", src, dst).CombinedOutput(); err != nil {
39
+		return fmt.Errorf("Error VFS copying directory: %s (%s)", err, output)
40
+	}
41
+	return nil
42
+}
43
+
44
+func (d *Driver) Create(id string, parent string) error {
45
+	dir := d.dir(id)
46
+	if err := os.MkdirAll(path.Dir(dir), 0700); err != nil {
47
+		return err
48
+	}
49
+	if err := os.Mkdir(dir, 0700); err != nil {
50
+		return err
51
+	}
52
+	if parent == "" {
53
+		return nil
54
+	}
55
+	parentDir, err := d.Get(parent)
56
+	if err != nil {
57
+		return fmt.Errorf("%s: %s", parent, err)
58
+	}
59
+	if err := copyDir(parentDir, dir); err != nil {
60
+		return err
61
+	}
62
+	return nil
63
+}
64
+
65
+func (d *Driver) dir(id string) string {
66
+	return path.Join(d.home, "dir", path.Base(id))
67
+}
68
+
69
+func (d *Driver) Remove(id string) error {
70
+	if _, err := os.Stat(d.dir(id)); err != nil {
71
+		return err
72
+	}
73
+	return os.RemoveAll(d.dir(id))
74
+}
75
+
76
+func (d *Driver) Get(id string) (string, error) {
77
+	dir := d.dir(id)
78
+	if st, err := os.Stat(dir); err != nil {
79
+		return "", err
80
+	} else if !st.IsDir() {
81
+		return "", fmt.Errorf("%s: not a directory", dir)
82
+	}
83
+	return dir, nil
84
+}
85
+
86
+func (d *Driver) Put(id string) {
87
+	// The vfs driver has no runtime resources (e.g. mounts)
88
+	// to clean up, so we don't need anything here
89
+}
90
+
91
+func (d *Driver) Exists(id string) bool {
92
+	_, err := os.Stat(d.dir(id))
93
+	return err == nil
94
+}
... ...
@@ -11,11 +11,11 @@ import (
11 11
 	"github.com/dotcloud/docker/runtime/execdriver/execdrivers"
12 12
 	"github.com/dotcloud/docker/runtime/execdriver/lxc"
13 13
 	"github.com/dotcloud/docker/graph"
14
-	"github.com/dotcloud/docker/graphdriver"
15
-	"github.com/dotcloud/docker/graphdriver/aufs"
16
-	_ "github.com/dotcloud/docker/graphdriver/btrfs"
17
-	_ "github.com/dotcloud/docker/graphdriver/devmapper"
18
-	_ "github.com/dotcloud/docker/graphdriver/vfs"
14
+	"github.com/dotcloud/docker/runtime/graphdriver"
15
+	"github.com/dotcloud/docker/runtime/graphdriver/aufs"
16
+	_ "github.com/dotcloud/docker/runtime/graphdriver/btrfs"
17
+	_ "github.com/dotcloud/docker/runtime/graphdriver/devmapper"
18
+	_ "github.com/dotcloud/docker/runtime/graphdriver/vfs"
19 19
 	"github.com/dotcloud/docker/image"
20 20
 	_ "github.com/dotcloud/docker/runtime/networkdriver/lxc"
21 21
 	"github.com/dotcloud/docker/runtime/networkdriver/portallocator"