Browse code

Remove the last references to overlayfs

This only renames docker internal structures.
It has no impact on the end-user.

Signed-off-by: Lénaïc Huard <lhuard@amadeus.com>

Lénaïc Huard authored on 2014/12/03 22:06:19
Showing 8 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,7 @@
0
+// +build !exclude_graphdriver_overlay
1
+
2
+package daemon
3
+
4
+import (
5
+	_ "github.com/docker/docker/daemon/graphdriver/overlay"
6
+)
0 7
deleted file mode 100644
... ...
@@ -1,7 +0,0 @@
1
-// +build !exclude_graphdriver_overlayfs
2
-
3
-package daemon
4
-
5
-import (
6
-	_ "github.com/docker/docker/daemon/graphdriver/overlayfs"
7
-)
8 1
new file mode 100644
... ...
@@ -0,0 +1,157 @@
0
+// +build linux
1
+
2
+package overlay
3
+
4
+import (
5
+	"fmt"
6
+	"io"
7
+	"os"
8
+	"path/filepath"
9
+	"syscall"
10
+
11
+	"github.com/docker/docker/pkg/system"
12
+)
13
+
14
+type CopyFlags int
15
+
16
+const (
17
+	CopyHardlink CopyFlags = 1 << iota
18
+)
19
+
20
+func copyRegular(srcPath, dstPath string, mode os.FileMode) error {
21
+	srcFile, err := os.Open(srcPath)
22
+	if err != nil {
23
+		return err
24
+	}
25
+	defer srcFile.Close()
26
+
27
+	dstFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE, mode)
28
+	if err != nil {
29
+		return err
30
+	}
31
+	defer dstFile.Close()
32
+
33
+	_, err = io.Copy(dstFile, srcFile)
34
+
35
+	return err
36
+}
37
+
38
+func copyXattr(srcPath, dstPath, attr string) error {
39
+	data, err := system.Lgetxattr(srcPath, attr)
40
+	if err != nil {
41
+		return err
42
+	}
43
+	if data != nil {
44
+		if err := system.Lsetxattr(dstPath, attr, data, 0); err != nil {
45
+			return err
46
+		}
47
+	}
48
+	return nil
49
+}
50
+
51
+func copyDir(srcDir, dstDir string, flags CopyFlags) error {
52
+	err := filepath.Walk(srcDir, func(srcPath string, f os.FileInfo, err error) error {
53
+		if err != nil {
54
+			return err
55
+		}
56
+
57
+		// Rebase path
58
+		relPath, err := filepath.Rel(srcDir, srcPath)
59
+		if err != nil {
60
+			return err
61
+		}
62
+
63
+		dstPath := filepath.Join(dstDir, relPath)
64
+		if err != nil {
65
+			return err
66
+		}
67
+
68
+		stat, ok := f.Sys().(*syscall.Stat_t)
69
+		if !ok {
70
+			return fmt.Errorf("Unable to get raw syscall.Stat_t data for %s", srcPath)
71
+		}
72
+
73
+		switch f.Mode() & os.ModeType {
74
+		case 0: // Regular file
75
+			if flags&CopyHardlink != 0 {
76
+				if err := os.Link(srcPath, dstPath); err != nil {
77
+					return err
78
+				}
79
+			} else {
80
+				if err := copyRegular(srcPath, dstPath, f.Mode()); err != nil {
81
+					return err
82
+				}
83
+			}
84
+
85
+		case os.ModeDir:
86
+			if err := os.Mkdir(dstPath, f.Mode()); err != nil && !os.IsExist(err) {
87
+				return err
88
+			}
89
+
90
+		case os.ModeSymlink:
91
+			link, err := os.Readlink(srcPath)
92
+			if err != nil {
93
+				return err
94
+			}
95
+
96
+			if err := os.Symlink(link, dstPath); err != nil {
97
+				return err
98
+			}
99
+
100
+		case os.ModeNamedPipe:
101
+			fallthrough
102
+		case os.ModeSocket:
103
+			if err := syscall.Mkfifo(dstPath, stat.Mode); err != nil {
104
+				return err
105
+			}
106
+
107
+		case os.ModeDevice:
108
+			if err := syscall.Mknod(dstPath, stat.Mode, int(stat.Rdev)); err != nil {
109
+				return err
110
+			}
111
+
112
+		default:
113
+			return fmt.Errorf("Unknown file type for %s\n", srcPath)
114
+		}
115
+
116
+		if err := os.Lchown(dstPath, int(stat.Uid), int(stat.Gid)); err != nil {
117
+			return err
118
+		}
119
+
120
+		if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil {
121
+			return err
122
+		}
123
+
124
+		// We need to copy this attribute if it appears in an overlay upper layer, as
125
+		// this function is used to copy those. It is set by overlay if a directory
126
+		// is removed and then re-created and should not inherit anything from the
127
+		// same dir in the lower dir.
128
+		if err := copyXattr(srcPath, dstPath, "trusted.overlay.opaque"); err != nil {
129
+			return err
130
+		}
131
+
132
+		isSymlink := f.Mode()&os.ModeSymlink != 0
133
+
134
+		// There is no LChmod, so ignore mode for symlink. Also, this
135
+		// must happen after chown, as that can modify the file mode
136
+		if !isSymlink {
137
+			if err := os.Chmod(dstPath, f.Mode()); err != nil {
138
+				return err
139
+			}
140
+		}
141
+
142
+		ts := []syscall.Timespec{stat.Atim, stat.Mtim}
143
+		// syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and
144
+		if !isSymlink {
145
+			if err := system.UtimesNano(dstPath, ts); err != nil {
146
+				return err
147
+			}
148
+		} else {
149
+			if err := system.LUtimesNano(dstPath, ts); err != nil {
150
+				return err
151
+			}
152
+		}
153
+		return nil
154
+	})
155
+	return err
156
+}
0 157
new file mode 100644
... ...
@@ -0,0 +1,369 @@
0
+// +build linux
1
+
2
+package overlay
3
+
4
+import (
5
+	"bufio"
6
+	"fmt"
7
+	"io/ioutil"
8
+	"os"
9
+	"os/exec"
10
+	"path"
11
+	"sync"
12
+	"syscall"
13
+
14
+	log "github.com/Sirupsen/logrus"
15
+	"github.com/docker/docker/daemon/graphdriver"
16
+	"github.com/docker/docker/pkg/archive"
17
+	"github.com/docker/libcontainer/label"
18
+)
19
+
20
+// This is a small wrapper over the NaiveDiffWriter that lets us have a custom
21
+// implementation of ApplyDiff()
22
+
23
+var (
24
+	ErrApplyDiffFallback = fmt.Errorf("Fall back to normal ApplyDiff")
25
+)
26
+
27
+type ApplyDiffProtoDriver interface {
28
+	graphdriver.ProtoDriver
29
+	ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error)
30
+}
31
+
32
+type naiveDiffDriverWithApply struct {
33
+	graphdriver.Driver
34
+	applyDiff ApplyDiffProtoDriver
35
+}
36
+
37
+func NaiveDiffDriverWithApply(driver ApplyDiffProtoDriver) graphdriver.Driver {
38
+	return &naiveDiffDriverWithApply{
39
+		Driver:    graphdriver.NaiveDiffDriver(driver),
40
+		applyDiff: driver,
41
+	}
42
+}
43
+
44
+func (d *naiveDiffDriverWithApply) ApplyDiff(id, parent string, diff archive.ArchiveReader) (int64, error) {
45
+	b, err := d.applyDiff.ApplyDiff(id, parent, diff)
46
+	if err == ErrApplyDiffFallback {
47
+		return d.Driver.ApplyDiff(id, parent, diff)
48
+	}
49
+	return b, err
50
+}
51
+
52
+// This backend uses the overlay union filesystem for containers
53
+// plus hard link file sharing for images.
54
+
55
+// Each container/image can have a "root" subdirectory which is a plain
56
+// filesystem hierarchy, or they can use overlay.
57
+
58
+// If they use overlay there is a "upper" directory and a "lower-id"
59
+// file, as well as "merged" and "work" directories. The "upper"
60
+// directory has the upper layer of the overlay, and "lower-id" contains
61
+// the id of the parent whose "root" directory shall be used as the lower
62
+// layer in the overlay. The overlay itself is mounted in the "merged"
63
+// directory, and the "work" dir is needed for overlay to work.
64
+
65
+// When a overlay layer is created there are two cases, either the
66
+// parent has a "root" dir, then we start out with a empty "upper"
67
+// directory overlaid on the parents root. This is typically the
68
+// case with the init layer of a container which is based on an image.
69
+// If there is no "root" in the parent, we inherit the lower-id from
70
+// the parent and start by making a copy if the parents "upper" dir.
71
+// This is typically the case for a container layer which copies
72
+// its parent -init upper layer.
73
+
74
+// Additionally we also have a custom implementation of ApplyLayer
75
+// which makes a recursive copy of the parent "root" layer using
76
+// hardlinks to share file data, and then applies the layer on top
77
+// of that. This means all child images share file (but not directory)
78
+// data with the parent.
79
+
80
+type ActiveMount struct {
81
+	count   int
82
+	path    string
83
+	mounted bool
84
+}
85
+type Driver struct {
86
+	home       string
87
+	sync.Mutex // Protects concurrent modification to active
88
+	active     map[string]*ActiveMount
89
+}
90
+
91
+func init() {
92
+	graphdriver.Register("overlay", Init)
93
+}
94
+
95
+func Init(home string, options []string) (graphdriver.Driver, error) {
96
+	if err := supportsOverlay(); err != nil {
97
+		return nil, graphdriver.ErrNotSupported
98
+	}
99
+
100
+	// Create the driver home dir
101
+	if err := os.MkdirAll(home, 0755); err != nil && !os.IsExist(err) {
102
+		return nil, err
103
+	}
104
+
105
+	d := &Driver{
106
+		home:   home,
107
+		active: make(map[string]*ActiveMount),
108
+	}
109
+
110
+	return NaiveDiffDriverWithApply(d), nil
111
+}
112
+
113
+func supportsOverlay() error {
114
+	// We can try to modprobe overlay first before looking at
115
+	// proc/filesystems for when overlay is supported
116
+	exec.Command("modprobe", "overlay").Run()
117
+
118
+	f, err := os.Open("/proc/filesystems")
119
+	if err != nil {
120
+		return err
121
+	}
122
+	defer f.Close()
123
+
124
+	s := bufio.NewScanner(f)
125
+	for s.Scan() {
126
+		if s.Text() == "nodev\toverlay" {
127
+			return nil
128
+		}
129
+	}
130
+	log.Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
131
+	return graphdriver.ErrNotSupported
132
+}
133
+
134
+func (d *Driver) String() string {
135
+	return "overlay"
136
+}
137
+
138
+func (d *Driver) Status() [][2]string {
139
+	return nil
140
+}
141
+
142
+func (d *Driver) Cleanup() error {
143
+	return nil
144
+}
145
+
146
+func (d *Driver) Create(id string, parent string) (retErr error) {
147
+	dir := d.dir(id)
148
+	if err := os.MkdirAll(path.Dir(dir), 0700); err != nil {
149
+		return err
150
+	}
151
+	if err := os.Mkdir(dir, 0700); err != nil {
152
+		return err
153
+	}
154
+
155
+	defer func() {
156
+		// Clean up on failure
157
+		if retErr != nil {
158
+			os.RemoveAll(dir)
159
+		}
160
+	}()
161
+
162
+	// Toplevel images are just a "root" dir
163
+	if parent == "" {
164
+		if err := os.Mkdir(path.Join(dir, "root"), 0755); err != nil {
165
+			return err
166
+		}
167
+		return nil
168
+	}
169
+
170
+	parentDir := d.dir(parent)
171
+
172
+	// Ensure parent exists
173
+	if _, err := os.Lstat(parentDir); err != nil {
174
+		return err
175
+	}
176
+
177
+	// If parent has a root, just do a overlay to it
178
+	parentRoot := path.Join(parentDir, "root")
179
+
180
+	if s, err := os.Lstat(parentRoot); err == nil {
181
+		if err := os.Mkdir(path.Join(dir, "upper"), s.Mode()); err != nil {
182
+			return err
183
+		}
184
+		if err := os.Mkdir(path.Join(dir, "work"), 0700); err != nil {
185
+			return err
186
+		}
187
+		if err := os.Mkdir(path.Join(dir, "merged"), 0700); err != nil {
188
+			return err
189
+		}
190
+		if err := ioutil.WriteFile(path.Join(dir, "lower-id"), []byte(parent), 0666); err != nil {
191
+			return err
192
+		}
193
+		return nil
194
+	}
195
+
196
+	// Otherwise, copy the upper and the lower-id from the parent
197
+
198
+	lowerId, err := ioutil.ReadFile(path.Join(parentDir, "lower-id"))
199
+	if err != nil {
200
+		return err
201
+	}
202
+
203
+	if err := ioutil.WriteFile(path.Join(dir, "lower-id"), lowerId, 0666); err != nil {
204
+		return err
205
+	}
206
+
207
+	parentUpperDir := path.Join(parentDir, "upper")
208
+	s, err := os.Lstat(parentUpperDir)
209
+	if err != nil {
210
+		return err
211
+	}
212
+
213
+	upperDir := path.Join(dir, "upper")
214
+	if err := os.Mkdir(upperDir, s.Mode()); err != nil {
215
+		return err
216
+	}
217
+	if err := os.Mkdir(path.Join(dir, "work"), 0700); err != nil {
218
+		return err
219
+	}
220
+	if err := os.Mkdir(path.Join(dir, "merged"), 0700); err != nil {
221
+		return err
222
+	}
223
+
224
+	return copyDir(parentUpperDir, upperDir, 0)
225
+}
226
+
227
+func (d *Driver) dir(id string) string {
228
+	return path.Join(d.home, id)
229
+}
230
+
231
+func (d *Driver) Remove(id string) error {
232
+	dir := d.dir(id)
233
+	if _, err := os.Stat(dir); err != nil {
234
+		return err
235
+	}
236
+	return os.RemoveAll(dir)
237
+}
238
+
239
+func (d *Driver) Get(id string, mountLabel string) (string, error) {
240
+	// Protect the d.active from concurrent access
241
+	d.Lock()
242
+	defer d.Unlock()
243
+
244
+	mount := d.active[id]
245
+	if mount != nil {
246
+		mount.count++
247
+		return mount.path, nil
248
+	} else {
249
+		mount = &ActiveMount{count: 1}
250
+	}
251
+
252
+	dir := d.dir(id)
253
+	if _, err := os.Stat(dir); err != nil {
254
+		return "", err
255
+	}
256
+
257
+	// If id has a root, just return it
258
+	rootDir := path.Join(dir, "root")
259
+	if _, err := os.Stat(rootDir); err == nil {
260
+		mount.path = rootDir
261
+		d.active[id] = mount
262
+		return mount.path, nil
263
+	}
264
+
265
+	lowerId, err := ioutil.ReadFile(path.Join(dir, "lower-id"))
266
+	if err != nil {
267
+		return "", err
268
+	}
269
+	lowerDir := path.Join(d.dir(string(lowerId)), "root")
270
+	upperDir := path.Join(dir, "upper")
271
+	workDir := path.Join(dir, "work")
272
+	mergedDir := path.Join(dir, "merged")
273
+
274
+	opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
275
+	if err := syscall.Mount("overlay", mergedDir, "overlay", 0, label.FormatMountLabel(opts, mountLabel)); err != nil {
276
+		return "", err
277
+	}
278
+	mount.path = mergedDir
279
+	mount.mounted = true
280
+	d.active[id] = mount
281
+
282
+	return mount.path, nil
283
+}
284
+
285
+func (d *Driver) Put(id string) {
286
+	// Protect the d.active from concurrent access
287
+	d.Lock()
288
+	defer d.Unlock()
289
+
290
+	mount := d.active[id]
291
+	if mount == nil {
292
+		log.Debugf("Put on a non-mounted device %s", id)
293
+		return
294
+	}
295
+
296
+	mount.count--
297
+	if mount.count > 0 {
298
+		return
299
+	}
300
+
301
+	if mount.mounted {
302
+		if err := syscall.Unmount(mount.path, 0); err != nil {
303
+			log.Debugf("Failed to unmount %s overlay: %v", id, err)
304
+		}
305
+	}
306
+
307
+	delete(d.active, id)
308
+}
309
+
310
+func (d *Driver) ApplyDiff(id string, parent string, diff archive.ArchiveReader) (bytes int64, err error) {
311
+	dir := d.dir(id)
312
+
313
+	if parent == "" {
314
+		return 0, ErrApplyDiffFallback
315
+	}
316
+
317
+	parentRootDir := path.Join(d.dir(parent), "root")
318
+	if _, err := os.Stat(parentRootDir); err != nil {
319
+		return 0, ErrApplyDiffFallback
320
+	}
321
+
322
+	// We now know there is a parent, and it has a "root" directory containing
323
+	// the full root filesystem. We can just hardlink it and apply the
324
+	// layer. This relies on two things:
325
+	// 1) ApplyDiff is only run once on a clean (no writes to upper layer) container
326
+	// 2) ApplyDiff doesn't do any in-place writes to files (would break hardlinks)
327
+	// These are all currently true and are not expected to break
328
+
329
+	tmpRootDir, err := ioutil.TempDir(dir, "tmproot")
330
+	if err != nil {
331
+		return 0, err
332
+	}
333
+	defer func() {
334
+		if err != nil {
335
+			os.RemoveAll(tmpRootDir)
336
+		} else {
337
+			os.RemoveAll(path.Join(dir, "upper"))
338
+			os.RemoveAll(path.Join(dir, "work"))
339
+			os.RemoveAll(path.Join(dir, "merged"))
340
+			os.RemoveAll(path.Join(dir, "lower-id"))
341
+		}
342
+	}()
343
+
344
+	if err = copyDir(parentRootDir, tmpRootDir, CopyHardlink); err != nil {
345
+		return 0, err
346
+	}
347
+
348
+	if err := archive.ApplyLayer(tmpRootDir, diff); err != nil {
349
+		return 0, err
350
+	}
351
+
352
+	rootDir := path.Join(dir, "root")
353
+	if err := os.Rename(tmpRootDir, rootDir); err != nil {
354
+		return 0, err
355
+	}
356
+
357
+	changes, err := archive.ChangesDirs(rootDir, parentRootDir)
358
+	if err != nil {
359
+		return 0, err
360
+	}
361
+
362
+	return archive.ChangesSize(rootDir, changes), nil
363
+}
364
+
365
+func (d *Driver) Exists(id string) bool {
366
+	_, err := os.Stat(d.dir(id))
367
+	return err == nil
368
+}
0 369
new file mode 100644
... ...
@@ -0,0 +1,28 @@
0
+package overlay
1
+
2
+import (
3
+	"github.com/docker/docker/daemon/graphdriver/graphtest"
4
+	"testing"
5
+)
6
+
7
+// This avoids creating a new driver for each test if all tests are run
8
+// Make sure to put new tests between TestOverlaySetup and TestOverlayTeardown
9
+func TestOverlaySetup(t *testing.T) {
10
+	graphtest.GetDriver(t, "overlay")
11
+}
12
+
13
+func TestOverlayCreateEmpty(t *testing.T) {
14
+	graphtest.DriverTestCreateEmpty(t, "overlay")
15
+}
16
+
17
+func TestOverlayCreateBase(t *testing.T) {
18
+	graphtest.DriverTestCreateBase(t, "overlay")
19
+}
20
+
21
+func TestOverlayCreateSnap(t *testing.T) {
22
+	graphtest.DriverTestCreateSnap(t, "overlay")
23
+}
24
+
25
+func TestOverlayTeardown(t *testing.T) {
26
+	graphtest.PutDriver(t)
27
+}
0 28
deleted file mode 100644
... ...
@@ -1,157 +0,0 @@
1
-// +build linux
2
-
3
-package overlayfs
4
-
5
-import (
6
-	"fmt"
7
-	"io"
8
-	"os"
9
-	"path/filepath"
10
-	"syscall"
11
-
12
-	"github.com/docker/docker/pkg/system"
13
-)
14
-
15
-type CopyFlags int
16
-
17
-const (
18
-	CopyHardlink CopyFlags = 1 << iota
19
-)
20
-
21
-func copyRegular(srcPath, dstPath string, mode os.FileMode) error {
22
-	srcFile, err := os.Open(srcPath)
23
-	if err != nil {
24
-		return err
25
-	}
26
-	defer srcFile.Close()
27
-
28
-	dstFile, err := os.OpenFile(dstPath, os.O_WRONLY|os.O_CREATE, mode)
29
-	if err != nil {
30
-		return err
31
-	}
32
-	defer dstFile.Close()
33
-
34
-	_, err = io.Copy(dstFile, srcFile)
35
-
36
-	return err
37
-}
38
-
39
-func copyXattr(srcPath, dstPath, attr string) error {
40
-	data, err := system.Lgetxattr(srcPath, attr)
41
-	if err != nil {
42
-		return err
43
-	}
44
-	if data != nil {
45
-		if err := system.Lsetxattr(dstPath, attr, data, 0); err != nil {
46
-			return err
47
-		}
48
-	}
49
-	return nil
50
-}
51
-
52
-func copyDir(srcDir, dstDir string, flags CopyFlags) error {
53
-	err := filepath.Walk(srcDir, func(srcPath string, f os.FileInfo, err error) error {
54
-		if err != nil {
55
-			return err
56
-		}
57
-
58
-		// Rebase path
59
-		relPath, err := filepath.Rel(srcDir, srcPath)
60
-		if err != nil {
61
-			return err
62
-		}
63
-
64
-		dstPath := filepath.Join(dstDir, relPath)
65
-		if err != nil {
66
-			return err
67
-		}
68
-
69
-		stat, ok := f.Sys().(*syscall.Stat_t)
70
-		if !ok {
71
-			return fmt.Errorf("Unable to get raw syscall.Stat_t data for %s", srcPath)
72
-		}
73
-
74
-		switch f.Mode() & os.ModeType {
75
-		case 0: // Regular file
76
-			if flags&CopyHardlink != 0 {
77
-				if err := os.Link(srcPath, dstPath); err != nil {
78
-					return err
79
-				}
80
-			} else {
81
-				if err := copyRegular(srcPath, dstPath, f.Mode()); err != nil {
82
-					return err
83
-				}
84
-			}
85
-
86
-		case os.ModeDir:
87
-			if err := os.Mkdir(dstPath, f.Mode()); err != nil && !os.IsExist(err) {
88
-				return err
89
-			}
90
-
91
-		case os.ModeSymlink:
92
-			link, err := os.Readlink(srcPath)
93
-			if err != nil {
94
-				return err
95
-			}
96
-
97
-			if err := os.Symlink(link, dstPath); err != nil {
98
-				return err
99
-			}
100
-
101
-		case os.ModeNamedPipe:
102
-			fallthrough
103
-		case os.ModeSocket:
104
-			if err := syscall.Mkfifo(dstPath, stat.Mode); err != nil {
105
-				return err
106
-			}
107
-
108
-		case os.ModeDevice:
109
-			if err := syscall.Mknod(dstPath, stat.Mode, int(stat.Rdev)); err != nil {
110
-				return err
111
-			}
112
-
113
-		default:
114
-			return fmt.Errorf("Unknown file type for %s\n", srcPath)
115
-		}
116
-
117
-		if err := os.Lchown(dstPath, int(stat.Uid), int(stat.Gid)); err != nil {
118
-			return err
119
-		}
120
-
121
-		if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil {
122
-			return err
123
-		}
124
-
125
-		// We need to copy this attribute if it appears in an overlayfs upper layer, as
126
-		// this function is used to copy those. It is set by overlayfs if a directory
127
-		// is removed and then re-created and should not inherit anything from the
128
-		// same dir in the lower dir.
129
-		if err := copyXattr(srcPath, dstPath, "trusted.overlay.opaque"); err != nil {
130
-			return err
131
-		}
132
-
133
-		isSymlink := f.Mode()&os.ModeSymlink != 0
134
-
135
-		// There is no LChmod, so ignore mode for symlink. Also, this
136
-		// must happen after chown, as that can modify the file mode
137
-		if !isSymlink {
138
-			if err := os.Chmod(dstPath, f.Mode()); err != nil {
139
-				return err
140
-			}
141
-		}
142
-
143
-		ts := []syscall.Timespec{stat.Atim, stat.Mtim}
144
-		// syscall.UtimesNano doesn't support a NOFOLLOW flag atm, and
145
-		if !isSymlink {
146
-			if err := system.UtimesNano(dstPath, ts); err != nil {
147
-				return err
148
-			}
149
-		} else {
150
-			if err := system.LUtimesNano(dstPath, ts); err != nil {
151
-				return err
152
-			}
153
-		}
154
-		return nil
155
-	})
156
-	return err
157
-}
158 1
deleted file mode 100644
... ...
@@ -1,369 +0,0 @@
1
-// +build linux
2
-
3
-package overlayfs
4
-
5
-import (
6
-	"bufio"
7
-	"fmt"
8
-	"io/ioutil"
9
-	"os"
10
-	"os/exec"
11
-	"path"
12
-	"sync"
13
-	"syscall"
14
-
15
-	log "github.com/Sirupsen/logrus"
16
-	"github.com/docker/docker/daemon/graphdriver"
17
-	"github.com/docker/docker/pkg/archive"
18
-	"github.com/docker/libcontainer/label"
19
-)
20
-
21
-// This is a small wrapper over the NaiveDiffWriter that lets us have a custom
22
-// implementation of ApplyDiff()
23
-
24
-var (
25
-	ErrApplyDiffFallback = fmt.Errorf("Fall back to normal ApplyDiff")
26
-)
27
-
28
-type ApplyDiffProtoDriver interface {
29
-	graphdriver.ProtoDriver
30
-	ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error)
31
-}
32
-
33
-type naiveDiffDriverWithApply struct {
34
-	graphdriver.Driver
35
-	applyDiff ApplyDiffProtoDriver
36
-}
37
-
38
-func NaiveDiffDriverWithApply(driver ApplyDiffProtoDriver) graphdriver.Driver {
39
-	return &naiveDiffDriverWithApply{
40
-		Driver:    graphdriver.NaiveDiffDriver(driver),
41
-		applyDiff: driver,
42
-	}
43
-}
44
-
45
-func (d *naiveDiffDriverWithApply) ApplyDiff(id, parent string, diff archive.ArchiveReader) (int64, error) {
46
-	b, err := d.applyDiff.ApplyDiff(id, parent, diff)
47
-	if err == ErrApplyDiffFallback {
48
-		return d.Driver.ApplyDiff(id, parent, diff)
49
-	}
50
-	return b, err
51
-}
52
-
53
-// This backend uses the overlay union filesystem for containers
54
-// plus hard link file sharing for images.
55
-
56
-// Each container/image can have a "root" subdirectory which is a plain
57
-// filesystem hierarchy, or they can use overlay.
58
-
59
-// If they use overlay there is a "upper" directory and a "lower-id"
60
-// file, as well as "merged" and "work" directories. The "upper"
61
-// directory has the upper layer of the overlay, and "lower-id" contains
62
-// the id of the parent whose "root" directory shall be used as the lower
63
-// layer in the overlay. The overlay itself is mounted in the "merged"
64
-// directory, and the "work" dir is needed for overlay to work.
65
-
66
-// When a overlay layer is created there are two cases, either the
67
-// parent has a "root" dir, then we start out with a empty "upper"
68
-// directory overlaid on the parents root. This is typically the
69
-// case with the init layer of a container which is based on an image.
70
-// If there is no "root" in the parent, we inherit the lower-id from
71
-// the parent and start by making a copy if the parents "upper" dir.
72
-// This is typically the case for a container layer which copies
73
-// its parent -init upper layer.
74
-
75
-// Additionally we also have a custom implementation of ApplyLayer
76
-// which makes a recursive copy of the parent "root" layer using
77
-// hardlinks to share file data, and then applies the layer on top
78
-// of that. This means all child images share file (but not directory)
79
-// data with the parent.
80
-
81
-type ActiveMount struct {
82
-	count   int
83
-	path    string
84
-	mounted bool
85
-}
86
-type Driver struct {
87
-	home       string
88
-	sync.Mutex // Protects concurrent modification to active
89
-	active     map[string]*ActiveMount
90
-}
91
-
92
-func init() {
93
-	graphdriver.Register("overlay", Init)
94
-}
95
-
96
-func Init(home string, options []string) (graphdriver.Driver, error) {
97
-	if err := supportsOverlayfs(); err != nil {
98
-		return nil, graphdriver.ErrNotSupported
99
-	}
100
-
101
-	// Create the driver home dir
102
-	if err := os.MkdirAll(home, 0755); err != nil && !os.IsExist(err) {
103
-		return nil, err
104
-	}
105
-
106
-	d := &Driver{
107
-		home:   home,
108
-		active: make(map[string]*ActiveMount),
109
-	}
110
-
111
-	return NaiveDiffDriverWithApply(d), nil
112
-}
113
-
114
-func supportsOverlayfs() error {
115
-	// We can try to modprobe overlay first before looking at
116
-	// proc/filesystems for when overlay is supported
117
-	exec.Command("modprobe", "overlay").Run()
118
-
119
-	f, err := os.Open("/proc/filesystems")
120
-	if err != nil {
121
-		return err
122
-	}
123
-	defer f.Close()
124
-
125
-	s := bufio.NewScanner(f)
126
-	for s.Scan() {
127
-		if s.Text() == "nodev\toverlay" {
128
-			return nil
129
-		}
130
-	}
131
-	log.Error("'overlay' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlay support loaded.")
132
-	return graphdriver.ErrNotSupported
133
-}
134
-
135
-func (d *Driver) String() string {
136
-	return "overlay"
137
-}
138
-
139
-func (d *Driver) Status() [][2]string {
140
-	return nil
141
-}
142
-
143
-func (d *Driver) Cleanup() error {
144
-	return nil
145
-}
146
-
147
-func (d *Driver) Create(id string, parent string) (retErr error) {
148
-	dir := d.dir(id)
149
-	if err := os.MkdirAll(path.Dir(dir), 0700); err != nil {
150
-		return err
151
-	}
152
-	if err := os.Mkdir(dir, 0700); err != nil {
153
-		return err
154
-	}
155
-
156
-	defer func() {
157
-		// Clean up on failure
158
-		if retErr != nil {
159
-			os.RemoveAll(dir)
160
-		}
161
-	}()
162
-
163
-	// Toplevel images are just a "root" dir
164
-	if parent == "" {
165
-		if err := os.Mkdir(path.Join(dir, "root"), 0755); err != nil {
166
-			return err
167
-		}
168
-		return nil
169
-	}
170
-
171
-	parentDir := d.dir(parent)
172
-
173
-	// Ensure parent exists
174
-	if _, err := os.Lstat(parentDir); err != nil {
175
-		return err
176
-	}
177
-
178
-	// If parent has a root, just do a overlay to it
179
-	parentRoot := path.Join(parentDir, "root")
180
-
181
-	if s, err := os.Lstat(parentRoot); err == nil {
182
-		if err := os.Mkdir(path.Join(dir, "upper"), s.Mode()); err != nil {
183
-			return err
184
-		}
185
-		if err := os.Mkdir(path.Join(dir, "work"), 0700); err != nil {
186
-			return err
187
-		}
188
-		if err := os.Mkdir(path.Join(dir, "merged"), 0700); err != nil {
189
-			return err
190
-		}
191
-		if err := ioutil.WriteFile(path.Join(dir, "lower-id"), []byte(parent), 0666); err != nil {
192
-			return err
193
-		}
194
-		return nil
195
-	}
196
-
197
-	// Otherwise, copy the upper and the lower-id from the parent
198
-
199
-	lowerId, err := ioutil.ReadFile(path.Join(parentDir, "lower-id"))
200
-	if err != nil {
201
-		return err
202
-	}
203
-
204
-	if err := ioutil.WriteFile(path.Join(dir, "lower-id"), lowerId, 0666); err != nil {
205
-		return err
206
-	}
207
-
208
-	parentUpperDir := path.Join(parentDir, "upper")
209
-	s, err := os.Lstat(parentUpperDir)
210
-	if err != nil {
211
-		return err
212
-	}
213
-
214
-	upperDir := path.Join(dir, "upper")
215
-	if err := os.Mkdir(upperDir, s.Mode()); err != nil {
216
-		return err
217
-	}
218
-	if err := os.Mkdir(path.Join(dir, "work"), 0700); err != nil {
219
-		return err
220
-	}
221
-	if err := os.Mkdir(path.Join(dir, "merged"), 0700); err != nil {
222
-		return err
223
-	}
224
-
225
-	return copyDir(parentUpperDir, upperDir, 0)
226
-}
227
-
228
-func (d *Driver) dir(id string) string {
229
-	return path.Join(d.home, id)
230
-}
231
-
232
-func (d *Driver) Remove(id string) error {
233
-	dir := d.dir(id)
234
-	if _, err := os.Stat(dir); err != nil {
235
-		return err
236
-	}
237
-	return os.RemoveAll(dir)
238
-}
239
-
240
-func (d *Driver) Get(id string, mountLabel string) (string, error) {
241
-	// Protect the d.active from concurrent access
242
-	d.Lock()
243
-	defer d.Unlock()
244
-
245
-	mount := d.active[id]
246
-	if mount != nil {
247
-		mount.count++
248
-		return mount.path, nil
249
-	} else {
250
-		mount = &ActiveMount{count: 1}
251
-	}
252
-
253
-	dir := d.dir(id)
254
-	if _, err := os.Stat(dir); err != nil {
255
-		return "", err
256
-	}
257
-
258
-	// If id has a root, just return it
259
-	rootDir := path.Join(dir, "root")
260
-	if _, err := os.Stat(rootDir); err == nil {
261
-		mount.path = rootDir
262
-		d.active[id] = mount
263
-		return mount.path, nil
264
-	}
265
-
266
-	lowerId, err := ioutil.ReadFile(path.Join(dir, "lower-id"))
267
-	if err != nil {
268
-		return "", err
269
-	}
270
-	lowerDir := path.Join(d.dir(string(lowerId)), "root")
271
-	upperDir := path.Join(dir, "upper")
272
-	workDir := path.Join(dir, "work")
273
-	mergedDir := path.Join(dir, "merged")
274
-
275
-	opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
276
-	if err := syscall.Mount("overlay", mergedDir, "overlay", 0, label.FormatMountLabel(opts, mountLabel)); err != nil {
277
-		return "", err
278
-	}
279
-	mount.path = mergedDir
280
-	mount.mounted = true
281
-	d.active[id] = mount
282
-
283
-	return mount.path, nil
284
-}
285
-
286
-func (d *Driver) Put(id string) {
287
-	// Protect the d.active from concurrent access
288
-	d.Lock()
289
-	defer d.Unlock()
290
-
291
-	mount := d.active[id]
292
-	if mount == nil {
293
-		log.Debugf("Put on a non-mounted device %s", id)
294
-		return
295
-	}
296
-
297
-	mount.count--
298
-	if mount.count > 0 {
299
-		return
300
-	}
301
-
302
-	if mount.mounted {
303
-		if err := syscall.Unmount(mount.path, 0); err != nil {
304
-			log.Debugf("Failed to unmount %s overlay: %v", id, err)
305
-		}
306
-	}
307
-
308
-	delete(d.active, id)
309
-}
310
-
311
-func (d *Driver) ApplyDiff(id string, parent string, diff archive.ArchiveReader) (bytes int64, err error) {
312
-	dir := d.dir(id)
313
-
314
-	if parent == "" {
315
-		return 0, ErrApplyDiffFallback
316
-	}
317
-
318
-	parentRootDir := path.Join(d.dir(parent), "root")
319
-	if _, err := os.Stat(parentRootDir); err != nil {
320
-		return 0, ErrApplyDiffFallback
321
-	}
322
-
323
-	// We now know there is a parent, and it has a "root" directory containing
324
-	// the full root filesystem. We can just hardlink it and apply the
325
-	// layer. This relies on two things:
326
-	// 1) ApplyDiff is only run once on a clean (no writes to upper layer) container
327
-	// 2) ApplyDiff doesn't do any in-place writes to files (would break hardlinks)
328
-	// These are all currently true and are not expected to break
329
-
330
-	tmpRootDir, err := ioutil.TempDir(dir, "tmproot")
331
-	if err != nil {
332
-		return 0, err
333
-	}
334
-	defer func() {
335
-		if err != nil {
336
-			os.RemoveAll(tmpRootDir)
337
-		} else {
338
-			os.RemoveAll(path.Join(dir, "upper"))
339
-			os.RemoveAll(path.Join(dir, "work"))
340
-			os.RemoveAll(path.Join(dir, "merged"))
341
-			os.RemoveAll(path.Join(dir, "lower-id"))
342
-		}
343
-	}()
344
-
345
-	if err = copyDir(parentRootDir, tmpRootDir, CopyHardlink); err != nil {
346
-		return 0, err
347
-	}
348
-
349
-	if err := archive.ApplyLayer(tmpRootDir, diff); err != nil {
350
-		return 0, err
351
-	}
352
-
353
-	rootDir := path.Join(dir, "root")
354
-	if err := os.Rename(tmpRootDir, rootDir); err != nil {
355
-		return 0, err
356
-	}
357
-
358
-	changes, err := archive.ChangesDirs(rootDir, parentRootDir)
359
-	if err != nil {
360
-		return 0, err
361
-	}
362
-
363
-	return archive.ChangesSize(rootDir, changes), nil
364
-}
365
-
366
-func (d *Driver) Exists(id string) bool {
367
-	_, err := os.Stat(d.dir(id))
368
-	return err == nil
369
-}
370 1
deleted file mode 100644
... ...
@@ -1,28 +0,0 @@
1
-package overlayfs
2
-
3
-import (
4
-	"github.com/docker/docker/daemon/graphdriver/graphtest"
5
-	"testing"
6
-)
7
-
8
-// This avoids creating a new driver for each test if all tests are run
9
-// Make sure to put new tests between TestOverlayfsSetup and TestOverlayfsTeardown
10
-func TestOverlayfsSetup(t *testing.T) {
11
-	graphtest.GetDriver(t, "overlayfs")
12
-}
13
-
14
-func TestOverlayfsCreateEmpty(t *testing.T) {
15
-	graphtest.DriverTestCreateEmpty(t, "overlayfs")
16
-}
17
-
18
-func TestOverlayfsCreateBase(t *testing.T) {
19
-	graphtest.DriverTestCreateBase(t, "overlayfs")
20
-}
21
-
22
-func TestOverlayfsCreateSnap(t *testing.T) {
23
-	graphtest.DriverTestCreateSnap(t, "overlayfs")
24
-}
25
-
26
-func TestOverlayfsTeardown(t *testing.T) {
27
-	graphtest.PutDriver(t)
28
-}