Browse Source

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 3 years ago
parent
commit
3903f16cd6

+ 0 - 8
contrib/check-config.sh

@@ -368,14 +368,6 @@ EXITCODE=0
 STORAGE=1
 STORAGE=1
 
 
 echo '- Storage Drivers:'
 echo '- Storage Drivers:'
-echo "  - \"$(wrap_color 'aufs' blue)\":"
-check_flags AUFS_FS | sed 's/^/    /'
-if ! is_set AUFS_FS && grep -q aufs /proc/filesystems; then
-	echo "      $(wrap_color '(note that some kernels include AUFS patches but not the AUFS_FS flag)' bold black)"
-fi
-[ "$EXITCODE" = 0 ] && STORAGE=0
-EXITCODE=0
-
 echo "  - \"$(wrap_color 'btrfs' blue)\":"
 echo "  - \"$(wrap_color 'btrfs' blue)\":"
 check_flags BTRFS_FS | sed 's/^/    /'
 check_flags BTRFS_FS | sed 's/^/    /'
 check_flags BTRFS_FS_POSIX_ACL | sed 's/^/    /'
 check_flags BTRFS_FS_POSIX_ACL | sed 's/^/    /'

+ 1 - 1
daemon/daemon_linux.go

@@ -116,7 +116,7 @@ func getCleanPatterns(id string) (regexps []*regexp.Regexp) {
 		id = "[0-9a-f]{64}"
 		id = "[0-9a-f]{64}"
 		patterns = append(patterns, "containers/"+id+"/mounts/shm", "containers/"+id+"/shm")
 		patterns = append(patterns, "containers/"+id+"/mounts/shm", "containers/"+id+"/shm")
 	}
 	}
-	patterns = append(patterns, "overlay2/"+id+"/merged$", "aufs/mnt/"+id+"$", "overlay/"+id+"/merged$", "zfs/graph/"+id+"$")
+	patterns = append(patterns, "overlay2/"+id+"/merged$", "overlay/"+id+"/merged$", "zfs/graph/"+id+"$")
 	for _, p := range patterns {
 	for _, p := range patterns {
 		r, err := regexp.Compile(p)
 		r, err := regexp.Compile(p)
 		if err == nil {
 		if err == nil {

+ 0 - 16
daemon/daemon_linux_test.go

@@ -145,22 +145,6 @@ func TestCleanupMountsByID(t *testing.T) {
 	d := &Daemon{
 	d := &Daemon{
 		root: "/var/lib/docker/",
 		root: "/var/lib/docker/",
 	}
 	}
-
-	t.Run("aufs", func(t *testing.T) {
-		expected := "/var/lib/docker/aufs/mnt/03ca4b49e71f1e49a41108829f4d5c70ac95934526e2af8984a1f65f1de0715d"
-		var unmounted int
-		unmount := func(target string) error {
-			if target == expected {
-				unmounted++
-			}
-			return nil
-		}
-
-		err := d.cleanupMountsFromReaderByID(strings.NewReader(mountsFixture), "03ca4b49e71f1e49a41108829f4d5c70ac95934526e2af8984a1f65f1de0715d", unmount)
-		assert.NilError(t, err)
-		assert.Equal(t, unmounted, 1, "Expected to unmount the root (and that only)")
-	})
-
 	t.Run("overlay2", func(t *testing.T) {
 	t.Run("overlay2", func(t *testing.T) {
 		expected := "/var/lib/docker/overlay2/3a4b807fcb98c208573f368c5654a6568545a7f92404a07d0045eb5c85acaf67/merged"
 		expected := "/var/lib/docker/overlay2/3a4b807fcb98c208573f368c5654a6568545a7f92404a07d0045eb5c85acaf67/merged"
 		var unmounted int
 		var unmounted int

+ 0 - 649
daemon/graphdriver/aufs/aufs.go

@@ -1,649 +0,0 @@
-//go:build linux
-// +build linux
-
-/*
-
-aufs driver directory structure
-
-  .
-  ├── layers // Metadata of layers
-  │   ├── 1
-  │   ├── 2
-  │   └── 3
-  ├── diff  // Content of the layer
-  │   ├── 1  // Contains layers that need to be mounted for the id
-  │   ├── 2
-  │   └── 3
-  └── mnt    // Mount points for the rw layers to be mounted
-      ├── 1
-      ├── 2
-      └── 3
-
-*/
-
-package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
-
-import (
-	"bufio"
-	"context"
-	"fmt"
-	"io"
-	"os"
-	"os/exec"
-	"path"
-	"path/filepath"
-	"strconv"
-	"strings"
-	"sync"
-
-	"github.com/containerd/containerd/pkg/userns"
-	"github.com/docker/docker/daemon/graphdriver"
-	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/chrootarchive"
-	"github.com/docker/docker/pkg/containerfs"
-	"github.com/docker/docker/pkg/directory"
-	"github.com/docker/docker/pkg/idtools"
-	"github.com/moby/locker"
-	"github.com/moby/sys/mount"
-	"github.com/opencontainers/selinux/go-selinux/label"
-	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
-	"github.com/vbatts/tar-split/tar/storage"
-	"golang.org/x/sys/unix"
-)
-
-var (
-	// ErrAufsNotSupported is returned if aufs is not supported by the host.
-	ErrAufsNotSupported = fmt.Errorf("AUFS was not found in /proc/filesystems")
-	// ErrAufsNested means aufs cannot be used bc we are in a user namespace
-	ErrAufsNested = fmt.Errorf("AUFS cannot be used in non-init user namespace")
-	backingFs     = "<unknown>"
-
-	enableDirpermLock sync.Once
-	enableDirperm     bool
-
-	logger = logrus.WithField("storage-driver", "aufs")
-)
-
-func init() {
-	graphdriver.Register("aufs", Init)
-}
-
-// Driver contains information about the filesystem mounted.
-type Driver struct {
-	root          string
-	idMap         idtools.IdentityMapping
-	ctr           *graphdriver.RefCounter
-	pathCacheLock sync.Mutex
-	pathCache     map[string]string
-	naiveDiff     graphdriver.DiffDriver
-	locker        *locker.Locker
-	mntL          sync.Mutex
-}
-
-// Init returns a new AUFS driver.
-// An error is returned if AUFS is not supported.
-func Init(root string, options []string, idMap idtools.IdentityMapping) (graphdriver.Driver, error) {
-	// Try to load the aufs kernel module
-	if err := supportsAufs(); err != nil {
-		logger.Error(err)
-		return nil, graphdriver.ErrNotSupported
-	}
-
-	// Perform feature detection on /var/lib/docker/aufs if it's an existing directory.
-	// This covers situations where /var/lib/docker/aufs is a mount, and on a different
-	// filesystem than /var/lib/docker.
-	// If the path does not exist, fall back to using /var/lib/docker for feature detection.
-	testdir := root
-	if _, err := os.Stat(testdir); os.IsNotExist(err) {
-		testdir = filepath.Dir(testdir)
-	}
-
-	fsMagic, err := graphdriver.GetFSMagic(testdir)
-	if err != nil {
-		return nil, err
-	}
-	if fsName, ok := graphdriver.FsNames[fsMagic]; ok {
-		backingFs = fsName
-	}
-
-	switch fsMagic {
-	case graphdriver.FsMagicAufs, graphdriver.FsMagicBtrfs, graphdriver.FsMagicEcryptfs:
-		logger.Errorf("AUFS is not supported over %s", backingFs)
-		return nil, graphdriver.ErrIncompatibleFS
-	}
-
-	paths := []string{
-		"mnt",
-		"diff",
-		"layers",
-	}
-
-	a := &Driver{
-		root:      root,
-		idMap:     idMap,
-		pathCache: make(map[string]string),
-		ctr:       graphdriver.NewRefCounter(graphdriver.NewFsChecker(graphdriver.FsMagicAufs)),
-		locker:    locker.New(),
-	}
-
-	currentID := idtools.CurrentIdentity()
-	dirID := idtools.Identity{
-		UID: currentID.UID,
-		GID: a.idMap.RootPair().GID,
-	}
-
-	// Create the root aufs driver dir
-	if err := idtools.MkdirAllAndChown(root, 0710, dirID); err != nil {
-		return nil, err
-	}
-
-	// Populate the dir structure
-	for _, p := range paths {
-		if err := idtools.MkdirAllAndChown(path.Join(root, p), 0710, dirID); err != nil {
-			return nil, err
-		}
-	}
-
-	for _, path := range []string{"mnt", "diff"} {
-		p := filepath.Join(root, path)
-		entries, err := os.ReadDir(p)
-		if err != nil {
-			logger.WithError(err).WithField("dir", p).Error("error reading dir entries")
-			continue
-		}
-		for _, entry := range entries {
-			if !entry.IsDir() {
-				continue
-			}
-			if strings.HasSuffix(entry.Name(), "-removing") {
-				logger.WithField("dir", entry.Name()).Debug("Cleaning up stale layer dir")
-				if err := containerfs.EnsureRemoveAll(filepath.Join(p, entry.Name())); err != nil {
-					logger.WithField("dir", entry.Name()).WithError(err).Error("Error removing stale layer dir")
-				}
-			}
-		}
-	}
-
-	a.naiveDiff = graphdriver.NewNaiveDiffDriver(a, a.idMap)
-	return a, nil
-}
-
-// Return a nil error if the kernel supports aufs
-// We cannot modprobe because inside dind modprobe fails
-// to run
-func supportsAufs() error {
-	// We can try to modprobe aufs first before looking at
-	// proc/filesystems for when aufs is supported
-	exec.Command("modprobe", "aufs").Run()
-
-	if userns.RunningInUserNS() {
-		return ErrAufsNested
-	}
-
-	f, err := os.Open("/proc/filesystems")
-	if err != nil {
-		return err
-	}
-	defer f.Close()
-
-	s := bufio.NewScanner(f)
-	for s.Scan() {
-		if strings.Contains(s.Text(), "aufs") {
-			return nil
-		}
-	}
-	return ErrAufsNotSupported
-}
-
-func (a *Driver) rootPath() string {
-	return a.root
-}
-
-func (*Driver) String() string {
-	return "aufs"
-}
-
-// Status returns current information about the filesystem such as root directory, number of directories mounted, etc.
-func (a *Driver) Status() [][2]string {
-	ids, _ := loadIds(path.Join(a.rootPath(), "layers"))
-	return [][2]string{
-		{"Root Dir", a.rootPath()},
-		{"Backing Filesystem", backingFs},
-		{"Dirs", strconv.Itoa(len(ids))},
-		{"Dirperm1 Supported", strconv.FormatBool(useDirperm())},
-	}
-}
-
-// GetMetadata not implemented
-func (a *Driver) GetMetadata(id string) (map[string]string, error) {
-	return nil, nil
-}
-
-// Exists returns true if the given id is registered with
-// this driver
-func (a *Driver) Exists(id string) bool {
-	if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil {
-		return false
-	}
-	return true
-}
-
-// CreateReadWrite creates a layer that is writable for use as a container
-// file system.
-func (a *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error {
-	return a.Create(id, parent, opts)
-}
-
-// Create three folders for each id
-// mnt, layers, and diff
-func (a *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) error {
-	if opts != nil && len(opts.StorageOpt) != 0 {
-		return fmt.Errorf("--storage-opt is not supported for aufs")
-	}
-
-	if err := a.createDirsFor(id); err != nil {
-		return err
-	}
-	// Write the layers metadata
-	f, err := os.Create(path.Join(a.rootPath(), "layers", id))
-	if err != nil {
-		return err
-	}
-	defer f.Close()
-
-	if parent != "" {
-		ids, err := getParentIDs(a.rootPath(), parent)
-		if err != nil {
-			return err
-		}
-
-		if _, err := fmt.Fprintln(f, parent); err != nil {
-			return err
-		}
-		for _, i := range ids {
-			if _, err := fmt.Fprintln(f, i); err != nil {
-				return err
-			}
-		}
-	}
-
-	return nil
-}
-
-// createDirsFor creates two directories for the given id.
-// mnt and diff
-func (a *Driver) createDirsFor(id string) error {
-	paths := []string{
-		"mnt",
-		"diff",
-	}
-
-	// Directory permission is 0755.
-	// The path of directories are <aufs_root_path>/mnt/<image_id>
-	// and <aufs_root_path>/diff/<image_id>
-	for _, p := range paths {
-		if err := idtools.MkdirAllAndChown(path.Join(a.rootPath(), p, id), 0755, a.idMap.RootPair()); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// Remove will unmount and remove the given id.
-func (a *Driver) Remove(id string) error {
-	a.locker.Lock(id)
-	defer a.locker.Unlock(id)
-	a.pathCacheLock.Lock()
-	mountpoint, exists := a.pathCache[id]
-	a.pathCacheLock.Unlock()
-	if !exists {
-		mountpoint = a.getMountpoint(id)
-	}
-
-	if err := a.unmount(mountpoint); err != nil {
-		logger.WithError(err).WithField("method", "Remove()").Warn()
-		return err
-	}
-
-	// Remove the layers file for the id
-	if err := os.Remove(path.Join(a.rootPath(), "layers", id)); err != nil && !os.IsNotExist(err) {
-		return errors.Wrapf(err, "error removing layers dir for %s", id)
-	}
-
-	if err := atomicRemove(a.getDiffPath(id)); err != nil {
-		return errors.Wrapf(err, "could not remove diff path for id %s", id)
-	}
-
-	// Atomically remove each directory in turn by first moving it out of the
-	// way (so that docker doesn't find it anymore) before doing removal of
-	// the whole tree.
-	if err := atomicRemove(mountpoint); err != nil {
-		if errors.Is(err, unix.EBUSY) {
-			logger.WithField("dir", mountpoint).WithError(err).Warn("error performing atomic remove due to EBUSY")
-		}
-		return errors.Wrapf(err, "could not remove mountpoint for id %s", id)
-	}
-
-	a.pathCacheLock.Lock()
-	delete(a.pathCache, id)
-	a.pathCacheLock.Unlock()
-	return nil
-}
-
-func atomicRemove(source string) error {
-	target := source + "-removing"
-
-	err := os.Rename(source, target)
-	switch {
-	case err == nil, os.IsNotExist(err):
-	case os.IsExist(err):
-		// Got error saying the target dir already exists, maybe the source doesn't exist due to a previous (failed) remove
-		if _, e := os.Stat(source); !os.IsNotExist(e) {
-			return errors.Wrapf(err, "target rename dir %q exists but should not, this needs to be manually cleaned up", target)
-		}
-	default:
-		return errors.Wrapf(err, "error preparing atomic delete")
-	}
-
-	return containerfs.EnsureRemoveAll(target)
-}
-
-// Get returns the rootfs path for the id.
-// This will mount the dir at its given path
-func (a *Driver) Get(id, mountLabel string) (string, error) {
-	a.locker.Lock(id)
-	defer a.locker.Unlock(id)
-	parents, err := a.getParentLayerPaths(id)
-	if err != nil && !os.IsNotExist(err) {
-		return "", err
-	}
-
-	a.pathCacheLock.Lock()
-	m, exists := a.pathCache[id]
-	a.pathCacheLock.Unlock()
-
-	if !exists {
-		m = a.getDiffPath(id)
-		if len(parents) > 0 {
-			m = a.getMountpoint(id)
-		}
-	}
-	if count := a.ctr.Increment(m); count > 1 {
-		return m, nil
-	}
-
-	// If a dir does not have a parent ( no layers )do not try to mount
-	// just return the diff path to the data
-	if len(parents) > 0 {
-		if err := a.mount(id, m, mountLabel, parents); err != nil {
-			return "", err
-		}
-	}
-
-	a.pathCacheLock.Lock()
-	a.pathCache[id] = m
-	a.pathCacheLock.Unlock()
-	return m, nil
-}
-
-// Put unmounts and updates list of active mounts.
-func (a *Driver) Put(id string) error {
-	a.locker.Lock(id)
-	defer a.locker.Unlock(id)
-	a.pathCacheLock.Lock()
-	m, exists := a.pathCache[id]
-	if !exists {
-		m = a.getMountpoint(id)
-		a.pathCache[id] = m
-	}
-	a.pathCacheLock.Unlock()
-	if count := a.ctr.Decrement(m); count > 0 {
-		return nil
-	}
-
-	err := a.unmount(m)
-	if err != nil {
-		logger.WithError(err).WithField("method", "Put()").Warn()
-	}
-	return err
-}
-
-// isParent returns if the passed in parent is the direct parent of the passed in layer
-func (a *Driver) isParent(id, parent string) bool {
-	parents, _ := getParentIDs(a.rootPath(), id)
-	if parent == "" && len(parents) > 0 {
-		return false
-	}
-	return !(len(parents) > 0 && parent != parents[0])
-}
-
-// Diff produces an archive of the changes between the specified
-// layer and its parent layer which may be "".
-func (a *Driver) Diff(id, parent string) (io.ReadCloser, error) {
-	if !a.isParent(id, parent) {
-		return a.naiveDiff.Diff(id, parent)
-	}
-
-	// AUFS doesn't need the parent layer to produce a diff.
-	return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
-		Compression:     archive.Uncompressed,
-		ExcludePatterns: []string{archive.WhiteoutMetaPrefix + "*", "!" + archive.WhiteoutOpaqueDir},
-		IDMap:           a.idMap,
-	})
-}
-
-type fileGetNilCloser struct {
-	storage.FileGetter
-}
-
-func (f fileGetNilCloser) Close() error {
-	return nil
-}
-
-// DiffGetter returns a FileGetCloser that can read files from the directory that
-// contains files for the layer differences. Used for direct access for tar-split.
-func (a *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) {
-	p := path.Join(a.rootPath(), "diff", id)
-	return fileGetNilCloser{storage.NewPathFileGetter(p)}, nil
-}
-
-func (a *Driver) applyDiff(id string, diff io.Reader) error {
-	return chrootarchive.UntarUncompressed(diff, path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
-		IDMap: a.idMap,
-	})
-}
-
-// DiffSize calculates the changes between the specified id
-// and its parent and returns the size in bytes of the changes
-// relative to its base filesystem directory.
-func (a *Driver) DiffSize(id, parent string) (size int64, err error) {
-	if !a.isParent(id, parent) {
-		return a.naiveDiff.DiffSize(id, parent)
-	}
-	// AUFS doesn't need the parent layer to calculate the diff size.
-	return directory.Size(context.TODO(), path.Join(a.rootPath(), "diff", id))
-}
-
-// ApplyDiff extracts the changeset from the given diff into the
-// layer with the specified id and parent, returning the size of the
-// new layer in bytes.
-func (a *Driver) ApplyDiff(id, parent string, diff io.Reader) (size int64, err error) {
-	if !a.isParent(id, parent) {
-		return a.naiveDiff.ApplyDiff(id, parent, diff)
-	}
-
-	// AUFS doesn't need the parent id to apply the diff if it is the direct parent.
-	if err = a.applyDiff(id, diff); err != nil {
-		return
-	}
-
-	return a.DiffSize(id, parent)
-}
-
-// Changes produces a list of changes between the specified layer
-// and its parent layer. If parent is "", then all changes will be ADD changes.
-func (a *Driver) Changes(id, parent string) ([]archive.Change, error) {
-	if !a.isParent(id, parent) {
-		return a.naiveDiff.Changes(id, parent)
-	}
-
-	// AUFS doesn't have snapshots, so we need to get changes from all parent
-	// layers.
-	layers, err := a.getParentLayerPaths(id)
-	if err != nil {
-		return nil, err
-	}
-	return archive.Changes(layers, path.Join(a.rootPath(), "diff", id))
-}
-
-func (a *Driver) getParentLayerPaths(id string) ([]string, error) {
-	parentIds, err := getParentIDs(a.rootPath(), id)
-	if err != nil {
-		return nil, err
-	}
-	layers := make([]string, len(parentIds))
-
-	// Get the diff paths for all the parent ids
-	for i, p := range parentIds {
-		layers[i] = path.Join(a.rootPath(), "diff", p)
-	}
-	return layers, nil
-}
-
-func (a *Driver) mount(id string, target string, mountLabel string, layers []string) error {
-	// If the id is mounted or we get an error return
-	if mounted, err := a.mounted(target); err != nil || mounted {
-		return err
-	}
-
-	rw := a.getDiffPath(id)
-
-	if err := a.aufsMount(layers, rw, target, mountLabel); err != nil {
-		return fmt.Errorf("error creating aufs mount to %s: %v", target, err)
-	}
-	return nil
-}
-
-func (a *Driver) unmount(mountPath string) error {
-	if mounted, err := a.mounted(mountPath); err != nil || !mounted {
-		return err
-	}
-	return Unmount(mountPath)
-}
-
-func (a *Driver) mounted(mountpoint string) (bool, error) {
-	return graphdriver.Mounted(graphdriver.FsMagicAufs, mountpoint)
-}
-
-// Cleanup aufs and unmount all mountpoints
-func (a *Driver) Cleanup() error {
-	dir := a.mntPath()
-	files, err := os.ReadDir(dir)
-	if err != nil {
-		return errors.Wrap(err, "aufs readdir error")
-	}
-	for _, f := range files {
-		if !f.IsDir() {
-			continue
-		}
-
-		m := path.Join(dir, f.Name())
-
-		if err := a.unmount(m); err != nil {
-			logger.WithError(err).WithField("method", "Cleanup()").Warn()
-		}
-	}
-	return mount.RecursiveUnmount(a.root)
-}
-
-func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err error) {
-	defer func() {
-		if err != nil {
-			mount.Unmount(target)
-		}
-	}()
-
-	// Mount options are clipped to page size(4096 bytes). If there are more
-	// layers then these are remounted individually using append.
-
-	offset := 54
-	if useDirperm() {
-		offset += len(",dirperm1")
-	}
-	b := make([]byte, unix.Getpagesize()-len(mountLabel)-offset) // room for xino & mountLabel
-	bp := copy(b, fmt.Sprintf("br:%s=rw", rw))
-
-	index := 0
-	for ; index < len(ro); index++ {
-		layer := fmt.Sprintf(":%s=ro+wh", ro[index])
-		if bp+len(layer) > len(b) {
-			break
-		}
-		bp += copy(b[bp:], layer)
-	}
-
-	opts := "dio,xino=/dev/shm/aufs.xino"
-	if useDirperm() {
-		opts += ",dirperm1"
-	}
-	data := label.FormatMountLabel(fmt.Sprintf("%s,%s", string(b[:bp]), opts), mountLabel)
-	a.mntL.Lock()
-	err = unix.Mount("none", target, "aufs", 0, data)
-	a.mntL.Unlock()
-	if err != nil {
-		err = errors.Wrap(err, "mount target="+target+" data="+data)
-		return
-	}
-
-	for index < len(ro) {
-		bp = 0
-		for ; index < len(ro); index++ {
-			layer := fmt.Sprintf("append:%s=ro+wh,", ro[index])
-			if bp+len(layer) > len(b) {
-				break
-			}
-			bp += copy(b[bp:], layer)
-		}
-		data := label.FormatMountLabel(string(b[:bp]), mountLabel)
-		a.mntL.Lock()
-		err = unix.Mount("none", target, "aufs", unix.MS_REMOUNT, data)
-		a.mntL.Unlock()
-		if err != nil {
-			err = errors.Wrap(err, "mount target="+target+" flags=MS_REMOUNT data="+data)
-			return
-		}
-	}
-
-	return
-}
-
-// useDirperm checks dirperm1 mount option can be used with the current
-// version of aufs.
-func useDirperm() bool {
-	enableDirpermLock.Do(func() {
-		base, err := os.MkdirTemp("", "docker-aufs-base")
-		if err != nil {
-			logger.Errorf("error checking dirperm1: %v", err)
-			return
-		}
-		defer os.RemoveAll(base)
-
-		union, err := os.MkdirTemp("", "docker-aufs-union")
-		if err != nil {
-			logger.Errorf("error checking dirperm1: %v", err)
-			return
-		}
-		defer os.RemoveAll(union)
-
-		opts := fmt.Sprintf("br:%s,dirperm1,xino=/dev/shm/aufs.xino", base)
-		if err := unix.Mount("none", union, "aufs", 0, opts); err != nil {
-			return
-		}
-		enableDirperm = true
-		if err := Unmount(union); err != nil {
-			logger.Errorf("error checking dirperm1: failed to unmount %v", err)
-		}
-	})
-	return enableDirperm
-}

+ 0 - 799
daemon/graphdriver/aufs/aufs_test.go

@@ -1,799 +0,0 @@
-//go:build linux
-// +build linux
-
-package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
-
-import (
-	"crypto/sha256"
-	"encoding/hex"
-	"fmt"
-	"os"
-	"path"
-	"path/filepath"
-	"strconv"
-	"sync"
-	"testing"
-
-	"github.com/docker/docker/daemon/graphdriver"
-	"github.com/docker/docker/pkg/archive"
-	"github.com/docker/docker/pkg/idtools"
-	"github.com/docker/docker/pkg/reexec"
-	"github.com/docker/docker/pkg/stringid"
-	"gotest.tools/v3/assert"
-	is "gotest.tools/v3/assert/cmp"
-)
-
-var (
-	tmpOuter = path.Join(os.TempDir(), "aufs-tests")
-	tmp      = path.Join(tmpOuter, "aufs")
-)
-
-func init() {
-	reexec.Init()
-}
-
-func testInit(dir string, t testing.TB) graphdriver.Driver {
-	d, err := Init(dir, nil, idtools.IdentityMapping{})
-	if err != nil {
-		if err == graphdriver.ErrNotSupported {
-			t.Skip(err)
-		} else {
-			t.Fatal(err)
-		}
-	}
-	return d
-}
-
-func newDriver(t testing.TB) *Driver {
-	if err := os.MkdirAll(tmp, 0755); err != nil {
-		t.Fatal(err)
-	}
-
-	d := testInit(tmp, t)
-	return d.(*Driver)
-}
-
-func TestNewDriver(t *testing.T) {
-	if err := os.MkdirAll(tmp, 0755); err != nil {
-		t.Fatal(err)
-	}
-
-	d := testInit(tmp, t)
-	defer os.RemoveAll(tmp)
-	if d == nil {
-		t.Fatal("Driver should not be nil")
-	}
-}
-
-func TestAufsString(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if d.String() != "aufs" {
-		t.Fatalf("Expected aufs got %s", d.String())
-	}
-}
-
-func TestCreateDirStructure(t *testing.T) {
-	newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	paths := []string{
-		"mnt",
-		"layers",
-		"diff",
-	}
-
-	for _, p := range paths {
-		if _, err := os.Stat(path.Join(tmp, p)); err != nil {
-			t.Fatal(err)
-		}
-	}
-}
-
-// We should be able to create two drivers with the same dir structure
-func TestNewDriverFromExistingDir(t *testing.T) {
-	if err := os.MkdirAll(tmp, 0755); err != nil {
-		t.Fatal(err)
-	}
-
-	testInit(tmp, t)
-	testInit(tmp, t)
-	os.RemoveAll(tmp)
-}
-
-func TestCreateNewDir(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.Create("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestCreateNewDirStructure(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.Create("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	paths := []string{
-		"mnt",
-		"diff",
-		"layers",
-	}
-
-	for _, p := range paths {
-		if _, err := os.Stat(path.Join(tmp, p, "1")); err != nil {
-			t.Fatal(err)
-		}
-	}
-}
-
-func TestRemoveImage(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.Create("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	if err := d.Remove("1"); err != nil {
-		t.Fatal(err)
-	}
-
-	paths := []string{
-		"mnt",
-		"diff",
-		"layers",
-	}
-
-	for _, p := range paths {
-		if _, err := os.Stat(path.Join(tmp, p, "1")); err == nil {
-			t.Fatalf("Error should not be nil because dirs with id 1 should be deleted: %s", p)
-		}
-		if _, err := os.Stat(path.Join(tmp, p, "1-removing")); err == nil {
-			t.Fatalf("Error should not be nil because dirs with id 1-removing should be deleted: %s", p)
-		}
-	}
-}
-
-func TestGetWithoutParent(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.Create("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	diffPath, err := d.Get("1", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	expected := path.Join(tmp, "diff", "1")
-	if diffPath != expected {
-		t.Fatalf("Expected path %s got %s", expected, diffPath)
-	}
-}
-
-func TestCleanupWithNoDirs(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	err := d.Cleanup()
-	assert.Check(t, err)
-}
-
-func TestCleanupWithDir(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.Create("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	if err := d.Cleanup(); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestMountedFalseResponse(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	err := d.Create("1", "", nil)
-	assert.NilError(t, err)
-
-	response, err := d.mounted(d.getDiffPath("1"))
-	assert.NilError(t, err)
-	assert.Check(t, !response)
-}
-
-func TestMountedTrueResponse(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-	defer d.Cleanup()
-
-	err := d.Create("1", "", nil)
-	assert.NilError(t, err)
-	err = d.Create("2", "1", nil)
-	assert.NilError(t, err)
-
-	_, err = d.Get("2", "")
-	assert.NilError(t, err)
-
-	response, err := d.mounted(d.pathCache["2"])
-	assert.NilError(t, err)
-	assert.Check(t, response)
-}
-
-func TestMountWithParent(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.Create("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-	if err := d.Create("2", "1", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	defer func() {
-		if err := d.Cleanup(); err != nil {
-			t.Fatal(err)
-		}
-	}()
-
-	mntPath, err := d.Get("2", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if mntPath == "" {
-		t.Fatal("mntPath should not be empty")
-	}
-
-	expected := path.Join(tmp, "mnt", "2")
-	if mntPath != expected {
-		t.Fatalf("Expected %s got %s", expected, mntPath)
-	}
-}
-
-func TestRemoveMountedDir(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.Create("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-	if err := d.Create("2", "1", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	defer func() {
-		if err := d.Cleanup(); err != nil {
-			t.Fatal(err)
-		}
-	}()
-
-	mntPath, err := d.Get("2", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if mntPath == "" {
-		t.Fatal("mntPath should not be empty")
-	}
-
-	mounted, err := d.mounted(d.pathCache["2"])
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if !mounted {
-		t.Fatal("Dir id 2 should be mounted")
-	}
-
-	if err := d.Remove("2"); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func TestCreateWithInvalidParent(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.Create("1", "docker", nil); err == nil {
-		t.Fatal("Error should not be nil with parent does not exist")
-	}
-}
-
-func TestGetDiff(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.CreateReadWrite("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	diffPath, err := d.Get("1", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Add a file to the diff path with a fixed size
-	size := int64(1024)
-
-	f, err := os.Create(path.Join(diffPath, "test_file"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err := f.Truncate(size); err != nil {
-		t.Fatal(err)
-	}
-	f.Close()
-
-	a, err := d.Diff("1", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if a == nil {
-		t.Fatal("Archive should not be nil")
-	}
-}
-
-func TestChanges(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.Create("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	if err := d.CreateReadWrite("2", "1", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	defer func() {
-		if err := d.Cleanup(); err != nil {
-			t.Fatal(err)
-		}
-	}()
-
-	mntPoint, err := d.Get("2", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Create a file to save in the mountpoint
-	f, err := os.Create(path.Join(mntPoint, "test.txt"))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if _, err := f.WriteString("testline"); err != nil {
-		t.Fatal(err)
-	}
-	if err := f.Close(); err != nil {
-		t.Fatal(err)
-	}
-
-	changes, err := d.Changes("2", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(changes) != 1 {
-		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
-	}
-	change := changes[0]
-
-	expectedPath := "/test.txt"
-	if change.Path != expectedPath {
-		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
-	}
-
-	if change.Kind != archive.ChangeAdd {
-		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
-	}
-
-	if err := d.CreateReadWrite("3", "2", nil); err != nil {
-		t.Fatal(err)
-	}
-	mntPoint, err = d.Get("3", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Create a file to save in the mountpoint
-	f, err = os.Create(path.Join(mntPoint, "test2.txt"))
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if _, err := f.WriteString("testline"); err != nil {
-		t.Fatal(err)
-	}
-	if err := f.Close(); err != nil {
-		t.Fatal(err)
-	}
-
-	changes, err = d.Changes("3", "2")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if len(changes) != 1 {
-		t.Fatalf("Dir 2 should have one change from parent got %d", len(changes))
-	}
-	change = changes[0]
-
-	expectedPath = "/test2.txt"
-	if change.Path != expectedPath {
-		t.Fatalf("Expected path %s got %s", expectedPath, change.Path)
-	}
-
-	if change.Kind != archive.ChangeAdd {
-		t.Fatalf("Change kind should be ChangeAdd got %s", change.Kind)
-	}
-}
-
-func TestDiffSize(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-
-	if err := d.CreateReadWrite("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	diffPath, err := d.Get("1", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Add a file to the diff path with a fixed size
-	size := int64(1024)
-
-	f, err := os.Create(path.Join(diffPath, "test_file"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err := f.Truncate(size); err != nil {
-		t.Fatal(err)
-	}
-	s, err := f.Stat()
-	if err != nil {
-		t.Fatal(err)
-	}
-	size = s.Size()
-	if err := f.Close(); err != nil {
-		t.Fatal(err)
-	}
-
-	diffSize, err := d.DiffSize("1", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if diffSize != size {
-		t.Fatalf("Expected size to be %d got %d", size, diffSize)
-	}
-}
-
-func TestChildDiffSize(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-	defer d.Cleanup()
-
-	if err := d.CreateReadWrite("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	diffPath, err := d.Get("1", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Add a file to the diff path with a fixed size
-	size := int64(1024)
-
-	f, err := os.Create(path.Join(diffPath, "test_file"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err := f.Truncate(size); err != nil {
-		t.Fatal(err)
-	}
-	s, err := f.Stat()
-	if err != nil {
-		t.Fatal(err)
-	}
-	size = s.Size()
-	if err := f.Close(); err != nil {
-		t.Fatal(err)
-	}
-
-	diffSize, err := d.DiffSize("1", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if diffSize != size {
-		t.Fatalf("Expected size to be %d got %d", size, diffSize)
-	}
-
-	if err := d.Create("2", "1", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	diffSize, err = d.DiffSize("2", "1")
-	if err != nil {
-		t.Fatal(err)
-	}
-	// The diff size for the child should be zero
-	if diffSize != 0 {
-		t.Fatalf("Expected size to be %d got %d", 0, diffSize)
-	}
-}
-
-func TestExists(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-	defer d.Cleanup()
-
-	if err := d.Create("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	if d.Exists("none") {
-		t.Fatal("id none should not exist in the driver")
-	}
-
-	if !d.Exists("1") {
-		t.Fatal("id 1 should exist in the driver")
-	}
-}
-
-func TestStatus(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-	defer d.Cleanup()
-
-	if err := d.Create("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	status := d.Status()
-	assert.Check(t, is.Len(status, 4))
-
-	rootDir := status[0]
-	dirs := status[2]
-	if rootDir[0] != "Root Dir" {
-		t.Fatalf("Expected Root Dir got %s", rootDir[0])
-	}
-	if rootDir[1] != d.rootPath() {
-		t.Fatalf("Expected %s got %s", d.rootPath(), rootDir[1])
-	}
-	if dirs[0] != "Dirs" {
-		t.Fatalf("Expected Dirs got %s", dirs[0])
-	}
-	if dirs[1] != "1" {
-		t.Fatalf("Expected 1 got %s", dirs[1])
-	}
-}
-
-func TestApplyDiff(t *testing.T) {
-	d := newDriver(t)
-	defer os.RemoveAll(tmp)
-	defer d.Cleanup()
-
-	if err := d.CreateReadWrite("1", "", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	diffPath, err := d.Get("1", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	// Add a file to the diff path with a fixed size
-	size := int64(1024)
-
-	f, err := os.Create(path.Join(diffPath, "test_file"))
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err := f.Truncate(size); err != nil {
-		t.Fatal(err)
-	}
-	f.Close()
-
-	diff, err := d.Diff("1", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	if err := d.Create("2", "", nil); err != nil {
-		t.Fatal(err)
-	}
-	if err := d.Create("3", "2", nil); err != nil {
-		t.Fatal(err)
-	}
-
-	if err := d.applyDiff("3", diff); err != nil {
-		t.Fatal(err)
-	}
-
-	// Ensure that the file is in the mount point for id 3
-
-	mountPoint, err := d.Get("3", "")
-	if err != nil {
-		t.Fatal(err)
-	}
-	if _, err := os.Stat(path.Join(mountPoint, "test_file")); err != nil {
-		t.Fatal(err)
-	}
-}
-
-func hash(c string) string {
-	h := sha256.New()
-	fmt.Fprint(h, c)
-	return hex.EncodeToString(h.Sum(nil))
-}
-
-func testMountMoreThan42Layers(t *testing.T, mountPath string) {
-	if err := os.MkdirAll(mountPath, 0755); err != nil {
-		t.Fatal(err)
-	}
-
-	defer os.RemoveAll(mountPath)
-	d := testInit(mountPath, t).(*Driver)
-	defer d.Cleanup()
-	var last string
-	var expected int
-
-	for i := 1; i < 127; i++ {
-		expected++
-		var (
-			parent  = strconv.Itoa(i - 1)
-			current = strconv.Itoa(i)
-		)
-
-		if parent == "0" {
-			parent = ""
-		} else {
-			parent = hash(parent)
-		}
-		current = hash(current)
-
-		err := d.CreateReadWrite(current, parent, nil)
-		assert.NilError(t, err, "current layer %d", i)
-
-		point, err := d.Get(current, "")
-		assert.NilError(t, err, "current layer %d", i)
-
-		f, err := os.Create(path.Join(point, current))
-		assert.NilError(t, err, "current layer %d", i)
-		f.Close()
-
-		if i%10 == 0 {
-			err := os.Remove(path.Join(point, parent))
-			assert.NilError(t, err, "current layer %d", i)
-			expected--
-		}
-		last = current
-	}
-
-	// Perform the actual mount for the top most image
-	point, err := d.Get(last, "")
-	assert.NilError(t, err)
-	files, err := os.ReadDir(point)
-	assert.NilError(t, err)
-	assert.Check(t, is.Len(files, expected))
-}
-
-func TestMountMoreThan42Layers(t *testing.T) {
-	defer os.RemoveAll(tmpOuter)
-	testMountMoreThan42Layers(t, tmp)
-}
-
-func TestMountMoreThan42LayersMatchingPathLength(t *testing.T) {
-	defer os.RemoveAll(tmpOuter)
-	zeroes := "0"
-	for {
-		// This finds a mount path so that when combined into aufs mount options
-		// 4096 byte boundary would be in between the paths or in permission
-		// section. For '/tmp' it will use '/tmp/aufs-tests/00000000/aufs'
-		mountPath := path.Join(tmpOuter, zeroes, "aufs")
-		pathLength := 77 + len(mountPath)
-
-		if mod := 4095 % pathLength; mod == 0 || mod > pathLength-2 {
-			t.Logf("Using path: %s", mountPath)
-			testMountMoreThan42Layers(t, mountPath)
-			return
-		}
-		zeroes += "0"
-	}
-}
-
-func BenchmarkConcurrentAccess(b *testing.B) {
-	b.StopTimer()
-	b.ResetTimer()
-
-	d := newDriver(b)
-	defer os.RemoveAll(tmp)
-	defer d.Cleanup()
-
-	numConcurrent := 256
-	// create a bunch of ids
-	ids := make([]string, numConcurrent)
-	for i := 0; i < numConcurrent; i++ {
-		ids[i] = stringid.GenerateRandomID()
-	}
-
-	if err := d.Create(ids[0], "", nil); err != nil {
-		b.Fatal(err)
-	}
-
-	if err := d.Create(ids[1], ids[0], nil); err != nil {
-		b.Fatal(err)
-	}
-
-	parent := ids[1]
-	ids = ids[2:]
-
-	chErr := make(chan error, numConcurrent)
-	var outerGroup sync.WaitGroup
-	outerGroup.Add(len(ids))
-	b.StartTimer()
-
-	// here's the actual bench
-	for _, id := range ids {
-		go func(id string) {
-			defer outerGroup.Done()
-			if err := d.Create(id, parent, nil); err != nil {
-				b.Logf("Create %s failed", id)
-				chErr <- err
-				return
-			}
-			var innerGroup sync.WaitGroup
-			for i := 0; i < b.N; i++ {
-				innerGroup.Add(1)
-				go func() {
-					d.Get(id, "")
-					d.Put(id)
-					innerGroup.Done()
-				}()
-			}
-			innerGroup.Wait()
-			d.Remove(id)
-		}(id)
-	}
-
-	outerGroup.Wait()
-	b.StopTimer()
-	close(chErr)
-	for err := range chErr {
-		if err != nil {
-			b.Log(err)
-			b.Fail()
-		}
-	}
-}
-
-func TestInitStaleCleanup(t *testing.T) {
-	if err := os.MkdirAll(tmp, 0755); err != nil {
-		t.Fatal(err)
-	}
-	defer os.RemoveAll(tmp)
-
-	for _, d := range []string{"diff", "mnt"} {
-		if err := os.MkdirAll(filepath.Join(tmp, d, "123-removing"), 0755); err != nil {
-			t.Fatal(err)
-		}
-	}
-
-	testInit(tmp, t)
-	for _, d := range []string{"diff", "mnt"} {
-		if _, err := os.Stat(filepath.Join(tmp, d, "123-removing")); err == nil {
-			t.Fatal("cleanup failed")
-		}
-	}
-}

+ 0 - 64
daemon/graphdriver/aufs/dirs.go

@@ -1,64 +0,0 @@
-//go:build linux
-// +build linux
-
-package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
-
-import (
-	"bufio"
-	"os"
-	"path"
-)
-
-// Return all the directories
-func loadIds(root string) ([]string, error) {
-	dirs, err := os.ReadDir(root)
-	if err != nil {
-		return nil, err
-	}
-	var out []string
-	for _, d := range dirs {
-		if !d.IsDir() {
-			out = append(out, d.Name())
-		}
-	}
-	return out, nil
-}
-
-// Read the layers file for the current id and return all the
-// layers represented by new lines in the file
-//
-// If there are no lines in the file then the id has no parent
-// and an empty slice is returned.
-func getParentIDs(root, id string) ([]string, error) {
-	f, err := os.Open(path.Join(root, "layers", id))
-	if err != nil {
-		return nil, err
-	}
-	defer f.Close()
-
-	var out []string
-	s := bufio.NewScanner(f)
-
-	for s.Scan() {
-		if t := s.Text(); t != "" {
-			out = append(out, s.Text())
-		}
-	}
-	return out, s.Err()
-}
-
-func (a *Driver) getMountpoint(id string) string {
-	return path.Join(a.mntPath(), id)
-}
-
-func (a *Driver) mntPath() string {
-	return path.Join(a.rootPath(), "mnt")
-}
-
-func (a *Driver) getDiffPath(id string) string {
-	return path.Join(a.diffPath(), id)
-}
-
-func (a *Driver) diffPath() string {
-	return path.Join(a.rootPath(), "diff")
-}

+ 0 - 56
daemon/graphdriver/aufs/mount.go

@@ -1,56 +0,0 @@
-//go:build linux
-// +build linux
-
-package aufs // import "github.com/docker/docker/daemon/graphdriver/aufs"
-
-import (
-	"os/exec"
-	"syscall"
-	"time"
-
-	"github.com/moby/sys/mount"
-	"github.com/pkg/errors"
-	"golang.org/x/sys/unix"
-)
-
-// Unmount the target specified.
-func Unmount(target string) error {
-	const retries = 5
-
-	// auplink flush
-	for i := 0; ; i++ {
-		out, err := exec.Command("auplink", target, "flush").CombinedOutput()
-		if err == nil {
-			break
-		}
-		rc := 0
-		if exiterr, ok := err.(*exec.ExitError); ok {
-			if status, ok := exiterr.Sys().(syscall.WaitStatus); ok {
-				rc = status.ExitStatus()
-			}
-		}
-		if i >= retries || rc != int(unix.EINVAL) {
-			logger.WithError(err).WithField("method", "Unmount").Warnf("auplink flush failed: %s", out)
-			break
-		}
-		// auplink failed to find target in /proc/self/mounts because
-		// kernel can't guarantee continuity while reading from it
-		// while mounts table is being changed
-		logger.Debugf("auplink flush error (retrying %d/%d): %s", i+1, retries, out)
-	}
-
-	// unmount
-	var err error
-	for i := 0; i < retries; i++ {
-		err = mount.Unmount(target)
-		if err != nil && errors.Is(err, unix.EBUSY) {
-			logger.Debugf("aufs unmount %s failed with EBUSY (retrying %d/%d)", target, i+1, retries)
-			time.Sleep(100 * time.Millisecond)
-			continue // try again
-		}
-		break
-	}
-
-	// either no error occurred, or another error
-	return err
-}

+ 14 - 1
daemon/graphdriver/driver.go

@@ -1,6 +1,7 @@
 package graphdriver // import "github.com/docker/docker/daemon/graphdriver"
 package graphdriver // import "github.com/docker/docker/daemon/graphdriver"
 
 
 import (
 import (
+	"fmt"
 	"io"
 	"io"
 	"os"
 	"os"
 	"path/filepath"
 	"path/filepath"
@@ -192,6 +193,9 @@ type Options struct {
 func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
 func New(name string, pg plugingetter.PluginGetter, config Options) (Driver, error) {
 	if name != "" {
 	if name != "" {
 		logrus.Infof("[graphdriver] trying configured driver: %s", name)
 		logrus.Infof("[graphdriver] trying configured driver: %s", name)
+		if err := checkRemoved(name); err != nil {
+			return nil, err
+		}
 		if isDeprecated(name) {
 		if isDeprecated(name) {
 			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)
 			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)
 		}
 		}
@@ -314,8 +318,17 @@ func isEmptyDir(name string) bool {
 func isDeprecated(name string) bool {
 func isDeprecated(name string) bool {
 	switch name {
 	switch name {
 	// NOTE: when deprecating a driver, update daemon.fillDriverInfo() accordingly
 	// NOTE: when deprecating a driver, update daemon.fillDriverInfo() accordingly
-	case "aufs", "devicemapper", "overlay":
+	case "devicemapper", "overlay":
 		return true
 		return true
 	}
 	}
 	return false
 	return false
 }
 }
+
+// checkRemoved checks if a storage-driver has been deprecated (and removed)
+func checkRemoved(name string) error {
+	switch name {
+	case "aufs":
+		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))
+	}
+	return nil
+}

+ 1 - 1
daemon/graphdriver/driver_linux.go

@@ -50,7 +50,7 @@ const (
 
 
 var (
 var (
 	// List of drivers that should be used in an order
 	// List of drivers that should be used in an order
-	priority = "overlay2,fuse-overlayfs,btrfs,zfs,aufs,overlay,devicemapper,vfs"
+	priority = "overlay2,fuse-overlayfs,btrfs,zfs,overlay,devicemapper,vfs"
 
 
 	// FsNames maps filesystem id to name of the filesystem.
 	// FsNames maps filesystem id to name of the filesystem.
 	FsNames = map[FsMagic]string{
 	FsNames = map[FsMagic]string{

+ 0 - 1
daemon/graphdriver/fsdiff.go

@@ -21,7 +21,6 @@ var (
 // capability of the Diffing methods on the local file system,
 // capability of the Diffing methods on the local file system,
 // which it may or may not support on its own. See the comment
 // which it may or may not support on its own. See the comment
 // on the exported NewNaiveDiffDriver function below.
 // on the exported NewNaiveDiffDriver function below.
-// Notably, the AUFS driver doesn't need to be wrapped like this.
 type NaiveDiffDriver struct {
 type NaiveDiffDriver struct {
 	ProtoDriver
 	ProtoDriver
 	idMap idtools.IdentityMapping
 	idMap idtools.IdentityMapping

+ 0 - 9
daemon/graphdriver/register/register_aufs.go

@@ -1,9 +0,0 @@
-//go:build !exclude_graphdriver_aufs && linux
-// +build !exclude_graphdriver_aufs,linux
-
-package register // import "github.com/docker/docker/daemon/graphdriver/register"
-
-import (
-	// register the aufs graphdriver
-	_ "github.com/docker/docker/daemon/graphdriver/aufs"
-)

+ 1 - 1
daemon/info.go

@@ -128,7 +128,7 @@ WARNING: The %s storage-driver is deprecated, and will be removed in a future re
          Refer to the documentation for more information: https://docs.docker.com/go/storage-driver/`
          Refer to the documentation for more information: https://docs.docker.com/go/storage-driver/`
 
 
 	switch v.Driver {
 	switch v.Driver {
-	case "aufs", "devicemapper", "overlay":
+	case "devicemapper", "overlay":
 		v.Warnings = append(v.Warnings, fmt.Sprintf(warnMsg, v.Driver))
 		v.Warnings = append(v.Warnings, fmt.Sprintf(warnMsg, v.Driver))
 	}
 	}
 
 

+ 0 - 1
project/ISSUE-TRIAGE.md

@@ -70,7 +70,6 @@ have:
 | area/security/selinux     |
 | area/security/selinux     |
 | area/security/trust       |
 | area/security/trust       |
 | area/storage              |
 | area/storage              |
-| area/storage/aufs         |
 | area/storage/btrfs        |
 | area/storage/btrfs        |
 | area/storage/devicemapper |
 | area/storage/devicemapper |
 | area/storage/overlay      |
 | area/storage/overlay      |

+ 1 - 8
project/PACKAGERS.md

@@ -94,14 +94,9 @@ To disable devicemapper:
 export DOCKER_BUILDTAGS='exclude_graphdriver_devicemapper'
 export DOCKER_BUILDTAGS='exclude_graphdriver_devicemapper'
 ```
 ```
 
 
-To disable aufs:
-```bash
-export DOCKER_BUILDTAGS='exclude_graphdriver_aufs'
-```
-
 NOTE: if you need to set more than one build tag, space separate them:
 NOTE: if you need to set more than one build tag, space separate them:
 ```bash
 ```bash
-export DOCKER_BUILDTAGS='exclude_graphdriver_aufs exclude_graphdriver_btrfs'
+export DOCKER_BUILDTAGS='exclude_graphdriver_devicemapper exclude_graphdriver_btrfs'
 ```
 ```
 
 
 ## System Dependencies
 ## System Dependencies
@@ -137,8 +132,6 @@ the client will even run on alternative platforms such as Mac OS X / Darwin.
 Some of Docker's features are activated by using optional command-line flags or
 Some of Docker's features are activated by using optional command-line flags or
 by having support for them in the kernel or userspace. A few examples include:
 by having support for them in the kernel or userspace. A few examples include:
 
 
-* AUFS graph driver (requires AUFS patches/support enabled in the kernel, and at
-  least the "auplink" utility from aufs-tools)
 * 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)
 * 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)
 * ZFS graph driver (requires userspace zfs-utils and a corresponding kernel module)
 * ZFS graph driver (requires userspace zfs-utils and a corresponding kernel module)
 * Libseccomp to allow running seccomp profiles with containers
 * Libseccomp to allow running seccomp profiles with containers