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>
| ... | ... |
@@ -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 |
|
| ... | ... |
@@ -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 |