Browse code

Merge pull request #9426 from lhuard1A/overlay_rename

Rename overlayfs to overlay

Michael Crosby authored on 2014/12/04 03:57:42
Showing 11 changed files
... ...
@@ -76,7 +76,7 @@ check_flags() {
76 76
 	for flag in "$@"; do
77 77
 		echo "- $(check_flag "$flag")"
78 78
 	done
79
-} 
79
+}
80 80
 
81 81
 if [ ! -e "$CONFIG" ]; then
82 82
 	wrap_warning "warning: $CONFIG does not exist, searching other paths for kernel config..."
... ...
@@ -165,8 +165,8 @@ echo '- Storage Drivers:'
165 165
 	echo '- "'$(wrap_color 'devicemapper' blue)'":'
166 166
 	check_flags BLK_DEV_DM DM_THIN_PROVISIONING EXT4_FS EXT4_FS_POSIX_ACL EXT4_FS_SECURITY | sed 's/^/  /'
167 167
 
168
-	echo '- "'$(wrap_color 'overlayfs' blue)'":'
169
-	check_flags OVERLAYFS_FS | sed 's/^/  /'
168
+	echo '- "'$(wrap_color 'overlay' blue)'":'
169
+	check_flags OVERLAY_FS | sed 's/^/  /'
170 170
 } | sed 's/^/  /'
171 171
 echo
172 172
 
173 173
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
-)
... ...
@@ -81,7 +81,7 @@ var (
81 81
 		"devicemapper",
82 82
 		"vfs",
83 83
 		// experimental, has to be enabled manually for now
84
-		"overlayfs",
84
+		"overlay",
85 85
 	}
86 86
 
87 87
 	ErrNotSupported   = errors.New("driver not supported")
88 88
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,370 +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
-	"strings"
13
-	"sync"
14
-	"syscall"
15
-
16
-	log "github.com/Sirupsen/logrus"
17
-	"github.com/docker/docker/daemon/graphdriver"
18
-	"github.com/docker/docker/pkg/archive"
19
-	"github.com/docker/libcontainer/label"
20
-)
21
-
22
-// This is a small wrapper over the NaiveDiffWriter that lets us have a custom
23
-// implementation of ApplyDiff()
24
-
25
-var (
26
-	ErrApplyDiffFallback = fmt.Errorf("Fall back to normal ApplyDiff")
27
-)
28
-
29
-type ApplyDiffProtoDriver interface {
30
-	graphdriver.ProtoDriver
31
-	ApplyDiff(id, parent string, diff archive.ArchiveReader) (bytes int64, err error)
32
-}
33
-
34
-type naiveDiffDriverWithApply struct {
35
-	graphdriver.Driver
36
-	applyDiff ApplyDiffProtoDriver
37
-}
38
-
39
-func NaiveDiffDriverWithApply(driver ApplyDiffProtoDriver) graphdriver.Driver {
40
-	return &naiveDiffDriverWithApply{
41
-		Driver:    graphdriver.NaiveDiffDriver(driver),
42
-		applyDiff: driver,
43
-	}
44
-}
45
-
46
-func (d *naiveDiffDriverWithApply) ApplyDiff(id, parent string, diff archive.ArchiveReader) (int64, error) {
47
-	b, err := d.applyDiff.ApplyDiff(id, parent, diff)
48
-	if err == ErrApplyDiffFallback {
49
-		return d.Driver.ApplyDiff(id, parent, diff)
50
-	}
51
-	return b, err
52
-}
53
-
54
-// This backend uses the overlayfs union filesystem for containers
55
-// plus hard link file sharing for images.
56
-
57
-// Each container/image can have a "root" subdirectory which is a plain
58
-// filesystem hierarchy, or they can use overlayfs.
59
-
60
-// If they use overlayfs there is a "upper" directory and a "lower-id"
61
-// file, as well as "merged" and "work" directories. The "upper"
62
-// directory has the upper layer of the overlay, and "lower-id" contains
63
-// the id of the parent whose "root" directory shall be used as the lower
64
-// layer in the overlay. The overlay itself is mounted in the "merged"
65
-// directory, and the "work" dir is needed for overlayfs to work.
66
-
67
-// When a overlay layer is created there are two cases, either the
68
-// parent has a "root" dir, then we start out with a empty "upper"
69
-// directory overlaid on the parents root. This is typically the
70
-// case with the init layer of a container which is based on an image.
71
-// If there is no "root" in the parent, we inherit the lower-id from
72
-// the parent and start by making a copy if the parents "upper" dir.
73
-// This is typically the case for a container layer which copies
74
-// its parent -init upper layer.
75
-
76
-// Additionally we also have a custom implementation of ApplyLayer
77
-// which makes a recursive copy of the parent "root" layer using
78
-// hardlinks to share file data, and then applies the layer on top
79
-// of that. This means all child images share file (but not directory)
80
-// data with the parent.
81
-
82
-type ActiveMount struct {
83
-	count   int
84
-	path    string
85
-	mounted bool
86
-}
87
-type Driver struct {
88
-	home       string
89
-	sync.Mutex // Protects concurrent modification to active
90
-	active     map[string]*ActiveMount
91
-}
92
-
93
-func init() {
94
-	graphdriver.Register("overlayfs", Init)
95
-}
96
-
97
-func Init(home string, options []string) (graphdriver.Driver, error) {
98
-	if err := supportsOverlayfs(); err != nil {
99
-		return nil, graphdriver.ErrNotSupported
100
-	}
101
-
102
-	// Create the driver home dir
103
-	if err := os.MkdirAll(home, 0755); err != nil && !os.IsExist(err) {
104
-		return nil, err
105
-	}
106
-
107
-	d := &Driver{
108
-		home:   home,
109
-		active: make(map[string]*ActiveMount),
110
-	}
111
-
112
-	return NaiveDiffDriverWithApply(d), nil
113
-}
114
-
115
-func supportsOverlayfs() error {
116
-	// We can try to modprobe overlayfs first before looking at
117
-	// proc/filesystems for when overlayfs is supported
118
-	exec.Command("modprobe", "overlayfs").Run()
119
-
120
-	f, err := os.Open("/proc/filesystems")
121
-	if err != nil {
122
-		return err
123
-	}
124
-	defer f.Close()
125
-
126
-	s := bufio.NewScanner(f)
127
-	for s.Scan() {
128
-		if strings.Contains(s.Text(), "overlayfs") {
129
-			return nil
130
-		}
131
-	}
132
-	log.Error("'overlayfs' not found as a supported filesystem on this host. Please ensure kernel is new enough and has overlayfs support loaded.")
133
-	return graphdriver.ErrNotSupported
134
-}
135
-
136
-func (d *Driver) String() string {
137
-	return "overlayfs"
138
-}
139
-
140
-func (d *Driver) Status() [][2]string {
141
-	return nil
142
-}
143
-
144
-func (d *Driver) Cleanup() error {
145
-	return nil
146
-}
147
-
148
-func (d *Driver) Create(id string, parent string) (retErr error) {
149
-	dir := d.dir(id)
150
-	if err := os.MkdirAll(path.Dir(dir), 0700); err != nil {
151
-		return err
152
-	}
153
-	if err := os.Mkdir(dir, 0700); err != nil {
154
-		return err
155
-	}
156
-
157
-	defer func() {
158
-		// Clean up on failure
159
-		if retErr != nil {
160
-			os.RemoveAll(dir)
161
-		}
162
-	}()
163
-
164
-	// Toplevel images are just a "root" dir
165
-	if parent == "" {
166
-		if err := os.Mkdir(path.Join(dir, "root"), 0755); err != nil {
167
-			return err
168
-		}
169
-		return nil
170
-	}
171
-
172
-	parentDir := d.dir(parent)
173
-
174
-	// Ensure parent exists
175
-	if _, err := os.Lstat(parentDir); err != nil {
176
-		return err
177
-	}
178
-
179
-	// If parent has a root, just do a overlayfs to it
180
-	parentRoot := path.Join(parentDir, "root")
181
-
182
-	if s, err := os.Lstat(parentRoot); err == nil {
183
-		if err := os.Mkdir(path.Join(dir, "upper"), s.Mode()); err != nil {
184
-			return err
185
-		}
186
-		if err := os.Mkdir(path.Join(dir, "work"), 0700); err != nil {
187
-			return err
188
-		}
189
-		if err := os.Mkdir(path.Join(dir, "merged"), 0700); err != nil {
190
-			return err
191
-		}
192
-		if err := ioutil.WriteFile(path.Join(dir, "lower-id"), []byte(parent), 0666); err != nil {
193
-			return err
194
-		}
195
-		return nil
196
-	}
197
-
198
-	// Otherwise, copy the upper and the lower-id from the parent
199
-
200
-	lowerId, err := ioutil.ReadFile(path.Join(parentDir, "lower-id"))
201
-	if err != nil {
202
-		return err
203
-	}
204
-
205
-	if err := ioutil.WriteFile(path.Join(dir, "lower-id"), lowerId, 0666); err != nil {
206
-		return err
207
-	}
208
-
209
-	parentUpperDir := path.Join(parentDir, "upper")
210
-	s, err := os.Lstat(parentUpperDir)
211
-	if err != nil {
212
-		return err
213
-	}
214
-
215
-	upperDir := path.Join(dir, "upper")
216
-	if err := os.Mkdir(upperDir, s.Mode()); err != nil {
217
-		return err
218
-	}
219
-	if err := os.Mkdir(path.Join(dir, "work"), 0700); err != nil {
220
-		return err
221
-	}
222
-	if err := os.Mkdir(path.Join(dir, "merged"), 0700); err != nil {
223
-		return err
224
-	}
225
-
226
-	return copyDir(parentUpperDir, upperDir, 0)
227
-}
228
-
229
-func (d *Driver) dir(id string) string {
230
-	return path.Join(d.home, id)
231
-}
232
-
233
-func (d *Driver) Remove(id string) error {
234
-	dir := d.dir(id)
235
-	if _, err := os.Stat(dir); err != nil {
236
-		return err
237
-	}
238
-	return os.RemoveAll(dir)
239
-}
240
-
241
-func (d *Driver) Get(id string, mountLabel string) (string, error) {
242
-	// Protect the d.active from concurrent access
243
-	d.Lock()
244
-	defer d.Unlock()
245
-
246
-	mount := d.active[id]
247
-	if mount != nil {
248
-		mount.count++
249
-		return mount.path, nil
250
-	} else {
251
-		mount = &ActiveMount{count: 1}
252
-	}
253
-
254
-	dir := d.dir(id)
255
-	if _, err := os.Stat(dir); err != nil {
256
-		return "", err
257
-	}
258
-
259
-	// If id has a root, just return it
260
-	rootDir := path.Join(dir, "root")
261
-	if _, err := os.Stat(rootDir); err == nil {
262
-		mount.path = rootDir
263
-		d.active[id] = mount
264
-		return mount.path, nil
265
-	}
266
-
267
-	lowerId, err := ioutil.ReadFile(path.Join(dir, "lower-id"))
268
-	if err != nil {
269
-		return "", err
270
-	}
271
-	lowerDir := path.Join(d.dir(string(lowerId)), "root")
272
-	upperDir := path.Join(dir, "upper")
273
-	workDir := path.Join(dir, "work")
274
-	mergedDir := path.Join(dir, "merged")
275
-
276
-	opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir)
277
-	if err := syscall.Mount("overlayfs", mergedDir, "overlayfs", 0, label.FormatMountLabel(opts, mountLabel)); err != nil {
278
-		return "", err
279
-	}
280
-	mount.path = mergedDir
281
-	mount.mounted = true
282
-	d.active[id] = mount
283
-
284
-	return mount.path, nil
285
-}
286
-
287
-func (d *Driver) Put(id string) {
288
-	// Protect the d.active from concurrent access
289
-	d.Lock()
290
-	defer d.Unlock()
291
-
292
-	mount := d.active[id]
293
-	if mount == nil {
294
-		log.Debugf("Put on a non-mounted device %s", id)
295
-		return
296
-	}
297
-
298
-	mount.count--
299
-	if mount.count > 0 {
300
-		return
301
-	}
302
-
303
-	if mount.mounted {
304
-		if err := syscall.Unmount(mount.path, 0); err != nil {
305
-			log.Debugf("Failed to unmount %s overlayfs: %v", id, err)
306
-		}
307
-	}
308
-
309
-	delete(d.active, id)
310
-}
311
-
312
-func (d *Driver) ApplyDiff(id string, parent string, diff archive.ArchiveReader) (bytes int64, err error) {
313
-	dir := d.dir(id)
314
-
315
-	if parent == "" {
316
-		return 0, ErrApplyDiffFallback
317
-	}
318
-
319
-	parentRootDir := path.Join(d.dir(parent), "root")
320
-	if _, err := os.Stat(parentRootDir); err != nil {
321
-		return 0, ErrApplyDiffFallback
322
-	}
323
-
324
-	// We now know there is a parent, and it has a "root" directory containing
325
-	// the full root filesystem. We can just hardlink it and apply the
326
-	// layer. This relies on two things:
327
-	// 1) ApplyDiff is only run once on a clean (no writes to upper layer) container
328
-	// 2) ApplyDiff doesn't do any in-place writes to files (would break hardlinks)
329
-	// These are all currently true and are not expected to break
330
-
331
-	tmpRootDir, err := ioutil.TempDir(dir, "tmproot")
332
-	if err != nil {
333
-		return 0, err
334
-	}
335
-	defer func() {
336
-		if err != nil {
337
-			os.RemoveAll(tmpRootDir)
338
-		} else {
339
-			os.RemoveAll(path.Join(dir, "upper"))
340
-			os.RemoveAll(path.Join(dir, "work"))
341
-			os.RemoveAll(path.Join(dir, "merged"))
342
-			os.RemoveAll(path.Join(dir, "lower-id"))
343
-		}
344
-	}()
345
-
346
-	if err = copyDir(parentRootDir, tmpRootDir, CopyHardlink); err != nil {
347
-		return 0, err
348
-	}
349
-
350
-	if err := archive.ApplyLayer(tmpRootDir, diff); err != nil {
351
-		return 0, err
352
-	}
353
-
354
-	rootDir := path.Join(dir, "root")
355
-	if err := os.Rename(tmpRootDir, rootDir); err != nil {
356
-		return 0, err
357
-	}
358
-
359
-	changes, err := archive.ChangesDirs(rootDir, parentRootDir)
360
-	if err != nil {
361
-		return 0, err
362
-	}
363
-
364
-	return archive.ChangesSize(rootDir, changes), nil
365
-}
366
-
367
-func (d *Driver) Exists(id string) bool {
368
-	_, err := os.Stat(d.dir(id))
369
-	return err == nil
370
-}
371 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
-}
... ...
@@ -156,7 +156,7 @@ string is equivalent to setting the `--tlsverify` flag. The following are equiva
156 156
 ### Daemon storage-driver option
157 157
 
158 158
 The Docker daemon has support for several different image layer storage drivers: `aufs`,
159
-`devicemapper`, `btrfs` and `overlayfs`.
159
+`devicemapper`, `btrfs` and `overlay`.
160 160
 
161 161
 The `aufs` driver is the oldest, but is based on a Linux kernel patch-set that
162 162
 is unlikely to be merged into the main kernel. These are also known to cause some
... ...
@@ -175,9 +175,9 @@ To tell the Docker daemon to use `devicemapper`, use
175 175
 The `btrfs` driver is very fast for `docker build` - but like `devicemapper` does not
176 176
 share executable memory between devices. Use `docker -d -s btrfs -g /mnt/btrfs_partition`.
177 177
 
178
-The `overlayfs` is a very fast union filesystem. It is now merged in the main
178
+The `overlay` is a very fast union filesystem. It is now merged in the main
179 179
 Linux kernel as of [3.18.0](https://lkml.org/lkml/2014/10/26/137).
180
-Call `docker -d -s overlayfs` to use it.
180
+Call `docker -d -s overlay` to use it.
181 181
 
182 182
 ### Docker exec-driver option
183 183