Browse code

daemon: remove deprecated AuFS storage driver

There's still some locations refering to AuFS;

- pkg/archive: I suspect most of that code is because the whiteout-files
are modelled after aufs (but possibly some code is only relevant to
images created with AuFS as storage driver; to be looked into).
- contrib/apparmor/template: likely some rules can be removed
- contrib/dockerize-disk.sh: very old contribution, and unlikely used
by anyone, but perhaps could be updated if we want to (or just removed).

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2022/05/25 00:02:30
Showing 14 changed files
... ...
@@ -368,14 +368,6 @@ EXITCODE=0
368 368
 STORAGE=1
369 369
 
370 370
 echo '- Storage Drivers:'
371
-echo "  - \"$(wrap_color 'aufs' blue)\":"
372
-check_flags AUFS_FS | sed 's/^/    /'
373
-if ! is_set AUFS_FS && grep -q aufs /proc/filesystems; then
374
-	echo "      $(wrap_color '(note that some kernels include AUFS patches but not the AUFS_FS flag)' bold black)"
375
-fi
376
-[ "$EXITCODE" = 0 ] && STORAGE=0
377
-EXITCODE=0
378
-
379 371
 echo "  - \"$(wrap_color 'btrfs' blue)\":"
380 372
 check_flags BTRFS_FS | sed 's/^/    /'
381 373
 check_flags BTRFS_FS_POSIX_ACL | sed 's/^/    /'
... ...
@@ -116,7 +116,7 @@ func getCleanPatterns(id string) (regexps []*regexp.Regexp) {
116 116
 		id = "[0-9a-f]{64}"
117 117
 		patterns = append(patterns, "containers/"+id+"/mounts/shm", "containers/"+id+"/shm")
118 118
 	}
119
-	patterns = append(patterns, "overlay2/"+id+"/merged$", "aufs/mnt/"+id+"$", "overlay/"+id+"/merged$", "zfs/graph/"+id+"$")
119
+	patterns = append(patterns, "overlay2/"+id+"/merged$", "overlay/"+id+"/merged$", "zfs/graph/"+id+"$")
120 120
 	for _, p := range patterns {
121 121
 		r, err := regexp.Compile(p)
122 122
 		if err == nil {
... ...
@@ -145,22 +145,6 @@ func TestCleanupMountsByID(t *testing.T) {
145 145
 	d := &Daemon{
146 146
 		root: "/var/lib/docker/",
147 147
 	}
148
-
149
-	t.Run("aufs", func(t *testing.T) {
150
-		expected := "/var/lib/docker/aufs/mnt/03ca4b49e71f1e49a41108829f4d5c70ac95934526e2af8984a1f65f1de0715d"
151
-		var unmounted int
152
-		unmount := func(target string) error {
153
-			if target == expected {
154
-				unmounted++
155
-			}
156
-			return nil
157
-		}
158
-
159
-		err := d.cleanupMountsFromReaderByID(strings.NewReader(mountsFixture), "03ca4b49e71f1e49a41108829f4d5c70ac95934526e2af8984a1f65f1de0715d", unmount)
160
-		assert.NilError(t, err)
161
-		assert.Equal(t, unmounted, 1, "Expected to unmount the root (and that only)")
162
-	})
163
-
164 148
 	t.Run("overlay2", func(t *testing.T) {
165 149
 		expected := "/var/lib/docker/overlay2/3a4b807fcb98c208573f368c5654a6568545a7f92404a07d0045eb5c85acaf67/merged"
166 150
 		var unmounted int
167 151
deleted file mode 100644
... ...
@@ -1,649 +0,0 @@
1
-//go:build linux
2
-// +build linux
3
-
4
-/*
5
-
6
-aufs driver directory structure
7
-
8
-  .
9
-  ├── layers // Metadata of layers
10
-  │   ├── 1
11
-  │   ├── 2
12
-  │   └── 3
13
-  ├── diff  // Content of the layer
14
-  │   ├── 1  // Contains layers that need to be mounted for the id
15
-  │   ├── 2
16
-  │   └── 3
17
-  └── mnt    // Mount points for the rw layers to be mounted
18
-      ├── 1
19
-      ├── 2
20
-      └── 3
21
-
22
-*/
23
-
24
-package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
25
-
26
-import (
27
-	"bufio"
28
-	"context"
29
-	"fmt"
30
-	"io"
31
-	"os"
32
-	"os/exec"
33
-	"path"
34
-	"path/filepath"
35
-	"strconv"
36
-	"strings"
37
-	"sync"
38
-
39
-	"github.com/containerd/containerd/pkg/userns"
40
-	"github.com/docker/docker/daemon/graphdriver"
41
-	"github.com/docker/docker/pkg/archive"
42
-	"github.com/docker/docker/pkg/chrootarchive"
43
-	"github.com/docker/docker/pkg/containerfs"
44
-	"github.com/docker/docker/pkg/directory"
45
-	"github.com/docker/docker/pkg/idtools"
46
-	"github.com/moby/locker"
47
-	"github.com/moby/sys/mount"
48
-	"github.com/opencontainers/selinux/go-selinux/label"
49
-	"github.com/pkg/errors"
50
-	"github.com/sirupsen/logrus"
51
-	"github.com/vbatts/tar-split/tar/storage"
52
-	"golang.org/x/sys/unix"
53
-)
54
-
55
-var (
56
-	// ErrAufsNotSupported is returned if aufs is not supported by the host.
57
-	ErrAufsNotSupported = fmt.Errorf("AUFS was not found in /proc/filesystems")
58
-	// ErrAufsNested means aufs cannot be used bc we are in a user namespace
59
-	ErrAufsNested = fmt.Errorf("AUFS cannot be used in non-init user namespace")
60
-	backingFs     = "<unknown>"
61
-
62
-	enableDirpermLock sync.Once
63
-	enableDirperm     bool
64
-
65
-	logger = logrus.WithField("storage-driver", "aufs")
66
-)
67
-
68
-func init() {
69
-	graphdriver.Register("aufs", Init)
70
-}
71
-
72
-// Driver contains information about the filesystem mounted.
73
-type Driver struct {
74
-	root          string
75
-	idMap         idtools.IdentityMapping
76
-	ctr           *graphdriver.RefCounter
77
-	pathCacheLock sync.Mutex
78
-	pathCache     map[string]string
79
-	naiveDiff     graphdriver.DiffDriver
80
-	locker        *locker.Locker
81
-	mntL          sync.Mutex
82
-}
83
-
84
-// Init returns a new AUFS driver.
85
-// An error is returned if AUFS is not supported.
86
-func Init(root string, options []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
87
-	// Try to load the aufs kernel module
88
-	if err := supportsAufs(); err != nil {
89
-		logger.Error(err)
90
-		return nil, graphdriver.ErrNotSupported
91
-	}
92
-
93
-	// Perform feature detection on /var/lib/docker/aufs if it's an existing directory.
94
-	// This covers situations where /var/lib/docker/aufs is a mount, and on a different
95
-	// filesystem than /var/lib/docker.
96
-	// If the path does not exist, fall back to using /var/lib/docker for feature detection.
97
-	testdir := root
98
-	if _, err := os.Stat(testdir); os.IsNotExist(err) {
99
-		testdir = filepath.Dir(testdir)
100
-	}
101
-
102
-	fsMagic, err := graphdriver.GetFSMagic(testdir)
103
-	if err != nil {
104
-		return nil, err
105
-	}
106
-	if fsName, ok := graphdriver.FsNames[fsMagic]; ok {
107
-		backingFs = fsName
108
-	}
109
-
110
-	switch fsMagic {
111
-	case graphdriver.FsMagicAufs, graphdriver.FsMagicBtrfs, graphdriver.FsMagicEcryptfs:
112
-		logger.Errorf("AUFS is not supported over %s", backingFs)
113
-		return nil, graphdriver.ErrIncompatibleFS
114
-	}
115
-
116
-	paths := []string{
117
-		"mnt",
118
-		"diff",
119
-		"layers",
120
-	}
121
-
122
-	a := &Driver{
123
-		root:      root,
124
-		idMap:     idMap,
125
-		pathCache: make(map[string]string),
126
-		ctr:       graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicAufs)),
127
-		locker:    locker.New(),
128
-	}
129
-
130
-	currentID := idtools.CurrentIdentity()
131
-	dirID := idtools.Identity{
132
-		UID: currentID.UID,
133
-		GID: a.idMap.RootPair().GID,
134
-	}
135
-
136
-	// Create the root aufs driver dir
137
-	if err := idtools.MkdirAllAndChown(root, 0710, dirID); err != nil {
138
-		return nil, err
139
-	}
140
-
141
-	// Populate the dir structure
142
-	for _, p := range paths {
143
-		if err := idtools.MkdirAllAndChown(path.Join(root, p), 0710, dirID); err != nil {
144
-			return nil, err
145
-		}
146
-	}
147
-
148
-	for _, path := range []string{"mnt", "diff"} {
149
-		p := filepath.Join(root, path)
150
-		entries, err := os.ReadDir(p)
151
-		if err != nil {
152
-			logger.WithError(err).WithField("dir", p).Error("error reading dir entries")
153
-			continue
154
-		}
155
-		for _, entry := range entries {
156
-			if !entry.IsDir() {
157
-				continue
158
-			}
159
-			if strings.HasSuffix(entry.Name(), "-removing") {
160
-				logger.WithField("dir", entry.Name()).Debug("Cleaning up stale layer dir")
161
-				if err := containerfs.EnsureRemoveAll(filepath.Join(p, entry.Name())); err != nil {
162
-					logger.WithField("dir", entry.Name()).WithError(err).Error("Error removing stale layer dir")
163
-				}
164
-			}
165
-		}
166
-	}
167
-
168
-	a.naiveDiff = graphdriver.NewNaiveDiffDriver(a, a.idMap)
169
-	return a, nil
170
-}
171
-
172
-// Return a nil error if the kernel supports aufs
173
-// We cannot modprobe because inside dind modprobe fails
174
-// to run
175
-func supportsAufs() error {
176
-	// We can try to modprobe aufs first before looking at
177
-	// proc/filesystems for when aufs is supported
178
-	exec.Command("modprobe", "aufs").Run()
179
-
180
-	if userns.RunningInUserNS() {
181
-		return ErrAufsNested
182
-	}
183
-
184
-	f, err := os.Open("/proc/filesystems")
185
-	if err != nil {
186
-		return err
187
-	}
188
-	defer f.Close()
189
-
190
-	s := bufio.NewScanner(f)
191
-	for s.Scan() {
192
-		if strings.Contains(s.Text(), "aufs") {
193
-			return nil
194
-		}
195
-	}
196
-	return ErrAufsNotSupported
197
-}
198
-
199
-func (a *Driver) rootPath() string {
200
-	return a.root
201
-}
202
-
203
-func (*Driver) String() string {
204
-	return "aufs"
205
-}
206
-
207
-// Status returns current information about the filesystem such as root directory, number of directories mounted, etc.
208
-func (a *Driver) Status() [][2]string {
209
-	ids, _ := loadIds(path.Join(a.rootPath(), "layers"))
210
-	return [][2]string{
211
-		{"Root Dir", a.rootPath()},
212
-		{"Backing Filesystem", backingFs},
213
-		{"Dirs", strconv.Itoa(len(ids))},
214
-		{"Dirperm1 Supported", strconv.FormatBool(useDirperm())},
215
-	}
216
-}
217
-
218
-// GetMetadata not implemented
219
-func (a *Driver) GetMetadata(id string) (map[string]string, error) {
220
-	return nil, nil
221
-}
222
-
223
-// Exists returns true if the given id is registered with
224
-// this driver
225
-func (a *Driver) Exists(id string) bool {
226
-	if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil {
227
-		return false
228
-	}
229
-	return true
230
-}
231
-
232
-// CreateReadWrite creates a layer that is writable for use as a container
233
-// file system.
234
-func (a *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
235
-	return a.Create(id, parent, opts)
236
-}
237
-
238
-// Create three folders for each id
239
-// mnt, layers, and diff
240
-func (a *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
241
-	if opts != nil && len(opts.StorageOpt) != 0 {
242
-		return fmt.Errorf("--storage-opt is not supported for aufs")
243
-	}
244
-
245
-	if err := a.createDirsFor(id); err != nil {
246
-		return err
247
-	}
248
-	// Write the layers metadata
249
-	f, err := os.Create(path.Join(a.rootPath(), "layers", id))
250
-	if err != nil {
251
-		return err
252
-	}
253
-	defer f.Close()
254
-
255
-	if parent != "" {
256
-		ids, err := getParentIDs(a.rootPath(), parent)
257
-		if err != nil {
258
-			return err
259
-		}
260
-
261
-		if _, err := fmt.Fprintln(f, parent); err != nil {
262
-			return err
263
-		}
264
-		for _, i := range ids {
265
-			if _, err := fmt.Fprintln(f, i); err != nil {
266
-				return err
267
-			}
268
-		}
269
-	}
270
-
271
-	return nil
272
-}
273
-
274
-// createDirsFor creates two directories for the given id.
275
-// mnt and diff
276
-func (a *Driver) createDirsFor(id string) error {
277
-	paths := []string{
278
-		"mnt",
279
-		"diff",
280
-	}
281
-
282
-	// Directory permission is 0755.
283
-	// The path of directories are <aufs_root_path>/mnt/<image_id>
284
-	// and <aufs_root_path>/diff/<image_id>
285
-	for _, p := range paths {
286
-		if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, a.idMap.RootPair()); err != nil {
287
-			return err
288
-		}
289
-	}
290
-	return nil
291
-}
292
-
293
-// Remove will unmount and remove the given id.
294
-func (a *Driver) Remove(id string) error {
295
-	a.locker.Lock(id)
296
-	defer a.locker.Unlock(id)
297
-	a.pathCacheLock.Lock()
298
-	mountpoint, exists := a.pathCache[id]
299
-	a.pathCacheLock.Unlock()
300
-	if !exists {
301
-		mountpoint = a.getMountpoint(id)
302
-	}
303
-
304
-	if err := a.unmount(mountpoint); err != nil {
305
-		logger.WithError(err).WithField("method", "Remove()").Warn()
306
-		return err
307
-	}
308
-
309
-	// Remove the layers file for the id
310
-	if err := os.Remove(path.Join(a.rootPath(), "layers", id)); err != nil && !os.IsNotExist(err) {
311
-		return errors.Wrapf(err, "error removing layers dir for %s", id)
312
-	}
313
-
314
-	if err := atomicRemove(a.getDiffPath(id)); err != nil {
315
-		return errors.Wrapf(err, "could not remove diff path for id %s", id)
316
-	}
317
-
318
-	// Atomically remove each directory in turn by first moving it out of the
319
-	// way (so that docker doesn't find it anymore) before doing removal of
320
-	// the whole tree.
321
-	if err := atomicRemove(mountpoint); err != nil {
322
-		if errors.Is(err, unix.EBUSY) {
323
-			logger.WithField("dir", mountpoint).WithError(err).Warn("error performing atomic remove due to EBUSY")
324
-		}
325
-		return errors.Wrapf(err, "could not remove mountpoint for id %s", id)
326
-	}
327
-
328
-	a.pathCacheLock.Lock()
329
-	delete(a.pathCache, id)
330
-	a.pathCacheLock.Unlock()
331
-	return nil
332
-}
333
-
334
-func atomicRemove(source string) error {
335
-	target := source + "-removing"
336
-
337
-	err := os.Rename(source, target)
338
-	switch {
339
-	case err == nil, os.IsNotExist(err):
340
-	case os.IsExist(err):
341
-		// Got error saying the target dir already exists, maybe the source doesn't exist due to a previous (failed) remove
342
-		if _, e := os.Stat(source); !os.IsNotExist(e) {
343
-			return errors.Wrapf(err, "target rename dir %q exists but should not, this needs to be manually cleaned up", target)
344
-		}
345
-	default:
346
-		return errors.Wrapf(err, "error preparing atomic delete")
347
-	}
348
-
349
-	return containerfs.EnsureRemoveAll(target)
350
-}
351
-
352
-// Get returns the rootfs path for the id.
353
-// This will mount the dir at its given path
354
-func (a *Driver) Get(id, mountLabel string) (string, error) {
355
-	a.locker.Lock(id)
356
-	defer a.locker.Unlock(id)
357
-	parents, err := a.getParentLayerPaths(id)
358
-	if err != nil && !os.IsNotExist(err) {
359
-		return "", err
360
-	}
361
-
362
-	a.pathCacheLock.Lock()
363
-	m, exists := a.pathCache[id]
364
-	a.pathCacheLock.Unlock()
365
-
366
-	if !exists {
367
-		m = a.getDiffPath(id)
368
-		if len(parents) > 0 {
369
-			m = a.getMountpoint(id)
370
-		}
371
-	}
372
-	if count := a.ctr.Increment(m); count > 1 {
373
-		return m, nil
374
-	}
375
-
376
-	// If a dir does not have a parent ( no layers )do not try to mount
377
-	// just return the diff path to the data
378
-	if len(parents) > 0 {
379
-		if err := a.mount(id, m, mountLabel, parents); err != nil {
380
-			return "", err
381
-		}
382
-	}
383
-
384
-	a.pathCacheLock.Lock()
385
-	a.pathCache[id] = m
386
-	a.pathCacheLock.Unlock()
387
-	return m, nil
388
-}
389
-
390
-// Put unmounts and updates list of active mounts.
391
-func (a *Driver) Put(id string) error {
392
-	a.locker.Lock(id)
393
-	defer a.locker.Unlock(id)
394
-	a.pathCacheLock.Lock()
395
-	m, exists := a.pathCache[id]
396
-	if !exists {
397
-		m = a.getMountpoint(id)
398
-		a.pathCache[id] = m
399
-	}
400
-	a.pathCacheLock.Unlock()
401
-	if count := a.ctr.Decrement(m); count > 0 {
402
-		return nil
403
-	}
404
-
405
-	err := a.unmount(m)
406
-	if err != nil {
407
-		logger.WithError(err).WithField("method", "Put()").Warn()
408
-	}
409
-	return err
410
-}
411
-
412
-// isParent returns if the passed in parent is the direct parent of the passed in layer
413
-func (a *Driver) isParent(id, parent string) bool {
414
-	parents, _ := getParentIDs(a.rootPath(), id)
415
-	if parent == "" && len(parents) > 0 {
416
-		return false
417
-	}
418
-	return !(len(parents) > 0 && parent != parents[0])
419
-}
420
-
421
-// Diff produces an archive of the changes between the specified
422
-// layer and its parent layer which may be "".
423
-func (a *Driver) Diff(id, parent string) (io.ReadCloser, error) {
424
-	if !a.isParent(id, parent) {
425
-		return a.naiveDiff.Diff(id, parent)
426
-	}
427
-
428
-	// AUFS doesn't need the parent layer to produce a diff.
429
-	return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
430
-		Compression:     archive.Uncompressed,
431
-		ExcludePatterns: []string{archive.WhiteoutMetaPrefix + "*", "!" + archive.WhiteoutOpaqueDir},
432
-		IDMap:           a.idMap,
433
-	})
434
-}
435
-
436
-type fileGetNilCloser struct {
437
-	storage.FileGetter
438
-}
439
-
440
-func (f fileGetNilCloser) Close() error {
441
-	return nil
442
-}
443
-
444
-// DiffGetter returns a FileGetCloser that can read files from the directory that
445
-// contains files for the layer differences. Used for direct access for tar-split.
446
-func (a *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
447
-	p := path.Join(a.rootPath(), "diff", id)
448
-	return fileGetNilCloser{storage.NewPathFileGetter(p)}, nil
449
-}
450
-
451
-func (a *Driver) applyDiff(id string, diff io.Reader) error {
452
-	return chrootarchive.UntarUncompressed(diff, path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
453
-		IDMap: a.idMap,
454
-	})
455
-}
456
-
457
-// DiffSize calculates the changes between the specified id
458
-// and its parent and returns the size in bytes of the changes
459
-// relative to its base filesystem directory.
460
-func (a *Driver) DiffSize(id, parent string) (size int64, err error) {
461
-	if !a.isParent(id, parent) {
462
-		return a.naiveDiff.DiffSize(id, parent)
463
-	}
464
-	// AUFS doesn't need the parent layer to calculate the diff size.
465
-	return directory.Size(context.TODO(), path.Join(a.rootPath(), "diff", id))
466
-}
467
-
468
-// ApplyDiff extracts the changeset from the given diff into the
469
-// layer with the specified id and parent, returning the size of the
470
-// new layer in bytes.
471
-func (a *Driver) ApplyDiff(id, parent string, diff io.Reader) (size int64, err error) {
472
-	if !a.isParent(id, parent) {
473
-		return a.naiveDiff.ApplyDiff(id, parent, diff)
474
-	}
475
-
476
-	// AUFS doesn't need the parent id to apply the diff if it is the direct parent.
477
-	if err = a.applyDiff(id, diff); err != nil {
478
-		return
479
-	}
480
-
481
-	return a.DiffSize(id, parent)
482
-}
483
-
484
-// Changes produces a list of changes between the specified layer
485
-// and its parent layer. If parent is "", then all changes will be ADD changes.
486
-func (a *Driver) Changes(id, parent string) ([]archive.Change, error) {
487
-	if !a.isParent(id, parent) {
488
-		return a.naiveDiff.Changes(id, parent)
489
-	}
490
-
491
-	// AUFS doesn't have snapshots, so we need to get changes from all parent
492
-	// layers.
493
-	layers, err := a.getParentLayerPaths(id)
494
-	if err != nil {
495
-		return nil, err
496
-	}
497
-	return archive.Changes(layers, path.Join(a.rootPath(), "diff", id))
498
-}
499
-
500
-func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
501
-	parentIds, err := getParentIDs(a.rootPath(), id)
502
-	if err != nil {
503
-		return nil, err
504
-	}
505
-	layers := make([]string, len(parentIds))
506
-
507
-	// Get the diff paths for all the parent ids
508
-	for i, p := range parentIds {
509
-		layers[i] = path.Join(a.rootPath(), "diff", p)
510
-	}
511
-	return layers, nil
512
-}
513
-
514
-func (a *Driver) mount(id string, target string, mountLabel string, layers []string) error {
515
-	// If the id is mounted or we get an error return
516
-	if mounted, err := a.mounted(target); err != nil || mounted {
517
-		return err
518
-	}
519
-
520
-	rw := a.getDiffPath(id)
521
-
522
-	if err := a.aufsMount(layers, rw, target, mountLabel); err != nil {
523
-		return fmt.Errorf("error creating aufs mount to %s: %v", target, err)
524
-	}
525
-	return nil
526
-}
527
-
528
-func (a *Driver) unmount(mountPath string) error {
529
-	if mounted, err := a.mounted(mountPath); err != nil || !mounted {
530
-		return err
531
-	}
532
-	return Unmount(mountPath)
533
-}
534
-
535
-func (a *Driver) mounted(mountpoint string) (bool, error) {
536
-	return graphdriver.Mounted(graphdriver.FsMagicAufs, mountpoint)
537
-}
538
-
539
-// Cleanup aufs and unmount all mountpoints
540
-func (a *Driver) Cleanup() error {
541
-	dir := a.mntPath()
542
-	files, err := os.ReadDir(dir)
543
-	if err != nil {
544
-		return errors.Wrap(err, "aufs readdir error")
545
-	}
546
-	for _, f := range files {
547
-		if !f.IsDir() {
548
-			continue
549
-		}
550
-
551
-		m := path.Join(dir, f.Name())
552
-
553
-		if err := a.unmount(m); err != nil {
554
-			logger.WithError(err).WithField("method", "Cleanup()").Warn()
555
-		}
556
-	}
557
-	return mount.RecursiveUnmount(a.root)
558
-}
559
-
560
-func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err error) {
561
-	defer func() {
562
-		if err != nil {
563
-			mount.Unmount(target)
564
-		}
565
-	}()
566
-
567
-	// Mount options are clipped to page size(4096 bytes). If there are more
568
-	// layers then these are remounted individually using append.
569
-
570
-	offset := 54
571
-	if useDirperm() {
572
-		offset += len(",dirperm1")
573
-	}
574
-	b := make([]byte, unix.Getpagesize()-len(mountLabel)-offset) // room for xino & mountLabel
575
-	bp := copy(b, fmt.Sprintf("br:%s=rw", rw))
576
-
577
-	index := 0
578
-	for ; index < len(ro); index++ {
579
-		layer := fmt.Sprintf(":%s=ro+wh", ro[index])
580
-		if bp+len(layer) > len(b) {
581
-			break
582
-		}
583
-		bp += copy(b[bp:], layer)
584
-	}
585
-
586
-	opts := "dio,xino=/dev/shm/aufs.xino"
587
-	if useDirperm() {
588
-		opts += ",dirperm1"
589
-	}
590
-	data := label.FormatMountLabel(fmt.Sprintf("%s,%s", string(b[:bp]), opts), mountLabel)
591
-	a.mntL.Lock()
592
-	err = unix.Mount("none", target, "aufs", 0, data)
593
-	a.mntL.Unlock()
594
-	if err != nil {
595
-		err = errors.Wrap(err, "mount target="+target+" data="+data)
596
-		return
597
-	}
598
-
599
-	for index < len(ro) {
600
-		bp = 0
601
-		for ; index < len(ro); index++ {
602
-			layer := fmt.Sprintf("append:%s=ro+wh,", ro[index])
603
-			if bp+len(layer) > len(b) {
604
-				break
605
-			}
606
-			bp += copy(b[bp:], layer)
607
-		}
608
-		data := label.FormatMountLabel(string(b[:bp]), mountLabel)
609
-		a.mntL.Lock()
610
-		err = unix.Mount("none", target, "aufs", unix.MS_REMOUNT, data)
611
-		a.mntL.Unlock()
612
-		if err != nil {
613
-			err = errors.Wrap(err, "mount target="+target+" flags=MS_REMOUNT data="+data)
614
-			return
615
-		}
616
-	}
617
-
618
-	return
619
-}
620
-
621
-// useDirperm checks dirperm1 mount option can be used with the current
622
-// version of aufs.
623
-func useDirperm() bool {
624
-	enableDirpermLock.Do(func() {
625
-		base, err := os.MkdirTemp("", "docker-aufs-base")
626
-		if err != nil {
627
-			logger.Errorf("error checking dirperm1: %v", err)
628
-			return
629
-		}
630
-		defer os.RemoveAll(base)
631
-
632
-		union, err := os.MkdirTemp("", "docker-aufs-union")
633
-		if err != nil {
634
-			logger.Errorf("error checking dirperm1: %v", err)
635
-			return
636
-		}
637
-		defer os.RemoveAll(union)
638
-
639
-		opts := fmt.Sprintf("br:%s,dirperm1,xino=/dev/shm/aufs.xino", base)
640
-		if err := unix.Mount("none", union, "aufs", 0, opts); err != nil {
641
-			return
642
-		}
643
-		enableDirperm = true
644
-		if err := Unmount(union); err != nil {
645
-			logger.Errorf("error checking dirperm1: failed to unmount %v", err)
646
-		}
647
-	})
648
-	return enableDirperm
649
-}
650 1
deleted file mode 100644
... ...
@@ -1,799 +0,0 @@
1
-//go:build linux
2
-// +build linux
3
-
4
-package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
5
-
6
-import (
7
-	"crypto/sha256"
8
-	"encoding/hex"
9
-	"fmt"
10
-	"os"
11
-	"path"
12
-	"path/filepath"
13
-	"strconv"
14
-	"sync"
15
-	"testing"
16
-
17
-	"github.com/docker/docker/daemon/graphdriver"
18
-	"github.com/docker/docker/pkg/archive"
19
-	"github.com/docker/docker/pkg/idtools"
20
-	"github.com/docker/docker/pkg/reexec"
21
-	"github.com/docker/docker/pkg/stringid"
22
-	"gotest.tools/v3/assert"
23
-	is "gotest.tools/v3/assert/cmp"
24
-)
25
-
26
-var (
27
-	tmpOuter = path.Join(os.TempDir(), "aufs-tests")
28
-	tmp      = path.Join(tmpOuter, "aufs")
29
-)
30
-
31
-func init() {
32
-	reexec.Init()
33
-}
34
-
35
-func testInit(dir string, t testing.TB) graphdriver.Driver {
36
-	d, err := Init(dir, nil, idtools.IdentityMapping{})
37
-	if err != nil {
38
-		if err == graphdriver.ErrNotSupported {
39
-			t.Skip(err)
40
-		} else {
41
-			t.Fatal(err)
42
-		}
43
-	}
44
-	return d
45
-}
46
-
47
-func newDriver(t testing.TB) *Driver {
48
-	if err := os.MkdirAll(tmp, 0755); err != nil {
49
-		t.Fatal(err)
50
-	}
51
-
52
-	d := testInit(tmp, t)
53
-	return d.(*Driver)
54
-}
55
-
56
-func TestNewDriver(t *testing.T) {
57
-	if err := os.MkdirAll(tmp, 0755); err != nil {
58
-		t.Fatal(err)
59
-	}
60
-
61
-	d := testInit(tmp, t)
62
-	defer os.RemoveAll(tmp)
63
-	if d == nil {
64
-		t.Fatal("Driver should not be nil")
65
-	}
66
-}
67
-
68
-func TestAufsString(t *testing.T) {
69
-	d := newDriver(t)
70
-	defer os.RemoveAll(tmp)
71
-
72
-	if d.String() != "aufs" {
73
-		t.Fatalf("Expected aufs got %s", d.String())
74
-	}
75
-}
76
-
77
-func TestCreateDirStructure(t *testing.T) {
78
-	newDriver(t)
79
-	defer os.RemoveAll(tmp)
80
-
81
-	paths := []string{
82
-		"mnt",
83
-		"layers",
84
-		"diff",
85
-	}
86
-
87
-	for _, p := range paths {
88
-		if _, err := os.Stat(path.Join(tmp, p)); err != nil {
89
-			t.Fatal(err)
90
-		}
91
-	}
92
-}
93
-
94
-// We should be able to create two drivers with the same dir structure
95
-func TestNewDriverFromExistingDir(t *testing.T) {
96
-	if err := os.MkdirAll(tmp, 0755); err != nil {
97
-		t.Fatal(err)
98
-	}
99
-
100
-	testInit(tmp, t)
101
-	testInit(tmp, t)
102
-	os.RemoveAll(tmp)
103
-}
104
-
105
-func TestCreateNewDir(t *testing.T) {
106
-	d := newDriver(t)
107
-	defer os.RemoveAll(tmp)
108
-
109
-	if err := d.Create("1", "", nil); err != nil {
110
-		t.Fatal(err)
111
-	}
112
-}
113
-
114
-func TestCreateNewDirStructure(t *testing.T) {
115
-	d := newDriver(t)
116
-	defer os.RemoveAll(tmp)
117
-
118
-	if err := d.Create("1", "", nil); err != nil {
119
-		t.Fatal(err)
120
-	}
121
-
122
-	paths := []string{
123
-		"mnt",
124
-		"diff",
125
-		"layers",
126
-	}
127
-
128
-	for _, p := range paths {
129
-		if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil {
130
-			t.Fatal(err)
131
-		}
132
-	}
133
-}
134
-
135
-func TestRemoveImage(t *testing.T) {
136
-	d := newDriver(t)
137
-	defer os.RemoveAll(tmp)
138
-
139
-	if err := d.Create("1", "", nil); err != nil {
140
-		t.Fatal(err)
141
-	}
142
-
143
-	if err := d.Remove("1"); err != nil {
144
-		t.Fatal(err)
145
-	}
146
-
147
-	paths := []string{
148
-		"mnt",
149
-		"diff",
150
-		"layers",
151
-	}
152
-
153
-	for _, p := range paths {
154
-		if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil {
155
-			t.Fatalf("Error should not be nil because dirs with id 1 should be deleted: %s", p)
156
-		}
157
-		if _, err := os.Stat(path.Join(tmp, p, "1-removing")); err == nil {
158
-			t.Fatalf("Error should not be nil because dirs with id 1-removing should be deleted: %s", p)
159
-		}
160
-	}
161
-}
162
-
163
-func TestGetWithoutParent(t *testing.T) {
164
-	d := newDriver(t)
165
-	defer os.RemoveAll(tmp)
166
-
167
-	if err := d.Create("1", "", nil); err != nil {
168
-		t.Fatal(err)
169
-	}
170
-
171
-	diffPath, err := d.Get("1", "")
172
-	if err != nil {
173
-		t.Fatal(err)
174
-	}
175
-	expected := path.Join(tmp, "diff", "1")
176
-	if diffPath != expected {
177
-		t.Fatalf("Expected path %s got %s", expected, diffPath)
178
-	}
179
-}
180
-
181
-func TestCleanupWithNoDirs(t *testing.T) {
182
-	d := newDriver(t)
183
-	defer os.RemoveAll(tmp)
184
-
185
-	err := d.Cleanup()
186
-	assert.Check(t, err)
187
-}
188
-
189
-func TestCleanupWithDir(t *testing.T) {
190
-	d := newDriver(t)
191
-	defer os.RemoveAll(tmp)
192
-
193
-	if err := d.Create("1", "", nil); err != nil {
194
-		t.Fatal(err)
195
-	}
196
-
197
-	if err := d.Cleanup(); err != nil {
198
-		t.Fatal(err)
199
-	}
200
-}
201
-
202
-func TestMountedFalseResponse(t *testing.T) {
203
-	d := newDriver(t)
204
-	defer os.RemoveAll(tmp)
205
-
206
-	err := d.Create("1", "", nil)
207
-	assert.NilError(t, err)
208
-
209
-	response, err := d.mounted(d.getDiffPath("1"))
210
-	assert.NilError(t, err)
211
-	assert.Check(t, !response)
212
-}
213
-
214
-func TestMountedTrueResponse(t *testing.T) {
215
-	d := newDriver(t)
216
-	defer os.RemoveAll(tmp)
217
-	defer d.Cleanup()
218
-
219
-	err := d.Create("1", "", nil)
220
-	assert.NilError(t, err)
221
-	err = d.Create("2", "1", nil)
222
-	assert.NilError(t, err)
223
-
224
-	_, err = d.Get("2", "")
225
-	assert.NilError(t, err)
226
-
227
-	response, err := d.mounted(d.pathCache["2"])
228
-	assert.NilError(t, err)
229
-	assert.Check(t, response)
230
-}
231
-
232
-func TestMountWithParent(t *testing.T) {
233
-	d := newDriver(t)
234
-	defer os.RemoveAll(tmp)
235
-
236
-	if err := d.Create("1", "", nil); err != nil {
237
-		t.Fatal(err)
238
-	}
239
-	if err := d.Create("2", "1", nil); err != nil {
240
-		t.Fatal(err)
241
-	}
242
-
243
-	defer func() {
244
-		if err := d.Cleanup(); err != nil {
245
-			t.Fatal(err)
246
-		}
247
-	}()
248
-
249
-	mntPath, err := d.Get("2", "")
250
-	if err != nil {
251
-		t.Fatal(err)
252
-	}
253
-	if mntPath == "" {
254
-		t.Fatal("mntPath should not be empty")
255
-	}
256
-
257
-	expected := path.Join(tmp, "mnt", "2")
258
-	if mntPath != expected {
259
-		t.Fatalf("Expected %s got %s", expected, mntPath)
260
-	}
261
-}
262
-
263
-func TestRemoveMountedDir(t *testing.T) {
264
-	d := newDriver(t)
265
-	defer os.RemoveAll(tmp)
266
-
267
-	if err := d.Create("1", "", nil); err != nil {
268
-		t.Fatal(err)
269
-	}
270
-	if err := d.Create("2", "1", nil); err != nil {
271
-		t.Fatal(err)
272
-	}
273
-
274
-	defer func() {
275
-		if err := d.Cleanup(); err != nil {
276
-			t.Fatal(err)
277
-		}
278
-	}()
279
-
280
-	mntPath, err := d.Get("2", "")
281
-	if err != nil {
282
-		t.Fatal(err)
283
-	}
284
-	if mntPath == "" {
285
-		t.Fatal("mntPath should not be empty")
286
-	}
287
-
288
-	mounted, err := d.mounted(d.pathCache["2"])
289
-	if err != nil {
290
-		t.Fatal(err)
291
-	}
292
-
293
-	if !mounted {
294
-		t.Fatal("Dir id 2 should be mounted")
295
-	}
296
-
297
-	if err := d.Remove("2"); err != nil {
298
-		t.Fatal(err)
299
-	}
300
-}
301
-
302
-func TestCreateWithInvalidParent(t *testing.T) {
303
-	d := newDriver(t)
304
-	defer os.RemoveAll(tmp)
305
-
306
-	if err := d.Create("1", "docker", nil); err == nil {
307
-		t.Fatal("Error should not be nil with parent does not exist")
308
-	}
309
-}
310
-
311
-func TestGetDiff(t *testing.T) {
312
-	d := newDriver(t)
313
-	defer os.RemoveAll(tmp)
314
-
315
-	if err := d.CreateReadWrite("1", "", nil); err != nil {
316
-		t.Fatal(err)
317
-	}
318
-
319
-	diffPath, err := d.Get("1", "")
320
-	if err != nil {
321
-		t.Fatal(err)
322
-	}
323
-
324
-	// Add a file to the diff path with a fixed size
325
-	size := int64(1024)
326
-
327
-	f, err := os.Create(path.Join(diffPath, "test_file"))
328
-	if err != nil {
329
-		t.Fatal(err)
330
-	}
331
-	if err := f.Truncate(size); err != nil {
332
-		t.Fatal(err)
333
-	}
334
-	f.Close()
335
-
336
-	a, err := d.Diff("1", "")
337
-	if err != nil {
338
-		t.Fatal(err)
339
-	}
340
-	if a == nil {
341
-		t.Fatal("Archive should not be nil")
342
-	}
343
-}
344
-
345
-func TestChanges(t *testing.T) {
346
-	d := newDriver(t)
347
-	defer os.RemoveAll(tmp)
348
-
349
-	if err := d.Create("1", "", nil); err != nil {
350
-		t.Fatal(err)
351
-	}
352
-
353
-	if err := d.CreateReadWrite("2", "1", nil); err != nil {
354
-		t.Fatal(err)
355
-	}
356
-
357
-	defer func() {
358
-		if err := d.Cleanup(); err != nil {
359
-			t.Fatal(err)
360
-		}
361
-	}()
362
-
363
-	mntPoint, err := d.Get("2", "")
364
-	if err != nil {
365
-		t.Fatal(err)
366
-	}
367
-
368
-	// Create a file to save in the mountpoint
369
-	f, err := os.Create(path.Join(mntPoint, "test.txt"))
370
-	if err != nil {
371
-		t.Fatal(err)
372
-	}
373
-
374
-	if _, err := f.WriteString("testline"); err != nil {
375
-		t.Fatal(err)
376
-	}
377
-	if err := f.Close(); err != nil {
378
-		t.Fatal(err)
379
-	}
380
-
381
-	changes, err := d.Changes("2", "")
382
-	if err != nil {
383
-		t.Fatal(err)
384
-	}
385
-	if len(changes) != 1 {
386
-		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
387
-	}
388
-	change := changes[0]
389
-
390
-	expectedPath := "/test.txt"
391
-	if change.Path != expectedPath {
392
-		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
393
-	}
394
-
395
-	if change.Kind != archive.ChangeAdd {
396
-		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
397
-	}
398
-
399
-	if err := d.CreateReadWrite("3", "2", nil); err != nil {
400
-		t.Fatal(err)
401
-	}
402
-	mntPoint, err = d.Get("3", "")
403
-	if err != nil {
404
-		t.Fatal(err)
405
-	}
406
-
407
-	// Create a file to save in the mountpoint
408
-	f, err = os.Create(path.Join(mntPoint, "test2.txt"))
409
-	if err != nil {
410
-		t.Fatal(err)
411
-	}
412
-
413
-	if _, err := f.WriteString("testline"); err != nil {
414
-		t.Fatal(err)
415
-	}
416
-	if err := f.Close(); err != nil {
417
-		t.Fatal(err)
418
-	}
419
-
420
-	changes, err = d.Changes("3", "2")
421
-	if err != nil {
422
-		t.Fatal(err)
423
-	}
424
-
425
-	if len(changes) != 1 {
426
-		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
427
-	}
428
-	change = changes[0]
429
-
430
-	expectedPath = "/test2.txt"
431
-	if change.Path != expectedPath {
432
-		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
433
-	}
434
-
435
-	if change.Kind != archive.ChangeAdd {
436
-		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
437
-	}
438
-}
439
-
440
-func TestDiffSize(t *testing.T) {
441
-	d := newDriver(t)
442
-	defer os.RemoveAll(tmp)
443
-
444
-	if err := d.CreateReadWrite("1", "", nil); err != nil {
445
-		t.Fatal(err)
446
-	}
447
-
448
-	diffPath, err := d.Get("1", "")
449
-	if err != nil {
450
-		t.Fatal(err)
451
-	}
452
-
453
-	// Add a file to the diff path with a fixed size
454
-	size := int64(1024)
455
-
456
-	f, err := os.Create(path.Join(diffPath, "test_file"))
457
-	if err != nil {
458
-		t.Fatal(err)
459
-	}
460
-	if err := f.Truncate(size); err != nil {
461
-		t.Fatal(err)
462
-	}
463
-	s, err := f.Stat()
464
-	if err != nil {
465
-		t.Fatal(err)
466
-	}
467
-	size = s.Size()
468
-	if err := f.Close(); err != nil {
469
-		t.Fatal(err)
470
-	}
471
-
472
-	diffSize, err := d.DiffSize("1", "")
473
-	if err != nil {
474
-		t.Fatal(err)
475
-	}
476
-	if diffSize != size {
477
-		t.Fatalf("Expected size to be %d got %d", size, diffSize)
478
-	}
479
-}
480
-
481
-func TestChildDiffSize(t *testing.T) {
482
-	d := newDriver(t)
483
-	defer os.RemoveAll(tmp)
484
-	defer d.Cleanup()
485
-
486
-	if err := d.CreateReadWrite("1", "", nil); err != nil {
487
-		t.Fatal(err)
488
-	}
489
-
490
-	diffPath, err := d.Get("1", "")
491
-	if err != nil {
492
-		t.Fatal(err)
493
-	}
494
-
495
-	// Add a file to the diff path with a fixed size
496
-	size := int64(1024)
497
-
498
-	f, err := os.Create(path.Join(diffPath, "test_file"))
499
-	if err != nil {
500
-		t.Fatal(err)
501
-	}
502
-	if err := f.Truncate(size); err != nil {
503
-		t.Fatal(err)
504
-	}
505
-	s, err := f.Stat()
506
-	if err != nil {
507
-		t.Fatal(err)
508
-	}
509
-	size = s.Size()
510
-	if err := f.Close(); err != nil {
511
-		t.Fatal(err)
512
-	}
513
-
514
-	diffSize, err := d.DiffSize("1", "")
515
-	if err != nil {
516
-		t.Fatal(err)
517
-	}
518
-	if diffSize != size {
519
-		t.Fatalf("Expected size to be %d got %d", size, diffSize)
520
-	}
521
-
522
-	if err := d.Create("2", "1", nil); err != nil {
523
-		t.Fatal(err)
524
-	}
525
-
526
-	diffSize, err = d.DiffSize("2", "1")
527
-	if err != nil {
528
-		t.Fatal(err)
529
-	}
530
-	// The diff size for the child should be zero
531
-	if diffSize != 0 {
532
-		t.Fatalf("Expected size to be %d got %d", 0, diffSize)
533
-	}
534
-}
535
-
536
-func TestExists(t *testing.T) {
537
-	d := newDriver(t)
538
-	defer os.RemoveAll(tmp)
539
-	defer d.Cleanup()
540
-
541
-	if err := d.Create("1", "", nil); err != nil {
542
-		t.Fatal(err)
543
-	}
544
-
545
-	if d.Exists("none") {
546
-		t.Fatal("id none should not exist in the driver")
547
-	}
548
-
549
-	if !d.Exists("1") {
550
-		t.Fatal("id 1 should exist in the driver")
551
-	}
552
-}
553
-
554
-func TestStatus(t *testing.T) {
555
-	d := newDriver(t)
556
-	defer os.RemoveAll(tmp)
557
-	defer d.Cleanup()
558
-
559
-	if err := d.Create("1", "", nil); err != nil {
560
-		t.Fatal(err)
561
-	}
562
-
563
-	status := d.Status()
564
-	assert.Check(t, is.Len(status, 4))
565
-
566
-	rootDir := status[0]
567
-	dirs := status[2]
568
-	if rootDir[0] != "Root Dir" {
569
-		t.Fatalf("Expected Root Dir got %s", rootDir[0])
570
-	}
571
-	if rootDir[1] != d.rootPath() {
572
-		t.Fatalf("Expected %s got %s", d.rootPath(), rootDir[1])
573
-	}
574
-	if dirs[0] != "Dirs" {
575
-		t.Fatalf("Expected Dirs got %s", dirs[0])
576
-	}
577
-	if dirs[1] != "1" {
578
-		t.Fatalf("Expected 1 got %s", dirs[1])
579
-	}
580
-}
581
-
582
-func TestApplyDiff(t *testing.T) {
583
-	d := newDriver(t)
584
-	defer os.RemoveAll(tmp)
585
-	defer d.Cleanup()
586
-
587
-	if err := d.CreateReadWrite("1", "", nil); err != nil {
588
-		t.Fatal(err)
589
-	}
590
-
591
-	diffPath, err := d.Get("1", "")
592
-	if err != nil {
593
-		t.Fatal(err)
594
-	}
595
-
596
-	// Add a file to the diff path with a fixed size
597
-	size := int64(1024)
598
-
599
-	f, err := os.Create(path.Join(diffPath, "test_file"))
600
-	if err != nil {
601
-		t.Fatal(err)
602
-	}
603
-	if err := f.Truncate(size); err != nil {
604
-		t.Fatal(err)
605
-	}
606
-	f.Close()
607
-
608
-	diff, err := d.Diff("1", "")
609
-	if err != nil {
610
-		t.Fatal(err)
611
-	}
612
-
613
-	if err := d.Create("2", "", nil); err != nil {
614
-		t.Fatal(err)
615
-	}
616
-	if err := d.Create("3", "2", nil); err != nil {
617
-		t.Fatal(err)
618
-	}
619
-
620
-	if err := d.applyDiff("3", diff); err != nil {
621
-		t.Fatal(err)
622
-	}
623
-
624
-	// Ensure that the file is in the mount point for id 3
625
-
626
-	mountPoint, err := d.Get("3", "")
627
-	if err != nil {
628
-		t.Fatal(err)
629
-	}
630
-	if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil {
631
-		t.Fatal(err)
632
-	}
633
-}
634
-
635
-func hash(c string) string {
636
-	h := sha256.New()
637
-	fmt.Fprint(h, c)
638
-	return hex.EncodeToString(h.Sum(nil))
639
-}
640
-
641
-func testMountMoreThan42Layers(t *testing.T, mountPath string) {
642
-	if err := os.MkdirAll(mountPath, 0755); err != nil {
643
-		t.Fatal(err)
644
-	}
645
-
646
-	defer os.RemoveAll(mountPath)
647
-	d := testInit(mountPath, t).(*Driver)
648
-	defer d.Cleanup()
649
-	var last string
650
-	var expected int
651
-
652
-	for i := 1; i < 127; i++ {
653
-		expected++
654
-		var (
655
-			parent  = strconv.Itoa(i - 1)
656
-			current = strconv.Itoa(i)
657
-		)
658
-
659
-		if parent == "0" {
660
-			parent = ""
661
-		} else {
662
-			parent = hash(parent)
663
-		}
664
-		current = hash(current)
665
-
666
-		err := d.CreateReadWrite(current, parent, nil)
667
-		assert.NilError(t, err, "current layer %d", i)
668
-
669
-		point, err := d.Get(current, "")
670
-		assert.NilError(t, err, "current layer %d", i)
671
-
672
-		f, err := os.Create(path.Join(point, current))
673
-		assert.NilError(t, err, "current layer %d", i)
674
-		f.Close()
675
-
676
-		if i%10 == 0 {
677
-			err := os.Remove(path.Join(point, parent))
678
-			assert.NilError(t, err, "current layer %d", i)
679
-			expected--
680
-		}
681
-		last = current
682
-	}
683
-
684
-	// Perform the actual mount for the top most image
685
-	point, err := d.Get(last, "")
686
-	assert.NilError(t, err)
687
-	files, err := os.ReadDir(point)
688
-	assert.NilError(t, err)
689
-	assert.Check(t, is.Len(files, expected))
690
-}
691
-
692
-func TestMountMoreThan42Layers(t *testing.T) {
693
-	defer os.RemoveAll(tmpOuter)
694
-	testMountMoreThan42Layers(t, tmp)
695
-}
696
-
697
-func TestMountMoreThan42LayersMatchingPathLength(t *testing.T) {
698
-	defer os.RemoveAll(tmpOuter)
699
-	zeroes := "0"
700
-	for {
701
-		// This finds a mount path so that when combined into aufs mount options
702
-		// 4096 byte boundary would be in between the paths or in permission
703
-		// section. For '/tmp' it will use '/tmp/aufs-tests/00000000/aufs'
704
-		mountPath := path.Join(tmpOuter, zeroes, "aufs")
705
-		pathLength := 77 + len(mountPath)
706
-
707
-		if mod := 4095 % pathLength; mod == 0 || mod > pathLength-2 {
708
-			t.Logf("Using path: %s", mountPath)
709
-			testMountMoreThan42Layers(t, mountPath)
710
-			return
711
-		}
712
-		zeroes += "0"
713
-	}
714
-}
715
-
716
-func BenchmarkConcurrentAccess(b *testing.B) {
717
-	b.StopTimer()
718
-	b.ResetTimer()
719
-
720
-	d := newDriver(b)
721
-	defer os.RemoveAll(tmp)
722
-	defer d.Cleanup()
723
-
724
-	numConcurrent := 256
725
-	// create a bunch of ids
726
-	ids := make([]string, numConcurrent)
727
-	for i := 0; i < numConcurrent; i++ {
728
-		ids[i] = stringid.GenerateRandomID()
729
-	}
730
-
731
-	if err := d.Create(ids[0], "", nil); err != nil {
732
-		b.Fatal(err)
733
-	}
734
-
735
-	if err := d.Create(ids[1], ids[0], nil); err != nil {
736
-		b.Fatal(err)
737
-	}
738
-
739
-	parent := ids[1]
740
-	ids = ids[2:]
741
-
742
-	chErr := make(chan error, numConcurrent)
743
-	var outerGroup sync.WaitGroup
744
-	outerGroup.Add(len(ids))
745
-	b.StartTimer()
746
-
747
-	// here's the actual bench
748
-	for _, id := range ids {
749
-		go func(id string) {
750
-			defer outerGroup.Done()
751
-			if err := d.Create(id, parent, nil); err != nil {
752
-				b.Logf("Create %s failed", id)
753
-				chErr <- err
754
-				return
755
-			}
756
-			var innerGroup sync.WaitGroup
757
-			for i := 0; i < b.N; i++ {
758
-				innerGroup.Add(1)
759
-				go func() {
760
-					d.Get(id, "")
761
-					d.Put(id)
762
-					innerGroup.Done()
763
-				}()
764
-			}
765
-			innerGroup.Wait()
766
-			d.Remove(id)
767
-		}(id)
768
-	}
769
-
770
-	outerGroup.Wait()
771
-	b.StopTimer()
772
-	close(chErr)
773
-	for err := range chErr {
774
-		if err != nil {
775
-			b.Log(err)
776
-			b.Fail()
777
-		}
778
-	}
779
-}
780
-
781
-func TestInitStaleCleanup(t *testing.T) {
782
-	if err := os.MkdirAll(tmp, 0755); err != nil {
783
-		t.Fatal(err)
784
-	}
785
-	defer os.RemoveAll(tmp)
786
-
787
-	for _, d := range []string{"diff", "mnt"} {
788
-		if err := os.MkdirAll(filepath.Join(tmp, d, "123-removing"), 0755); err != nil {
789
-			t.Fatal(err)
790
-		}
791
-	}
792
-
793
-	testInit(tmp, t)
794
-	for _, d := range []string{"diff", "mnt"} {
795
-		if _, err := os.Stat(filepath.Join(tmp, d, "123-removing")); err == nil {
796
-			t.Fatal("cleanup failed")
797
-		}
798
-	}
799
-}
800 1
deleted file mode 100644
... ...
@@ -1,64 +0,0 @@
1
-//go:build linux
2
-// +build linux
3
-
4
-package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
5
-
6
-import (
7
-	"bufio"
8
-	"os"
9
-	"path"
10
-)
11
-
12
-// Return all the directories
13
-func loadIds(root string) ([]string, error) {
14
-	dirs, err := os.ReadDir(root)
15
-	if err != nil {
16
-		return nil, err
17
-	}
18
-	var out []string
19
-	for _, d := range dirs {
20
-		if !d.IsDir() {
21
-			out = append(out, d.Name())
22
-		}
23
-	}
24
-	return out, nil
25
-}
26
-
27
-// Read the layers file for the current id and return all the
28
-// layers represented by new lines in the file
29
-//
30
-// If there are no lines in the file then the id has no parent
31
-// and an empty slice is returned.
32
-func getParentIDs(root, id string) ([]string, error) {
33
-	f, err := os.Open(path.Join(root, "layers", id))
34
-	if err != nil {
35
-		return nil, err
36
-	}
37
-	defer f.Close()
38
-
39
-	var out []string
40
-	s := bufio.NewScanner(f)
41
-
42
-	for s.Scan() {
43
-		if t := s.Text(); t != "" {
44
-			out = append(out, s.Text())
45
-		}
46
-	}
47
-	return out, s.Err()
48
-}
49
-
50
-func (a *Driver) getMountpoint(id string) string {
51
-	return path.Join(a.mntPath(), id)
52
-}
53
-
54
-func (a *Driver) mntPath() string {
55
-	return path.Join(a.rootPath(), "mnt")
56
-}
57
-
58
-func (a *Driver) getDiffPath(id string) string {
59
-	return path.Join(a.diffPath(), id)
60
-}
61
-
62
-func (a *Driver) diffPath() string {
63
-	return path.Join(a.rootPath(), "diff")
64
-}
65 1
deleted file mode 100644
... ...
@@ -1,56 +0,0 @@
1
-//go:build linux
2
-// +build linux
3
-
4
-package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
5
-
6
-import (
7
-	"os/exec"
8
-	"syscall"
9
-	"time"
10
-
11
-	"github.com/moby/sys/mount"
12
-	"github.com/pkg/errors"
13
-	"golang.org/x/sys/unix"
14
-)
15
-
16
-// Unmount the target specified.
17
-func Unmount(target string) error {
18
-	const retries = 5
19
-
20
-	// auplink flush
21
-	for i := 0; ; i++ {
22
-		out, err := exec.Command("auplink", target, "flush").CombinedOutput()
23
-		if err == nil {
24
-			break
25
-		}
26
-		rc := 0
27
-		if exiterr, ok := err.(*exec.ExitError); ok {
28
-			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
29
-				rc = status.ExitStatus()
30
-			}
31
-		}
32
-		if i >= retries || rc != int(unix.EINVAL) {
33
-			logger.WithError(err).WithField("method", "Unmount").Warnf("auplink flush failed: %s", out)
34
-			break
35
-		}
36
-		// auplink failed to find target in /proc/self/mounts because
37
-		// kernel can't guarantee continuity while reading from it
38
-		// while mounts table is being changed
39
-		logger.Debugf("auplink flush error (retrying %d/%d): %s", i+1, retries, out)
40
-	}
41
-
42
-	// unmount
43
-	var err error
44
-	for i := 0; i < retries; i++ {
45
-		err = mount.Unmount(target)
46
-		if err != nil && errors.Is(err, unix.EBUSY) {
47
-			logger.Debugf("aufs unmount %s failed with EBUSY (retrying %d/%d)", target, i+1, retries)
48
-			time.Sleep(100 * time.Millisecond)
49
-			continue // try again
50
-		}
51
-		break
52
-	}
53
-
54
-	// either no error occurred, or another error
55
-	return err
56
-}
... ...
@@ -1,6 +1,7 @@
1 1
 package graphdriver // import "github.com/docker/docker/daemon/graphdriver"
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"io"
5 6
 	"os"
6 7
 	"path/filepath"
... ...
@@ -192,6 +193,9 @@ type Options struct {
192 192
 func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
193 193
 	if name != "" {
194 194
 		logrus.Infof("[graphdriver] trying configured driver: %s", name)
195
+		if err := checkRemoved(name); err != nil {
196
+			return nil, err
197
+		}
195 198
 		if isDeprecated(name) {
196 199
 			logrus.Warnf("[graphdriver] WARNING: the %s storage-driver is deprecated and will be removed in a future release; visit https://docs.docker.com/go/storage-driver/ for more information", name)
197 200
 		}
... ...
@@ -314,8 +318,17 @@ func isEmptyDir(name string) bool {
314 314
 func isDeprecated(name string) bool {
315 315
 	switch name {
316 316
 	// NOTE: when deprecating a driver, update daemon.fillDriverInfo() accordingly
317
-	case "aufs", "devicemapper", "overlay":
317
+	case "devicemapper", "overlay":
318 318
 		return true
319 319
 	}
320 320
 	return false
321 321
 }
322
+
323
+// checkRemoved checks if a storage-driver has been deprecated (and removed)
324
+func checkRemoved(name string) error {
325
+	switch name {
326
+	case "aufs":
327
+		return NotSupportedError(fmt.Sprintf("[graphdriver] ERROR: the %s storage-driver has been deprecated and removed; visit https://docs.docker.com/go/storage-driver/ for more information", name))
328
+	}
329
+	return nil
330
+}
... ...
@@ -50,7 +50,7 @@ const (
50 50
 
51 51
 var (
52 52
 	// List of drivers that should be used in an order
53
-	priority = "overlay2,fuse-overlayfs,btrfs,zfs,aufs,overlay,devicemapper,vfs"
53
+	priority = "overlay2,fuse-overlayfs,btrfs,zfs,overlay,devicemapper,vfs"
54 54
 
55 55
 	// FsNames maps filesystem id to name of the filesystem.
56 56
 	FsNames = map[FsMagic]string{
... ...
@@ -21,7 +21,6 @@ var (
21 21
 // capability of the Diffing methods on the local file system,
22 22
 // which it may or may not support on its own. See the comment
23 23
 // on the exported NewNaiveDiffDriver function below.
24
-// Notably, the AUFS driver doesn't need to be wrapped like this.
25 24
 type NaiveDiffDriver struct {
26 25
 	ProtoDriver
27 26
 	idMap idtools.IdentityMapping
28 27
deleted file mode 100644
... ...
@@ -1,9 +0,0 @@
1
-//go:build !exclude_graphdriver_aufs && linux
2
-// +build !exclude_graphdriver_aufs,linux
3
-
4
-package register // import "github.com/docker/docker/daemon/graphdriver/register"
5
-
6
-import (
7
-	// register the aufs graphdriver
8
-	_ "github.com/docker/docker/daemon/graphdriver/aufs"
9
-)
... ...
@@ -128,7 +128,7 @@ WARNING: The %s storage-driver is deprecated, and will be removed in a future re
128 128
          Refer to the documentation for more information: https://docs.docker.com/go/storage-driver/`
129 129
 
130 130
 	switch v.Driver {
131
-	case "aufs", "devicemapper", "overlay":
131
+	case "devicemapper", "overlay":
132 132
 		v.Warnings = append(v.Warnings, fmt.Sprintf(warnMsg, v.Driver))
133 133
 	}
134 134
 
... ...
@@ -70,7 +70,6 @@ have:
70 70
 | area/security/selinux     |
71 71
 | area/security/trust       |
72 72
 | area/storage              |
73
-| area/storage/aufs         |
74 73
 | area/storage/btrfs        |
75 74
 | area/storage/devicemapper |
76 75
 | area/storage/overlay      |
... ...
@@ -94,14 +94,9 @@ To disable devicemapper:
94 94
 export DOCKER_BUILDTAGS='exclude_graphdriver_devicemapper'
95 95
 ```
96 96
 
97
-To disable aufs:
98
-```bash
99
-export DOCKER_BUILDTAGS='exclude_graphdriver_aufs'
100
-```
101
-
102 97
 NOTE: if you need to set more than one build tag, space separate them:
103 98
 ```bash
104
-export DOCKER_BUILDTAGS='exclude_graphdriver_aufs exclude_graphdriver_btrfs'
99
+export DOCKER_BUILDTAGS='exclude_graphdriver_devicemapper exclude_graphdriver_btrfs'
105 100
 ```
106 101
 
107 102
 ## System Dependencies
... ...
@@ -137,8 +132,6 @@ the client will even run on alternative platforms such as Mac OS X / Darwin.
137 137
 Some of Docker's features are activated by using optional command-line flags or
138 138
 by having support for them in the kernel or userspace. A few examples include:
139 139
 
140
-* AUFS graph driver (requires AUFS patches/support enabled in the kernel, and at
141
-  least the "auplink" utility from aufs-tools)
142 140
 * BTRFS graph driver (requires suitable kernel headers: `linux/btrfs.h` and `linux/btrfs_tree.h`, present in 4.12+; and BTRFS support enabled in the kernel)
143 141
 * ZFS graph driver (requires userspace zfs-utils and a corresponding kernel module)
144 142
 * Libseccomp to allow running seccomp profiles with containers