Browse code

Move all drivers to the same subdir graphdriver

Guillaume J. Charmes authored on 2013/11/16 08:48:24
Showing 31 changed files
1 1
deleted file mode 100644
... ...
@@ -1,320 +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
-	"github.com/dotcloud/docker/utils"
29
-	"log"
30
-	"os"
31
-	"os/exec"
32
-	"path"
33
-	"strings"
34
-)
35
-
36
-func init() {
37
-	graphdriver.Register("aufs", Init)
38
-}
39
-
40
-type AufsDriver struct {
41
-	root string
42
-}
43
-
44
-// New returns a new AUFS driver.
45
-// An error is returned if AUFS is not supported.
46
-func Init(root string) (graphdriver.Driver, error) {
47
-	// Try to load the aufs kernel module
48
-	if err := supportsAufs(); err != nil {
49
-		return nil, err
50
-	}
51
-	paths := []string{
52
-		"mnt",
53
-		"diff",
54
-		"layers",
55
-	}
56
-
57
-	// Create the root aufs driver dir and return
58
-	// if it already exists
59
-	// If not populate the dir structure
60
-	if err := os.MkdirAll(root, 0755); err != nil {
61
-		if os.IsExist(err) {
62
-			return &AufsDriver{root}, nil
63
-		}
64
-		return nil, err
65
-	}
66
-
67
-	for _, p := range paths {
68
-		if err := os.MkdirAll(path.Join(root, p), 0755); err != nil {
69
-			return nil, err
70
-		}
71
-	}
72
-	return &AufsDriver{root}, nil
73
-}
74
-
75
-// Return a nil error if the kernel supports aufs
76
-// We cannot modprobe because inside dind modprobe fails
77
-// to run
78
-func supportsAufs() error {
79
-	// We can try to modprobe aufs first before looking at
80
-	// proc/filesystems for when aufs is supported
81
-	exec.Command("modprobe", "aufs").Run()
82
-
83
-	f, err := os.Open("/proc/filesystems")
84
-	if err != nil {
85
-		return err
86
-	}
87
-	defer f.Close()
88
-
89
-	s := bufio.NewScanner(f)
90
-	for s.Scan() {
91
-		if strings.Contains(s.Text(), "aufs") {
92
-			return nil
93
-		}
94
-	}
95
-	return fmt.Errorf("AUFS was not found in /proc/filesystems")
96
-}
97
-
98
-func (a *AufsDriver) rootPath() string {
99
-	return a.root
100
-}
101
-
102
-func (a *AufsDriver) String() string {
103
-	return "aufs"
104
-}
105
-
106
-func (d *AufsDriver) Status() [][2]string {
107
-	return nil
108
-}
109
-
110
-// Three folders are created for each id
111
-// mnt, layers, and diff
112
-func (a *AufsDriver) Create(id, parent string) error {
113
-	if err := a.createDirsFor(id); err != nil {
114
-		return err
115
-	}
116
-	// Write the layers metadata
117
-	f, err := os.Create(path.Join(a.rootPath(), "layers", id))
118
-	if err != nil {
119
-		return err
120
-	}
121
-	defer f.Close()
122
-
123
-	if parent != "" {
124
-		ids, err := getParentIds(a.rootPath(), parent)
125
-		if err != nil {
126
-			return err
127
-		}
128
-
129
-		if _, err := fmt.Fprintln(f, parent); err != nil {
130
-			return err
131
-		}
132
-		for _, i := range ids {
133
-			if _, err := fmt.Fprintln(f, i); err != nil {
134
-				return err
135
-			}
136
-		}
137
-	}
138
-	return nil
139
-}
140
-
141
-func (a *AufsDriver) createDirsFor(id string) error {
142
-	paths := []string{
143
-		"mnt",
144
-		"diff",
145
-	}
146
-
147
-	for _, p := range paths {
148
-		if err := os.MkdirAll(path.Join(a.rootPath(), p, id), 0755); err != nil {
149
-			return err
150
-		}
151
-	}
152
-	return nil
153
-}
154
-
155
-// Unmount and remove the dir information
156
-func (a *AufsDriver) Remove(id string) error {
157
-	// Make sure the dir is umounted first
158
-	if err := a.unmount(id); err != nil {
159
-		return err
160
-	}
161
-	tmpDirs := []string{
162
-		"mnt",
163
-		"diff",
164
-	}
165
-
166
-	// Remove the dirs atomically
167
-	for _, p := range tmpDirs {
168
-		// We need to use a temp dir in the same dir as the driver so Rename
169
-		// does not fall back to the slow copy if /tmp and the driver dir
170
-		// are on different devices
171
-		tmp := path.Join(a.rootPath(), "tmp", p, id)
172
-		if err := os.MkdirAll(tmp, 0755); err != nil {
173
-			return err
174
-		}
175
-		realPath := path.Join(a.rootPath(), p, id)
176
-		if err := os.Rename(realPath, tmp); err != nil {
177
-			return err
178
-		}
179
-		defer os.RemoveAll(tmp)
180
-	}
181
-
182
-	// Remove the layers file for the id
183
-	return os.Remove(path.Join(a.rootPath(), "layers", id))
184
-}
185
-
186
-// Return the rootfs path for the id
187
-// This will mount the dir at it's given path
188
-func (a *AufsDriver) Get(id string) (string, error) {
189
-	ids, err := getParentIds(a.rootPath(), id)
190
-	if err != nil {
191
-		if !os.IsNotExist(err) {
192
-			return "", err
193
-		}
194
-		ids = []string{}
195
-	}
196
-
197
-	// If a dir does not have a parent ( no layers )do not try to mount
198
-	// just return the diff path to the data
199
-	out := path.Join(a.rootPath(), "diff", id)
200
-	if len(ids) > 0 {
201
-		out = path.Join(a.rootPath(), "mnt", id)
202
-		if err := a.mount(id); err != nil {
203
-			return "", err
204
-		}
205
-	}
206
-	return out, nil
207
-}
208
-
209
-// Returns an archive of the contents for the id
210
-func (a *AufsDriver) Diff(id string) (archive.Archive, error) {
211
-	return archive.TarFilter(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
212
-		Recursive:   true,
213
-		Compression: archive.Uncompressed,
214
-	})
215
-}
216
-
217
-func (a *AufsDriver) ApplyDiff(id string, diff archive.Archive) error {
218
-	return archive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
219
-}
220
-
221
-// Returns the size of the contents for the id
222
-func (a *AufsDriver) Size(id string) (int64, error) {
223
-	return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
224
-}
225
-
226
-func (a *AufsDriver) Changes(id string) ([]archive.Change, error) {
227
-	layers, err := a.getParentLayerPaths(id)
228
-	if err != nil {
229
-		return nil, err
230
-	}
231
-	return archive.Changes(layers, path.Join(a.rootPath(), "diff", id))
232
-}
233
-
234
-func (a *AufsDriver) getParentLayerPaths(id string) ([]string, error) {
235
-	parentIds, err := getParentIds(a.rootPath(), id)
236
-	if err != nil {
237
-		return nil, err
238
-	}
239
-	if len(parentIds) == 0 {
240
-		return nil, fmt.Errorf("Dir %s does not have any parent layers", id)
241
-	}
242
-	layers := make([]string, len(parentIds))
243
-
244
-	// Get the diff paths for all the parent ids
245
-	for i, p := range parentIds {
246
-		layers[i] = path.Join(a.rootPath(), "diff", p)
247
-	}
248
-	return layers, nil
249
-}
250
-
251
-func (a *AufsDriver) mount(id string) error {
252
-	// If the id is mounted or we get an error return
253
-	if mounted, err := a.mounted(id); err != nil || mounted {
254
-		return err
255
-	}
256
-
257
-	var (
258
-		target = path.Join(a.rootPath(), "mnt", id)
259
-		rw     = path.Join(a.rootPath(), "diff", id)
260
-	)
261
-
262
-	layers, err := a.getParentLayerPaths(id)
263
-	if err != nil {
264
-		return err
265
-	}
266
-
267
-	if err := a.aufsMount(layers, rw, target); err != nil {
268
-		return err
269
-	}
270
-	return nil
271
-}
272
-
273
-func (a *AufsDriver) unmount(id string) error {
274
-	if mounted, err := a.mounted(id); err != nil || !mounted {
275
-		return err
276
-	}
277
-	target := path.Join(a.rootPath(), "mnt", id)
278
-	return Unmount(target)
279
-}
280
-
281
-func (a *AufsDriver) mounted(id string) (bool, error) {
282
-	target := path.Join(a.rootPath(), "mnt", id)
283
-	return Mounted(target)
284
-}
285
-
286
-// During cleanup aufs needs to unmount all mountpoints
287
-func (a *AufsDriver) Cleanup() error {
288
-	ids, err := loadIds(path.Join(a.rootPath(), "layers"))
289
-	if err != nil {
290
-		return err
291
-	}
292
-	for _, id := range ids {
293
-		if err := a.unmount(id); err != nil {
294
-			return err
295
-		}
296
-	}
297
-	return nil
298
-}
299
-
300
-func (a *AufsDriver) aufsMount(ro []string, rw, target string) error {
301
-	rwBranch := fmt.Sprintf("%v=rw", rw)
302
-	roBranches := ""
303
-	for _, layer := range ro {
304
-		roBranches += fmt.Sprintf("%v=ro+wh:", layer)
305
-	}
306
-	branches := fmt.Sprintf("br:%v:%v,xino=/dev/shm/aufs.xino", rwBranch, roBranches)
307
-
308
-	//if error, try to load aufs kernel module
309
-	if err := mount("none", target, "aufs", 0, branches); err != nil {
310
-		log.Printf("Kernel does not support AUFS, trying to load the AUFS module with modprobe...")
311
-		if err := exec.Command("modprobe", "aufs").Run(); err != nil {
312
-			return fmt.Errorf("Unable to load the AUFS module")
313
-		}
314
-		log.Printf("...module loaded.")
315
-		if err := mount("none", target, "aufs", 0, branches); err != nil {
316
-			return fmt.Errorf("Unable to mount using aufs %s", err)
317
-		}
318
-	}
319
-	return nil
320
-}
321 1
deleted file mode 100644
... ...
@@ -1,517 +0,0 @@
1
-package aufs
2
-
3
-import (
4
-	"github.com/dotcloud/docker/archive"
5
-	"os"
6
-	"path"
7
-	"testing"
8
-)
9
-
10
-var (
11
-	tmp = path.Join(os.TempDir(), "aufs-tests", "aufs")
12
-)
13
-
14
-func newDriver(t *testing.T) *AufsDriver {
15
-	if err := os.MkdirAll(tmp, 0755); err != nil {
16
-		t.Fatal(err)
17
-	}
18
-
19
-	d, err := Init(tmp)
20
-	if err != nil {
21
-		t.Fatal(err)
22
-	}
23
-	return d.(*AufsDriver)
24
-}
25
-
26
-func TestNewAufsDriver(t *testing.T) {
27
-	if err := os.MkdirAll(tmp, 0755); err != nil {
28
-		t.Fatal(err)
29
-	}
30
-
31
-	d, err := Init(tmp)
32
-	if err != nil {
33
-		t.Fatal(err)
34
-	}
35
-	defer os.RemoveAll(tmp)
36
-	if d == nil {
37
-		t.Fatalf("Driver should not be nil")
38
-	}
39
-}
40
-
41
-func TestAufsString(t *testing.T) {
42
-	d := newDriver(t)
43
-	defer os.RemoveAll(tmp)
44
-
45
-	if d.String() != "aufs" {
46
-		t.Fatalf("Expected aufs got %s", d.String())
47
-	}
48
-}
49
-
50
-func TestCreateDirStructure(t *testing.T) {
51
-	newDriver(t)
52
-	defer os.RemoveAll(tmp)
53
-
54
-	paths := []string{
55
-		"mnt",
56
-		"layers",
57
-		"diff",
58
-	}
59
-
60
-	for _, p := range paths {
61
-		if _, err := os.Stat(path.Join(tmp, p)); err != nil {
62
-			t.Fatal(err)
63
-		}
64
-	}
65
-}
66
-
67
-// We should be able to create two drivers with the same dir structure
68
-func TestNewDriverFromExistingDir(t *testing.T) {
69
-	if err := os.MkdirAll(tmp, 0755); err != nil {
70
-		t.Fatal(err)
71
-	}
72
-
73
-	if _, err := Init(tmp); err != nil {
74
-		t.Fatal(err)
75
-	}
76
-	if _, err := Init(tmp); err != nil {
77
-		t.Fatal(err)
78
-	}
79
-	os.RemoveAll(tmp)
80
-}
81
-
82
-func TestCreateNewDir(t *testing.T) {
83
-	d := newDriver(t)
84
-	defer os.RemoveAll(tmp)
85
-
86
-	if err := d.Create("1", ""); err != nil {
87
-		t.Fatal(err)
88
-	}
89
-}
90
-
91
-func TestCreateNewDirStructure(t *testing.T) {
92
-	d := newDriver(t)
93
-	defer os.RemoveAll(tmp)
94
-
95
-	if err := d.Create("1", ""); err != nil {
96
-		t.Fatal(err)
97
-	}
98
-
99
-	paths := []string{
100
-		"mnt",
101
-		"diff",
102
-		"layers",
103
-	}
104
-
105
-	for _, p := range paths {
106
-		if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil {
107
-			t.Fatal(err)
108
-		}
109
-	}
110
-}
111
-
112
-func TestRemoveImage(t *testing.T) {
113
-	d := newDriver(t)
114
-	defer os.RemoveAll(tmp)
115
-
116
-	if err := d.Create("1", ""); err != nil {
117
-		t.Fatal(err)
118
-	}
119
-
120
-	if err := d.Remove("1"); err != nil {
121
-		t.Fatal(err)
122
-	}
123
-
124
-	paths := []string{
125
-		"mnt",
126
-		"diff",
127
-		"layers",
128
-	}
129
-
130
-	for _, p := range paths {
131
-		if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil {
132
-			t.Fatalf("Error should not be nil because dirs with id 1 should be delted: %s", p)
133
-		}
134
-	}
135
-}
136
-
137
-func TestGetWithoutParent(t *testing.T) {
138
-	d := newDriver(t)
139
-	defer os.RemoveAll(tmp)
140
-
141
-	if err := d.Create("1", ""); err != nil {
142
-		t.Fatal(err)
143
-	}
144
-
145
-	diffPath, err := d.Get("1")
146
-	if err != nil {
147
-		t.Fatal(err)
148
-	}
149
-	expected := path.Join(tmp, "diff", "1")
150
-	if diffPath != expected {
151
-		t.Fatalf("Expected path %s got %s", expected, diffPath)
152
-	}
153
-}
154
-
155
-func TestCleanupWithNoDirs(t *testing.T) {
156
-	d := newDriver(t)
157
-	defer os.RemoveAll(tmp)
158
-
159
-	if err := d.Cleanup(); err != nil {
160
-		t.Fatal(err)
161
-	}
162
-}
163
-
164
-func TestCleanupWithDir(t *testing.T) {
165
-	d := newDriver(t)
166
-	defer os.RemoveAll(tmp)
167
-
168
-	if err := d.Create("1", ""); err != nil {
169
-		t.Fatal(err)
170
-	}
171
-
172
-	if err := d.Cleanup(); err != nil {
173
-		t.Fatal(err)
174
-	}
175
-}
176
-
177
-func TestMountedFalseResponse(t *testing.T) {
178
-	d := newDriver(t)
179
-	defer os.RemoveAll(tmp)
180
-
181
-	if err := d.Create("1", ""); err != nil {
182
-		t.Fatal(err)
183
-	}
184
-
185
-	response, err := d.mounted("1")
186
-	if err != nil {
187
-		t.Fatal(err)
188
-	}
189
-
190
-	if response != false {
191
-		t.Fatalf("Response if dir id 1 is mounted should be false")
192
-	}
193
-}
194
-
195
-func TestMountedTrueReponse(t *testing.T) {
196
-	d := newDriver(t)
197
-	defer os.RemoveAll(tmp)
198
-	defer d.Cleanup()
199
-
200
-	if err := d.Create("1", ""); err != nil {
201
-		t.Fatal(err)
202
-	}
203
-	if err := d.Create("2", "1"); err != nil {
204
-		t.Fatal(err)
205
-	}
206
-
207
-	_, err := d.Get("2")
208
-	if err != nil {
209
-		t.Fatal(err)
210
-	}
211
-
212
-	response, err := d.mounted("2")
213
-	if err != nil {
214
-		t.Fatal(err)
215
-	}
216
-
217
-	if response != true {
218
-		t.Fatalf("Response if dir id 2 is mounted should be true")
219
-	}
220
-}
221
-
222
-func TestMountWithParent(t *testing.T) {
223
-	d := newDriver(t)
224
-	defer os.RemoveAll(tmp)
225
-
226
-	if err := d.Create("1", ""); err != nil {
227
-		t.Fatal(err)
228
-	}
229
-	if err := d.Create("2", "1"); err != nil {
230
-		t.Fatal(err)
231
-	}
232
-
233
-	defer func() {
234
-		if err := d.Cleanup(); err != nil {
235
-			t.Fatal(err)
236
-		}
237
-	}()
238
-
239
-	mntPath, err := d.Get("2")
240
-	if err != nil {
241
-		t.Fatal(err)
242
-	}
243
-	if mntPath == "" {
244
-		t.Fatal("mntPath should not be empty string")
245
-	}
246
-
247
-	expected := path.Join(tmp, "mnt", "2")
248
-	if mntPath != expected {
249
-		t.Fatalf("Expected %s got %s", expected, mntPath)
250
-	}
251
-}
252
-
253
-func TestRemoveMountedDir(t *testing.T) {
254
-	d := newDriver(t)
255
-	defer os.RemoveAll(tmp)
256
-
257
-	if err := d.Create("1", ""); err != nil {
258
-		t.Fatal(err)
259
-	}
260
-	if err := d.Create("2", "1"); err != nil {
261
-		t.Fatal(err)
262
-	}
263
-
264
-	defer func() {
265
-		if err := d.Cleanup(); err != nil {
266
-			t.Fatal(err)
267
-		}
268
-	}()
269
-
270
-	mntPath, err := d.Get("2")
271
-	if err != nil {
272
-		t.Fatal(err)
273
-	}
274
-	if mntPath == "" {
275
-		t.Fatal("mntPath should not be empty string")
276
-	}
277
-
278
-	mounted, err := d.mounted("2")
279
-	if err != nil {
280
-		t.Fatal(err)
281
-	}
282
-
283
-	if !mounted {
284
-		t.Fatalf("Dir id 2 should be mounted")
285
-	}
286
-
287
-	if err := d.Remove("2"); err != nil {
288
-		t.Fatal(err)
289
-	}
290
-}
291
-
292
-func TestCreateWithInvalidParent(t *testing.T) {
293
-	d := newDriver(t)
294
-	defer os.RemoveAll(tmp)
295
-
296
-	if err := d.Create("1", "docker"); err == nil {
297
-		t.Fatalf("Error should not be nil with parent does not exist")
298
-	}
299
-}
300
-
301
-func TestGetDiff(t *testing.T) {
302
-	d := newDriver(t)
303
-	defer os.RemoveAll(tmp)
304
-
305
-	if err := d.Create("1", ""); err != nil {
306
-		t.Fatal(err)
307
-	}
308
-
309
-	diffPath, err := d.Get("1")
310
-	if err != nil {
311
-		t.Fatal(err)
312
-	}
313
-
314
-	// Add a file to the diff path with a fixed size
315
-	size := int64(1024)
316
-
317
-	f, err := os.Create(path.Join(diffPath, "test_file"))
318
-	if err != nil {
319
-		t.Fatal(err)
320
-	}
321
-	if err := f.Truncate(size); err != nil {
322
-		t.Fatal(err)
323
-	}
324
-	f.Close()
325
-
326
-	a, err := d.Diff("1")
327
-	if err != nil {
328
-		t.Fatal(err)
329
-	}
330
-	if a == nil {
331
-		t.Fatalf("Archive should not be nil")
332
-	}
333
-}
334
-
335
-func TestChanges(t *testing.T) {
336
-	d := newDriver(t)
337
-	defer os.RemoveAll(tmp)
338
-
339
-	if err := d.Create("1", ""); err != nil {
340
-		t.Fatal(err)
341
-	}
342
-	if err := d.Create("2", "1"); err != nil {
343
-		t.Fatal(err)
344
-	}
345
-
346
-	defer func() {
347
-		if err := d.Cleanup(); err != nil {
348
-			t.Fatal(err)
349
-		}
350
-	}()
351
-
352
-	mntPoint, err := d.Get("2")
353
-	if err != nil {
354
-		t.Fatal(err)
355
-	}
356
-
357
-	// Create a file to save in the mountpoint
358
-	f, err := os.Create(path.Join(mntPoint, "test.txt"))
359
-	if err != nil {
360
-		t.Fatal(err)
361
-	}
362
-
363
-	if _, err := f.WriteString("testline"); err != nil {
364
-		t.Fatal(err)
365
-	}
366
-	if err := f.Close(); err != nil {
367
-		t.Fatal(err)
368
-	}
369
-
370
-	changes, err := d.Changes("2")
371
-	if err != nil {
372
-		t.Fatal(err)
373
-	}
374
-	if len(changes) != 1 {
375
-		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
376
-	}
377
-	change := changes[0]
378
-
379
-	expectedPath := "/test.txt"
380
-	if change.Path != expectedPath {
381
-		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
382
-	}
383
-
384
-	if change.Kind != archive.ChangeAdd {
385
-		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
386
-	}
387
-
388
-	if err := d.Create("3", "2"); err != nil {
389
-		t.Fatal(err)
390
-	}
391
-	mntPoint, err = d.Get("3")
392
-	if err != nil {
393
-		t.Fatal(err)
394
-	}
395
-
396
-	// Create a file to save in the mountpoint
397
-	f, err = os.Create(path.Join(mntPoint, "test2.txt"))
398
-	if err != nil {
399
-		t.Fatal(err)
400
-	}
401
-
402
-	if _, err := f.WriteString("testline"); err != nil {
403
-		t.Fatal(err)
404
-	}
405
-	if err := f.Close(); err != nil {
406
-		t.Fatal(err)
407
-	}
408
-
409
-	changes, err = d.Changes("3")
410
-	if err != nil {
411
-		t.Fatal(err)
412
-	}
413
-
414
-	if len(changes) != 1 {
415
-		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
416
-	}
417
-	change = changes[0]
418
-
419
-	expectedPath = "/test2.txt"
420
-	if change.Path != expectedPath {
421
-		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
422
-	}
423
-
424
-	if change.Kind != archive.ChangeAdd {
425
-		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
426
-	}
427
-}
428
-
429
-func TestDiffSize(t *testing.T) {
430
-	d := newDriver(t)
431
-	defer os.RemoveAll(tmp)
432
-
433
-	if err := d.Create("1", ""); err != nil {
434
-		t.Fatal(err)
435
-	}
436
-
437
-	diffPath, err := d.Get("1")
438
-	if err != nil {
439
-		t.Fatal(err)
440
-	}
441
-
442
-	// Add a file to the diff path with a fixed size
443
-	size := int64(1024)
444
-
445
-	f, err := os.Create(path.Join(diffPath, "test_file"))
446
-	if err != nil {
447
-		t.Fatal(err)
448
-	}
449
-	f.Truncate(size)
450
-	s, err := f.Stat()
451
-	if err != nil {
452
-		t.Fatal(err)
453
-	}
454
-	size = s.Size()
455
-	if err := f.Close(); err != nil {
456
-		t.Fatal(err)
457
-	}
458
-
459
-	diffSize, err := d.Size("1")
460
-	if err != nil {
461
-		t.Fatal(err)
462
-	}
463
-	if diffSize != size {
464
-		t.Fatalf("Expected size to be %d got %d", size, diffSize)
465
-	}
466
-}
467
-
468
-func TestApplyDiff(t *testing.T) {
469
-	d := newDriver(t)
470
-	defer os.RemoveAll(tmp)
471
-	defer d.Cleanup()
472
-
473
-	if err := d.Create("1", ""); err != nil {
474
-		t.Fatal(err)
475
-	}
476
-
477
-	diffPath, err := d.Get("1")
478
-	if err != nil {
479
-		t.Fatal(err)
480
-	}
481
-
482
-	// Add a file to the diff path with a fixed size
483
-	size := int64(1024)
484
-
485
-	f, err := os.Create(path.Join(diffPath, "test_file"))
486
-	if err != nil {
487
-		t.Fatal(err)
488
-	}
489
-	f.Truncate(size)
490
-	f.Close()
491
-
492
-	diff, err := d.Diff("1")
493
-	if err != nil {
494
-		t.Fatal(err)
495
-	}
496
-
497
-	if err := d.Create("2", ""); err != nil {
498
-		t.Fatal(err)
499
-	}
500
-	if err := d.Create("3", "2"); err != nil {
501
-		t.Fatal(err)
502
-	}
503
-
504
-	if err := d.ApplyDiff("3", diff); err != nil {
505
-		t.Fatal(err)
506
-	}
507
-
508
-	// Ensure that the file is in the mount point for id 3
509
-
510
-	mountPoint, err := d.Get("3")
511
-	if err != nil {
512
-		t.Fatal(err)
513
-	}
514
-	if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil {
515
-		t.Fatal(err)
516
-	}
517
-}
518 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,37 +0,0 @@
1
-package aufs
2
-
3
-import (
4
-	"github.com/dotcloud/docker/utils"
5
-	"os"
6
-	"os/exec"
7
-	"path/filepath"
8
-	"syscall"
9
-)
10
-
11
-func Unmount(target string) error {
12
-	if err := exec.Command("auplink", target, "flush").Run(); err != nil {
13
-		utils.Errorf("[warning]: couldn't run auplink before unmount: %s", err)
14
-	}
15
-	if err := syscall.Unmount(target, 0); err != nil {
16
-		return err
17
-	}
18
-	return nil
19
-}
20
-
21
-func Mounted(mountpoint string) (bool, error) {
22
-	mntpoint, err := os.Stat(mountpoint)
23
-	if err != nil {
24
-		if os.IsNotExist(err) {
25
-			return false, nil
26
-		}
27
-		return false, err
28
-	}
29
-	parent, err := os.Stat(filepath.Join(mountpoint, ".."))
30
-	if err != nil {
31
-		return false, err
32
-	}
33
-	mntpointSt := mntpoint.Sys().(*syscall.Stat_t)
34
-	parentSt := parent.Sys().(*syscall.Stat_t)
35
-
36
-	return mntpointSt.Dev != parentSt.Dev, nil
37
-}
38 1
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-package aufs
2
-
3
-import "errors"
4
-
5
-func mount(source string, target string, fstype string, flags uintptr, data string) (err error) {
6
-	return errors.New("mount is not implemented on darwin")
7
-}
8 1
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-package aufs
2
-
3
-import "syscall"
4
-
5
-func mount(source string, target string, fstype string, flags uintptr, data string) (err error) {
6
-	return syscall.Mount(source, target, fstype, flags, data)
7
-}
8 1
deleted file mode 100644
... ...
@@ -1,803 +0,0 @@
1
-package devmapper
2
-
3
-import (
4
-	"encoding/json"
5
-	"fmt"
6
-	"github.com/dotcloud/docker/utils"
7
-	"io"
8
-	"io/ioutil"
9
-	"os"
10
-	"os/exec"
11
-	"path"
12
-	"path/filepath"
13
-	"strconv"
14
-	"sync"
15
-	"syscall"
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
-
34
-type MetaData struct {
35
-	Devices map[string]*DevInfo `json:devices`
36
-}
37
-
38
-type DeviceSet struct {
39
-	MetaData
40
-	sync.Mutex
41
-	root             string
42
-	devicePrefix     string
43
-	TransactionId    uint64
44
-	NewTransactionId uint64
45
-	nextFreeDevice   int
46
-	activeMounts     map[string]int
47
-}
48
-
49
-type DiskUsage struct {
50
-	Used  uint64
51
-	Total uint64
52
-}
53
-
54
-type Status struct {
55
-	PoolName         string
56
-	DataLoopback     string
57
-	MetadataLoopback string
58
-	Data             DiskUsage
59
-	Metadata         DiskUsage
60
-}
61
-
62
-func getDevName(name string) string {
63
-	return "/dev/mapper/" + name
64
-}
65
-
66
-func (info *DevInfo) Name() string {
67
-	hash := info.Hash
68
-	if hash == "" {
69
-		hash = "base"
70
-	}
71
-	return fmt.Sprintf("%s-%s", info.devices.devicePrefix, hash)
72
-}
73
-
74
-func (info *DevInfo) DevName() string {
75
-	return getDevName(info.Name())
76
-}
77
-
78
-func (devices *DeviceSet) loopbackDir() string {
79
-	return path.Join(devices.root, "devicemapper")
80
-}
81
-
82
-func (devices *DeviceSet) jsonFile() string {
83
-	return path.Join(devices.loopbackDir(), "json")
84
-}
85
-
86
-func (devices *DeviceSet) getPoolName() string {
87
-	return devices.devicePrefix + "-pool"
88
-}
89
-
90
-func (devices *DeviceSet) getPoolDevName() string {
91
-	return getDevName(devices.getPoolName())
92
-}
93
-
94
-func (devices *DeviceSet) hasImage(name string) bool {
95
-	dirname := devices.loopbackDir()
96
-	filename := path.Join(dirname, name)
97
-
98
-	_, err := os.Stat(filename)
99
-	return err == nil
100
-}
101
-
102
-// ensureImage creates a sparse file of <size> bytes at the path
103
-// <root>/devicemapper/<name>.
104
-// If the file already exists, it does nothing.
105
-// Either way it returns the full path.
106
-func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
107
-	dirname := devices.loopbackDir()
108
-	filename := path.Join(dirname, name)
109
-
110
-	if err := os.MkdirAll(dirname, 0700); err != nil && !os.IsExist(err) {
111
-		return "", err
112
-	}
113
-
114
-	if _, err := os.Stat(filename); err != nil {
115
-		if !os.IsNotExist(err) {
116
-			return "", err
117
-		}
118
-		utils.Debugf("Creating loopback file %s for device-manage use", filename)
119
-		file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0600)
120
-		if err != nil {
121
-			return "", err
122
-		}
123
-		defer file.Close()
124
-
125
-		if err = file.Truncate(size); err != nil {
126
-			return "", err
127
-		}
128
-	}
129
-	return filename, nil
130
-}
131
-
132
-func (devices *DeviceSet) allocateDeviceId() int {
133
-	// TODO: Add smarter reuse of deleted devices
134
-	id := devices.nextFreeDevice
135
-	devices.nextFreeDevice = devices.nextFreeDevice + 1
136
-	return id
137
-}
138
-
139
-func (devices *DeviceSet) allocateTransactionId() uint64 {
140
-	devices.NewTransactionId = devices.NewTransactionId + 1
141
-	return devices.NewTransactionId
142
-}
143
-
144
-func (devices *DeviceSet) saveMetadata() error {
145
-	jsonData, err := json.Marshal(devices.MetaData)
146
-	if err != nil {
147
-		return fmt.Errorf("Error encoding metaadata to json: %s", err)
148
-	}
149
-	tmpFile, err := ioutil.TempFile(filepath.Dir(devices.jsonFile()), ".json")
150
-	if err != nil {
151
-		return fmt.Errorf("Error creating metadata file: %s", err)
152
-	}
153
-
154
-	n, err := tmpFile.Write(jsonData)
155
-	if err != nil {
156
-		return fmt.Errorf("Error writing metadata to %s: %s", tmpFile.Name(), err)
157
-	}
158
-	if n < len(jsonData) {
159
-		return io.ErrShortWrite
160
-	}
161
-	if err := tmpFile.Sync(); err != nil {
162
-		return fmt.Errorf("Error syncing metadata file %s: %s", tmpFile.Name(), err)
163
-	}
164
-	if err := tmpFile.Close(); err != nil {
165
-		return fmt.Errorf("Error closing metadata file %s: %s", tmpFile.Name(), err)
166
-	}
167
-	if err := os.Rename(tmpFile.Name(), devices.jsonFile()); err != nil {
168
-		return fmt.Errorf("Error committing metadata file", err)
169
-	}
170
-
171
-	if devices.NewTransactionId != devices.TransactionId {
172
-		if err = setTransactionId(devices.getPoolDevName(), devices.TransactionId, devices.NewTransactionId); err != nil {
173
-			return fmt.Errorf("Error setting devmapper transition ID: %s", err)
174
-		}
175
-		devices.TransactionId = devices.NewTransactionId
176
-	}
177
-	return nil
178
-}
179
-
180
-func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*DevInfo, error) {
181
-	utils.Debugf("registerDevice(%v, %v)", id, hash)
182
-	info := &DevInfo{
183
-		Hash:          hash,
184
-		DeviceId:      id,
185
-		Size:          size,
186
-		TransactionId: devices.allocateTransactionId(),
187
-		Initialized:   false,
188
-		devices:       devices,
189
-	}
190
-
191
-	devices.Devices[hash] = info
192
-	if err := devices.saveMetadata(); err != nil {
193
-		// Try to remove unused device
194
-		delete(devices.Devices, hash)
195
-		return nil, err
196
-	}
197
-
198
-	return info, nil
199
-}
200
-
201
-func (devices *DeviceSet) activateDeviceIfNeeded(hash string) error {
202
-	utils.Debugf("activateDeviceIfNeeded(%v)", hash)
203
-	info := devices.Devices[hash]
204
-	if info == nil {
205
-		return fmt.Errorf("Unknown device %s", hash)
206
-	}
207
-
208
-	if devinfo, _ := getInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
209
-		return nil
210
-	}
211
-
212
-	return activateDevice(devices.getPoolDevName(), info.Name(), info.DeviceId, info.Size)
213
-}
214
-
215
-func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
216
-	devname := info.DevName()
217
-
218
-	err := exec.Command("mkfs.ext4", "-E", "discard,lazy_itable_init=0,lazy_journal_init=0", devname).Run()
219
-	if err != nil {
220
-		err = exec.Command("mkfs.ext4", "-E", "discard,lazy_itable_init=0", devname).Run()
221
-	}
222
-	if err != nil {
223
-		utils.Debugf("\n--->Err: %s\n", err)
224
-		return err
225
-	}
226
-	return nil
227
-}
228
-
229
-func (devices *DeviceSet) loadMetaData() error {
230
-	utils.Debugf("loadMetadata()")
231
-	defer utils.Debugf("loadMetadata END")
232
-	_, _, _, params, err := getStatus(devices.getPoolName())
233
-	if err != nil {
234
-		utils.Debugf("\n--->Err: %s\n", err)
235
-		return err
236
-	}
237
-
238
-	if _, err := fmt.Sscanf(params, "%d", &devices.TransactionId); err != nil {
239
-		utils.Debugf("\n--->Err: %s\n", err)
240
-		return err
241
-	}
242
-	devices.NewTransactionId = devices.TransactionId
243
-
244
-	jsonData, err := ioutil.ReadFile(devices.jsonFile())
245
-	if err != nil && !os.IsNotExist(err) {
246
-		utils.Debugf("\n--->Err: %s\n", err)
247
-		return err
248
-	}
249
-
250
-	devices.MetaData.Devices = make(map[string]*DevInfo)
251
-	if jsonData != nil {
252
-		if err := json.Unmarshal(jsonData, &devices.MetaData); err != nil {
253
-			utils.Debugf("\n--->Err: %s\n", err)
254
-			return err
255
-		}
256
-	}
257
-
258
-	for hash, d := range devices.Devices {
259
-		d.Hash = hash
260
-		d.devices = devices
261
-
262
-		if d.DeviceId >= devices.nextFreeDevice {
263
-			devices.nextFreeDevice = d.DeviceId + 1
264
-		}
265
-
266
-		// If the transaction id is larger than the actual one we lost the device due to some crash
267
-		if d.TransactionId > devices.TransactionId {
268
-			utils.Debugf("Removing lost device %s with id %d", hash, d.TransactionId)
269
-			delete(devices.Devices, hash)
270
-		}
271
-	}
272
-	return nil
273
-}
274
-
275
-func (devices *DeviceSet) setupBaseImage() error {
276
-	oldInfo := devices.Devices[""]
277
-	if oldInfo != nil && oldInfo.Initialized {
278
-		return nil
279
-	}
280
-
281
-	if oldInfo != nil && !oldInfo.Initialized {
282
-		utils.Debugf("Removing uninitialized base image")
283
-		if err := devices.removeDevice(""); err != nil {
284
-			utils.Debugf("\n--->Err: %s\n", err)
285
-			return err
286
-		}
287
-	}
288
-
289
-	utils.Debugf("Initializing base device-manager snapshot")
290
-
291
-	id := devices.allocateDeviceId()
292
-
293
-	// Create initial device
294
-	if err := createDevice(devices.getPoolDevName(), id); err != nil {
295
-		utils.Debugf("\n--->Err: %s\n", err)
296
-		return err
297
-	}
298
-
299
-	utils.Debugf("Registering base device (id %v) with FS size %v", id, DefaultBaseFsSize)
300
-	info, err := devices.registerDevice(id, "", DefaultBaseFsSize)
301
-	if err != nil {
302
-		_ = deleteDevice(devices.getPoolDevName(), id)
303
-		utils.Debugf("\n--->Err: %s\n", err)
304
-		return err
305
-	}
306
-
307
-	utils.Debugf("Creating filesystem on base device-manager snapshot")
308
-
309
-	if err = devices.activateDeviceIfNeeded(""); err != nil {
310
-		utils.Debugf("\n--->Err: %s\n", err)
311
-		return err
312
-	}
313
-
314
-	if err := devices.createFilesystem(info); err != nil {
315
-		utils.Debugf("\n--->Err: %s\n", err)
316
-		return err
317
-	}
318
-
319
-	info.Initialized = true
320
-	if err = devices.saveMetadata(); err != nil {
321
-		info.Initialized = false
322
-		utils.Debugf("\n--->Err: %s\n", err)
323
-		return err
324
-	}
325
-
326
-	return nil
327
-}
328
-
329
-func setCloseOnExec(name string) {
330
-	fileInfos, _ := ioutil.ReadDir("/proc/self/fd")
331
-	if fileInfos != nil {
332
-		for _, i := range fileInfos {
333
-			link, _ := os.Readlink(filepath.Join("/proc/self/fd", i.Name()))
334
-			if link == name {
335
-				fd, err := strconv.Atoi(i.Name())
336
-				if err == nil {
337
-					syscall.CloseOnExec(fd)
338
-				}
339
-			}
340
-		}
341
-	}
342
-}
343
-
344
-func (devices *DeviceSet) log(level int, file string, line int, dmError int, message string) {
345
-	if level >= 7 {
346
-		return // Ignore _LOG_DEBUG
347
-	}
348
-
349
-	utils.Debugf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message)
350
-}
351
-
352
-func major(device uint64) uint64 {
353
-	return (device >> 8) & 0xfff
354
-}
355
-
356
-func minor(device uint64) uint64 {
357
-	return (device & 0xff) | ((device >> 12) & 0xfff00)
358
-}
359
-
360
-func (devices *DeviceSet) initDevmapper() error {
361
-	logInit(devices)
362
-
363
-	// Make sure the sparse images exist in <root>/devicemapper/data and
364
-	// <root>/devicemapper/metadata
365
-
366
-	createdLoopback := !devices.hasImage("data") || !devices.hasImage("metadata")
367
-	data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
368
-	if err != nil {
369
-		utils.Debugf("Error device ensureImage (data): %s\n", err)
370
-		return err
371
-	}
372
-	metadata, err := devices.ensureImage("metadata", DefaultMetaDataLoopbackSize)
373
-	if err != nil {
374
-		utils.Debugf("Error device ensureImage (metadata): %s\n", err)
375
-		return err
376
-	}
377
-
378
-	// Set the device prefix from the device id and inode of the docker root dir
379
-
380
-	st, err := os.Stat(devices.root)
381
-	if err != nil {
382
-		return fmt.Errorf("Error looking up dir %s: %s", devices.root, err)
383
-	}
384
-	sysSt := st.Sys().(*syscall.Stat_t)
385
-	// "reg-" stands for "regular file".
386
-	// In the future we might use "dev-" for "device file", etc.
387
-	// docker-maj,min[-inode] stands for:
388
-	//	- Managed by docker
389
-	//	- The target of this device is at major <maj> and minor <min>
390
-	//	- If <inode> is defined, use that file inside the device as a loopback image. Otherwise use the device itself.
391
-	devices.devicePrefix = fmt.Sprintf("docker-%d:%d-%d", major(sysSt.Dev), minor(sysSt.Dev), sysSt.Ino)
392
-	utils.Debugf("Generated prefix: %s", devices.devicePrefix)
393
-
394
-	// Check for the existence of the device <prefix>-pool
395
-	utils.Debugf("Checking for existence of the pool '%s'", devices.getPoolName())
396
-	info, err := getInfo(devices.getPoolName())
397
-	if info == nil {
398
-		utils.Debugf("Error device getInfo: %s", err)
399
-		return err
400
-	}
401
-
402
-	// It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files
403
-	// that are not Close-on-exec, and lxc-start will die if it inherits any unexpected files,
404
-	// so we add this badhack to make sure it closes itself
405
-	setCloseOnExec("/dev/mapper/control")
406
-
407
-	// If the pool doesn't exist, create it
408
-	if info.Exists == 0 {
409
-		utils.Debugf("Pool doesn't exist. Creating it.")
410
-
411
-		dataFile, err := AttachLoopDevice(data)
412
-		if err != nil {
413
-			utils.Debugf("\n--->Err: %s\n", err)
414
-			return err
415
-		}
416
-		defer dataFile.Close()
417
-
418
-		metadataFile, err := AttachLoopDevice(metadata)
419
-		if err != nil {
420
-			utils.Debugf("\n--->Err: %s\n", err)
421
-			return err
422
-		}
423
-		defer metadataFile.Close()
424
-
425
-		if err := createPool(devices.getPoolName(), dataFile, metadataFile); err != nil {
426
-			utils.Debugf("\n--->Err: %s\n", err)
427
-			return err
428
-		}
429
-	}
430
-
431
-	// If we didn't just create the data or metadata image, we need to
432
-	// load the metadata from the existing file.
433
-	if !createdLoopback {
434
-		if err = devices.loadMetaData(); err != nil {
435
-			utils.Debugf("\n--->Err: %s\n", err)
436
-			return err
437
-		}
438
-	}
439
-
440
-	// Setup the base image
441
-	if err := devices.setupBaseImage(); err != nil {
442
-		utils.Debugf("Error device setupBaseImage: %s\n", err)
443
-		return err
444
-	}
445
-
446
-	return nil
447
-}
448
-
449
-func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
450
-	devices.Lock()
451
-	defer devices.Unlock()
452
-
453
-	if devices.Devices[hash] != nil {
454
-		return fmt.Errorf("hash %s already exists", hash)
455
-	}
456
-
457
-	baseInfo := devices.Devices[baseHash]
458
-	if baseInfo == nil {
459
-		return fmt.Errorf("Error adding device for '%s': can't find device for parent '%s'", hash, baseHash)
460
-	}
461
-
462
-	deviceId := devices.allocateDeviceId()
463
-
464
-	if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
465
-		utils.Debugf("Error creating snap device: %s\n", err)
466
-		return err
467
-	}
468
-
469
-	if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil {
470
-		deleteDevice(devices.getPoolDevName(), deviceId)
471
-		utils.Debugf("Error registering device: %s\n", err)
472
-		return err
473
-	}
474
-	return nil
475
-}
476
-
477
-func (devices *DeviceSet) removeDevice(hash string) error {
478
-	info := devices.Devices[hash]
479
-	if info == nil {
480
-		return fmt.Errorf("hash %s doesn't exists", hash)
481
-	}
482
-
483
-	devinfo, _ := getInfo(info.Name())
484
-	if devinfo != nil && devinfo.Exists != 0 {
485
-		if err := removeDevice(info.Name()); err != nil {
486
-			utils.Debugf("Error removing device: %s\n", err)
487
-			return err
488
-		}
489
-	}
490
-
491
-	if info.Initialized {
492
-		info.Initialized = false
493
-		if err := devices.saveMetadata(); err != nil {
494
-			utils.Debugf("Error saving meta data: %s\n", err)
495
-			return err
496
-		}
497
-	}
498
-
499
-	if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
500
-		utils.Debugf("Error deleting device: %s\n", err)
501
-		return err
502
-	}
503
-
504
-	devices.allocateTransactionId()
505
-	delete(devices.Devices, info.Hash)
506
-
507
-	if err := devices.saveMetadata(); err != nil {
508
-		devices.Devices[info.Hash] = info
509
-		utils.Debugf("Error saving meta data: %s\n", err)
510
-		return err
511
-	}
512
-
513
-	return nil
514
-}
515
-
516
-func (devices *DeviceSet) RemoveDevice(hash string) error {
517
-	devices.Lock()
518
-	defer devices.Unlock()
519
-
520
-	return devices.removeDevice(hash)
521
-}
522
-
523
-func (devices *DeviceSet) deactivateDevice(hash string) error {
524
-	utils.Debugf("[devmapper] deactivateDevice(%s)", hash)
525
-	defer utils.Debugf("[devmapper] deactivateDevice END")
526
-	var devname string
527
-	// FIXME: shouldn't we just register the pool into devices?
528
-	devname, err := devices.byHash(hash)
529
-	if err != nil {
530
-		return err
531
-	}
532
-	devinfo, err := getInfo(devname)
533
-	if err != nil {
534
-		utils.Debugf("\n--->Err: %s\n", err)
535
-		return err
536
-	}
537
-	if devinfo.Exists != 0 {
538
-		if err := removeDevice(devname); err != nil {
539
-			utils.Debugf("\n--->Err: %s\n", err)
540
-			return err
541
-		}
542
-		if err := devices.waitRemove(hash); err != nil {
543
-			return err
544
-		}
545
-	}
546
-
547
-	return nil
548
-}
549
-
550
-// waitRemove blocks until either:
551
-// a) the device registered at <device_set_prefix>-<hash> is removed,
552
-// or b) the 1 second timeout expires.
553
-func (devices *DeviceSet) waitRemove(hash string) error {
554
-	utils.Debugf("[deviceset %s] waitRemove(%s)", devices.devicePrefix, hash)
555
-	defer utils.Debugf("[deviceset %s] waitRemove END", devices.devicePrefix, hash)
556
-	devname, err := devices.byHash(hash)
557
-	if err != nil {
558
-		return err
559
-	}
560
-	i := 0
561
-	for ; i < 1000; i += 1 {
562
-		devinfo, err := getInfo(devname)
563
-		if err != nil {
564
-			// If there is an error we assume the device doesn't exist.
565
-			// The error might actually be something else, but we can't differentiate.
566
-			return nil
567
-		}
568
-		utils.Debugf("Waiting for removal of %s: exists=%d", devname, devinfo.Exists)
569
-		if devinfo.Exists == 0 {
570
-			break
571
-		}
572
-		time.Sleep(1 * time.Millisecond)
573
-	}
574
-	if i == 1000 {
575
-		return fmt.Errorf("Timeout while waiting for device %s to be removed", devname)
576
-	}
577
-	return nil
578
-}
579
-
580
-// waitClose blocks until either:
581
-// a) the device registered at <device_set_prefix>-<hash> is closed,
582
-// or b) the 1 second timeout expires.
583
-func (devices *DeviceSet) waitClose(hash string) error {
584
-	devname, err := devices.byHash(hash)
585
-	if err != nil {
586
-		return err
587
-	}
588
-	i := 0
589
-	for ; i < 1000; i += 1 {
590
-		devinfo, err := getInfo(devname)
591
-		if err != nil {
592
-			return err
593
-		}
594
-		utils.Debugf("Waiting for unmount of %s: opencount=%d", devname, devinfo.OpenCount)
595
-		if devinfo.OpenCount == 0 {
596
-			break
597
-		}
598
-		time.Sleep(1 * time.Millisecond)
599
-	}
600
-	if i == 1000 {
601
-		return fmt.Errorf("Timeout while waiting for device %s to close", devname)
602
-	}
603
-	return nil
604
-}
605
-
606
-// byHash is a hack to allow looking up the deviceset's pool by the hash "pool".
607
-// FIXME: it seems probably cleaner to register the pool in devices.Devices,
608
-// but I am afraid of arcane implications deep in the devicemapper code,
609
-// so this will do.
610
-func (devices *DeviceSet) byHash(hash string) (devname string, err error) {
611
-	if hash == "pool" {
612
-		return devices.getPoolDevName(), nil
613
-	}
614
-	info := devices.Devices[hash]
615
-	if info == nil {
616
-		return "", fmt.Errorf("hash %s doesn't exists", hash)
617
-	}
618
-	return info.Name(), nil
619
-}
620
-
621
-func (devices *DeviceSet) Shutdown() error {
622
-	utils.Debugf("[deviceset %s] shutdown()", devices.devicePrefix)
623
-	defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
624
-	devices.Lock()
625
-	utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
626
-	defer devices.Unlock()
627
-
628
-	for path, count := range devices.activeMounts {
629
-		for i := count; i > 0; i-- {
630
-			if err := syscall.Unmount(path, 0); err != nil {
631
-				utils.Debugf("Shutdown unmounting %s, error: %s\n", path, err)
632
-			}
633
-		}
634
-		delete(devices.activeMounts, path)
635
-	}
636
-
637
-	for _, d := range devices.Devices {
638
-		if err := devices.waitClose(d.Hash); err != nil {
639
-			utils.Errorf("Warning: error waiting for device %s to unmount: %s\n", d.Hash, err)
640
-		}
641
-		if err := devices.deactivateDevice(d.Hash); err != nil {
642
-			utils.Debugf("Shutdown deactivate %s , error: %s\n", d.Hash, err)
643
-		}
644
-	}
645
-
646
-	pool := devices.getPoolDevName()
647
-	if devinfo, err := getInfo(pool); err == nil && devinfo.Exists != 0 {
648
-		if err := devices.deactivateDevice("pool"); err != nil {
649
-			utils.Debugf("Shutdown deactivate %s , error: %s\n", pool, err)
650
-		}
651
-	}
652
-
653
-	return nil
654
-}
655
-
656
-func (devices *DeviceSet) MountDevice(hash, path string, readOnly bool) error {
657
-	devices.Lock()
658
-	defer devices.Unlock()
659
-
660
-	if err := devices.activateDeviceIfNeeded(hash); err != nil {
661
-		return fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
662
-	}
663
-
664
-	info := devices.Devices[hash]
665
-
666
-	var flags uintptr = syscall.MS_MGC_VAL
667
-
668
-	if readOnly {
669
-		flags = flags | syscall.MS_RDONLY
670
-	}
671
-
672
-	err := syscall.Mount(info.DevName(), path, "ext4", flags, "discard")
673
-	if err != nil && err == syscall.EINVAL {
674
-		err = syscall.Mount(info.DevName(), path, "ext4", flags, "")
675
-	}
676
-	if err != nil {
677
-		return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err)
678
-	}
679
-
680
-	count := devices.activeMounts[path]
681
-	devices.activeMounts[path] = count + 1
682
-
683
-	return devices.setInitialized(hash)
684
-}
685
-
686
-func (devices *DeviceSet) UnmountDevice(hash, path string, deactivate bool) error {
687
-	utils.Debugf("[devmapper] UnmountDevice(hash=%s path=%s)", hash, path)
688
-	defer utils.Debugf("[devmapper] UnmountDevice END")
689
-	devices.Lock()
690
-	defer devices.Unlock()
691
-
692
-	utils.Debugf("[devmapper] Unmount(%s)", path)
693
-	if err := syscall.Unmount(path, 0); err != nil {
694
-		utils.Debugf("\n--->Err: %s\n", err)
695
-		return err
696
-	}
697
-	utils.Debugf("[devmapper] Unmount done")
698
-	// Wait for the unmount to be effective,
699
-	// by watching the value of Info.OpenCount for the device
700
-	if err := devices.waitClose(hash); err != nil {
701
-		return err
702
-	}
703
-
704
-	if count := devices.activeMounts[path]; count > 1 {
705
-		devices.activeMounts[path] = count - 1
706
-	} else {
707
-		delete(devices.activeMounts, path)
708
-	}
709
-
710
-	if deactivate {
711
-		devices.deactivateDevice(hash)
712
-	}
713
-
714
-	return nil
715
-}
716
-
717
-func (devices *DeviceSet) HasDevice(hash string) bool {
718
-	devices.Lock()
719
-	defer devices.Unlock()
720
-
721
-	return devices.Devices[hash] != nil
722
-}
723
-
724
-func (devices *DeviceSet) HasInitializedDevice(hash string) bool {
725
-	devices.Lock()
726
-	defer devices.Unlock()
727
-
728
-	info := devices.Devices[hash]
729
-	return info != nil && info.Initialized
730
-}
731
-
732
-func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
733
-	devices.Lock()
734
-	defer devices.Unlock()
735
-
736
-	info := devices.Devices[hash]
737
-	if info == nil {
738
-		return false
739
-	}
740
-	devinfo, _ := getInfo(info.Name())
741
-	return devinfo != nil && devinfo.Exists != 0
742
-}
743
-
744
-func (devices *DeviceSet) setInitialized(hash string) error {
745
-	info := devices.Devices[hash]
746
-	if info == nil {
747
-		return fmt.Errorf("Unknown device %s", hash)
748
-	}
749
-
750
-	info.Initialized = true
751
-	if err := devices.saveMetadata(); err != nil {
752
-		info.Initialized = false
753
-		utils.Debugf("\n--->Err: %s\n", err)
754
-		return err
755
-	}
756
-
757
-	return nil
758
-}
759
-
760
-func (devices *DeviceSet) Status() *Status {
761
-	devices.Lock()
762
-	defer devices.Unlock()
763
-
764
-	status := &Status{}
765
-
766
-	status.PoolName = devices.getPoolName()
767
-	status.DataLoopback = path.Join(devices.loopbackDir(), "data")
768
-	status.MetadataLoopback = path.Join(devices.loopbackDir(), "metadata")
769
-
770
-	_, totalSizeInSectors, _, params, err := getStatus(devices.getPoolName())
771
-	if err == nil {
772
-		var transactionId, dataUsed, dataTotal, metadataUsed, metadataTotal uint64
773
-		if _, err := fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionId, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal); err == nil {
774
-			// Convert from blocks to bytes
775
-			blockSizeInSectors := totalSizeInSectors / dataTotal
776
-
777
-			status.Data.Used = dataUsed * blockSizeInSectors * 512
778
-			status.Data.Total = dataTotal * blockSizeInSectors * 512
779
-
780
-			// metadata blocks are always 4k
781
-			status.Metadata.Used = metadataUsed * 4096
782
-			status.Metadata.Total = metadataTotal * 4096
783
-		}
784
-	}
785
-
786
-	return status
787
-}
788
-
789
-func NewDeviceSet(root string) (*DeviceSet, error) {
790
-	SetDevDir("/dev")
791
-
792
-	devices := &DeviceSet{
793
-		root:         root,
794
-		MetaData:     MetaData{Devices: make(map[string]*DevInfo)},
795
-		activeMounts: make(map[string]int),
796
-	}
797
-
798
-	if err := devices.initDevmapper(); err != nil {
799
-		return nil, err
800
-	}
801
-
802
-	return devices, nil
803
-}
804 1
deleted file mode 100644
... ...
@@ -1,505 +0,0 @@
1
-package devmapper
2
-
3
-import (
4
-	"errors"
5
-	"fmt"
6
-	"github.com/dotcloud/docker/utils"
7
-	"os"
8
-	"runtime"
9
-)
10
-
11
-type DevmapperLogger interface {
12
-	log(level int, file string, line int, dmError int, message string)
13
-}
14
-
15
-const (
16
-	DeviceCreate TaskType = iota
17
-	DeviceReload
18
-	DeviceRemove
19
-	DeviceRemoveAll
20
-	DeviceSuspend
21
-	DeviceResume
22
-	DeviceInfo
23
-	DeviceDeps
24
-	DeviceRename
25
-	DeviceVersion
26
-	DeviceStatus
27
-	DeviceTable
28
-	DeviceWaitevent
29
-	DeviceList
30
-	DeviceClear
31
-	DeviceMknodes
32
-	DeviceListVersions
33
-	DeviceTargetMsg
34
-	DeviceSetGeometry
35
-)
36
-
37
-const (
38
-	AddNodeOnResume AddNodeType = iota
39
-	AddNodeOnCreate
40
-)
41
-
42
-var (
43
-	ErrTaskRun              = errors.New("dm_task_run failed")
44
-	ErrTaskSetName          = errors.New("dm_task_set_name failed")
45
-	ErrTaskSetMessage       = errors.New("dm_task_set_message failed")
46
-	ErrTaskSetAddNode       = errors.New("dm_task_set_add_node failed")
47
-	ErrTaskSetRo            = errors.New("dm_task_set_ro failed")
48
-	ErrTaskAddTarget        = errors.New("dm_task_add_target failed")
49
-	ErrTaskSetSector        = errors.New("dm_task_set_sector failed")
50
-	ErrTaskGetInfo          = errors.New("dm_task_get_info failed")
51
-	ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version 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
-)
63
-
64
-type (
65
-	Task struct {
66
-		unmanaged *CDmTask
67
-	}
68
-	Info struct {
69
-		Exists        int
70
-		Suspended     int
71
-		LiveTable     int
72
-		InactiveTable int
73
-		OpenCount     int32
74
-		EventNr       uint32
75
-		Major         uint32
76
-		Minor         uint32
77
-		ReadOnly      int
78
-		TargetCount   int32
79
-	}
80
-	TaskType    int
81
-	AddNodeType int
82
-)
83
-
84
-func (t *Task) destroy() {
85
-	if t != nil {
86
-		DmTaskDestory(t.unmanaged)
87
-		runtime.SetFinalizer(t, nil)
88
-	}
89
-}
90
-
91
-func TaskCreate(tasktype TaskType) *Task {
92
-	Ctask := DmTaskCreate(int(tasktype))
93
-	if Ctask == nil {
94
-		return nil
95
-	}
96
-	task := &Task{unmanaged: Ctask}
97
-	runtime.SetFinalizer(task, (*Task).destroy)
98
-	return task
99
-}
100
-
101
-func (t *Task) Run() error {
102
-	if res := DmTaskRun(t.unmanaged); res != 1 {
103
-		return ErrTaskRun
104
-	}
105
-	return nil
106
-}
107
-
108
-func (t *Task) SetName(name string) error {
109
-	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
110
-		return ErrTaskSetName
111
-	}
112
-	return nil
113
-}
114
-
115
-func (t *Task) SetMessage(message string) error {
116
-	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
117
-		return ErrTaskSetMessage
118
-	}
119
-	return nil
120
-}
121
-
122
-func (t *Task) SetSector(sector uint64) error {
123
-	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
124
-		return ErrTaskSetSector
125
-	}
126
-	return nil
127
-}
128
-
129
-func (t *Task) SetCookie(cookie *uint, flags uint16) error {
130
-	if cookie == nil {
131
-		return ErrNilCookie
132
-	}
133
-	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
134
-		return ErrTaskSetCookie
135
-	}
136
-	return nil
137
-}
138
-
139
-func (t *Task) SetAddNode(addNode AddNodeType) error {
140
-	if addNode != AddNodeOnResume && addNode != AddNodeOnCreate {
141
-		return ErrInvalidAddNode
142
-	}
143
-	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
144
-		return ErrTaskSetAddNode
145
-	}
146
-	return nil
147
-}
148
-
149
-func (t *Task) SetRo() error {
150
-	if res := DmTaskSetRo(t.unmanaged); res != 1 {
151
-		return ErrTaskSetRo
152
-	}
153
-	return nil
154
-}
155
-
156
-func (t *Task) AddTarget(start, size uint64, ttype, params string) error {
157
-	if res := DmTaskAddTarget(t.unmanaged, start, size,
158
-		ttype, params); res != 1 {
159
-		return ErrTaskAddTarget
160
-	}
161
-	return nil
162
-}
163
-
164
-func (t *Task) GetInfo() (*Info, error) {
165
-	info := &Info{}
166
-	if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
167
-		return nil, ErrTaskGetInfo
168
-	}
169
-	return info, nil
170
-}
171
-
172
-func (t *Task) GetNextTarget(next uintptr) (nextPtr uintptr, start uint64,
173
-	length uint64, targetType string, params string) {
174
-
175
-	return DmGetNextTarget(t.unmanaged, next, &start, &length,
176
-			&targetType, &params),
177
-		start, length, targetType, params
178
-}
179
-
180
-func AttachLoopDevice(filename string) (*os.File, error) {
181
-	var fd int
182
-	res := DmAttachLoopDevice(filename, &fd)
183
-	if res == "" {
184
-		return nil, ErrAttachLoopbackDevice
185
-	}
186
-	return os.NewFile(uintptr(fd), res), nil
187
-}
188
-
189
-func UdevWait(cookie uint) error {
190
-	if res := DmUdevWait(cookie); res != 1 {
191
-		utils.Debugf("Failed to wait on udev cookie %d", cookie)
192
-		return ErrUdevWait
193
-	}
194
-	return nil
195
-}
196
-
197
-func LogInitVerbose(level int) {
198
-	DmLogInitVerbose(level)
199
-}
200
-
201
-var dmLogger DevmapperLogger = nil
202
-
203
-func logInit(logger DevmapperLogger) {
204
-	dmLogger = logger
205
-	LogWithErrnoInit()
206
-}
207
-
208
-func SetDevDir(dir string) error {
209
-	if res := DmSetDevDir(dir); res != 1 {
210
-		utils.Debugf("Error dm_set_dev_dir")
211
-		return ErrSetDevDir
212
-	}
213
-	return nil
214
-}
215
-
216
-func GetLibraryVersion() (string, error) {
217
-	var version string
218
-	if res := DmGetLibraryVersion(&version); res != 1 {
219
-		return "", ErrGetLibraryVersion
220
-	}
221
-	return version, nil
222
-}
223
-
224
-// Useful helper for cleanup
225
-func RemoveDevice(name string) error {
226
-	task := TaskCreate(DeviceRemove)
227
-	if task == nil {
228
-		return ErrCreateRemoveTask
229
-	}
230
-	if err := task.SetName(name); err != nil {
231
-		utils.Debugf("Can't set task name %s", name)
232
-		return err
233
-	}
234
-	if err := task.Run(); err != nil {
235
-		return ErrRunRemoveDevice
236
-	}
237
-	return nil
238
-}
239
-
240
-func GetBlockDeviceSize(file *os.File) (uint64, error) {
241
-	size, errno := DmGetBlockSize(file.Fd())
242
-	if size == -1 || errno != 0 {
243
-		return 0, ErrGetBlockSize
244
-	}
245
-	return uint64(size), nil
246
-}
247
-
248
-// This is the programmatic example of "dmsetup create"
249
-func createPool(poolName string, dataFile *os.File, metadataFile *os.File) error {
250
-	task, err := createTask(DeviceCreate, poolName)
251
-	if task == nil {
252
-		return err
253
-	}
254
-
255
-	size, err := GetBlockDeviceSize(dataFile)
256
-	if err != nil {
257
-		return fmt.Errorf("Can't get data size")
258
-	}
259
-
260
-	params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
261
-	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
262
-		return fmt.Errorf("Can't add target")
263
-	}
264
-
265
-	var cookie uint = 0
266
-	if err := task.SetCookie(&cookie, 0); err != nil {
267
-		return fmt.Errorf("Can't set cookie")
268
-	}
269
-
270
-	if err := task.Run(); err != nil {
271
-		return fmt.Errorf("Error running DeviceCreate (createPool)")
272
-	}
273
-
274
-	UdevWait(cookie)
275
-
276
-	return nil
277
-}
278
-
279
-func createTask(t TaskType, name string) (*Task, error) {
280
-	task := TaskCreate(t)
281
-	if task == nil {
282
-		return nil, fmt.Errorf("Can't create task of type %d", int(t))
283
-	}
284
-	if err := task.SetName(name); err != nil {
285
-		return nil, fmt.Errorf("Can't set task name %s", name)
286
-	}
287
-	return task, nil
288
-}
289
-
290
-func getInfo(name string) (*Info, error) {
291
-	task, err := createTask(DeviceInfo, name)
292
-	if task == nil {
293
-		return nil, err
294
-	}
295
-	if err := task.Run(); err != nil {
296
-		return nil, err
297
-	}
298
-	return task.GetInfo()
299
-}
300
-
301
-func getStatus(name string) (uint64, uint64, string, string, error) {
302
-	task, err := createTask(DeviceStatus, name)
303
-	if task == nil {
304
-		utils.Debugf("getStatus: Error createTask: %s", err)
305
-		return 0, 0, "", "", err
306
-	}
307
-	if err := task.Run(); err != nil {
308
-		utils.Debugf("getStatus: Error Run: %s", err)
309
-		return 0, 0, "", "", err
310
-	}
311
-
312
-	devinfo, err := task.GetInfo()
313
-	if err != nil {
314
-		utils.Debugf("getStatus: Error GetInfo: %s", err)
315
-		return 0, 0, "", "", err
316
-	}
317
-	if devinfo.Exists == 0 {
318
-		utils.Debugf("getStatus: Non existing device %s", name)
319
-		return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
320
-	}
321
-
322
-	_, start, length, target_type, params := task.GetNextTarget(0)
323
-	return start, length, target_type, params, nil
324
-}
325
-
326
-func setTransactionId(poolName string, oldId uint64, newId uint64) error {
327
-	task, err := createTask(DeviceTargetMsg, poolName)
328
-	if task == nil {
329
-		return err
330
-	}
331
-
332
-	if err := task.SetSector(0); err != nil {
333
-		return fmt.Errorf("Can't set sector")
334
-	}
335
-
336
-	if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
337
-		return fmt.Errorf("Can't set message")
338
-	}
339
-
340
-	if err := task.Run(); err != nil {
341
-		return fmt.Errorf("Error running setTransactionId")
342
-	}
343
-	return nil
344
-}
345
-
346
-func suspendDevice(name string) error {
347
-	task, err := createTask(DeviceSuspend, name)
348
-	if task == nil {
349
-		return err
350
-	}
351
-	if err := task.Run(); err != nil {
352
-		return fmt.Errorf("Error running DeviceSuspend")
353
-	}
354
-	return nil
355
-}
356
-
357
-func resumeDevice(name string) error {
358
-	task, err := createTask(DeviceResume, name)
359
-	if task == nil {
360
-		return err
361
-	}
362
-
363
-	var cookie uint = 0
364
-	if err := task.SetCookie(&cookie, 0); err != nil {
365
-		return fmt.Errorf("Can't set cookie")
366
-	}
367
-
368
-	if err := task.Run(); err != nil {
369
-		return fmt.Errorf("Error running DeviceSuspend")
370
-	}
371
-
372
-	UdevWait(cookie)
373
-
374
-	return nil
375
-}
376
-
377
-func createDevice(poolName string, deviceId int) error {
378
-	utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
379
-	task, err := createTask(DeviceTargetMsg, poolName)
380
-	if task == nil {
381
-		return err
382
-	}
383
-
384
-	if err := task.SetSector(0); err != nil {
385
-		return fmt.Errorf("Can't set sector")
386
-	}
387
-
388
-	if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
389
-		return fmt.Errorf("Can't set message")
390
-	}
391
-
392
-	if err := task.Run(); err != nil {
393
-		return fmt.Errorf("Error running createDevice")
394
-	}
395
-	return nil
396
-}
397
-
398
-func deleteDevice(poolName string, deviceId int) error {
399
-	task, err := createTask(DeviceTargetMsg, poolName)
400
-	if task == nil {
401
-		return err
402
-	}
403
-
404
-	if err := task.SetSector(0); err != nil {
405
-		return fmt.Errorf("Can't set sector")
406
-	}
407
-
408
-	if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
409
-		return fmt.Errorf("Can't set message")
410
-	}
411
-
412
-	if err := task.Run(); err != nil {
413
-		return fmt.Errorf("Error running deleteDevice")
414
-	}
415
-	return nil
416
-}
417
-
418
-func removeDevice(name string) error {
419
-	utils.Debugf("[devmapper] removeDevice START")
420
-	defer utils.Debugf("[devmapper] removeDevice END")
421
-	task, err := createTask(DeviceRemove, name)
422
-	if task == nil {
423
-		return err
424
-	}
425
-	if err = task.Run(); err != nil {
426
-		return fmt.Errorf("Error running removeDevice")
427
-	}
428
-	return nil
429
-}
430
-
431
-func activateDevice(poolName string, name string, deviceId int, size uint64) error {
432
-	task, err := createTask(DeviceCreate, name)
433
-	if task == nil {
434
-		return err
435
-	}
436
-
437
-	params := fmt.Sprintf("%s %d", poolName, deviceId)
438
-	if err := task.AddTarget(0, size/512, "thin", params); err != nil {
439
-		return fmt.Errorf("Can't add target")
440
-	}
441
-	if err := task.SetAddNode(AddNodeOnCreate); err != nil {
442
-		return fmt.Errorf("Can't add node")
443
-	}
444
-
445
-	var cookie uint = 0
446
-	if err := task.SetCookie(&cookie, 0); err != nil {
447
-		return fmt.Errorf("Can't set cookie")
448
-	}
449
-
450
-	if err := task.Run(); err != nil {
451
-		return fmt.Errorf("Error running DeviceCreate (activateDevice)")
452
-	}
453
-
454
-	UdevWait(cookie)
455
-
456
-	return nil
457
-}
458
-
459
-func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
460
-	devinfo, _ := getInfo(baseName)
461
-	doSuspend := devinfo != nil && devinfo.Exists != 0
462
-
463
-	if doSuspend {
464
-		if err := suspendDevice(baseName); err != nil {
465
-			return err
466
-		}
467
-	}
468
-
469
-	task, err := createTask(DeviceTargetMsg, poolName)
470
-	if task == nil {
471
-		if doSuspend {
472
-			resumeDevice(baseName)
473
-		}
474
-		return err
475
-	}
476
-
477
-	if err := task.SetSector(0); err != nil {
478
-		if doSuspend {
479
-			resumeDevice(baseName)
480
-		}
481
-		return fmt.Errorf("Can't set sector")
482
-	}
483
-
484
-	if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
485
-		if doSuspend {
486
-			resumeDevice(baseName)
487
-		}
488
-		return fmt.Errorf("Can't set message")
489
-	}
490
-
491
-	if err := task.Run(); err != nil {
492
-		if doSuspend {
493
-			resumeDevice(baseName)
494
-		}
495
-		return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
496
-	}
497
-
498
-	if doSuspend {
499
-		if err := resumeDevice(baseName); err != nil {
500
-			return err
501
-		}
502
-	}
503
-
504
-	return nil
505
-}
506 1
deleted file mode 100644
... ...
@@ -1,13 +0,0 @@
1
-package devmapper
2
-
3
-import "C"
4
-
5
-// Due to the way cgo works this has to be in a separate file, as devmapper.go has
6
-// definitions in the cgo block, which is incompatible with using "//export"
7
-
8
-//export DevmapperLogCallback
9
-func DevmapperLogCallback(level C.int, file *C.char, line C.int, dm_errno_or_class C.int, message *C.char) {
10
-	if dmLogger != nil {
11
-		dmLogger.log(int(level), C.GoString(file), int(line), int(dm_errno_or_class), C.GoString(message))
12
-	}
13
-}
14 1
deleted file mode 100644
... ...
@@ -1,285 +0,0 @@
1
-package devmapper
2
-
3
-import (
4
-	"syscall"
5
-	"testing"
6
-)
7
-
8
-func TestTaskCreate(t *testing.T) {
9
-	// Test success
10
-	taskCreate(t, DeviceInfo)
11
-
12
-	// Test Failure
13
-	DmTaskCreate = dmTaskCreateFail
14
-	defer func() { DmTaskCreate = dmTaskCreateFct }()
15
-	if task := TaskCreate(-1); task != nil {
16
-		t.Fatalf("An error should have occured while creating an invalid task.")
17
-	}
18
-}
19
-
20
-func TestTaskRun(t *testing.T) {
21
-	task := taskCreate(t, DeviceInfo)
22
-
23
-	// Test success
24
-	// Perform the RUN
25
-	if err := task.Run(); err != nil {
26
-		t.Fatal(err)
27
-	}
28
-	// Make sure we don't have error with GetInfo
29
-	if _, err := task.GetInfo(); err != nil {
30
-		t.Fatal(err)
31
-	}
32
-
33
-	// Test failure
34
-	DmTaskRun = dmTaskRunFail
35
-	defer func() { DmTaskRun = dmTaskRunFct }()
36
-
37
-	task = taskCreate(t, DeviceInfo)
38
-	// Perform the RUN
39
-	if err := task.Run(); err != ErrTaskRun {
40
-		t.Fatalf("An error should have occured while running task.")
41
-	}
42
-	// Make sure GetInfo also fails
43
-	if _, err := task.GetInfo(); err != ErrTaskGetInfo {
44
-		t.Fatalf("GetInfo should fail if task.Run() failed.")
45
-	}
46
-}
47
-
48
-func TestTaskSetName(t *testing.T) {
49
-	task := taskCreate(t, DeviceInfo)
50
-
51
-	// Test success
52
-	if err := task.SetName("test"); err != nil {
53
-		t.Fatal(err)
54
-	}
55
-
56
-	// Test failure
57
-	DmTaskSetName = dmTaskSetNameFail
58
-	defer func() { DmTaskSetName = dmTaskSetNameFct }()
59
-
60
-	if err := task.SetName("test"); err != ErrTaskSetName {
61
-		t.Fatalf("An error should have occured while runnign SetName.")
62
-	}
63
-}
64
-
65
-func TestTaskSetMessage(t *testing.T) {
66
-	task := taskCreate(t, DeviceInfo)
67
-
68
-	// Test success
69
-	if err := task.SetMessage("test"); err != nil {
70
-		t.Fatal(err)
71
-	}
72
-
73
-	// Test failure
74
-	DmTaskSetMessage = dmTaskSetMessageFail
75
-	defer func() { DmTaskSetMessage = dmTaskSetMessageFct }()
76
-
77
-	if err := task.SetMessage("test"); err != ErrTaskSetMessage {
78
-		t.Fatalf("An error should have occured while runnign SetMessage.")
79
-	}
80
-}
81
-
82
-func TestTaskSetSector(t *testing.T) {
83
-	task := taskCreate(t, DeviceInfo)
84
-
85
-	// Test success
86
-	if err := task.SetSector(128); err != nil {
87
-		t.Fatal(err)
88
-	}
89
-
90
-	DmTaskSetSector = dmTaskSetSectorFail
91
-	defer func() { DmTaskSetSector = dmTaskSetSectorFct }()
92
-
93
-	// Test failure
94
-	if err := task.SetSector(0); err != ErrTaskSetSector {
95
-		t.Fatalf("An error should have occured while running SetSector.")
96
-	}
97
-}
98
-
99
-func TestTaskSetCookie(t *testing.T) {
100
-	var (
101
-		cookie uint = 0
102
-		task        = taskCreate(t, DeviceInfo)
103
-	)
104
-
105
-	// Test success
106
-	if err := task.SetCookie(&cookie, 0); err != nil {
107
-		t.Fatal(err)
108
-	}
109
-
110
-	// Test failure
111
-	if err := task.SetCookie(nil, 0); err != ErrNilCookie {
112
-		t.Fatalf("An error should have occured while running SetCookie with nil cookie.")
113
-	}
114
-
115
-	DmTaskSetCookie = dmTaskSetCookieFail
116
-	defer func() { DmTaskSetCookie = dmTaskSetCookieFct }()
117
-
118
-	if err := task.SetCookie(&cookie, 0); err != ErrTaskSetCookie {
119
-		t.Fatalf("An error should have occured while running SetCookie.")
120
-	}
121
-}
122
-
123
-func TestTaskSetAddNode(t *testing.T) {
124
-	task := taskCreate(t, DeviceInfo)
125
-
126
-	// Test success
127
-	if err := task.SetAddNode(0); err != nil {
128
-		t.Fatal(err)
129
-	}
130
-
131
-	// Test failure
132
-	if err := task.SetAddNode(-1); err != ErrInvalidAddNode {
133
-		t.Fatalf("An error should have occured running SetAddNode with wrong node.")
134
-	}
135
-
136
-	DmTaskSetAddNode = dmTaskSetAddNodeFail
137
-	defer func() { DmTaskSetAddNode = dmTaskSetAddNodeFct }()
138
-
139
-	if err := task.SetAddNode(0); err != ErrTaskSetAddNode {
140
-		t.Fatalf("An error should have occured running SetAddNode.")
141
-	}
142
-}
143
-
144
-func TestTaskSetRo(t *testing.T) {
145
-	task := taskCreate(t, DeviceInfo)
146
-
147
-	// Test success
148
-	if err := task.SetRo(); err != nil {
149
-		t.Fatal(err)
150
-	}
151
-
152
-	// Test failure
153
-	DmTaskSetRo = dmTaskSetRoFail
154
-	defer func() { DmTaskSetRo = dmTaskSetRoFct }()
155
-
156
-	if err := task.SetRo(); err != ErrTaskSetRo {
157
-		t.Fatalf("An error should have occured running SetRo.")
158
-	}
159
-}
160
-
161
-func TestTaskAddTarget(t *testing.T) {
162
-	task := taskCreate(t, DeviceInfo)
163
-
164
-	// Test success
165
-	if err := task.AddTarget(0, 128, "thinp", ""); err != nil {
166
-		t.Fatal(err)
167
-	}
168
-
169
-	// Test failure
170
-	DmTaskAddTarget = dmTaskAddTargetFail
171
-	defer func() { DmTaskAddTarget = dmTaskAddTargetFct }()
172
-
173
-	if err := task.AddTarget(0, 128, "thinp", ""); err != ErrTaskAddTarget {
174
-		t.Fatalf("An error should have occured running AddTarget.")
175
-	}
176
-}
177
-
178
-// func TestTaskGetInfo(t *testing.T) {
179
-// 	task := taskCreate(t, DeviceInfo)
180
-
181
-// 	// Test success
182
-// 	if _, err := task.GetInfo(); err != nil {
183
-// 		t.Fatal(err)
184
-// 	}
185
-
186
-// 	// Test failure
187
-// 	DmTaskGetInfo = dmTaskGetInfoFail
188
-// 	defer func() { DmTaskGetInfo = dmTaskGetInfoFct }()
189
-
190
-// 	if _, err := task.GetInfo(); err != ErrTaskGetInfo {
191
-// 		t.Fatalf("An error should have occured running GetInfo.")
192
-// 	}
193
-// }
194
-
195
-// func TestTaskGetNextTarget(t *testing.T) {
196
-// 	task := taskCreate(t, DeviceInfo)
197
-
198
-// 	if next, _, _, _, _ := task.GetNextTarget(0); next == 0 {
199
-// 		t.Fatalf("The next target should not be 0.")
200
-// 	}
201
-// }
202
-
203
-/// Utils
204
-func taskCreate(t *testing.T, taskType TaskType) *Task {
205
-	task := TaskCreate(taskType)
206
-	if task == nil {
207
-		t.Fatalf("Error creating task")
208
-	}
209
-	return task
210
-}
211
-
212
-/// Failure function replacement
213
-func dmTaskCreateFail(t int) *CDmTask {
214
-	return nil
215
-}
216
-
217
-func dmTaskRunFail(task *CDmTask) int {
218
-	return -1
219
-}
220
-
221
-func dmTaskSetNameFail(task *CDmTask, name string) int {
222
-	return -1
223
-}
224
-
225
-func dmTaskSetMessageFail(task *CDmTask, message string) int {
226
-	return -1
227
-}
228
-
229
-func dmTaskSetSectorFail(task *CDmTask, sector uint64) int {
230
-	return -1
231
-}
232
-
233
-func dmTaskSetCookieFail(task *CDmTask, cookie *uint, flags uint16) int {
234
-	return -1
235
-}
236
-
237
-func dmTaskSetAddNodeFail(task *CDmTask, addNode AddNodeType) int {
238
-	return -1
239
-}
240
-
241
-func dmTaskSetRoFail(task *CDmTask) int {
242
-	return -1
243
-}
244
-
245
-func dmTaskAddTargetFail(task *CDmTask,
246
-	start, size uint64, ttype, params string) int {
247
-	return -1
248
-}
249
-
250
-func dmTaskGetDriverVersionFail(task *CDmTask, version *string) int {
251
-	return -1
252
-}
253
-
254
-func dmTaskGetInfoFail(task *CDmTask, info *Info) int {
255
-	return -1
256
-}
257
-
258
-func dmGetNextTargetFail(task *CDmTask, next uintptr, start, length *uint64,
259
-	target, params *string) uintptr {
260
-	return 0
261
-}
262
-
263
-func dmAttachLoopDeviceFail(filename string, fd *int) string {
264
-	return ""
265
-}
266
-
267
-func sysGetBlockSizeFail(fd uintptr, size *uint64) syscall.Errno {
268
-	return 1
269
-}
270
-
271
-func dmGetBlockSizeFail(fd uintptr) int64 {
272
-	return -1
273
-}
274
-
275
-func dmUdevWaitFail(cookie uint) int {
276
-	return -1
277
-}
278
-
279
-func dmSetDevDirFail(dir string) int {
280
-	return -1
281
-}
282
-
283
-func dmGetLibraryVersionFail(version *string) int {
284
-	return -1
285
-}
286 1
deleted file mode 100644
... ...
@@ -1,330 +0,0 @@
1
-package devmapper
2
-
3
-/*
4
-#cgo LDFLAGS: -L. -ldevmapper
5
-#include <stdio.h>
6
-#include <stdlib.h>
7
-#include <unistd.h>
8
-#include <libdevmapper.h>
9
-#include <linux/loop.h>
10
-#include <sys/types.h>
11
-#include <sys/stat.h>
12
-#include <fcntl.h>
13
-#include <sys/ioctl.h>
14
-#include <linux/fs.h>
15
-#include <errno.h>
16
-
17
-#ifndef LOOP_CTL_GET_FREE
18
-#define LOOP_CTL_GET_FREE       0x4C82
19
-#endif
20
-
21
-// FIXME: this could easily be rewritten in go
22
-char*			attach_loop_device(const char *filename, int *loop_fd_out)
23
-{
24
-  struct loop_info64	loopinfo = {0};
25
-  struct stat		st;
26
-  char			buf[64];
27
-  int			i, loop_fd, fd, start_index;
28
-  char*			loopname;
29
-
30
-
31
-  *loop_fd_out = -1;
32
-
33
-  start_index = 0;
34
-  fd = open("/dev/loop-control", O_RDONLY);
35
-  if (fd >= 0) {
36
-    start_index = ioctl(fd, LOOP_CTL_GET_FREE);
37
-    close(fd);
38
-
39
-    if (start_index < 0)
40
-      start_index = 0;
41
-  }
42
-
43
-  fd = open(filename, O_RDWR);
44
-  if (fd < 0) {
45
-    perror("open");
46
-    return NULL;
47
-  }
48
-
49
-  loop_fd = -1;
50
-  for (i = start_index ; loop_fd < 0 ; i++ ) {
51
-    if (sprintf(buf, "/dev/loop%d", i) < 0) {
52
-	close(fd);
53
-	return NULL;
54
-    }
55
-
56
-    if (stat(buf, &st)) {
57
-      if (!S_ISBLK(st.st_mode)) {
58
-	 fprintf(stderr, "[error] Loopback device %s is not a block device.\n", buf);
59
-      } else if (errno == ENOENT) {
60
-	fprintf(stderr, "[error] There are no more loopback device available.\n");
61
-      } else {
62
-	fprintf(stderr, "[error] Unkown error trying to stat the loopback device %s (errno: %d).\n", buf, errno);
63
-      }
64
-      close(fd);
65
-      return NULL;
66
-    }
67
-
68
-    loop_fd = open(buf, O_RDWR);
69
-    if (loop_fd < 0 && errno == ENOENT) {
70
-      fprintf(stderr, "[error] The loopback device %s does not exists.\n", buf);
71
-      close(fd);
72
-      return NULL;
73
-    } else if (loop_fd < 0) {
74
-	fprintf(stderr, "[error] Unkown error openning the loopback device %s. (errno: %d)\n", buf, errno);
75
-	continue;
76
-    }
77
-
78
-    if (ioctl(loop_fd, LOOP_SET_FD, (void *)(size_t)fd) < 0) {
79
-      int errsv = errno;
80
-      close(loop_fd);
81
-      loop_fd = -1;
82
-      if (errsv != EBUSY) {
83
-        close(fd);
84
-        fprintf(stderr, "cannot set up loopback device %s: %s", buf, strerror(errsv));
85
-        return NULL;
86
-      }
87
-      continue;
88
-    }
89
-
90
-    close(fd);
91
-
92
-    strncpy((char*)loopinfo.lo_file_name, buf, LO_NAME_SIZE);
93
-    loopinfo.lo_offset = 0;
94
-    loopinfo.lo_flags = LO_FLAGS_AUTOCLEAR;
95
-
96
-    if (ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo) < 0) {
97
-      perror("ioctl LOOP_SET_STATUS64");
98
-      if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
99
-        perror("ioctl LOOP_CLR_FD");
100
-      }
101
-      close(loop_fd);
102
-      fprintf (stderr, "cannot set up loopback device info");
103
-      return (NULL);
104
-    }
105
-
106
-    loopname = strdup(buf);
107
-    if (loopname == NULL) {
108
-      close(loop_fd);
109
-      return (NULL);
110
-    }
111
-
112
-    *loop_fd_out = loop_fd;
113
-    return (loopname);
114
-  }
115
-
116
-  return (NULL);
117
-}
118
-
119
-extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
120
-
121
-static void	log_cb(int level, const char *file, int line,
122
-		       int dm_errno_or_class, const char *f, ...)
123
-{
124
-  char buffer[256];
125
-  va_list ap;
126
-
127
-  va_start(ap, f);
128
-  vsnprintf(buffer, 256, f, ap);
129
-  va_end(ap);
130
-
131
-  DevmapperLogCallback(level, (char *)file, line, dm_errno_or_class, buffer);
132
-}
133
-
134
-static void	log_with_errno_init()
135
-{
136
-  dm_log_with_errno_init(log_cb);
137
-}
138
-
139
-*/
140
-import "C"
141
-
142
-import (
143
-	"syscall"
144
-	"unsafe"
145
-)
146
-
147
-type (
148
-	CDmTask C.struct_dm_task
149
-)
150
-
151
-var (
152
-	DmTaskDestory       = dmTaskDestroyFct
153
-	DmTaskCreate        = dmTaskCreateFct
154
-	DmTaskRun           = dmTaskRunFct
155
-	DmTaskSetName       = dmTaskSetNameFct
156
-	DmTaskSetMessage    = dmTaskSetMessageFct
157
-	DmTaskSetSector     = dmTaskSetSectorFct
158
-	DmTaskSetCookie     = dmTaskSetCookieFct
159
-	DmTaskSetAddNode    = dmTaskSetAddNodeFct
160
-	DmTaskSetRo         = dmTaskSetRoFct
161
-	DmTaskAddTarget     = dmTaskAddTargetFct
162
-	DmTaskGetInfo       = dmTaskGetInfoFct
163
-	DmGetNextTarget     = dmGetNextTargetFct
164
-	DmGetBlockSize      = dmGetBlockSizeFct
165
-	DmAttachLoopDevice  = dmAttachLoopDeviceFct
166
-	DmUdevWait          = dmUdevWaitFct
167
-	DmLogInitVerbose    = dmLogInitVerboseFct
168
-	DmSetDevDir         = dmSetDevDirFct
169
-	DmGetLibraryVersion = dmGetLibraryVersionFct
170
-	LogWithErrnoInit    = logWithErrnoInitFct
171
-	GetBlockSize        = getBlockSizeFct
172
-)
173
-
174
-func free(p *C.char) {
175
-	C.free(unsafe.Pointer(p))
176
-}
177
-
178
-func dmTaskDestroyFct(task *CDmTask) {
179
-	C.dm_task_destroy((*C.struct_dm_task)(task))
180
-}
181
-
182
-func dmTaskCreateFct(taskType int) *CDmTask {
183
-	return (*CDmTask)(C.dm_task_create(C.int(taskType)))
184
-}
185
-
186
-func dmTaskRunFct(task *CDmTask) int {
187
-	return int(C.dm_task_run((*C.struct_dm_task)(task)))
188
-}
189
-
190
-func dmTaskSetNameFct(task *CDmTask, name string) int {
191
-	Cname := C.CString(name)
192
-	defer free(Cname)
193
-
194
-	return int(C.dm_task_set_name((*C.struct_dm_task)(task),
195
-		Cname))
196
-}
197
-
198
-func dmTaskSetMessageFct(task *CDmTask, message string) int {
199
-	Cmessage := C.CString(message)
200
-	defer free(Cmessage)
201
-
202
-	return int(C.dm_task_set_message((*C.struct_dm_task)(task),
203
-		Cmessage))
204
-}
205
-
206
-func dmTaskSetSectorFct(task *CDmTask, sector uint64) int {
207
-	return int(C.dm_task_set_sector((*C.struct_dm_task)(task),
208
-		C.uint64_t(sector)))
209
-}
210
-
211
-func dmTaskSetCookieFct(task *CDmTask, cookie *uint, flags uint16) int {
212
-	cCookie := C.uint32_t(*cookie)
213
-	defer func() {
214
-		*cookie = uint(cCookie)
215
-	}()
216
-	return int(C.dm_task_set_cookie((*C.struct_dm_task)(task), &cCookie,
217
-		C.uint16_t(flags)))
218
-}
219
-
220
-func dmTaskSetAddNodeFct(task *CDmTask, addNode AddNodeType) int {
221
-	return int(C.dm_task_set_add_node((*C.struct_dm_task)(task),
222
-		C.dm_add_node_t(addNode)))
223
-}
224
-
225
-func dmTaskSetRoFct(task *CDmTask) int {
226
-	return int(C.dm_task_set_ro((*C.struct_dm_task)(task)))
227
-}
228
-
229
-func dmTaskAddTargetFct(task *CDmTask,
230
-	start, size uint64, ttype, params string) int {
231
-
232
-	Cttype := C.CString(ttype)
233
-	defer free(Cttype)
234
-
235
-	Cparams := C.CString(params)
236
-	defer free(Cparams)
237
-
238
-	return int(C.dm_task_add_target((*C.struct_dm_task)(task),
239
-		C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
240
-}
241
-
242
-func dmGetBlockSizeFct(fd uintptr) (int64, syscall.Errno) {
243
-	var size int64
244
-	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BLKGETSIZE64,
245
-		uintptr(unsafe.Pointer(&size)))
246
-	return size, err
247
-}
248
-
249
-func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
250
-	Cinfo := C.struct_dm_info{}
251
-	defer func() {
252
-		info.Exists = int(Cinfo.exists)
253
-		info.Suspended = int(Cinfo.suspended)
254
-		info.LiveTable = int(Cinfo.live_table)
255
-		info.InactiveTable = int(Cinfo.inactive_table)
256
-		info.OpenCount = int32(Cinfo.open_count)
257
-		info.EventNr = uint32(Cinfo.event_nr)
258
-		info.Major = uint32(Cinfo.major)
259
-		info.Minor = uint32(Cinfo.minor)
260
-		info.ReadOnly = int(Cinfo.read_only)
261
-		info.TargetCount = int32(Cinfo.target_count)
262
-	}()
263
-	return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
264
-}
265
-
266
-func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64,
267
-	target, params *string) uintptr {
268
-
269
-	var (
270
-		Cstart, Clength      C.uint64_t
271
-		CtargetType, Cparams *C.char
272
-	)
273
-	defer func() {
274
-		*start = uint64(Cstart)
275
-		*length = uint64(Clength)
276
-		*target = C.GoString(CtargetType)
277
-		*params = C.GoString(Cparams)
278
-	}()
279
-	nextp := C.dm_get_next_target((*C.struct_dm_task)(task),
280
-		unsafe.Pointer(next), &Cstart, &Clength, &CtargetType, &Cparams)
281
-	return uintptr(nextp)
282
-}
283
-
284
-func dmAttachLoopDeviceFct(filename string, fd *int) string {
285
-	cFilename := C.CString(filename)
286
-	defer free(cFilename)
287
-
288
-	var cFd C.int
289
-	defer func() {
290
-		*fd = int(cFd)
291
-	}()
292
-
293
-	ret := C.attach_loop_device(cFilename, &cFd)
294
-	defer free(ret)
295
-	return C.GoString(ret)
296
-}
297
-
298
-func getBlockSizeFct(fd uintptr, size *uint64) syscall.Errno {
299
-	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BLKGETSIZE64,
300
-		uintptr(unsafe.Pointer(&size)))
301
-	return err
302
-}
303
-
304
-func dmUdevWaitFct(cookie uint) int {
305
-	return int(C.dm_udev_wait(C.uint32_t(cookie)))
306
-}
307
-
308
-func dmLogInitVerboseFct(level int) {
309
-	C.dm_log_init_verbose(C.int(level))
310
-}
311
-
312
-func logWithErrnoInitFct() {
313
-	C.log_with_errno_init()
314
-}
315
-
316
-func dmSetDevDirFct(dir string) int {
317
-	Cdir := C.CString(dir)
318
-	defer free(Cdir)
319
-
320
-	return int(C.dm_set_dev_dir(Cdir))
321
-}
322
-
323
-func dmGetLibraryVersionFct(version *string) int {
324
-	buffer := C.CString(string(make([]byte, 128)))
325
-	defer free(buffer)
326
-	defer func() {
327
-		*version = C.GoString(buffer)
328
-	}()
329
-	return int(C.dm_get_library_version(buffer, 128))
330
-}
331 1
deleted file mode 100644
... ...
@@ -1,62 +0,0 @@
1
-package main
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/devmapper"
6
-	"os"
7
-)
8
-
9
-func usage() {
10
-	fmt.Printf("Usage: %s [snap new-id base-id] | [remove id] | [mount id mountpoint]\n", os.Args[0])
11
-	os.Exit(1)
12
-}
13
-
14
-func main() {
15
-	devices := devmapper.NewDeviceSet("/var/lib/docker")
16
-
17
-	if len(os.Args) < 2 {
18
-		usage()
19
-	}
20
-
21
-	cmd := os.Args[1]
22
-	if cmd == "snap" {
23
-		if len(os.Args) < 4 {
24
-			usage()
25
-		}
26
-
27
-		err := devices.AddDevice(os.Args[2], os.Args[3])
28
-		if err != nil {
29
-			fmt.Println("Can't create snap device: ", err)
30
-			os.Exit(1)
31
-		}
32
-	} else if cmd == "remove" {
33
-		if len(os.Args) < 3 {
34
-			usage()
35
-		}
36
-
37
-		err := devices.RemoveDevice(os.Args[2])
38
-		if err != nil {
39
-			fmt.Println("Can't remove device: ", err)
40
-			os.Exit(1)
41
-		}
42
-	} else if cmd == "mount" {
43
-		if len(os.Args) < 4 {
44
-			usage()
45
-		}
46
-
47
-		err := devices.MountDevice(os.Args[2], os.Args[3])
48
-		if err != nil {
49
-			fmt.Println("Can't create snap device: ", err)
50
-			os.Exit(1)
51
-		}
52
-	} else {
53
-		fmt.Printf("Unknown command %s\n", cmd)
54
-		if len(os.Args) < 4 {
55
-			usage()
56
-		}
57
-
58
-		os.Exit(1)
59
-	}
60
-
61
-	return
62
-}
63 1
deleted file mode 100644
... ...
@@ -1,92 +0,0 @@
1
-package devmapper
2
-
3
-import (
4
-	"fmt"
5
-	"github.com/dotcloud/docker/graphdriver"
6
-	"os"
7
-	"path"
8
-)
9
-
10
-func init() {
11
-	graphdriver.Register("devicemapper", Init)
12
-}
13
-
14
-// Placeholder interfaces, to be replaced
15
-// at integration.
16
-
17
-// End of placeholder interfaces.
18
-
19
-type Driver struct {
20
-	*DeviceSet
21
-	home string
22
-}
23
-
24
-func Init(home string) (graphdriver.Driver, error) {
25
-	deviceSet, err := NewDeviceSet(home)
26
-	if err != nil {
27
-		return nil, err
28
-	}
29
-	d := &Driver{
30
-		DeviceSet: deviceSet,
31
-		home:      home,
32
-	}
33
-	return d, nil
34
-}
35
-
36
-func (d *Driver) String() string {
37
-	return "devicemapper"
38
-}
39
-
40
-func (d *Driver) Status() [][2]string {
41
-	s := d.DeviceSet.Status()
42
-
43
-	status := [][2]string{
44
-		{"Pool Name", s.PoolName},
45
-		{"Data file", s.DataLoopback},
46
-		{"Metadata file", s.MetadataLoopback},
47
-		{"Data Space Used", fmt.Sprintf("%.1f Mb", float64(s.Data.Used)/(1024*1024))},
48
-		{"Data Space Total", fmt.Sprintf("%.1f Mb", float64(s.Data.Total)/(1024*1024))},
49
-		{"Metadata Space Used", fmt.Sprintf("%.1f Mb", float64(s.Metadata.Used)/(1024*1024))},
50
-		{"Metadata Space Total", fmt.Sprintf("%.1f Mb", float64(s.Metadata.Total)/(1024*1024))},
51
-	}
52
-	return status
53
-}
54
-
55
-func (d *Driver) Cleanup() error {
56
-	return d.DeviceSet.Shutdown()
57
-}
58
-
59
-func (d *Driver) Create(id string, parent string) error {
60
-	return d.DeviceSet.AddDevice(id, parent)
61
-}
62
-
63
-func (d *Driver) Remove(id string) error {
64
-	return d.DeviceSet.RemoveDevice(id)
65
-}
66
-
67
-func (d *Driver) Get(id string) (string, error) {
68
-	mp := path.Join(d.home, "mnt", id)
69
-	if err := d.mount(id, mp); err != nil {
70
-		return "", err
71
-	}
72
-	return mp, nil
73
-}
74
-
75
-func (d *Driver) Size(id string) (int64, error) {
76
-	return -1, fmt.Errorf("Not implemented")
77
-}
78
-
79
-func (d *Driver) mount(id, mountPoint string) error {
80
-	// Create the target directories if they don't exist
81
-	if err := os.MkdirAll(mountPoint, 0755); err != nil && !os.IsExist(err) {
82
-		return err
83
-	}
84
-	// If mountpoint is already mounted, do nothing
85
-	if mounted, err := Mounted(mountPoint); err != nil {
86
-		return fmt.Errorf("Error checking mountpoint: %s", err)
87
-	} else if mounted {
88
-		return nil
89
-	}
90
-	// Mount the device
91
-	return d.DeviceSet.MountDevice(id, mountPoint, false)
92
-}
93 1
deleted file mode 100644
... ...
@@ -1,301 +0,0 @@
1
-package devmapper
2
-
3
-import (
4
-	"io/ioutil"
5
-	"os"
6
-	"path"
7
-	"testing"
8
-)
9
-
10
-func init() {
11
-	// Reduce the size the the base fs and loopback for the tests
12
-	DefaultDataLoopbackSize = 300 * 1024 * 1024
13
-	DefaultMetaDataLoopbackSize = 200 * 1024 * 1024
14
-	DefaultBaseFsSize = 300 * 1024 * 1024
15
-
16
-}
17
-
18
-func mkTestDirectory(t *testing.T) string {
19
-	dir, err := ioutil.TempDir("", "docker-test-devmapper-")
20
-	if err != nil {
21
-		t.Fatal(err)
22
-	}
23
-	return dir
24
-}
25
-
26
-func newDriver(t *testing.T) *Driver {
27
-	home := mkTestDirectory(t)
28
-	d, err := Init(home)
29
-	if err != nil {
30
-		t.Fatal(err)
31
-	}
32
-	return d.(*Driver)
33
-}
34
-
35
-func cleanup(d *Driver) {
36
-	d.Cleanup()
37
-	os.RemoveAll(d.home)
38
-}
39
-
40
-func TestInit(t *testing.T) {
41
-	home := mkTestDirectory(t)
42
-	defer os.RemoveAll(home)
43
-	driver, err := Init(home)
44
-	if err != nil {
45
-		t.Fatal(err)
46
-	}
47
-	defer func() {
48
-		if err := driver.Cleanup(); err != nil {
49
-			t.Fatal(err)
50
-		}
51
-	}()
52
-
53
-	id := "foo"
54
-	if err := driver.Create(id, ""); err != nil {
55
-		t.Fatal(err)
56
-	}
57
-	dir, err := driver.Get(id)
58
-	if err != nil {
59
-		t.Fatal(err)
60
-	}
61
-	if st, err := os.Stat(dir); err != nil {
62
-		t.Fatal(err)
63
-	} else if !st.IsDir() {
64
-		t.Fatalf("Get(%V) did not return a directory", id)
65
-	}
66
-}
67
-
68
-func TestDriverName(t *testing.T) {
69
-	d := newDriver(t)
70
-	defer cleanup(d)
71
-
72
-	if d.String() != "devicemapper" {
73
-		t.Fatalf("Expected driver name to be devicemapper got %s", d.String())
74
-	}
75
-}
76
-
77
-func TestDriverCreate(t *testing.T) {
78
-	d := newDriver(t)
79
-	defer cleanup(d)
80
-
81
-	if err := d.Create("1", ""); err != nil {
82
-		t.Fatal(err)
83
-	}
84
-}
85
-
86
-func TestDriverRemove(t *testing.T) {
87
-	d := newDriver(t)
88
-	defer cleanup(d)
89
-
90
-	if err := d.Create("1", ""); err != nil {
91
-		t.Fatal(err)
92
-	}
93
-
94
-	if err := d.Remove("1"); err != nil {
95
-		t.Fatal(err)
96
-	}
97
-}
98
-
99
-func TestCleanup(t *testing.T) {
100
-	d := newDriver(t)
101
-	defer os.RemoveAll(d.home)
102
-
103
-	mountPoints := make([]string, 2)
104
-
105
-	if err := d.Create("1", ""); err != nil {
106
-		t.Fatal(err)
107
-	}
108
-	// Mount the id
109
-	p, err := d.Get("1")
110
-	if err != nil {
111
-		t.Fatal(err)
112
-	}
113
-	mountPoints[0] = p
114
-
115
-	if err := d.Create("2", "1"); err != nil {
116
-		t.Fatal(err)
117
-	}
118
-
119
-	p, err = d.Get("2")
120
-	if err != nil {
121
-		t.Fatal(err)
122
-	}
123
-	mountPoints[1] = p
124
-
125
-	// Ensure that all the mount points are currently mounted
126
-	for _, p := range mountPoints {
127
-		if mounted, err := Mounted(p); err != nil {
128
-			t.Fatal(err)
129
-		} else if !mounted {
130
-			t.Fatalf("Expected %s to be mounted", p)
131
-		}
132
-	}
133
-
134
-	// Ensure that devices are active
135
-	for _, p := range []string{"1", "2"} {
136
-		if !d.HasActivatedDevice(p) {
137
-			t.Fatalf("Expected %s to have an active device", p)
138
-		}
139
-	}
140
-
141
-	if err := d.Cleanup(); err != nil {
142
-		t.Fatal(err)
143
-	}
144
-
145
-	// Ensure that all the mount points are no longer mounted
146
-	for _, p := range mountPoints {
147
-		if mounted, err := Mounted(p); err != nil {
148
-			t.Fatal(err)
149
-		} else if mounted {
150
-			t.Fatalf("Expected %s to not be mounted", p)
151
-		}
152
-	}
153
-
154
-	// Ensure that devices are no longer activated
155
-	for _, p := range []string{"1", "2"} {
156
-		if d.HasActivatedDevice(p) {
157
-			t.Fatalf("Expected %s not be an active device", p)
158
-		}
159
-	}
160
-}
161
-
162
-func TestNotMounted(t *testing.T) {
163
-	d := newDriver(t)
164
-	defer cleanup(d)
165
-
166
-	if err := d.Create("1", ""); err != nil {
167
-		t.Fatal(err)
168
-	}
169
-
170
-	mounted, err := Mounted(path.Join(d.home, "mnt", "1"))
171
-	if err != nil {
172
-		t.Fatal(err)
173
-	}
174
-	if mounted {
175
-		t.Fatal("Id 1 should not be mounted")
176
-	}
177
-}
178
-
179
-func TestMounted(t *testing.T) {
180
-	d := newDriver(t)
181
-	defer cleanup(d)
182
-
183
-	if err := d.Create("1", ""); err != nil {
184
-		t.Fatal(err)
185
-	}
186
-	if _, err := d.Get("1"); err != nil {
187
-		t.Fatal(err)
188
-	}
189
-
190
-	mounted, err := Mounted(path.Join(d.home, "mnt", "1"))
191
-	if err != nil {
192
-		t.Fatal(err)
193
-	}
194
-	if !mounted {
195
-		t.Fatal("Id 1 should be mounted")
196
-	}
197
-}
198
-
199
-func TestInitCleanedDriver(t *testing.T) {
200
-	d := newDriver(t)
201
-
202
-	if err := d.Create("1", ""); err != nil {
203
-		t.Fatal(err)
204
-	}
205
-	if _, err := d.Get("1"); err != nil {
206
-		t.Fatal(err)
207
-	}
208
-
209
-	if err := d.Cleanup(); err != nil {
210
-		t.Fatal(err)
211
-	}
212
-
213
-	driver, err := Init(d.home)
214
-	if err != nil {
215
-		t.Fatal(err)
216
-	}
217
-	d = driver.(*Driver)
218
-	defer cleanup(d)
219
-
220
-	if _, err := d.Get("1"); err != nil {
221
-		t.Fatal(err)
222
-	}
223
-}
224
-
225
-func TestMountMountedDriver(t *testing.T) {
226
-	d := newDriver(t)
227
-	defer cleanup(d)
228
-
229
-	if err := d.Create("1", ""); err != nil {
230
-		t.Fatal(err)
231
-	}
232
-
233
-	// Perform get on same id to ensure that it will
234
-	// not be mounted twice
235
-	if _, err := d.Get("1"); err != nil {
236
-		t.Fatal(err)
237
-	}
238
-	if _, err := d.Get("1"); err != nil {
239
-		t.Fatal(err)
240
-	}
241
-}
242
-
243
-func TestGetReturnsValidDevice(t *testing.T) {
244
-	d := newDriver(t)
245
-	defer cleanup(d)
246
-
247
-	if err := d.Create("1", ""); err != nil {
248
-		t.Fatal(err)
249
-	}
250
-
251
-	if !d.HasDevice("1") {
252
-		t.Fatalf("Expected id 1 to be in device set")
253
-	}
254
-
255
-	if _, err := d.Get("1"); err != nil {
256
-		t.Fatal(err)
257
-	}
258
-
259
-	if !d.HasActivatedDevice("1") {
260
-		t.Fatalf("Expected id 1 to be activated")
261
-	}
262
-
263
-	if !d.HasInitializedDevice("1") {
264
-		t.Fatalf("Expected id 1 to be initialized")
265
-	}
266
-}
267
-
268
-func TestDriverGetSize(t *testing.T) {
269
-	t.Skipf("Size is currently not implemented")
270
-
271
-	d := newDriver(t)
272
-	defer cleanup(d)
273
-
274
-	if err := d.Create("1", ""); err != nil {
275
-		t.Fatal(err)
276
-	}
277
-
278
-	mountPoint, err := d.Get("1")
279
-	if err != nil {
280
-		t.Fatal(err)
281
-	}
282
-
283
-	size := int64(1024)
284
-
285
-	f, err := os.Create(path.Join(mountPoint, "test_file"))
286
-	if err != nil {
287
-		t.Fatal(err)
288
-	}
289
-	if err := f.Truncate(size); err != nil {
290
-		t.Fatal(err)
291
-	}
292
-	f.Close()
293
-
294
-	diffSize, err := d.Size("1")
295
-	if err != nil {
296
-		t.Fatal(err)
297
-	}
298
-	if diffSize != size {
299
-		t.Fatalf("Expected size %d got %d", size, diffSize)
300
-	}
301
-}
302 1
deleted file mode 100644
... ...
@@ -1,27 +0,0 @@
1
-package devmapper
2
-
3
-import (
4
-	"os"
5
-	"path/filepath"
6
-	"syscall"
7
-)
8
-
9
-// FIXME: this is copy-pasted from the aufs driver.
10
-// It should be moved into the core.
11
-
12
-func Mounted(mountpoint string) (bool, error) {
13
-	mntpoint, err := os.Stat(mountpoint)
14
-	if err != nil {
15
-		if os.IsNotExist(err) {
16
-			return false, nil
17
-		}
18
-		return false, err
19
-	}
20
-	parent, err := os.Stat(filepath.Join(mountpoint, ".."))
21
-	if err != nil {
22
-		return false, err
23
-	}
24
-	mntpointSt := mntpoint.Sys().(*syscall.Stat_t)
25
-	parentSt := parent.Sys().(*syscall.Stat_t)
26
-	return mntpointSt.Dev != parentSt.Dev, nil
27
-}
28 1
new file mode 100644
... ...
@@ -0,0 +1,320 @@
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/graphdriver"
27
+	"github.com/dotcloud/docker/utils"
28
+	"log"
29
+	"os"
30
+	"os/exec"
31
+	"path"
32
+	"strings"
33
+)
34
+
35
+func init() {
36
+	graphdriver.Register("aufs", Init)
37
+}
38
+
39
+type AufsDriver struct {
40
+	root string
41
+}
42
+
43
+// New returns a new AUFS driver.
44
+// An error is returned if AUFS is not supported.
45
+func Init(root string) (graphdriver.Driver, error) {
46
+	// Try to load the aufs kernel module
47
+	if err := supportsAufs(); err != nil {
48
+		return nil, err
49
+	}
50
+	paths := []string{
51
+		"mnt",
52
+		"diff",
53
+		"layers",
54
+	}
55
+
56
+	// Create the root aufs driver dir and return
57
+	// if it already exists
58
+	// If not populate the dir structure
59
+	if err := os.MkdirAll(root, 0755); err != nil {
60
+		if os.IsExist(err) {
61
+			return &AufsDriver{root}, nil
62
+		}
63
+		return nil, err
64
+	}
65
+
66
+	for _, p := range paths {
67
+		if err := os.MkdirAll(path.Join(root, p), 0755); err != nil {
68
+			return nil, err
69
+		}
70
+	}
71
+	return &AufsDriver{root}, nil
72
+}
73
+
74
+// Return a nil error if the kernel supports aufs
75
+// We cannot modprobe because inside dind modprobe fails
76
+// to run
77
+func supportsAufs() error {
78
+	// We can try to modprobe aufs first before looking at
79
+	// proc/filesystems for when aufs is supported
80
+	exec.Command("modprobe", "aufs").Run()
81
+
82
+	f, err := os.Open("/proc/filesystems")
83
+	if err != nil {
84
+		return err
85
+	}
86
+	defer f.Close()
87
+
88
+	s := bufio.NewScanner(f)
89
+	for s.Scan() {
90
+		if strings.Contains(s.Text(), "aufs") {
91
+			return nil
92
+		}
93
+	}
94
+	return fmt.Errorf("AUFS was not found in /proc/filesystems")
95
+}
96
+
97
+func (a *AufsDriver) rootPath() string {
98
+	return a.root
99
+}
100
+
101
+func (a *AufsDriver) String() string {
102
+	return "aufs"
103
+}
104
+
105
+func (d *AufsDriver) Status() [][2]string {
106
+	return nil
107
+}
108
+
109
+// Three folders are created for each id
110
+// mnt, layers, and diff
111
+func (a *AufsDriver) Create(id, parent string) error {
112
+	if err := a.createDirsFor(id); err != nil {
113
+		return err
114
+	}
115
+	// Write the layers metadata
116
+	f, err := os.Create(path.Join(a.rootPath(), "layers", id))
117
+	if err != nil {
118
+		return err
119
+	}
120
+	defer f.Close()
121
+
122
+	if parent != "" {
123
+		ids, err := getParentIds(a.rootPath(), parent)
124
+		if err != nil {
125
+			return err
126
+		}
127
+
128
+		if _, err := fmt.Fprintln(f, parent); err != nil {
129
+			return err
130
+		}
131
+		for _, i := range ids {
132
+			if _, err := fmt.Fprintln(f, i); err != nil {
133
+				return err
134
+			}
135
+		}
136
+	}
137
+	return nil
138
+}
139
+
140
+func (a *AufsDriver) createDirsFor(id string) error {
141
+	paths := []string{
142
+		"mnt",
143
+		"diff",
144
+	}
145
+
146
+	for _, p := range paths {
147
+		if err := os.MkdirAll(path.Join(a.rootPath(), p, id), 0755); err != nil {
148
+			return err
149
+		}
150
+	}
151
+	return nil
152
+}
153
+
154
+// Unmount and remove the dir information
155
+func (a *AufsDriver) Remove(id string) error {
156
+	// Make sure the dir is umounted first
157
+	if err := a.unmount(id); err != nil {
158
+		return err
159
+	}
160
+	tmpDirs := []string{
161
+		"mnt",
162
+		"diff",
163
+	}
164
+
165
+	// Remove the dirs atomically
166
+	for _, p := range tmpDirs {
167
+		// We need to use a temp dir in the same dir as the driver so Rename
168
+		// does not fall back to the slow copy if /tmp and the driver dir
169
+		// are on different devices
170
+		tmp := path.Join(a.rootPath(), "tmp", p, id)
171
+		if err := os.MkdirAll(tmp, 0755); err != nil {
172
+			return err
173
+		}
174
+		realPath := path.Join(a.rootPath(), p, id)
175
+		if err := os.Rename(realPath, tmp); err != nil {
176
+			return err
177
+		}
178
+		defer os.RemoveAll(tmp)
179
+	}
180
+
181
+	// Remove the layers file for the id
182
+	return os.Remove(path.Join(a.rootPath(), "layers", id))
183
+}
184
+
185
+// Return the rootfs path for the id
186
+// This will mount the dir at it's given path
187
+func (a *AufsDriver) Get(id string) (string, error) {
188
+	ids, err := getParentIds(a.rootPath(), id)
189
+	if err != nil {
190
+		if !os.IsNotExist(err) {
191
+			return "", err
192
+		}
193
+		ids = []string{}
194
+	}
195
+
196
+	// If a dir does not have a parent ( no layers )do not try to mount
197
+	// just return the diff path to the data
198
+	out := path.Join(a.rootPath(), "diff", id)
199
+	if len(ids) > 0 {
200
+		out = path.Join(a.rootPath(), "mnt", id)
201
+		if err := a.mount(id); err != nil {
202
+			return "", err
203
+		}
204
+	}
205
+	return out, nil
206
+}
207
+
208
+// Returns an archive of the contents for the id
209
+func (a *AufsDriver) Diff(id string) (archive.Archive, error) {
210
+	return archive.TarFilter(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
211
+		Recursive:   true,
212
+		Compression: archive.Uncompressed,
213
+	})
214
+}
215
+
216
+func (a *AufsDriver) ApplyDiff(id string, diff archive.Archive) error {
217
+	return archive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil)
218
+}
219
+
220
+// Returns the size of the contents for the id
221
+func (a *AufsDriver) Size(id string) (int64, error) {
222
+	return utils.TreeSize(path.Join(a.rootPath(), "diff", id))
223
+}
224
+
225
+func (a *AufsDriver) Changes(id string) ([]archive.Change, error) {
226
+	layers, err := a.getParentLayerPaths(id)
227
+	if err != nil {
228
+		return nil, err
229
+	}
230
+	return archive.Changes(layers, path.Join(a.rootPath(), "diff", id))
231
+}
232
+
233
+func (a *AufsDriver) getParentLayerPaths(id string) ([]string, error) {
234
+	parentIds, err := getParentIds(a.rootPath(), id)
235
+	if err != nil {
236
+		return nil, err
237
+	}
238
+	if len(parentIds) == 0 {
239
+		return nil, fmt.Errorf("Dir %s does not have any parent layers", id)
240
+	}
241
+	layers := make([]string, len(parentIds))
242
+
243
+	// Get the diff paths for all the parent ids
244
+	for i, p := range parentIds {
245
+		layers[i] = path.Join(a.rootPath(), "diff", p)
246
+	}
247
+	return layers, nil
248
+}
249
+
250
+func (a *AufsDriver) mount(id string) error {
251
+	// If the id is mounted or we get an error return
252
+	if mounted, err := a.mounted(id); err != nil || mounted {
253
+		return err
254
+	}
255
+
256
+	var (
257
+		target = path.Join(a.rootPath(), "mnt", id)
258
+		rw     = path.Join(a.rootPath(), "diff", id)
259
+	)
260
+
261
+	layers, err := a.getParentLayerPaths(id)
262
+	if err != nil {
263
+		return err
264
+	}
265
+
266
+	if err := a.aufsMount(layers, rw, target); err != nil {
267
+		return err
268
+	}
269
+	return nil
270
+}
271
+
272
+func (a *AufsDriver) unmount(id string) error {
273
+	if mounted, err := a.mounted(id); err != nil || !mounted {
274
+		return err
275
+	}
276
+	target := path.Join(a.rootPath(), "mnt", id)
277
+	return Unmount(target)
278
+}
279
+
280
+func (a *AufsDriver) mounted(id string) (bool, error) {
281
+	target := path.Join(a.rootPath(), "mnt", id)
282
+	return Mounted(target)
283
+}
284
+
285
+// During cleanup aufs needs to unmount all mountpoints
286
+func (a *AufsDriver) Cleanup() error {
287
+	ids, err := loadIds(path.Join(a.rootPath(), "layers"))
288
+	if err != nil {
289
+		return err
290
+	}
291
+	for _, id := range ids {
292
+		if err := a.unmount(id); err != nil {
293
+			return err
294
+		}
295
+	}
296
+	return nil
297
+}
298
+
299
+func (a *AufsDriver) aufsMount(ro []string, rw, target string) error {
300
+	rwBranch := fmt.Sprintf("%v=rw", rw)
301
+	roBranches := ""
302
+	for _, layer := range ro {
303
+		roBranches += fmt.Sprintf("%v=ro+wh:", layer)
304
+	}
305
+	branches := fmt.Sprintf("br:%v:%v,xino=/dev/shm/aufs.xino", rwBranch, roBranches)
306
+
307
+	//if error, try to load aufs kernel module
308
+	if err := mount("none", target, "aufs", 0, branches); err != nil {
309
+		log.Printf("Kernel does not support AUFS, trying to load the AUFS module with modprobe...")
310
+		if err := exec.Command("modprobe", "aufs").Run(); err != nil {
311
+			return fmt.Errorf("Unable to load the AUFS module")
312
+		}
313
+		log.Printf("...module loaded.")
314
+		if err := mount("none", target, "aufs", 0, branches); err != nil {
315
+			return fmt.Errorf("Unable to mount using aufs %s", err)
316
+		}
317
+	}
318
+	return nil
319
+}
0 320
new file mode 100644
... ...
@@ -0,0 +1,517 @@
0
+package aufs
1
+
2
+import (
3
+	"github.com/dotcloud/docker/archive"
4
+	"os"
5
+	"path"
6
+	"testing"
7
+)
8
+
9
+var (
10
+	tmp = path.Join(os.TempDir(), "aufs-tests", "aufs")
11
+)
12
+
13
+func newDriver(t *testing.T) *AufsDriver {
14
+	if err := os.MkdirAll(tmp, 0755); err != nil {
15
+		t.Fatal(err)
16
+	}
17
+
18
+	d, err := Init(tmp)
19
+	if err != nil {
20
+		t.Fatal(err)
21
+	}
22
+	return d.(*AufsDriver)
23
+}
24
+
25
+func TestNewAufsDriver(t *testing.T) {
26
+	if err := os.MkdirAll(tmp, 0755); err != nil {
27
+		t.Fatal(err)
28
+	}
29
+
30
+	d, err := Init(tmp)
31
+	if err != nil {
32
+		t.Fatal(err)
33
+	}
34
+	defer os.RemoveAll(tmp)
35
+	if d == nil {
36
+		t.Fatalf("Driver should not be nil")
37
+	}
38
+}
39
+
40
+func TestAufsString(t *testing.T) {
41
+	d := newDriver(t)
42
+	defer os.RemoveAll(tmp)
43
+
44
+	if d.String() != "aufs" {
45
+		t.Fatalf("Expected aufs got %s", d.String())
46
+	}
47
+}
48
+
49
+func TestCreateDirStructure(t *testing.T) {
50
+	newDriver(t)
51
+	defer os.RemoveAll(tmp)
52
+
53
+	paths := []string{
54
+		"mnt",
55
+		"layers",
56
+		"diff",
57
+	}
58
+
59
+	for _, p := range paths {
60
+		if _, err := os.Stat(path.Join(tmp, p)); err != nil {
61
+			t.Fatal(err)
62
+		}
63
+	}
64
+}
65
+
66
+// We should be able to create two drivers with the same dir structure
67
+func TestNewDriverFromExistingDir(t *testing.T) {
68
+	if err := os.MkdirAll(tmp, 0755); err != nil {
69
+		t.Fatal(err)
70
+	}
71
+
72
+	if _, err := Init(tmp); err != nil {
73
+		t.Fatal(err)
74
+	}
75
+	if _, err := Init(tmp); err != nil {
76
+		t.Fatal(err)
77
+	}
78
+	os.RemoveAll(tmp)
79
+}
80
+
81
+func TestCreateNewDir(t *testing.T) {
82
+	d := newDriver(t)
83
+	defer os.RemoveAll(tmp)
84
+
85
+	if err := d.Create("1", ""); err != nil {
86
+		t.Fatal(err)
87
+	}
88
+}
89
+
90
+func TestCreateNewDirStructure(t *testing.T) {
91
+	d := newDriver(t)
92
+	defer os.RemoveAll(tmp)
93
+
94
+	if err := d.Create("1", ""); err != nil {
95
+		t.Fatal(err)
96
+	}
97
+
98
+	paths := []string{
99
+		"mnt",
100
+		"diff",
101
+		"layers",
102
+	}
103
+
104
+	for _, p := range paths {
105
+		if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil {
106
+			t.Fatal(err)
107
+		}
108
+	}
109
+}
110
+
111
+func TestRemoveImage(t *testing.T) {
112
+	d := newDriver(t)
113
+	defer os.RemoveAll(tmp)
114
+
115
+	if err := d.Create("1", ""); err != nil {
116
+		t.Fatal(err)
117
+	}
118
+
119
+	if err := d.Remove("1"); err != nil {
120
+		t.Fatal(err)
121
+	}
122
+
123
+	paths := []string{
124
+		"mnt",
125
+		"diff",
126
+		"layers",
127
+	}
128
+
129
+	for _, p := range paths {
130
+		if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil {
131
+			t.Fatalf("Error should not be nil because dirs with id 1 should be delted: %s", p)
132
+		}
133
+	}
134
+}
135
+
136
+func TestGetWithoutParent(t *testing.T) {
137
+	d := newDriver(t)
138
+	defer os.RemoveAll(tmp)
139
+
140
+	if err := d.Create("1", ""); err != nil {
141
+		t.Fatal(err)
142
+	}
143
+
144
+	diffPath, err := d.Get("1")
145
+	if err != nil {
146
+		t.Fatal(err)
147
+	}
148
+	expected := path.Join(tmp, "diff", "1")
149
+	if diffPath != expected {
150
+		t.Fatalf("Expected path %s got %s", expected, diffPath)
151
+	}
152
+}
153
+
154
+func TestCleanupWithNoDirs(t *testing.T) {
155
+	d := newDriver(t)
156
+	defer os.RemoveAll(tmp)
157
+
158
+	if err := d.Cleanup(); err != nil {
159
+		t.Fatal(err)
160
+	}
161
+}
162
+
163
+func TestCleanupWithDir(t *testing.T) {
164
+	d := newDriver(t)
165
+	defer os.RemoveAll(tmp)
166
+
167
+	if err := d.Create("1", ""); err != nil {
168
+		t.Fatal(err)
169
+	}
170
+
171
+	if err := d.Cleanup(); err != nil {
172
+		t.Fatal(err)
173
+	}
174
+}
175
+
176
+func TestMountedFalseResponse(t *testing.T) {
177
+	d := newDriver(t)
178
+	defer os.RemoveAll(tmp)
179
+
180
+	if err := d.Create("1", ""); err != nil {
181
+		t.Fatal(err)
182
+	}
183
+
184
+	response, err := d.mounted("1")
185
+	if err != nil {
186
+		t.Fatal(err)
187
+	}
188
+
189
+	if response != false {
190
+		t.Fatalf("Response if dir id 1 is mounted should be false")
191
+	}
192
+}
193
+
194
+func TestMountedTrueReponse(t *testing.T) {
195
+	d := newDriver(t)
196
+	defer os.RemoveAll(tmp)
197
+	defer d.Cleanup()
198
+
199
+	if err := d.Create("1", ""); err != nil {
200
+		t.Fatal(err)
201
+	}
202
+	if err := d.Create("2", "1"); err != nil {
203
+		t.Fatal(err)
204
+	}
205
+
206
+	_, err := d.Get("2")
207
+	if err != nil {
208
+		t.Fatal(err)
209
+	}
210
+
211
+	response, err := d.mounted("2")
212
+	if err != nil {
213
+		t.Fatal(err)
214
+	}
215
+
216
+	if response != true {
217
+		t.Fatalf("Response if dir id 2 is mounted should be true")
218
+	}
219
+}
220
+
221
+func TestMountWithParent(t *testing.T) {
222
+	d := newDriver(t)
223
+	defer os.RemoveAll(tmp)
224
+
225
+	if err := d.Create("1", ""); err != nil {
226
+		t.Fatal(err)
227
+	}
228
+	if err := d.Create("2", "1"); err != nil {
229
+		t.Fatal(err)
230
+	}
231
+
232
+	defer func() {
233
+		if err := d.Cleanup(); err != nil {
234
+			t.Fatal(err)
235
+		}
236
+	}()
237
+
238
+	mntPath, err := d.Get("2")
239
+	if err != nil {
240
+		t.Fatal(err)
241
+	}
242
+	if mntPath == "" {
243
+		t.Fatal("mntPath should not be empty string")
244
+	}
245
+
246
+	expected := path.Join(tmp, "mnt", "2")
247
+	if mntPath != expected {
248
+		t.Fatalf("Expected %s got %s", expected, mntPath)
249
+	}
250
+}
251
+
252
+func TestRemoveMountedDir(t *testing.T) {
253
+	d := newDriver(t)
254
+	defer os.RemoveAll(tmp)
255
+
256
+	if err := d.Create("1", ""); err != nil {
257
+		t.Fatal(err)
258
+	}
259
+	if err := d.Create("2", "1"); err != nil {
260
+		t.Fatal(err)
261
+	}
262
+
263
+	defer func() {
264
+		if err := d.Cleanup(); err != nil {
265
+			t.Fatal(err)
266
+		}
267
+	}()
268
+
269
+	mntPath, err := d.Get("2")
270
+	if err != nil {
271
+		t.Fatal(err)
272
+	}
273
+	if mntPath == "" {
274
+		t.Fatal("mntPath should not be empty string")
275
+	}
276
+
277
+	mounted, err := d.mounted("2")
278
+	if err != nil {
279
+		t.Fatal(err)
280
+	}
281
+
282
+	if !mounted {
283
+		t.Fatalf("Dir id 2 should be mounted")
284
+	}
285
+
286
+	if err := d.Remove("2"); err != nil {
287
+		t.Fatal(err)
288
+	}
289
+}
290
+
291
+func TestCreateWithInvalidParent(t *testing.T) {
292
+	d := newDriver(t)
293
+	defer os.RemoveAll(tmp)
294
+
295
+	if err := d.Create("1", "docker"); err == nil {
296
+		t.Fatalf("Error should not be nil with parent does not exist")
297
+	}
298
+}
299
+
300
+func TestGetDiff(t *testing.T) {
301
+	d := newDriver(t)
302
+	defer os.RemoveAll(tmp)
303
+
304
+	if err := d.Create("1", ""); err != nil {
305
+		t.Fatal(err)
306
+	}
307
+
308
+	diffPath, err := d.Get("1")
309
+	if err != nil {
310
+		t.Fatal(err)
311
+	}
312
+
313
+	// Add a file to the diff path with a fixed size
314
+	size := int64(1024)
315
+
316
+	f, err := os.Create(path.Join(diffPath, "test_file"))
317
+	if err != nil {
318
+		t.Fatal(err)
319
+	}
320
+	if err := f.Truncate(size); err != nil {
321
+		t.Fatal(err)
322
+	}
323
+	f.Close()
324
+
325
+	a, err := d.Diff("1")
326
+	if err != nil {
327
+		t.Fatal(err)
328
+	}
329
+	if a == nil {
330
+		t.Fatalf("Archive should not be nil")
331
+	}
332
+}
333
+
334
+func TestChanges(t *testing.T) {
335
+	d := newDriver(t)
336
+	defer os.RemoveAll(tmp)
337
+
338
+	if err := d.Create("1", ""); err != nil {
339
+		t.Fatal(err)
340
+	}
341
+	if err := d.Create("2", "1"); err != nil {
342
+		t.Fatal(err)
343
+	}
344
+
345
+	defer func() {
346
+		if err := d.Cleanup(); err != nil {
347
+			t.Fatal(err)
348
+		}
349
+	}()
350
+
351
+	mntPoint, err := d.Get("2")
352
+	if err != nil {
353
+		t.Fatal(err)
354
+	}
355
+
356
+	// Create a file to save in the mountpoint
357
+	f, err := os.Create(path.Join(mntPoint, "test.txt"))
358
+	if err != nil {
359
+		t.Fatal(err)
360
+	}
361
+
362
+	if _, err := f.WriteString("testline"); err != nil {
363
+		t.Fatal(err)
364
+	}
365
+	if err := f.Close(); err != nil {
366
+		t.Fatal(err)
367
+	}
368
+
369
+	changes, err := d.Changes("2")
370
+	if err != nil {
371
+		t.Fatal(err)
372
+	}
373
+	if len(changes) != 1 {
374
+		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
375
+	}
376
+	change := changes[0]
377
+
378
+	expectedPath := "/test.txt"
379
+	if change.Path != expectedPath {
380
+		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
381
+	}
382
+
383
+	if change.Kind != archive.ChangeAdd {
384
+		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
385
+	}
386
+
387
+	if err := d.Create("3", "2"); err != nil {
388
+		t.Fatal(err)
389
+	}
390
+	mntPoint, err = d.Get("3")
391
+	if err != nil {
392
+		t.Fatal(err)
393
+	}
394
+
395
+	// Create a file to save in the mountpoint
396
+	f, err = os.Create(path.Join(mntPoint, "test2.txt"))
397
+	if err != nil {
398
+		t.Fatal(err)
399
+	}
400
+
401
+	if _, err := f.WriteString("testline"); err != nil {
402
+		t.Fatal(err)
403
+	}
404
+	if err := f.Close(); err != nil {
405
+		t.Fatal(err)
406
+	}
407
+
408
+	changes, err = d.Changes("3")
409
+	if err != nil {
410
+		t.Fatal(err)
411
+	}
412
+
413
+	if len(changes) != 1 {
414
+		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
415
+	}
416
+	change = changes[0]
417
+
418
+	expectedPath = "/test2.txt"
419
+	if change.Path != expectedPath {
420
+		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
421
+	}
422
+
423
+	if change.Kind != archive.ChangeAdd {
424
+		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
425
+	}
426
+}
427
+
428
+func TestDiffSize(t *testing.T) {
429
+	d := newDriver(t)
430
+	defer os.RemoveAll(tmp)
431
+
432
+	if err := d.Create("1", ""); err != nil {
433
+		t.Fatal(err)
434
+	}
435
+
436
+	diffPath, err := d.Get("1")
437
+	if err != nil {
438
+		t.Fatal(err)
439
+	}
440
+
441
+	// Add a file to the diff path with a fixed size
442
+	size := int64(1024)
443
+
444
+	f, err := os.Create(path.Join(diffPath, "test_file"))
445
+	if err != nil {
446
+		t.Fatal(err)
447
+	}
448
+	f.Truncate(size)
449
+	s, err := f.Stat()
450
+	if err != nil {
451
+		t.Fatal(err)
452
+	}
453
+	size = s.Size()
454
+	if err := f.Close(); err != nil {
455
+		t.Fatal(err)
456
+	}
457
+
458
+	diffSize, err := d.Size("1")
459
+	if err != nil {
460
+		t.Fatal(err)
461
+	}
462
+	if diffSize != size {
463
+		t.Fatalf("Expected size to be %d got %d", size, diffSize)
464
+	}
465
+}
466
+
467
+func TestApplyDiff(t *testing.T) {
468
+	d := newDriver(t)
469
+	defer os.RemoveAll(tmp)
470
+	defer d.Cleanup()
471
+
472
+	if err := d.Create("1", ""); err != nil {
473
+		t.Fatal(err)
474
+	}
475
+
476
+	diffPath, err := d.Get("1")
477
+	if err != nil {
478
+		t.Fatal(err)
479
+	}
480
+
481
+	// Add a file to the diff path with a fixed size
482
+	size := int64(1024)
483
+
484
+	f, err := os.Create(path.Join(diffPath, "test_file"))
485
+	if err != nil {
486
+		t.Fatal(err)
487
+	}
488
+	f.Truncate(size)
489
+	f.Close()
490
+
491
+	diff, err := d.Diff("1")
492
+	if err != nil {
493
+		t.Fatal(err)
494
+	}
495
+
496
+	if err := d.Create("2", ""); err != nil {
497
+		t.Fatal(err)
498
+	}
499
+	if err := d.Create("3", "2"); err != nil {
500
+		t.Fatal(err)
501
+	}
502
+
503
+	if err := d.ApplyDiff("3", diff); err != nil {
504
+		t.Fatal(err)
505
+	}
506
+
507
+	// Ensure that the file is in the mount point for id 3
508
+
509
+	mountPoint, err := d.Get("3")
510
+	if err != nil {
511
+		t.Fatal(err)
512
+	}
513
+	if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil {
514
+		t.Fatal(err)
515
+	}
516
+}
0 517
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,37 @@
0
+package aufs
1
+
2
+import (
3
+	"github.com/dotcloud/docker/utils"
4
+	"os"
5
+	"os/exec"
6
+	"path/filepath"
7
+	"syscall"
8
+)
9
+
10
+func Unmount(target string) error {
11
+	if err := exec.Command("auplink", target, "flush").Run(); err != nil {
12
+		utils.Errorf("[warning]: couldn't run auplink before unmount: %s", err)
13
+	}
14
+	if err := syscall.Unmount(target, 0); err != nil {
15
+		return err
16
+	}
17
+	return nil
18
+}
19
+
20
+func Mounted(mountpoint string) (bool, error) {
21
+	mntpoint, err := os.Stat(mountpoint)
22
+	if err != nil {
23
+		if os.IsNotExist(err) {
24
+			return false, nil
25
+		}
26
+		return false, err
27
+	}
28
+	parent, err := os.Stat(filepath.Join(mountpoint, ".."))
29
+	if err != nil {
30
+		return false, err
31
+	}
32
+	mntpointSt := mntpoint.Sys().(*syscall.Stat_t)
33
+	parentSt := parent.Sys().(*syscall.Stat_t)
34
+
35
+	return mntpointSt.Dev != parentSt.Dev, nil
36
+}
0 37
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+package aufs
1
+
2
+import "errors"
3
+
4
+func mount(source string, target string, fstype string, flags uintptr, data string) (err error) {
5
+	return errors.New("mount is not implemented on darwin")
6
+}
0 7
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+package aufs
1
+
2
+import "syscall"
3
+
4
+func mount(source string, target string, fstype string, flags uintptr, data string) (err error) {
5
+	return syscall.Mount(source, target, fstype, flags, data)
6
+}
0 7
new file mode 100644
... ...
@@ -0,0 +1,803 @@
0
+package devmapper
1
+
2
+import (
3
+	"encoding/json"
4
+	"fmt"
5
+	"github.com/dotcloud/docker/utils"
6
+	"io"
7
+	"io/ioutil"
8
+	"os"
9
+	"os/exec"
10
+	"path"
11
+	"path/filepath"
12
+	"strconv"
13
+	"sync"
14
+	"syscall"
15
+	"time"
16
+)
17
+
18
+var (
19
+	DefaultDataLoopbackSize     int64  = 100 * 1024 * 1024 * 1024
20
+	DefaultMetaDataLoopbackSize int64  = 2 * 1024 * 1024 * 1024
21
+	DefaultBaseFsSize           uint64 = 10 * 1024 * 1024 * 1024
22
+)
23
+
24
+type DevInfo struct {
25
+	Hash          string     `json:"-"`
26
+	DeviceId      int        `json:"device_id"`
27
+	Size          uint64     `json:"size"`
28
+	TransactionId uint64     `json:"transaction_id"`
29
+	Initialized   bool       `json:"initialized"`
30
+	devices       *DeviceSet `json:"-"`
31
+}
32
+
33
+type MetaData struct {
34
+	Devices map[string]*DevInfo `json:devices`
35
+}
36
+
37
+type DeviceSet struct {
38
+	MetaData
39
+	sync.Mutex
40
+	root             string
41
+	devicePrefix     string
42
+	TransactionId    uint64
43
+	NewTransactionId uint64
44
+	nextFreeDevice   int
45
+	activeMounts     map[string]int
46
+}
47
+
48
+type DiskUsage struct {
49
+	Used  uint64
50
+	Total uint64
51
+}
52
+
53
+type Status struct {
54
+	PoolName         string
55
+	DataLoopback     string
56
+	MetadataLoopback string
57
+	Data             DiskUsage
58
+	Metadata         DiskUsage
59
+}
60
+
61
+func getDevName(name string) string {
62
+	return "/dev/mapper/" + name
63
+}
64
+
65
+func (info *DevInfo) Name() string {
66
+	hash := info.Hash
67
+	if hash == "" {
68
+		hash = "base"
69
+	}
70
+	return fmt.Sprintf("%s-%s", info.devices.devicePrefix, hash)
71
+}
72
+
73
+func (info *DevInfo) DevName() string {
74
+	return getDevName(info.Name())
75
+}
76
+
77
+func (devices *DeviceSet) loopbackDir() string {
78
+	return path.Join(devices.root, "devicemapper")
79
+}
80
+
81
+func (devices *DeviceSet) jsonFile() string {
82
+	return path.Join(devices.loopbackDir(), "json")
83
+}
84
+
85
+func (devices *DeviceSet) getPoolName() string {
86
+	return devices.devicePrefix + "-pool"
87
+}
88
+
89
+func (devices *DeviceSet) getPoolDevName() string {
90
+	return getDevName(devices.getPoolName())
91
+}
92
+
93
+func (devices *DeviceSet) hasImage(name string) bool {
94
+	dirname := devices.loopbackDir()
95
+	filename := path.Join(dirname, name)
96
+
97
+	_, err := os.Stat(filename)
98
+	return err == nil
99
+}
100
+
101
+// ensureImage creates a sparse file of <size> bytes at the path
102
+// <root>/devicemapper/<name>.
103
+// If the file already exists, it does nothing.
104
+// Either way it returns the full path.
105
+func (devices *DeviceSet) ensureImage(name string, size int64) (string, error) {
106
+	dirname := devices.loopbackDir()
107
+	filename := path.Join(dirname, name)
108
+
109
+	if err := os.MkdirAll(dirname, 0700); err != nil && !os.IsExist(err) {
110
+		return "", err
111
+	}
112
+
113
+	if _, err := os.Stat(filename); err != nil {
114
+		if !os.IsNotExist(err) {
115
+			return "", err
116
+		}
117
+		utils.Debugf("Creating loopback file %s for device-manage use", filename)
118
+		file, err := os.OpenFile(filename, os.O_RDWR|os.O_CREATE, 0600)
119
+		if err != nil {
120
+			return "", err
121
+		}
122
+		defer file.Close()
123
+
124
+		if err = file.Truncate(size); err != nil {
125
+			return "", err
126
+		}
127
+	}
128
+	return filename, nil
129
+}
130
+
131
+func (devices *DeviceSet) allocateDeviceId() int {
132
+	// TODO: Add smarter reuse of deleted devices
133
+	id := devices.nextFreeDevice
134
+	devices.nextFreeDevice = devices.nextFreeDevice + 1
135
+	return id
136
+}
137
+
138
+func (devices *DeviceSet) allocateTransactionId() uint64 {
139
+	devices.NewTransactionId = devices.NewTransactionId + 1
140
+	return devices.NewTransactionId
141
+}
142
+
143
+func (devices *DeviceSet) saveMetadata() error {
144
+	jsonData, err := json.Marshal(devices.MetaData)
145
+	if err != nil {
146
+		return fmt.Errorf("Error encoding metaadata to json: %s", err)
147
+	}
148
+	tmpFile, err := ioutil.TempFile(filepath.Dir(devices.jsonFile()), ".json")
149
+	if err != nil {
150
+		return fmt.Errorf("Error creating metadata file: %s", err)
151
+	}
152
+
153
+	n, err := tmpFile.Write(jsonData)
154
+	if err != nil {
155
+		return fmt.Errorf("Error writing metadata to %s: %s", tmpFile.Name(), err)
156
+	}
157
+	if n < len(jsonData) {
158
+		return io.ErrShortWrite
159
+	}
160
+	if err := tmpFile.Sync(); err != nil {
161
+		return fmt.Errorf("Error syncing metadata file %s: %s", tmpFile.Name(), err)
162
+	}
163
+	if err := tmpFile.Close(); err != nil {
164
+		return fmt.Errorf("Error closing metadata file %s: %s", tmpFile.Name(), err)
165
+	}
166
+	if err := os.Rename(tmpFile.Name(), devices.jsonFile()); err != nil {
167
+		return fmt.Errorf("Error committing metadata file", err)
168
+	}
169
+
170
+	if devices.NewTransactionId != devices.TransactionId {
171
+		if err = setTransactionId(devices.getPoolDevName(), devices.TransactionId, devices.NewTransactionId); err != nil {
172
+			return fmt.Errorf("Error setting devmapper transition ID: %s", err)
173
+		}
174
+		devices.TransactionId = devices.NewTransactionId
175
+	}
176
+	return nil
177
+}
178
+
179
+func (devices *DeviceSet) registerDevice(id int, hash string, size uint64) (*DevInfo, error) {
180
+	utils.Debugf("registerDevice(%v, %v)", id, hash)
181
+	info := &DevInfo{
182
+		Hash:          hash,
183
+		DeviceId:      id,
184
+		Size:          size,
185
+		TransactionId: devices.allocateTransactionId(),
186
+		Initialized:   false,
187
+		devices:       devices,
188
+	}
189
+
190
+	devices.Devices[hash] = info
191
+	if err := devices.saveMetadata(); err != nil {
192
+		// Try to remove unused device
193
+		delete(devices.Devices, hash)
194
+		return nil, err
195
+	}
196
+
197
+	return info, nil
198
+}
199
+
200
+func (devices *DeviceSet) activateDeviceIfNeeded(hash string) error {
201
+	utils.Debugf("activateDeviceIfNeeded(%v)", hash)
202
+	info := devices.Devices[hash]
203
+	if info == nil {
204
+		return fmt.Errorf("Unknown device %s", hash)
205
+	}
206
+
207
+	if devinfo, _ := getInfo(info.Name()); devinfo != nil && devinfo.Exists != 0 {
208
+		return nil
209
+	}
210
+
211
+	return activateDevice(devices.getPoolDevName(), info.Name(), info.DeviceId, info.Size)
212
+}
213
+
214
+func (devices *DeviceSet) createFilesystem(info *DevInfo) error {
215
+	devname := info.DevName()
216
+
217
+	err := exec.Command("mkfs.ext4", "-E", "discard,lazy_itable_init=0,lazy_journal_init=0", devname).Run()
218
+	if err != nil {
219
+		err = exec.Command("mkfs.ext4", "-E", "discard,lazy_itable_init=0", devname).Run()
220
+	}
221
+	if err != nil {
222
+		utils.Debugf("\n--->Err: %s\n", err)
223
+		return err
224
+	}
225
+	return nil
226
+}
227
+
228
+func (devices *DeviceSet) loadMetaData() error {
229
+	utils.Debugf("loadMetadata()")
230
+	defer utils.Debugf("loadMetadata END")
231
+	_, _, _, params, err := getStatus(devices.getPoolName())
232
+	if err != nil {
233
+		utils.Debugf("\n--->Err: %s\n", err)
234
+		return err
235
+	}
236
+
237
+	if _, err := fmt.Sscanf(params, "%d", &devices.TransactionId); err != nil {
238
+		utils.Debugf("\n--->Err: %s\n", err)
239
+		return err
240
+	}
241
+	devices.NewTransactionId = devices.TransactionId
242
+
243
+	jsonData, err := ioutil.ReadFile(devices.jsonFile())
244
+	if err != nil && !os.IsNotExist(err) {
245
+		utils.Debugf("\n--->Err: %s\n", err)
246
+		return err
247
+	}
248
+
249
+	devices.MetaData.Devices = make(map[string]*DevInfo)
250
+	if jsonData != nil {
251
+		if err := json.Unmarshal(jsonData, &devices.MetaData); err != nil {
252
+			utils.Debugf("\n--->Err: %s\n", err)
253
+			return err
254
+		}
255
+	}
256
+
257
+	for hash, d := range devices.Devices {
258
+		d.Hash = hash
259
+		d.devices = devices
260
+
261
+		if d.DeviceId >= devices.nextFreeDevice {
262
+			devices.nextFreeDevice = d.DeviceId + 1
263
+		}
264
+
265
+		// If the transaction id is larger than the actual one we lost the device due to some crash
266
+		if d.TransactionId > devices.TransactionId {
267
+			utils.Debugf("Removing lost device %s with id %d", hash, d.TransactionId)
268
+			delete(devices.Devices, hash)
269
+		}
270
+	}
271
+	return nil
272
+}
273
+
274
+func (devices *DeviceSet) setupBaseImage() error {
275
+	oldInfo := devices.Devices[""]
276
+	if oldInfo != nil && oldInfo.Initialized {
277
+		return nil
278
+	}
279
+
280
+	if oldInfo != nil && !oldInfo.Initialized {
281
+		utils.Debugf("Removing uninitialized base image")
282
+		if err := devices.removeDevice(""); err != nil {
283
+			utils.Debugf("\n--->Err: %s\n", err)
284
+			return err
285
+		}
286
+	}
287
+
288
+	utils.Debugf("Initializing base device-manager snapshot")
289
+
290
+	id := devices.allocateDeviceId()
291
+
292
+	// Create initial device
293
+	if err := createDevice(devices.getPoolDevName(), id); err != nil {
294
+		utils.Debugf("\n--->Err: %s\n", err)
295
+		return err
296
+	}
297
+
298
+	utils.Debugf("Registering base device (id %v) with FS size %v", id, DefaultBaseFsSize)
299
+	info, err := devices.registerDevice(id, "", DefaultBaseFsSize)
300
+	if err != nil {
301
+		_ = deleteDevice(devices.getPoolDevName(), id)
302
+		utils.Debugf("\n--->Err: %s\n", err)
303
+		return err
304
+	}
305
+
306
+	utils.Debugf("Creating filesystem on base device-manager snapshot")
307
+
308
+	if err = devices.activateDeviceIfNeeded(""); err != nil {
309
+		utils.Debugf("\n--->Err: %s\n", err)
310
+		return err
311
+	}
312
+
313
+	if err := devices.createFilesystem(info); err != nil {
314
+		utils.Debugf("\n--->Err: %s\n", err)
315
+		return err
316
+	}
317
+
318
+	info.Initialized = true
319
+	if err = devices.saveMetadata(); err != nil {
320
+		info.Initialized = false
321
+		utils.Debugf("\n--->Err: %s\n", err)
322
+		return err
323
+	}
324
+
325
+	return nil
326
+}
327
+
328
+func setCloseOnExec(name string) {
329
+	fileInfos, _ := ioutil.ReadDir("/proc/self/fd")
330
+	if fileInfos != nil {
331
+		for _, i := range fileInfos {
332
+			link, _ := os.Readlink(filepath.Join("/proc/self/fd", i.Name()))
333
+			if link == name {
334
+				fd, err := strconv.Atoi(i.Name())
335
+				if err == nil {
336
+					syscall.CloseOnExec(fd)
337
+				}
338
+			}
339
+		}
340
+	}
341
+}
342
+
343
+func (devices *DeviceSet) log(level int, file string, line int, dmError int, message string) {
344
+	if level >= 7 {
345
+		return // Ignore _LOG_DEBUG
346
+	}
347
+
348
+	utils.Debugf("libdevmapper(%d): %s:%d (%d) %s", level, file, line, dmError, message)
349
+}
350
+
351
+func major(device uint64) uint64 {
352
+	return (device >> 8) & 0xfff
353
+}
354
+
355
+func minor(device uint64) uint64 {
356
+	return (device & 0xff) | ((device >> 12) & 0xfff00)
357
+}
358
+
359
+func (devices *DeviceSet) initDevmapper() error {
360
+	logInit(devices)
361
+
362
+	// Make sure the sparse images exist in <root>/devicemapper/data and
363
+	// <root>/devicemapper/metadata
364
+
365
+	createdLoopback := !devices.hasImage("data") || !devices.hasImage("metadata")
366
+	data, err := devices.ensureImage("data", DefaultDataLoopbackSize)
367
+	if err != nil {
368
+		utils.Debugf("Error device ensureImage (data): %s\n", err)
369
+		return err
370
+	}
371
+	metadata, err := devices.ensureImage("metadata", DefaultMetaDataLoopbackSize)
372
+	if err != nil {
373
+		utils.Debugf("Error device ensureImage (metadata): %s\n", err)
374
+		return err
375
+	}
376
+
377
+	// Set the device prefix from the device id and inode of the docker root dir
378
+
379
+	st, err := os.Stat(devices.root)
380
+	if err != nil {
381
+		return fmt.Errorf("Error looking up dir %s: %s", devices.root, err)
382
+	}
383
+	sysSt := st.Sys().(*syscall.Stat_t)
384
+	// "reg-" stands for "regular file".
385
+	// In the future we might use "dev-" for "device file", etc.
386
+	// docker-maj,min[-inode] stands for:
387
+	//	- Managed by docker
388
+	//	- The target of this device is at major <maj> and minor <min>
389
+	//	- If <inode> is defined, use that file inside the device as a loopback image. Otherwise use the device itself.
390
+	devices.devicePrefix = fmt.Sprintf("docker-%d:%d-%d", major(sysSt.Dev), minor(sysSt.Dev), sysSt.Ino)
391
+	utils.Debugf("Generated prefix: %s", devices.devicePrefix)
392
+
393
+	// Check for the existence of the device <prefix>-pool
394
+	utils.Debugf("Checking for existence of the pool '%s'", devices.getPoolName())
395
+	info, err := getInfo(devices.getPoolName())
396
+	if info == nil {
397
+		utils.Debugf("Error device getInfo: %s", err)
398
+		return err
399
+	}
400
+
401
+	// It seems libdevmapper opens this without O_CLOEXEC, and go exec will not close files
402
+	// that are not Close-on-exec, and lxc-start will die if it inherits any unexpected files,
403
+	// so we add this badhack to make sure it closes itself
404
+	setCloseOnExec("/dev/mapper/control")
405
+
406
+	// If the pool doesn't exist, create it
407
+	if info.Exists == 0 {
408
+		utils.Debugf("Pool doesn't exist. Creating it.")
409
+
410
+		dataFile, err := AttachLoopDevice(data)
411
+		if err != nil {
412
+			utils.Debugf("\n--->Err: %s\n", err)
413
+			return err
414
+		}
415
+		defer dataFile.Close()
416
+
417
+		metadataFile, err := AttachLoopDevice(metadata)
418
+		if err != nil {
419
+			utils.Debugf("\n--->Err: %s\n", err)
420
+			return err
421
+		}
422
+		defer metadataFile.Close()
423
+
424
+		if err := createPool(devices.getPoolName(), dataFile, metadataFile); err != nil {
425
+			utils.Debugf("\n--->Err: %s\n", err)
426
+			return err
427
+		}
428
+	}
429
+
430
+	// If we didn't just create the data or metadata image, we need to
431
+	// load the metadata from the existing file.
432
+	if !createdLoopback {
433
+		if err = devices.loadMetaData(); err != nil {
434
+			utils.Debugf("\n--->Err: %s\n", err)
435
+			return err
436
+		}
437
+	}
438
+
439
+	// Setup the base image
440
+	if err := devices.setupBaseImage(); err != nil {
441
+		utils.Debugf("Error device setupBaseImage: %s\n", err)
442
+		return err
443
+	}
444
+
445
+	return nil
446
+}
447
+
448
+func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
449
+	devices.Lock()
450
+	defer devices.Unlock()
451
+
452
+	if devices.Devices[hash] != nil {
453
+		return fmt.Errorf("hash %s already exists", hash)
454
+	}
455
+
456
+	baseInfo := devices.Devices[baseHash]
457
+	if baseInfo == nil {
458
+		return fmt.Errorf("Error adding device for '%s': can't find device for parent '%s'", hash, baseHash)
459
+	}
460
+
461
+	deviceId := devices.allocateDeviceId()
462
+
463
+	if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
464
+		utils.Debugf("Error creating snap device: %s\n", err)
465
+		return err
466
+	}
467
+
468
+	if _, err := devices.registerDevice(deviceId, hash, baseInfo.Size); err != nil {
469
+		deleteDevice(devices.getPoolDevName(), deviceId)
470
+		utils.Debugf("Error registering device: %s\n", err)
471
+		return err
472
+	}
473
+	return nil
474
+}
475
+
476
+func (devices *DeviceSet) removeDevice(hash string) error {
477
+	info := devices.Devices[hash]
478
+	if info == nil {
479
+		return fmt.Errorf("hash %s doesn't exists", hash)
480
+	}
481
+
482
+	devinfo, _ := getInfo(info.Name())
483
+	if devinfo != nil && devinfo.Exists != 0 {
484
+		if err := removeDevice(info.Name()); err != nil {
485
+			utils.Debugf("Error removing device: %s\n", err)
486
+			return err
487
+		}
488
+	}
489
+
490
+	if info.Initialized {
491
+		info.Initialized = false
492
+		if err := devices.saveMetadata(); err != nil {
493
+			utils.Debugf("Error saving meta data: %s\n", err)
494
+			return err
495
+		}
496
+	}
497
+
498
+	if err := deleteDevice(devices.getPoolDevName(), info.DeviceId); err != nil {
499
+		utils.Debugf("Error deleting device: %s\n", err)
500
+		return err
501
+	}
502
+
503
+	devices.allocateTransactionId()
504
+	delete(devices.Devices, info.Hash)
505
+
506
+	if err := devices.saveMetadata(); err != nil {
507
+		devices.Devices[info.Hash] = info
508
+		utils.Debugf("Error saving meta data: %s\n", err)
509
+		return err
510
+	}
511
+
512
+	return nil
513
+}
514
+
515
+func (devices *DeviceSet) RemoveDevice(hash string) error {
516
+	devices.Lock()
517
+	defer devices.Unlock()
518
+
519
+	return devices.removeDevice(hash)
520
+}
521
+
522
+func (devices *DeviceSet) deactivateDevice(hash string) error {
523
+	utils.Debugf("[devmapper] deactivateDevice(%s)", hash)
524
+	defer utils.Debugf("[devmapper] deactivateDevice END")
525
+	var devname string
526
+	// FIXME: shouldn't we just register the pool into devices?
527
+	devname, err := devices.byHash(hash)
528
+	if err != nil {
529
+		return err
530
+	}
531
+	devinfo, err := getInfo(devname)
532
+	if err != nil {
533
+		utils.Debugf("\n--->Err: %s\n", err)
534
+		return err
535
+	}
536
+	if devinfo.Exists != 0 {
537
+		if err := removeDevice(devname); err != nil {
538
+			utils.Debugf("\n--->Err: %s\n", err)
539
+			return err
540
+		}
541
+		if err := devices.waitRemove(hash); err != nil {
542
+			return err
543
+		}
544
+	}
545
+
546
+	return nil
547
+}
548
+
549
+// waitRemove blocks until either:
550
+// a) the device registered at <device_set_prefix>-<hash> is removed,
551
+// or b) the 1 second timeout expires.
552
+func (devices *DeviceSet) waitRemove(hash string) error {
553
+	utils.Debugf("[deviceset %s] waitRemove(%s)", devices.devicePrefix, hash)
554
+	defer utils.Debugf("[deviceset %s] waitRemove END", devices.devicePrefix, hash)
555
+	devname, err := devices.byHash(hash)
556
+	if err != nil {
557
+		return err
558
+	}
559
+	i := 0
560
+	for ; i < 1000; i += 1 {
561
+		devinfo, err := getInfo(devname)
562
+		if err != nil {
563
+			// If there is an error we assume the device doesn't exist.
564
+			// The error might actually be something else, but we can't differentiate.
565
+			return nil
566
+		}
567
+		utils.Debugf("Waiting for removal of %s: exists=%d", devname, devinfo.Exists)
568
+		if devinfo.Exists == 0 {
569
+			break
570
+		}
571
+		time.Sleep(1 * time.Millisecond)
572
+	}
573
+	if i == 1000 {
574
+		return fmt.Errorf("Timeout while waiting for device %s to be removed", devname)
575
+	}
576
+	return nil
577
+}
578
+
579
+// waitClose blocks until either:
580
+// a) the device registered at <device_set_prefix>-<hash> is closed,
581
+// or b) the 1 second timeout expires.
582
+func (devices *DeviceSet) waitClose(hash string) error {
583
+	devname, err := devices.byHash(hash)
584
+	if err != nil {
585
+		return err
586
+	}
587
+	i := 0
588
+	for ; i < 1000; i += 1 {
589
+		devinfo, err := getInfo(devname)
590
+		if err != nil {
591
+			return err
592
+		}
593
+		utils.Debugf("Waiting for unmount of %s: opencount=%d", devname, devinfo.OpenCount)
594
+		if devinfo.OpenCount == 0 {
595
+			break
596
+		}
597
+		time.Sleep(1 * time.Millisecond)
598
+	}
599
+	if i == 1000 {
600
+		return fmt.Errorf("Timeout while waiting for device %s to close", devname)
601
+	}
602
+	return nil
603
+}
604
+
605
+// byHash is a hack to allow looking up the deviceset's pool by the hash "pool".
606
+// FIXME: it seems probably cleaner to register the pool in devices.Devices,
607
+// but I am afraid of arcane implications deep in the devicemapper code,
608
+// so this will do.
609
+func (devices *DeviceSet) byHash(hash string) (devname string, err error) {
610
+	if hash == "pool" {
611
+		return devices.getPoolDevName(), nil
612
+	}
613
+	info := devices.Devices[hash]
614
+	if info == nil {
615
+		return "", fmt.Errorf("hash %s doesn't exists", hash)
616
+	}
617
+	return info.Name(), nil
618
+}
619
+
620
+func (devices *DeviceSet) Shutdown() error {
621
+	utils.Debugf("[deviceset %s] shutdown()", devices.devicePrefix)
622
+	defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
623
+	devices.Lock()
624
+	utils.Debugf("[devmapper] Shutting down DeviceSet: %s", devices.root)
625
+	defer devices.Unlock()
626
+
627
+	for path, count := range devices.activeMounts {
628
+		for i := count; i > 0; i-- {
629
+			if err := syscall.Unmount(path, 0); err != nil {
630
+				utils.Debugf("Shutdown unmounting %s, error: %s\n", path, err)
631
+			}
632
+		}
633
+		delete(devices.activeMounts, path)
634
+	}
635
+
636
+	for _, d := range devices.Devices {
637
+		if err := devices.waitClose(d.Hash); err != nil {
638
+			utils.Errorf("Warning: error waiting for device %s to unmount: %s\n", d.Hash, err)
639
+		}
640
+		if err := devices.deactivateDevice(d.Hash); err != nil {
641
+			utils.Debugf("Shutdown deactivate %s , error: %s\n", d.Hash, err)
642
+		}
643
+	}
644
+
645
+	pool := devices.getPoolDevName()
646
+	if devinfo, err := getInfo(pool); err == nil && devinfo.Exists != 0 {
647
+		if err := devices.deactivateDevice("pool"); err != nil {
648
+			utils.Debugf("Shutdown deactivate %s , error: %s\n", pool, err)
649
+		}
650
+	}
651
+
652
+	return nil
653
+}
654
+
655
+func (devices *DeviceSet) MountDevice(hash, path string, readOnly bool) error {
656
+	devices.Lock()
657
+	defer devices.Unlock()
658
+
659
+	if err := devices.activateDeviceIfNeeded(hash); err != nil {
660
+		return fmt.Errorf("Error activating devmapper device for '%s': %s", hash, err)
661
+	}
662
+
663
+	info := devices.Devices[hash]
664
+
665
+	var flags uintptr = syscall.MS_MGC_VAL
666
+
667
+	if readOnly {
668
+		flags = flags | syscall.MS_RDONLY
669
+	}
670
+
671
+	err := syscall.Mount(info.DevName(), path, "ext4", flags, "discard")
672
+	if err != nil && err == syscall.EINVAL {
673
+		err = syscall.Mount(info.DevName(), path, "ext4", flags, "")
674
+	}
675
+	if err != nil {
676
+		return fmt.Errorf("Error mounting '%s' on '%s': %s", info.DevName(), path, err)
677
+	}
678
+
679
+	count := devices.activeMounts[path]
680
+	devices.activeMounts[path] = count + 1
681
+
682
+	return devices.setInitialized(hash)
683
+}
684
+
685
+func (devices *DeviceSet) UnmountDevice(hash, path string, deactivate bool) error {
686
+	utils.Debugf("[devmapper] UnmountDevice(hash=%s path=%s)", hash, path)
687
+	defer utils.Debugf("[devmapper] UnmountDevice END")
688
+	devices.Lock()
689
+	defer devices.Unlock()
690
+
691
+	utils.Debugf("[devmapper] Unmount(%s)", path)
692
+	if err := syscall.Unmount(path, 0); err != nil {
693
+		utils.Debugf("\n--->Err: %s\n", err)
694
+		return err
695
+	}
696
+	utils.Debugf("[devmapper] Unmount done")
697
+	// Wait for the unmount to be effective,
698
+	// by watching the value of Info.OpenCount for the device
699
+	if err := devices.waitClose(hash); err != nil {
700
+		return err
701
+	}
702
+
703
+	if count := devices.activeMounts[path]; count > 1 {
704
+		devices.activeMounts[path] = count - 1
705
+	} else {
706
+		delete(devices.activeMounts, path)
707
+	}
708
+
709
+	if deactivate {
710
+		devices.deactivateDevice(hash)
711
+	}
712
+
713
+	return nil
714
+}
715
+
716
+func (devices *DeviceSet) HasDevice(hash string) bool {
717
+	devices.Lock()
718
+	defer devices.Unlock()
719
+
720
+	return devices.Devices[hash] != nil
721
+}
722
+
723
+func (devices *DeviceSet) HasInitializedDevice(hash string) bool {
724
+	devices.Lock()
725
+	defer devices.Unlock()
726
+
727
+	info := devices.Devices[hash]
728
+	return info != nil && info.Initialized
729
+}
730
+
731
+func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
732
+	devices.Lock()
733
+	defer devices.Unlock()
734
+
735
+	info := devices.Devices[hash]
736
+	if info == nil {
737
+		return false
738
+	}
739
+	devinfo, _ := getInfo(info.Name())
740
+	return devinfo != nil && devinfo.Exists != 0
741
+}
742
+
743
+func (devices *DeviceSet) setInitialized(hash string) error {
744
+	info := devices.Devices[hash]
745
+	if info == nil {
746
+		return fmt.Errorf("Unknown device %s", hash)
747
+	}
748
+
749
+	info.Initialized = true
750
+	if err := devices.saveMetadata(); err != nil {
751
+		info.Initialized = false
752
+		utils.Debugf("\n--->Err: %s\n", err)
753
+		return err
754
+	}
755
+
756
+	return nil
757
+}
758
+
759
+func (devices *DeviceSet) Status() *Status {
760
+	devices.Lock()
761
+	defer devices.Unlock()
762
+
763
+	status := &Status{}
764
+
765
+	status.PoolName = devices.getPoolName()
766
+	status.DataLoopback = path.Join(devices.loopbackDir(), "data")
767
+	status.MetadataLoopback = path.Join(devices.loopbackDir(), "metadata")
768
+
769
+	_, totalSizeInSectors, _, params, err := getStatus(devices.getPoolName())
770
+	if err == nil {
771
+		var transactionId, dataUsed, dataTotal, metadataUsed, metadataTotal uint64
772
+		if _, err := fmt.Sscanf(params, "%d %d/%d %d/%d", &transactionId, &metadataUsed, &metadataTotal, &dataUsed, &dataTotal); err == nil {
773
+			// Convert from blocks to bytes
774
+			blockSizeInSectors := totalSizeInSectors / dataTotal
775
+
776
+			status.Data.Used = dataUsed * blockSizeInSectors * 512
777
+			status.Data.Total = dataTotal * blockSizeInSectors * 512
778
+
779
+			// metadata blocks are always 4k
780
+			status.Metadata.Used = metadataUsed * 4096
781
+			status.Metadata.Total = metadataTotal * 4096
782
+		}
783
+	}
784
+
785
+	return status
786
+}
787
+
788
+func NewDeviceSet(root string) (*DeviceSet, error) {
789
+	SetDevDir("/dev")
790
+
791
+	devices := &DeviceSet{
792
+		root:         root,
793
+		MetaData:     MetaData{Devices: make(map[string]*DevInfo)},
794
+		activeMounts: make(map[string]int),
795
+	}
796
+
797
+	if err := devices.initDevmapper(); err != nil {
798
+		return nil, err
799
+	}
800
+
801
+	return devices, nil
802
+}
0 803
new file mode 100644
... ...
@@ -0,0 +1,505 @@
0
+package devmapper
1
+
2
+import (
3
+	"errors"
4
+	"fmt"
5
+	"github.com/dotcloud/docker/utils"
6
+	"os"
7
+	"runtime"
8
+)
9
+
10
+type DevmapperLogger interface {
11
+	log(level int, file string, line int, dmError int, message string)
12
+}
13
+
14
+const (
15
+	DeviceCreate TaskType = iota
16
+	DeviceReload
17
+	DeviceRemove
18
+	DeviceRemoveAll
19
+	DeviceSuspend
20
+	DeviceResume
21
+	DeviceInfo
22
+	DeviceDeps
23
+	DeviceRename
24
+	DeviceVersion
25
+	DeviceStatus
26
+	DeviceTable
27
+	DeviceWaitevent
28
+	DeviceList
29
+	DeviceClear
30
+	DeviceMknodes
31
+	DeviceListVersions
32
+	DeviceTargetMsg
33
+	DeviceSetGeometry
34
+)
35
+
36
+const (
37
+	AddNodeOnResume AddNodeType = iota
38
+	AddNodeOnCreate
39
+)
40
+
41
+var (
42
+	ErrTaskRun              = errors.New("dm_task_run failed")
43
+	ErrTaskSetName          = errors.New("dm_task_set_name failed")
44
+	ErrTaskSetMessage       = errors.New("dm_task_set_message failed")
45
+	ErrTaskSetAddNode       = errors.New("dm_task_set_add_node failed")
46
+	ErrTaskSetRo            = errors.New("dm_task_set_ro failed")
47
+	ErrTaskAddTarget        = errors.New("dm_task_add_target failed")
48
+	ErrTaskSetSector        = errors.New("dm_task_set_sector failed")
49
+	ErrTaskGetInfo          = errors.New("dm_task_get_info failed")
50
+	ErrTaskGetDriverVersion = errors.New("dm_task_get_driver_version failed")
51
+	ErrTaskSetCookie        = errors.New("dm_task_set_cookie failed")
52
+	ErrNilCookie            = errors.New("cookie ptr can't be nil")
53
+	ErrAttachLoopbackDevice = errors.New("loopback mounting failed")
54
+	ErrGetBlockSize         = errors.New("Can't get block size")
55
+	ErrUdevWait             = errors.New("wait on udev cookie failed")
56
+	ErrSetDevDir            = errors.New("dm_set_dev_dir failed")
57
+	ErrGetLibraryVersion    = errors.New("dm_get_library_version failed")
58
+	ErrCreateRemoveTask     = errors.New("Can't create task of type DeviceRemove")
59
+	ErrRunRemoveDevice      = errors.New("running removeDevice failed")
60
+	ErrInvalidAddNode       = errors.New("Invalide AddNoce type")
61
+)
62
+
63
+type (
64
+	Task struct {
65
+		unmanaged *CDmTask
66
+	}
67
+	Info struct {
68
+		Exists        int
69
+		Suspended     int
70
+		LiveTable     int
71
+		InactiveTable int
72
+		OpenCount     int32
73
+		EventNr       uint32
74
+		Major         uint32
75
+		Minor         uint32
76
+		ReadOnly      int
77
+		TargetCount   int32
78
+	}
79
+	TaskType    int
80
+	AddNodeType int
81
+)
82
+
83
+func (t *Task) destroy() {
84
+	if t != nil {
85
+		DmTaskDestory(t.unmanaged)
86
+		runtime.SetFinalizer(t, nil)
87
+	}
88
+}
89
+
90
+func TaskCreate(tasktype TaskType) *Task {
91
+	Ctask := DmTaskCreate(int(tasktype))
92
+	if Ctask == nil {
93
+		return nil
94
+	}
95
+	task := &Task{unmanaged: Ctask}
96
+	runtime.SetFinalizer(task, (*Task).destroy)
97
+	return task
98
+}
99
+
100
+func (t *Task) Run() error {
101
+	if res := DmTaskRun(t.unmanaged); res != 1 {
102
+		return ErrTaskRun
103
+	}
104
+	return nil
105
+}
106
+
107
+func (t *Task) SetName(name string) error {
108
+	if res := DmTaskSetName(t.unmanaged, name); res != 1 {
109
+		return ErrTaskSetName
110
+	}
111
+	return nil
112
+}
113
+
114
+func (t *Task) SetMessage(message string) error {
115
+	if res := DmTaskSetMessage(t.unmanaged, message); res != 1 {
116
+		return ErrTaskSetMessage
117
+	}
118
+	return nil
119
+}
120
+
121
+func (t *Task) SetSector(sector uint64) error {
122
+	if res := DmTaskSetSector(t.unmanaged, sector); res != 1 {
123
+		return ErrTaskSetSector
124
+	}
125
+	return nil
126
+}
127
+
128
+func (t *Task) SetCookie(cookie *uint, flags uint16) error {
129
+	if cookie == nil {
130
+		return ErrNilCookie
131
+	}
132
+	if res := DmTaskSetCookie(t.unmanaged, cookie, flags); res != 1 {
133
+		return ErrTaskSetCookie
134
+	}
135
+	return nil
136
+}
137
+
138
+func (t *Task) SetAddNode(addNode AddNodeType) error {
139
+	if addNode != AddNodeOnResume && addNode != AddNodeOnCreate {
140
+		return ErrInvalidAddNode
141
+	}
142
+	if res := DmTaskSetAddNode(t.unmanaged, addNode); res != 1 {
143
+		return ErrTaskSetAddNode
144
+	}
145
+	return nil
146
+}
147
+
148
+func (t *Task) SetRo() error {
149
+	if res := DmTaskSetRo(t.unmanaged); res != 1 {
150
+		return ErrTaskSetRo
151
+	}
152
+	return nil
153
+}
154
+
155
+func (t *Task) AddTarget(start, size uint64, ttype, params string) error {
156
+	if res := DmTaskAddTarget(t.unmanaged, start, size,
157
+		ttype, params); res != 1 {
158
+		return ErrTaskAddTarget
159
+	}
160
+	return nil
161
+}
162
+
163
+func (t *Task) GetInfo() (*Info, error) {
164
+	info := &Info{}
165
+	if res := DmTaskGetInfo(t.unmanaged, info); res != 1 {
166
+		return nil, ErrTaskGetInfo
167
+	}
168
+	return info, nil
169
+}
170
+
171
+func (t *Task) GetNextTarget(next uintptr) (nextPtr uintptr, start uint64,
172
+	length uint64, targetType string, params string) {
173
+
174
+	return DmGetNextTarget(t.unmanaged, next, &start, &length,
175
+			&targetType, &params),
176
+		start, length, targetType, params
177
+}
178
+
179
+func AttachLoopDevice(filename string) (*os.File, error) {
180
+	var fd int
181
+	res := DmAttachLoopDevice(filename, &fd)
182
+	if res == "" {
183
+		return nil, ErrAttachLoopbackDevice
184
+	}
185
+	return os.NewFile(uintptr(fd), res), nil
186
+}
187
+
188
+func UdevWait(cookie uint) error {
189
+	if res := DmUdevWait(cookie); res != 1 {
190
+		utils.Debugf("Failed to wait on udev cookie %d", cookie)
191
+		return ErrUdevWait
192
+	}
193
+	return nil
194
+}
195
+
196
+func LogInitVerbose(level int) {
197
+	DmLogInitVerbose(level)
198
+}
199
+
200
+var dmLogger DevmapperLogger = nil
201
+
202
+func logInit(logger DevmapperLogger) {
203
+	dmLogger = logger
204
+	LogWithErrnoInit()
205
+}
206
+
207
+func SetDevDir(dir string) error {
208
+	if res := DmSetDevDir(dir); res != 1 {
209
+		utils.Debugf("Error dm_set_dev_dir")
210
+		return ErrSetDevDir
211
+	}
212
+	return nil
213
+}
214
+
215
+func GetLibraryVersion() (string, error) {
216
+	var version string
217
+	if res := DmGetLibraryVersion(&version); res != 1 {
218
+		return "", ErrGetLibraryVersion
219
+	}
220
+	return version, nil
221
+}
222
+
223
+// Useful helper for cleanup
224
+func RemoveDevice(name string) error {
225
+	task := TaskCreate(DeviceRemove)
226
+	if task == nil {
227
+		return ErrCreateRemoveTask
228
+	}
229
+	if err := task.SetName(name); err != nil {
230
+		utils.Debugf("Can't set task name %s", name)
231
+		return err
232
+	}
233
+	if err := task.Run(); err != nil {
234
+		return ErrRunRemoveDevice
235
+	}
236
+	return nil
237
+}
238
+
239
+func GetBlockDeviceSize(file *os.File) (uint64, error) {
240
+	size, errno := DmGetBlockSize(file.Fd())
241
+	if size == -1 || errno != 0 {
242
+		return 0, ErrGetBlockSize
243
+	}
244
+	return uint64(size), nil
245
+}
246
+
247
+// This is the programmatic example of "dmsetup create"
248
+func createPool(poolName string, dataFile *os.File, metadataFile *os.File) error {
249
+	task, err := createTask(DeviceCreate, poolName)
250
+	if task == nil {
251
+		return err
252
+	}
253
+
254
+	size, err := GetBlockDeviceSize(dataFile)
255
+	if err != nil {
256
+		return fmt.Errorf("Can't get data size")
257
+	}
258
+
259
+	params := metadataFile.Name() + " " + dataFile.Name() + " 128 32768"
260
+	if err := task.AddTarget(0, size/512, "thin-pool", params); err != nil {
261
+		return fmt.Errorf("Can't add target")
262
+	}
263
+
264
+	var cookie uint = 0
265
+	if err := task.SetCookie(&cookie, 0); err != nil {
266
+		return fmt.Errorf("Can't set cookie")
267
+	}
268
+
269
+	if err := task.Run(); err != nil {
270
+		return fmt.Errorf("Error running DeviceCreate (createPool)")
271
+	}
272
+
273
+	UdevWait(cookie)
274
+
275
+	return nil
276
+}
277
+
278
+func createTask(t TaskType, name string) (*Task, error) {
279
+	task := TaskCreate(t)
280
+	if task == nil {
281
+		return nil, fmt.Errorf("Can't create task of type %d", int(t))
282
+	}
283
+	if err := task.SetName(name); err != nil {
284
+		return nil, fmt.Errorf("Can't set task name %s", name)
285
+	}
286
+	return task, nil
287
+}
288
+
289
+func getInfo(name string) (*Info, error) {
290
+	task, err := createTask(DeviceInfo, name)
291
+	if task == nil {
292
+		return nil, err
293
+	}
294
+	if err := task.Run(); err != nil {
295
+		return nil, err
296
+	}
297
+	return task.GetInfo()
298
+}
299
+
300
+func getStatus(name string) (uint64, uint64, string, string, error) {
301
+	task, err := createTask(DeviceStatus, name)
302
+	if task == nil {
303
+		utils.Debugf("getStatus: Error createTask: %s", err)
304
+		return 0, 0, "", "", err
305
+	}
306
+	if err := task.Run(); err != nil {
307
+		utils.Debugf("getStatus: Error Run: %s", err)
308
+		return 0, 0, "", "", err
309
+	}
310
+
311
+	devinfo, err := task.GetInfo()
312
+	if err != nil {
313
+		utils.Debugf("getStatus: Error GetInfo: %s", err)
314
+		return 0, 0, "", "", err
315
+	}
316
+	if devinfo.Exists == 0 {
317
+		utils.Debugf("getStatus: Non existing device %s", name)
318
+		return 0, 0, "", "", fmt.Errorf("Non existing device %s", name)
319
+	}
320
+
321
+	_, start, length, target_type, params := task.GetNextTarget(0)
322
+	return start, length, target_type, params, nil
323
+}
324
+
325
+func setTransactionId(poolName string, oldId uint64, newId uint64) error {
326
+	task, err := createTask(DeviceTargetMsg, poolName)
327
+	if task == nil {
328
+		return err
329
+	}
330
+
331
+	if err := task.SetSector(0); err != nil {
332
+		return fmt.Errorf("Can't set sector")
333
+	}
334
+
335
+	if err := task.SetMessage(fmt.Sprintf("set_transaction_id %d %d", oldId, newId)); err != nil {
336
+		return fmt.Errorf("Can't set message")
337
+	}
338
+
339
+	if err := task.Run(); err != nil {
340
+		return fmt.Errorf("Error running setTransactionId")
341
+	}
342
+	return nil
343
+}
344
+
345
+func suspendDevice(name string) error {
346
+	task, err := createTask(DeviceSuspend, name)
347
+	if task == nil {
348
+		return err
349
+	}
350
+	if err := task.Run(); err != nil {
351
+		return fmt.Errorf("Error running DeviceSuspend")
352
+	}
353
+	return nil
354
+}
355
+
356
+func resumeDevice(name string) error {
357
+	task, err := createTask(DeviceResume, name)
358
+	if task == nil {
359
+		return err
360
+	}
361
+
362
+	var cookie uint = 0
363
+	if err := task.SetCookie(&cookie, 0); err != nil {
364
+		return fmt.Errorf("Can't set cookie")
365
+	}
366
+
367
+	if err := task.Run(); err != nil {
368
+		return fmt.Errorf("Error running DeviceSuspend")
369
+	}
370
+
371
+	UdevWait(cookie)
372
+
373
+	return nil
374
+}
375
+
376
+func createDevice(poolName string, deviceId int) error {
377
+	utils.Debugf("[devmapper] createDevice(poolName=%v, deviceId=%v)", poolName, deviceId)
378
+	task, err := createTask(DeviceTargetMsg, poolName)
379
+	if task == nil {
380
+		return err
381
+	}
382
+
383
+	if err := task.SetSector(0); err != nil {
384
+		return fmt.Errorf("Can't set sector")
385
+	}
386
+
387
+	if err := task.SetMessage(fmt.Sprintf("create_thin %d", deviceId)); err != nil {
388
+		return fmt.Errorf("Can't set message")
389
+	}
390
+
391
+	if err := task.Run(); err != nil {
392
+		return fmt.Errorf("Error running createDevice")
393
+	}
394
+	return nil
395
+}
396
+
397
+func deleteDevice(poolName string, deviceId int) error {
398
+	task, err := createTask(DeviceTargetMsg, poolName)
399
+	if task == nil {
400
+		return err
401
+	}
402
+
403
+	if err := task.SetSector(0); err != nil {
404
+		return fmt.Errorf("Can't set sector")
405
+	}
406
+
407
+	if err := task.SetMessage(fmt.Sprintf("delete %d", deviceId)); err != nil {
408
+		return fmt.Errorf("Can't set message")
409
+	}
410
+
411
+	if err := task.Run(); err != nil {
412
+		return fmt.Errorf("Error running deleteDevice")
413
+	}
414
+	return nil
415
+}
416
+
417
+func removeDevice(name string) error {
418
+	utils.Debugf("[devmapper] removeDevice START")
419
+	defer utils.Debugf("[devmapper] removeDevice END")
420
+	task, err := createTask(DeviceRemove, name)
421
+	if task == nil {
422
+		return err
423
+	}
424
+	if err = task.Run(); err != nil {
425
+		return fmt.Errorf("Error running removeDevice")
426
+	}
427
+	return nil
428
+}
429
+
430
+func activateDevice(poolName string, name string, deviceId int, size uint64) error {
431
+	task, err := createTask(DeviceCreate, name)
432
+	if task == nil {
433
+		return err
434
+	}
435
+
436
+	params := fmt.Sprintf("%s %d", poolName, deviceId)
437
+	if err := task.AddTarget(0, size/512, "thin", params); err != nil {
438
+		return fmt.Errorf("Can't add target")
439
+	}
440
+	if err := task.SetAddNode(AddNodeOnCreate); err != nil {
441
+		return fmt.Errorf("Can't add node")
442
+	}
443
+
444
+	var cookie uint = 0
445
+	if err := task.SetCookie(&cookie, 0); err != nil {
446
+		return fmt.Errorf("Can't set cookie")
447
+	}
448
+
449
+	if err := task.Run(); err != nil {
450
+		return fmt.Errorf("Error running DeviceCreate (activateDevice)")
451
+	}
452
+
453
+	UdevWait(cookie)
454
+
455
+	return nil
456
+}
457
+
458
+func (devices *DeviceSet) createSnapDevice(poolName string, deviceId int, baseName string, baseDeviceId int) error {
459
+	devinfo, _ := getInfo(baseName)
460
+	doSuspend := devinfo != nil && devinfo.Exists != 0
461
+
462
+	if doSuspend {
463
+		if err := suspendDevice(baseName); err != nil {
464
+			return err
465
+		}
466
+	}
467
+
468
+	task, err := createTask(DeviceTargetMsg, poolName)
469
+	if task == nil {
470
+		if doSuspend {
471
+			resumeDevice(baseName)
472
+		}
473
+		return err
474
+	}
475
+
476
+	if err := task.SetSector(0); err != nil {
477
+		if doSuspend {
478
+			resumeDevice(baseName)
479
+		}
480
+		return fmt.Errorf("Can't set sector")
481
+	}
482
+
483
+	if err := task.SetMessage(fmt.Sprintf("create_snap %d %d", deviceId, baseDeviceId)); err != nil {
484
+		if doSuspend {
485
+			resumeDevice(baseName)
486
+		}
487
+		return fmt.Errorf("Can't set message")
488
+	}
489
+
490
+	if err := task.Run(); err != nil {
491
+		if doSuspend {
492
+			resumeDevice(baseName)
493
+		}
494
+		return fmt.Errorf("Error running DeviceCreate (createSnapDevice)")
495
+	}
496
+
497
+	if doSuspend {
498
+		if err := resumeDevice(baseName); err != nil {
499
+			return err
500
+		}
501
+	}
502
+
503
+	return nil
504
+}
0 505
new file mode 100644
... ...
@@ -0,0 +1,13 @@
0
+package devmapper
1
+
2
+import "C"
3
+
4
+// Due to the way cgo works this has to be in a separate file, as devmapper.go has
5
+// definitions in the cgo block, which is incompatible with using "//export"
6
+
7
+//export DevmapperLogCallback
8
+func DevmapperLogCallback(level C.int, file *C.char, line C.int, dm_errno_or_class C.int, message *C.char) {
9
+	if dmLogger != nil {
10
+		dmLogger.log(int(level), C.GoString(file), int(line), int(dm_errno_or_class), C.GoString(message))
11
+	}
12
+}
0 13
new file mode 100644
... ...
@@ -0,0 +1,285 @@
0
+package devmapper
1
+
2
+import (
3
+	"syscall"
4
+	"testing"
5
+)
6
+
7
+func TestTaskCreate(t *testing.T) {
8
+	// Test success
9
+	taskCreate(t, DeviceInfo)
10
+
11
+	// Test Failure
12
+	DmTaskCreate = dmTaskCreateFail
13
+	defer func() { DmTaskCreate = dmTaskCreateFct }()
14
+	if task := TaskCreate(-1); task != nil {
15
+		t.Fatalf("An error should have occured while creating an invalid task.")
16
+	}
17
+}
18
+
19
+func TestTaskRun(t *testing.T) {
20
+	task := taskCreate(t, DeviceInfo)
21
+
22
+	// Test success
23
+	// Perform the RUN
24
+	if err := task.Run(); err != nil {
25
+		t.Fatal(err)
26
+	}
27
+	// Make sure we don't have error with GetInfo
28
+	if _, err := task.GetInfo(); err != nil {
29
+		t.Fatal(err)
30
+	}
31
+
32
+	// Test failure
33
+	DmTaskRun = dmTaskRunFail
34
+	defer func() { DmTaskRun = dmTaskRunFct }()
35
+
36
+	task = taskCreate(t, DeviceInfo)
37
+	// Perform the RUN
38
+	if err := task.Run(); err != ErrTaskRun {
39
+		t.Fatalf("An error should have occured while running task.")
40
+	}
41
+	// Make sure GetInfo also fails
42
+	if _, err := task.GetInfo(); err != ErrTaskGetInfo {
43
+		t.Fatalf("GetInfo should fail if task.Run() failed.")
44
+	}
45
+}
46
+
47
+func TestTaskSetName(t *testing.T) {
48
+	task := taskCreate(t, DeviceInfo)
49
+
50
+	// Test success
51
+	if err := task.SetName("test"); err != nil {
52
+		t.Fatal(err)
53
+	}
54
+
55
+	// Test failure
56
+	DmTaskSetName = dmTaskSetNameFail
57
+	defer func() { DmTaskSetName = dmTaskSetNameFct }()
58
+
59
+	if err := task.SetName("test"); err != ErrTaskSetName {
60
+		t.Fatalf("An error should have occured while runnign SetName.")
61
+	}
62
+}
63
+
64
+func TestTaskSetMessage(t *testing.T) {
65
+	task := taskCreate(t, DeviceInfo)
66
+
67
+	// Test success
68
+	if err := task.SetMessage("test"); err != nil {
69
+		t.Fatal(err)
70
+	}
71
+
72
+	// Test failure
73
+	DmTaskSetMessage = dmTaskSetMessageFail
74
+	defer func() { DmTaskSetMessage = dmTaskSetMessageFct }()
75
+
76
+	if err := task.SetMessage("test"); err != ErrTaskSetMessage {
77
+		t.Fatalf("An error should have occured while runnign SetMessage.")
78
+	}
79
+}
80
+
81
+func TestTaskSetSector(t *testing.T) {
82
+	task := taskCreate(t, DeviceInfo)
83
+
84
+	// Test success
85
+	if err := task.SetSector(128); err != nil {
86
+		t.Fatal(err)
87
+	}
88
+
89
+	DmTaskSetSector = dmTaskSetSectorFail
90
+	defer func() { DmTaskSetSector = dmTaskSetSectorFct }()
91
+
92
+	// Test failure
93
+	if err := task.SetSector(0); err != ErrTaskSetSector {
94
+		t.Fatalf("An error should have occured while running SetSector.")
95
+	}
96
+}
97
+
98
+func TestTaskSetCookie(t *testing.T) {
99
+	var (
100
+		cookie uint = 0
101
+		task        = taskCreate(t, DeviceInfo)
102
+	)
103
+
104
+	// Test success
105
+	if err := task.SetCookie(&cookie, 0); err != nil {
106
+		t.Fatal(err)
107
+	}
108
+
109
+	// Test failure
110
+	if err := task.SetCookie(nil, 0); err != ErrNilCookie {
111
+		t.Fatalf("An error should have occured while running SetCookie with nil cookie.")
112
+	}
113
+
114
+	DmTaskSetCookie = dmTaskSetCookieFail
115
+	defer func() { DmTaskSetCookie = dmTaskSetCookieFct }()
116
+
117
+	if err := task.SetCookie(&cookie, 0); err != ErrTaskSetCookie {
118
+		t.Fatalf("An error should have occured while running SetCookie.")
119
+	}
120
+}
121
+
122
+func TestTaskSetAddNode(t *testing.T) {
123
+	task := taskCreate(t, DeviceInfo)
124
+
125
+	// Test success
126
+	if err := task.SetAddNode(0); err != nil {
127
+		t.Fatal(err)
128
+	}
129
+
130
+	// Test failure
131
+	if err := task.SetAddNode(-1); err != ErrInvalidAddNode {
132
+		t.Fatalf("An error should have occured running SetAddNode with wrong node.")
133
+	}
134
+
135
+	DmTaskSetAddNode = dmTaskSetAddNodeFail
136
+	defer func() { DmTaskSetAddNode = dmTaskSetAddNodeFct }()
137
+
138
+	if err := task.SetAddNode(0); err != ErrTaskSetAddNode {
139
+		t.Fatalf("An error should have occured running SetAddNode.")
140
+	}
141
+}
142
+
143
+func TestTaskSetRo(t *testing.T) {
144
+	task := taskCreate(t, DeviceInfo)
145
+
146
+	// Test success
147
+	if err := task.SetRo(); err != nil {
148
+		t.Fatal(err)
149
+	}
150
+
151
+	// Test failure
152
+	DmTaskSetRo = dmTaskSetRoFail
153
+	defer func() { DmTaskSetRo = dmTaskSetRoFct }()
154
+
155
+	if err := task.SetRo(); err != ErrTaskSetRo {
156
+		t.Fatalf("An error should have occured running SetRo.")
157
+	}
158
+}
159
+
160
+func TestTaskAddTarget(t *testing.T) {
161
+	task := taskCreate(t, DeviceInfo)
162
+
163
+	// Test success
164
+	if err := task.AddTarget(0, 128, "thinp", ""); err != nil {
165
+		t.Fatal(err)
166
+	}
167
+
168
+	// Test failure
169
+	DmTaskAddTarget = dmTaskAddTargetFail
170
+	defer func() { DmTaskAddTarget = dmTaskAddTargetFct }()
171
+
172
+	if err := task.AddTarget(0, 128, "thinp", ""); err != ErrTaskAddTarget {
173
+		t.Fatalf("An error should have occured running AddTarget.")
174
+	}
175
+}
176
+
177
+// func TestTaskGetInfo(t *testing.T) {
178
+// 	task := taskCreate(t, DeviceInfo)
179
+
180
+// 	// Test success
181
+// 	if _, err := task.GetInfo(); err != nil {
182
+// 		t.Fatal(err)
183
+// 	}
184
+
185
+// 	// Test failure
186
+// 	DmTaskGetInfo = dmTaskGetInfoFail
187
+// 	defer func() { DmTaskGetInfo = dmTaskGetInfoFct }()
188
+
189
+// 	if _, err := task.GetInfo(); err != ErrTaskGetInfo {
190
+// 		t.Fatalf("An error should have occured running GetInfo.")
191
+// 	}
192
+// }
193
+
194
+// func TestTaskGetNextTarget(t *testing.T) {
195
+// 	task := taskCreate(t, DeviceInfo)
196
+
197
+// 	if next, _, _, _, _ := task.GetNextTarget(0); next == 0 {
198
+// 		t.Fatalf("The next target should not be 0.")
199
+// 	}
200
+// }
201
+
202
+/// Utils
203
+func taskCreate(t *testing.T, taskType TaskType) *Task {
204
+	task := TaskCreate(taskType)
205
+	if task == nil {
206
+		t.Fatalf("Error creating task")
207
+	}
208
+	return task
209
+}
210
+
211
+/// Failure function replacement
212
+func dmTaskCreateFail(t int) *CDmTask {
213
+	return nil
214
+}
215
+
216
+func dmTaskRunFail(task *CDmTask) int {
217
+	return -1
218
+}
219
+
220
+func dmTaskSetNameFail(task *CDmTask, name string) int {
221
+	return -1
222
+}
223
+
224
+func dmTaskSetMessageFail(task *CDmTask, message string) int {
225
+	return -1
226
+}
227
+
228
+func dmTaskSetSectorFail(task *CDmTask, sector uint64) int {
229
+	return -1
230
+}
231
+
232
+func dmTaskSetCookieFail(task *CDmTask, cookie *uint, flags uint16) int {
233
+	return -1
234
+}
235
+
236
+func dmTaskSetAddNodeFail(task *CDmTask, addNode AddNodeType) int {
237
+	return -1
238
+}
239
+
240
+func dmTaskSetRoFail(task *CDmTask) int {
241
+	return -1
242
+}
243
+
244
+func dmTaskAddTargetFail(task *CDmTask,
245
+	start, size uint64, ttype, params string) int {
246
+	return -1
247
+}
248
+
249
+func dmTaskGetDriverVersionFail(task *CDmTask, version *string) int {
250
+	return -1
251
+}
252
+
253
+func dmTaskGetInfoFail(task *CDmTask, info *Info) int {
254
+	return -1
255
+}
256
+
257
+func dmGetNextTargetFail(task *CDmTask, next uintptr, start, length *uint64,
258
+	target, params *string) uintptr {
259
+	return 0
260
+}
261
+
262
+func dmAttachLoopDeviceFail(filename string, fd *int) string {
263
+	return ""
264
+}
265
+
266
+func sysGetBlockSizeFail(fd uintptr, size *uint64) syscall.Errno {
267
+	return 1
268
+}
269
+
270
+func dmGetBlockSizeFail(fd uintptr) int64 {
271
+	return -1
272
+}
273
+
274
+func dmUdevWaitFail(cookie uint) int {
275
+	return -1
276
+}
277
+
278
+func dmSetDevDirFail(dir string) int {
279
+	return -1
280
+}
281
+
282
+func dmGetLibraryVersionFail(version *string) int {
283
+	return -1
284
+}
0 285
new file mode 100644
... ...
@@ -0,0 +1,330 @@
0
+package devmapper
1
+
2
+/*
3
+#cgo LDFLAGS: -L. -ldevmapper
4
+#include <stdio.h>
5
+#include <stdlib.h>
6
+#include <unistd.h>
7
+#include <libdevmapper.h>
8
+#include <linux/loop.h>
9
+#include <sys/types.h>
10
+#include <sys/stat.h>
11
+#include <fcntl.h>
12
+#include <sys/ioctl.h>
13
+#include <linux/fs.h>
14
+#include <errno.h>
15
+
16
+#ifndef LOOP_CTL_GET_FREE
17
+#define LOOP_CTL_GET_FREE       0x4C82
18
+#endif
19
+
20
+// FIXME: this could easily be rewritten in go
21
+char*			attach_loop_device(const char *filename, int *loop_fd_out)
22
+{
23
+  struct loop_info64	loopinfo = {0};
24
+  struct stat		st;
25
+  char			buf[64];
26
+  int			i, loop_fd, fd, start_index;
27
+  char*			loopname;
28
+
29
+
30
+  *loop_fd_out = -1;
31
+
32
+  start_index = 0;
33
+  fd = open("/dev/loop-control", O_RDONLY);
34
+  if (fd >= 0) {
35
+    start_index = ioctl(fd, LOOP_CTL_GET_FREE);
36
+    close(fd);
37
+
38
+    if (start_index < 0)
39
+      start_index = 0;
40
+  }
41
+
42
+  fd = open(filename, O_RDWR);
43
+  if (fd < 0) {
44
+    perror("open");
45
+    return NULL;
46
+  }
47
+
48
+  loop_fd = -1;
49
+  for (i = start_index ; loop_fd < 0 ; i++ ) {
50
+    if (sprintf(buf, "/dev/loop%d", i) < 0) {
51
+	close(fd);
52
+	return NULL;
53
+    }
54
+
55
+    if (stat(buf, &st)) {
56
+      if (!S_ISBLK(st.st_mode)) {
57
+	 fprintf(stderr, "[error] Loopback device %s is not a block device.\n", buf);
58
+      } else if (errno == ENOENT) {
59
+	fprintf(stderr, "[error] There are no more loopback device available.\n");
60
+      } else {
61
+	fprintf(stderr, "[error] Unkown error trying to stat the loopback device %s (errno: %d).\n", buf, errno);
62
+      }
63
+      close(fd);
64
+      return NULL;
65
+    }
66
+
67
+    loop_fd = open(buf, O_RDWR);
68
+    if (loop_fd < 0 && errno == ENOENT) {
69
+      fprintf(stderr, "[error] The loopback device %s does not exists.\n", buf);
70
+      close(fd);
71
+      return NULL;
72
+    } else if (loop_fd < 0) {
73
+	fprintf(stderr, "[error] Unkown error openning the loopback device %s. (errno: %d)\n", buf, errno);
74
+	continue;
75
+    }
76
+
77
+    if (ioctl(loop_fd, LOOP_SET_FD, (void *)(size_t)fd) < 0) {
78
+      int errsv = errno;
79
+      close(loop_fd);
80
+      loop_fd = -1;
81
+      if (errsv != EBUSY) {
82
+        close(fd);
83
+        fprintf(stderr, "cannot set up loopback device %s: %s", buf, strerror(errsv));
84
+        return NULL;
85
+      }
86
+      continue;
87
+    }
88
+
89
+    close(fd);
90
+
91
+    strncpy((char*)loopinfo.lo_file_name, buf, LO_NAME_SIZE);
92
+    loopinfo.lo_offset = 0;
93
+    loopinfo.lo_flags = LO_FLAGS_AUTOCLEAR;
94
+
95
+    if (ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo) < 0) {
96
+      perror("ioctl LOOP_SET_STATUS64");
97
+      if (ioctl(loop_fd, LOOP_CLR_FD, 0) < 0) {
98
+        perror("ioctl LOOP_CLR_FD");
99
+      }
100
+      close(loop_fd);
101
+      fprintf (stderr, "cannot set up loopback device info");
102
+      return (NULL);
103
+    }
104
+
105
+    loopname = strdup(buf);
106
+    if (loopname == NULL) {
107
+      close(loop_fd);
108
+      return (NULL);
109
+    }
110
+
111
+    *loop_fd_out = loop_fd;
112
+    return (loopname);
113
+  }
114
+
115
+  return (NULL);
116
+}
117
+
118
+extern void DevmapperLogCallback(int level, char *file, int line, int dm_errno_or_class, char *str);
119
+
120
+static void	log_cb(int level, const char *file, int line,
121
+		       int dm_errno_or_class, const char *f, ...)
122
+{
123
+  char buffer[256];
124
+  va_list ap;
125
+
126
+  va_start(ap, f);
127
+  vsnprintf(buffer, 256, f, ap);
128
+  va_end(ap);
129
+
130
+  DevmapperLogCallback(level, (char *)file, line, dm_errno_or_class, buffer);
131
+}
132
+
133
+static void	log_with_errno_init()
134
+{
135
+  dm_log_with_errno_init(log_cb);
136
+}
137
+
138
+*/
139
+import "C"
140
+
141
+import (
142
+	"syscall"
143
+	"unsafe"
144
+)
145
+
146
+type (
147
+	CDmTask C.struct_dm_task
148
+)
149
+
150
+var (
151
+	DmTaskDestory       = dmTaskDestroyFct
152
+	DmTaskCreate        = dmTaskCreateFct
153
+	DmTaskRun           = dmTaskRunFct
154
+	DmTaskSetName       = dmTaskSetNameFct
155
+	DmTaskSetMessage    = dmTaskSetMessageFct
156
+	DmTaskSetSector     = dmTaskSetSectorFct
157
+	DmTaskSetCookie     = dmTaskSetCookieFct
158
+	DmTaskSetAddNode    = dmTaskSetAddNodeFct
159
+	DmTaskSetRo         = dmTaskSetRoFct
160
+	DmTaskAddTarget     = dmTaskAddTargetFct
161
+	DmTaskGetInfo       = dmTaskGetInfoFct
162
+	DmGetNextTarget     = dmGetNextTargetFct
163
+	DmGetBlockSize      = dmGetBlockSizeFct
164
+	DmAttachLoopDevice  = dmAttachLoopDeviceFct
165
+	DmUdevWait          = dmUdevWaitFct
166
+	DmLogInitVerbose    = dmLogInitVerboseFct
167
+	DmSetDevDir         = dmSetDevDirFct
168
+	DmGetLibraryVersion = dmGetLibraryVersionFct
169
+	LogWithErrnoInit    = logWithErrnoInitFct
170
+	GetBlockSize        = getBlockSizeFct
171
+)
172
+
173
+func free(p *C.char) {
174
+	C.free(unsafe.Pointer(p))
175
+}
176
+
177
+func dmTaskDestroyFct(task *CDmTask) {
178
+	C.dm_task_destroy((*C.struct_dm_task)(task))
179
+}
180
+
181
+func dmTaskCreateFct(taskType int) *CDmTask {
182
+	return (*CDmTask)(C.dm_task_create(C.int(taskType)))
183
+}
184
+
185
+func dmTaskRunFct(task *CDmTask) int {
186
+	return int(C.dm_task_run((*C.struct_dm_task)(task)))
187
+}
188
+
189
+func dmTaskSetNameFct(task *CDmTask, name string) int {
190
+	Cname := C.CString(name)
191
+	defer free(Cname)
192
+
193
+	return int(C.dm_task_set_name((*C.struct_dm_task)(task),
194
+		Cname))
195
+}
196
+
197
+func dmTaskSetMessageFct(task *CDmTask, message string) int {
198
+	Cmessage := C.CString(message)
199
+	defer free(Cmessage)
200
+
201
+	return int(C.dm_task_set_message((*C.struct_dm_task)(task),
202
+		Cmessage))
203
+}
204
+
205
+func dmTaskSetSectorFct(task *CDmTask, sector uint64) int {
206
+	return int(C.dm_task_set_sector((*C.struct_dm_task)(task),
207
+		C.uint64_t(sector)))
208
+}
209
+
210
+func dmTaskSetCookieFct(task *CDmTask, cookie *uint, flags uint16) int {
211
+	cCookie := C.uint32_t(*cookie)
212
+	defer func() {
213
+		*cookie = uint(cCookie)
214
+	}()
215
+	return int(C.dm_task_set_cookie((*C.struct_dm_task)(task), &cCookie,
216
+		C.uint16_t(flags)))
217
+}
218
+
219
+func dmTaskSetAddNodeFct(task *CDmTask, addNode AddNodeType) int {
220
+	return int(C.dm_task_set_add_node((*C.struct_dm_task)(task),
221
+		C.dm_add_node_t(addNode)))
222
+}
223
+
224
+func dmTaskSetRoFct(task *CDmTask) int {
225
+	return int(C.dm_task_set_ro((*C.struct_dm_task)(task)))
226
+}
227
+
228
+func dmTaskAddTargetFct(task *CDmTask,
229
+	start, size uint64, ttype, params string) int {
230
+
231
+	Cttype := C.CString(ttype)
232
+	defer free(Cttype)
233
+
234
+	Cparams := C.CString(params)
235
+	defer free(Cparams)
236
+
237
+	return int(C.dm_task_add_target((*C.struct_dm_task)(task),
238
+		C.uint64_t(start), C.uint64_t(size), Cttype, Cparams))
239
+}
240
+
241
+func dmGetBlockSizeFct(fd uintptr) (int64, syscall.Errno) {
242
+	var size int64
243
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BLKGETSIZE64,
244
+		uintptr(unsafe.Pointer(&size)))
245
+	return size, err
246
+}
247
+
248
+func dmTaskGetInfoFct(task *CDmTask, info *Info) int {
249
+	Cinfo := C.struct_dm_info{}
250
+	defer func() {
251
+		info.Exists = int(Cinfo.exists)
252
+		info.Suspended = int(Cinfo.suspended)
253
+		info.LiveTable = int(Cinfo.live_table)
254
+		info.InactiveTable = int(Cinfo.inactive_table)
255
+		info.OpenCount = int32(Cinfo.open_count)
256
+		info.EventNr = uint32(Cinfo.event_nr)
257
+		info.Major = uint32(Cinfo.major)
258
+		info.Minor = uint32(Cinfo.minor)
259
+		info.ReadOnly = int(Cinfo.read_only)
260
+		info.TargetCount = int32(Cinfo.target_count)
261
+	}()
262
+	return int(C.dm_task_get_info((*C.struct_dm_task)(task), &Cinfo))
263
+}
264
+
265
+func dmGetNextTargetFct(task *CDmTask, next uintptr, start, length *uint64,
266
+	target, params *string) uintptr {
267
+
268
+	var (
269
+		Cstart, Clength      C.uint64_t
270
+		CtargetType, Cparams *C.char
271
+	)
272
+	defer func() {
273
+		*start = uint64(Cstart)
274
+		*length = uint64(Clength)
275
+		*target = C.GoString(CtargetType)
276
+		*params = C.GoString(Cparams)
277
+	}()
278
+	nextp := C.dm_get_next_target((*C.struct_dm_task)(task),
279
+		unsafe.Pointer(next), &Cstart, &Clength, &CtargetType, &Cparams)
280
+	return uintptr(nextp)
281
+}
282
+
283
+func dmAttachLoopDeviceFct(filename string, fd *int) string {
284
+	cFilename := C.CString(filename)
285
+	defer free(cFilename)
286
+
287
+	var cFd C.int
288
+	defer func() {
289
+		*fd = int(cFd)
290
+	}()
291
+
292
+	ret := C.attach_loop_device(cFilename, &cFd)
293
+	defer free(ret)
294
+	return C.GoString(ret)
295
+}
296
+
297
+func getBlockSizeFct(fd uintptr, size *uint64) syscall.Errno {
298
+	_, _, err := syscall.Syscall(syscall.SYS_IOCTL, fd, C.BLKGETSIZE64,
299
+		uintptr(unsafe.Pointer(&size)))
300
+	return err
301
+}
302
+
303
+func dmUdevWaitFct(cookie uint) int {
304
+	return int(C.dm_udev_wait(C.uint32_t(cookie)))
305
+}
306
+
307
+func dmLogInitVerboseFct(level int) {
308
+	C.dm_log_init_verbose(C.int(level))
309
+}
310
+
311
+func logWithErrnoInitFct() {
312
+	C.log_with_errno_init()
313
+}
314
+
315
+func dmSetDevDirFct(dir string) int {
316
+	Cdir := C.CString(dir)
317
+	defer free(Cdir)
318
+
319
+	return int(C.dm_set_dev_dir(Cdir))
320
+}
321
+
322
+func dmGetLibraryVersionFct(version *string) int {
323
+	buffer := C.CString(string(make([]byte, 128)))
324
+	defer free(buffer)
325
+	defer func() {
326
+		*version = C.GoString(buffer)
327
+	}()
328
+	return int(C.dm_get_library_version(buffer, 128))
329
+}
0 330
new file mode 100644
... ...
@@ -0,0 +1,62 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"github.com/dotcloud/docker/devmapper"
5
+	"os"
6
+)
7
+
8
+func usage() {
9
+	fmt.Printf("Usage: %s [snap new-id base-id] | [remove id] | [mount id mountpoint]\n", os.Args[0])
10
+	os.Exit(1)
11
+}
12
+
13
+func main() {
14
+	devices := devmapper.NewDeviceSet("/var/lib/docker")
15
+
16
+	if len(os.Args) < 2 {
17
+		usage()
18
+	}
19
+
20
+	cmd := os.Args[1]
21
+	if cmd == "snap" {
22
+		if len(os.Args) < 4 {
23
+			usage()
24
+		}
25
+
26
+		err := devices.AddDevice(os.Args[2], os.Args[3])
27
+		if err != nil {
28
+			fmt.Println("Can't create snap device: ", err)
29
+			os.Exit(1)
30
+		}
31
+	} else if cmd == "remove" {
32
+		if len(os.Args) < 3 {
33
+			usage()
34
+		}
35
+
36
+		err := devices.RemoveDevice(os.Args[2])
37
+		if err != nil {
38
+			fmt.Println("Can't remove device: ", err)
39
+			os.Exit(1)
40
+		}
41
+	} else if cmd == "mount" {
42
+		if len(os.Args) < 4 {
43
+			usage()
44
+		}
45
+
46
+		err := devices.MountDevice(os.Args[2], os.Args[3])
47
+		if err != nil {
48
+			fmt.Println("Can't create snap device: ", err)
49
+			os.Exit(1)
50
+		}
51
+	} else {
52
+		fmt.Printf("Unknown command %s\n", cmd)
53
+		if len(os.Args) < 4 {
54
+			usage()
55
+		}
56
+
57
+		os.Exit(1)
58
+	}
59
+
60
+	return
61
+}
0 62
new file mode 100644
... ...
@@ -0,0 +1,92 @@
0
+package devmapper
1
+
2
+import (
3
+	"fmt"
4
+	"github.com/dotcloud/docker/graphdriver"
5
+	"os"
6
+	"path"
7
+)
8
+
9
+func init() {
10
+	graphdriver.Register("devicemapper", Init)
11
+}
12
+
13
+// Placeholder interfaces, to be replaced
14
+// at integration.
15
+
16
+// End of placeholder interfaces.
17
+
18
+type Driver struct {
19
+	*DeviceSet
20
+	home string
21
+}
22
+
23
+func Init(home string) (graphdriver.Driver, error) {
24
+	deviceSet, err := NewDeviceSet(home)
25
+	if err != nil {
26
+		return nil, err
27
+	}
28
+	d := &Driver{
29
+		DeviceSet: deviceSet,
30
+		home:      home,
31
+	}
32
+	return d, nil
33
+}
34
+
35
+func (d *Driver) String() string {
36
+	return "devicemapper"
37
+}
38
+
39
+func (d *Driver) Status() [][2]string {
40
+	s := d.DeviceSet.Status()
41
+
42
+	status := [][2]string{
43
+		{"Pool Name", s.PoolName},
44
+		{"Data file", s.DataLoopback},
45
+		{"Metadata file", s.MetadataLoopback},
46
+		{"Data Space Used", fmt.Sprintf("%.1f Mb", float64(s.Data.Used)/(1024*1024))},
47
+		{"Data Space Total", fmt.Sprintf("%.1f Mb", float64(s.Data.Total)/(1024*1024))},
48
+		{"Metadata Space Used", fmt.Sprintf("%.1f Mb", float64(s.Metadata.Used)/(1024*1024))},
49
+		{"Metadata Space Total", fmt.Sprintf("%.1f Mb", float64(s.Metadata.Total)/(1024*1024))},
50
+	}
51
+	return status
52
+}
53
+
54
+func (d *Driver) Cleanup() error {
55
+	return d.DeviceSet.Shutdown()
56
+}
57
+
58
+func (d *Driver) Create(id string, parent string) error {
59
+	return d.DeviceSet.AddDevice(id, parent)
60
+}
61
+
62
+func (d *Driver) Remove(id string) error {
63
+	return d.DeviceSet.RemoveDevice(id)
64
+}
65
+
66
+func (d *Driver) Get(id string) (string, error) {
67
+	mp := path.Join(d.home, "mnt", id)
68
+	if err := d.mount(id, mp); err != nil {
69
+		return "", err
70
+	}
71
+	return mp, nil
72
+}
73
+
74
+func (d *Driver) Size(id string) (int64, error) {
75
+	return -1, fmt.Errorf("Not implemented")
76
+}
77
+
78
+func (d *Driver) mount(id, mountPoint string) error {
79
+	// Create the target directories if they don't exist
80
+	if err := os.MkdirAll(mountPoint, 0755); err != nil && !os.IsExist(err) {
81
+		return err
82
+	}
83
+	// If mountpoint is already mounted, do nothing
84
+	if mounted, err := Mounted(mountPoint); err != nil {
85
+		return fmt.Errorf("Error checking mountpoint: %s", err)
86
+	} else if mounted {
87
+		return nil
88
+	}
89
+	// Mount the device
90
+	return d.DeviceSet.MountDevice(id, mountPoint, false)
91
+}
0 92
new file mode 100644
... ...
@@ -0,0 +1,301 @@
0
+package devmapper
1
+
2
+import (
3
+	"io/ioutil"
4
+	"os"
5
+	"path"
6
+	"testing"
7
+)
8
+
9
+func init() {
10
+	// Reduce the size the the base fs and loopback for the tests
11
+	DefaultDataLoopbackSize = 300 * 1024 * 1024
12
+	DefaultMetaDataLoopbackSize = 200 * 1024 * 1024
13
+	DefaultBaseFsSize = 300 * 1024 * 1024
14
+
15
+}
16
+
17
+func mkTestDirectory(t *testing.T) string {
18
+	dir, err := ioutil.TempDir("", "docker-test-devmapper-")
19
+	if err != nil {
20
+		t.Fatal(err)
21
+	}
22
+	return dir
23
+}
24
+
25
+func newDriver(t *testing.T) *Driver {
26
+	home := mkTestDirectory(t)
27
+	d, err := Init(home)
28
+	if err != nil {
29
+		t.Fatal(err)
30
+	}
31
+	return d.(*Driver)
32
+}
33
+
34
+func cleanup(d *Driver) {
35
+	d.Cleanup()
36
+	os.RemoveAll(d.home)
37
+}
38
+
39
+func TestInit(t *testing.T) {
40
+	home := mkTestDirectory(t)
41
+	defer os.RemoveAll(home)
42
+	driver, err := Init(home)
43
+	if err != nil {
44
+		t.Fatal(err)
45
+	}
46
+	defer func() {
47
+		if err := driver.Cleanup(); err != nil {
48
+			t.Fatal(err)
49
+		}
50
+	}()
51
+
52
+	id := "foo"
53
+	if err := driver.Create(id, ""); err != nil {
54
+		t.Fatal(err)
55
+	}
56
+	dir, err := driver.Get(id)
57
+	if err != nil {
58
+		t.Fatal(err)
59
+	}
60
+	if st, err := os.Stat(dir); err != nil {
61
+		t.Fatal(err)
62
+	} else if !st.IsDir() {
63
+		t.Fatalf("Get(%V) did not return a directory", id)
64
+	}
65
+}
66
+
67
+func TestDriverName(t *testing.T) {
68
+	d := newDriver(t)
69
+	defer cleanup(d)
70
+
71
+	if d.String() != "devicemapper" {
72
+		t.Fatalf("Expected driver name to be devicemapper got %s", d.String())
73
+	}
74
+}
75
+
76
+func TestDriverCreate(t *testing.T) {
77
+	d := newDriver(t)
78
+	defer cleanup(d)
79
+
80
+	if err := d.Create("1", ""); err != nil {
81
+		t.Fatal(err)
82
+	}
83
+}
84
+
85
+func TestDriverRemove(t *testing.T) {
86
+	d := newDriver(t)
87
+	defer cleanup(d)
88
+
89
+	if err := d.Create("1", ""); err != nil {
90
+		t.Fatal(err)
91
+	}
92
+
93
+	if err := d.Remove("1"); err != nil {
94
+		t.Fatal(err)
95
+	}
96
+}
97
+
98
+func TestCleanup(t *testing.T) {
99
+	d := newDriver(t)
100
+	defer os.RemoveAll(d.home)
101
+
102
+	mountPoints := make([]string, 2)
103
+
104
+	if err := d.Create("1", ""); err != nil {
105
+		t.Fatal(err)
106
+	}
107
+	// Mount the id
108
+	p, err := d.Get("1")
109
+	if err != nil {
110
+		t.Fatal(err)
111
+	}
112
+	mountPoints[0] = p
113
+
114
+	if err := d.Create("2", "1"); err != nil {
115
+		t.Fatal(err)
116
+	}
117
+
118
+	p, err = d.Get("2")
119
+	if err != nil {
120
+		t.Fatal(err)
121
+	}
122
+	mountPoints[1] = p
123
+
124
+	// Ensure that all the mount points are currently mounted
125
+	for _, p := range mountPoints {
126
+		if mounted, err := Mounted(p); err != nil {
127
+			t.Fatal(err)
128
+		} else if !mounted {
129
+			t.Fatalf("Expected %s to be mounted", p)
130
+		}
131
+	}
132
+
133
+	// Ensure that devices are active
134
+	for _, p := range []string{"1", "2"} {
135
+		if !d.HasActivatedDevice(p) {
136
+			t.Fatalf("Expected %s to have an active device", p)
137
+		}
138
+	}
139
+
140
+	if err := d.Cleanup(); err != nil {
141
+		t.Fatal(err)
142
+	}
143
+
144
+	// Ensure that all the mount points are no longer mounted
145
+	for _, p := range mountPoints {
146
+		if mounted, err := Mounted(p); err != nil {
147
+			t.Fatal(err)
148
+		} else if mounted {
149
+			t.Fatalf("Expected %s to not be mounted", p)
150
+		}
151
+	}
152
+
153
+	// Ensure that devices are no longer activated
154
+	for _, p := range []string{"1", "2"} {
155
+		if d.HasActivatedDevice(p) {
156
+			t.Fatalf("Expected %s not be an active device", p)
157
+		}
158
+	}
159
+}
160
+
161
+func TestNotMounted(t *testing.T) {
162
+	d := newDriver(t)
163
+	defer cleanup(d)
164
+
165
+	if err := d.Create("1", ""); err != nil {
166
+		t.Fatal(err)
167
+	}
168
+
169
+	mounted, err := Mounted(path.Join(d.home, "mnt", "1"))
170
+	if err != nil {
171
+		t.Fatal(err)
172
+	}
173
+	if mounted {
174
+		t.Fatal("Id 1 should not be mounted")
175
+	}
176
+}
177
+
178
+func TestMounted(t *testing.T) {
179
+	d := newDriver(t)
180
+	defer cleanup(d)
181
+
182
+	if err := d.Create("1", ""); err != nil {
183
+		t.Fatal(err)
184
+	}
185
+	if _, err := d.Get("1"); err != nil {
186
+		t.Fatal(err)
187
+	}
188
+
189
+	mounted, err := Mounted(path.Join(d.home, "mnt", "1"))
190
+	if err != nil {
191
+		t.Fatal(err)
192
+	}
193
+	if !mounted {
194
+		t.Fatal("Id 1 should be mounted")
195
+	}
196
+}
197
+
198
+func TestInitCleanedDriver(t *testing.T) {
199
+	d := newDriver(t)
200
+
201
+	if err := d.Create("1", ""); err != nil {
202
+		t.Fatal(err)
203
+	}
204
+	if _, err := d.Get("1"); err != nil {
205
+		t.Fatal(err)
206
+	}
207
+
208
+	if err := d.Cleanup(); err != nil {
209
+		t.Fatal(err)
210
+	}
211
+
212
+	driver, err := Init(d.home)
213
+	if err != nil {
214
+		t.Fatal(err)
215
+	}
216
+	d = driver.(*Driver)
217
+	defer cleanup(d)
218
+
219
+	if _, err := d.Get("1"); err != nil {
220
+		t.Fatal(err)
221
+	}
222
+}
223
+
224
+func TestMountMountedDriver(t *testing.T) {
225
+	d := newDriver(t)
226
+	defer cleanup(d)
227
+
228
+	if err := d.Create("1", ""); err != nil {
229
+		t.Fatal(err)
230
+	}
231
+
232
+	// Perform get on same id to ensure that it will
233
+	// not be mounted twice
234
+	if _, err := d.Get("1"); err != nil {
235
+		t.Fatal(err)
236
+	}
237
+	if _, err := d.Get("1"); err != nil {
238
+		t.Fatal(err)
239
+	}
240
+}
241
+
242
+func TestGetReturnsValidDevice(t *testing.T) {
243
+	d := newDriver(t)
244
+	defer cleanup(d)
245
+
246
+	if err := d.Create("1", ""); err != nil {
247
+		t.Fatal(err)
248
+	}
249
+
250
+	if !d.HasDevice("1") {
251
+		t.Fatalf("Expected id 1 to be in device set")
252
+	}
253
+
254
+	if _, err := d.Get("1"); err != nil {
255
+		t.Fatal(err)
256
+	}
257
+
258
+	if !d.HasActivatedDevice("1") {
259
+		t.Fatalf("Expected id 1 to be activated")
260
+	}
261
+
262
+	if !d.HasInitializedDevice("1") {
263
+		t.Fatalf("Expected id 1 to be initialized")
264
+	}
265
+}
266
+
267
+func TestDriverGetSize(t *testing.T) {
268
+	t.Skipf("Size is currently not implemented")
269
+
270
+	d := newDriver(t)
271
+	defer cleanup(d)
272
+
273
+	if err := d.Create("1", ""); err != nil {
274
+		t.Fatal(err)
275
+	}
276
+
277
+	mountPoint, err := d.Get("1")
278
+	if err != nil {
279
+		t.Fatal(err)
280
+	}
281
+
282
+	size := int64(1024)
283
+
284
+	f, err := os.Create(path.Join(mountPoint, "test_file"))
285
+	if err != nil {
286
+		t.Fatal(err)
287
+	}
288
+	if err := f.Truncate(size); err != nil {
289
+		t.Fatal(err)
290
+	}
291
+	f.Close()
292
+
293
+	diffSize, err := d.Size("1")
294
+	if err != nil {
295
+		t.Fatal(err)
296
+	}
297
+	if diffSize != size {
298
+		t.Fatalf("Expected size %d got %d", size, diffSize)
299
+	}
300
+}
0 301
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+package devmapper
1
+
2
+import (
3
+	"os"
4
+	"path/filepath"
5
+	"syscall"
6
+)
7
+
8
+// FIXME: this is copy-pasted from the aufs driver.
9
+// It should be moved into the core.
10
+
11
+func Mounted(mountpoint string) (bool, error) {
12
+	mntpoint, err := os.Stat(mountpoint)
13
+	if err != nil {
14
+		if os.IsNotExist(err) {
15
+			return false, nil
16
+		}
17
+		return false, err
18
+	}
19
+	parent, err := os.Stat(filepath.Join(mountpoint, ".."))
20
+	if err != nil {
21
+		return false, err
22
+	}
23
+	mntpointSt := mntpoint.Sys().(*syscall.Stat_t)
24
+	parentSt := parent.Sys().(*syscall.Stat_t)
25
+	return mntpointSt.Dev != parentSt.Dev, nil
26
+}
... ...
@@ -6,10 +6,10 @@ import (
6 6
 	"database/sql"
7 7
 	"fmt"
8 8
 	"github.com/dotcloud/docker/archive"
9
-	_ "github.com/dotcloud/docker/aufs"
10
-	_ "github.com/dotcloud/docker/devmapper"
11 9
 	"github.com/dotcloud/docker/gograph"
12 10
 	"github.com/dotcloud/docker/graphdriver"
11
+	_ "github.com/dotcloud/docker/graphdriver/aufs"
12
+	_ "github.com/dotcloud/docker/graphdriver/devmapper"
13 13
 	_ "github.com/dotcloud/docker/graphdriver/dummy"
14 14
 	"github.com/dotcloud/docker/utils"
15 15
 	"io"