github.com/uppal0016/docker_new@v0.0.0-20240123060250-1c98be13ac2c/daemon/graphdriver/aufs/aufs.go (about) 1 // +build linux 2 3 /* 4 5 aufs driver directory structure 6 7 . 8 ├── layers // Metadata of layers 9 │ ├── 1 10 │ ├── 2 11 │ └── 3 12 ├── diff // Content of the layer 13 │ ├── 1 // Contains layers that need to be mounted for the id 14 │ ├── 2 15 │ └── 3 16 └── mnt // Mount points for the rw layers to be mounted 17 ├── 1 18 ├── 2 19 └── 3 20 21 */ 22 23 package aufs 24 25 import ( 26 "bufio" 27 "fmt" 28 "io/ioutil" 29 "os" 30 "os/exec" 31 "path" 32 "path/filepath" 33 "strings" 34 "sync" 35 "syscall" 36 37 "github.com/Sirupsen/logrus" 38 "github.com/vbatts/tar-split/tar/storage" 39 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/directory" 44 "github.com/docker/docker/pkg/idtools" 45 mountpk "github.com/docker/docker/pkg/mount" 46 "github.com/docker/docker/pkg/stringid" 47 48 "github.com/opencontainers/runc/libcontainer/label" 49 rsystem "github.com/opencontainers/runc/libcontainer/system" 50 ) 51 52 var ( 53 // ErrAufsNotSupported is returned if aufs is not supported by the host. 54 ErrAufsNotSupported = fmt.Errorf("AUFS was not found in /proc/filesystems") 55 // ErrAufsNested means aufs cannot be used bc we are in a user namespace 56 ErrAufsNested = fmt.Errorf("AUFS cannot be used in non-init user namespace") 57 incompatibleFsMagic = []graphdriver.FsMagic{ 58 graphdriver.FsMagicBtrfs, 59 graphdriver.FsMagicAufs, 60 } 61 backingFs = "<unknown>" 62 63 enableDirpermLock sync.Once 64 enableDirperm bool 65 ) 66 67 func init() { 68 graphdriver.Register("aufs", Init) 69 } 70 71 // Driver contains information about the filesystem mounted. 72 type Driver struct { 73 sync.Mutex 74 root string 75 uidMaps []idtools.IDMap 76 gidMaps []idtools.IDMap 77 pathCacheLock sync.Mutex 78 pathCache map[string]string 79 } 80 81 // Init returns a new AUFS driver. 82 // An error is returned if AUFS is not supported. 83 func Init(root string, options []string, uidMaps, gidMaps []idtools.IDMap) (graphdriver.Driver, error) { 84 85 // Try to load the aufs kernel module 86 if err := supportsAufs(); err != nil { 87 return nil, graphdriver.ErrNotSupported 88 } 89 90 fsMagic, err := graphdriver.GetFSMagic(root) 91 if err != nil { 92 return nil, err 93 } 94 if fsName, ok := graphdriver.FsNames[fsMagic]; ok { 95 backingFs = fsName 96 } 97 98 for _, magic := range incompatibleFsMagic { 99 if fsMagic == magic { 100 return nil, graphdriver.ErrIncompatibleFS 101 } 102 } 103 104 paths := []string{ 105 "mnt", 106 "diff", 107 "layers", 108 } 109 110 a := &Driver{ 111 root: root, 112 uidMaps: uidMaps, 113 gidMaps: gidMaps, 114 pathCache: make(map[string]string), 115 } 116 117 rootUID, rootGID, err := idtools.GetRootUIDGID(uidMaps, gidMaps) 118 if err != nil { 119 return nil, err 120 } 121 // Create the root aufs driver dir and return 122 // if it already exists 123 // If not populate the dir structure 124 if err := idtools.MkdirAllAs(root, 0700, rootUID, rootGID); err != nil { 125 if os.IsExist(err) { 126 return a, nil 127 } 128 return nil, err 129 } 130 131 if err := mountpk.MakePrivate(root); err != nil { 132 return nil, err 133 } 134 135 // Populate the dir structure 136 for _, p := range paths { 137 if err := idtools.MkdirAllAs(path.Join(root, p), 0700, rootUID, rootGID); err != nil { 138 return nil, err 139 } 140 } 141 return a, nil 142 } 143 144 // Return a nil error if the kernel supports aufs 145 // We cannot modprobe because inside dind modprobe fails 146 // to run 147 func supportsAufs() error { 148 // We can try to modprobe aufs first before looking at 149 // proc/filesystems for when aufs is supported 150 exec.Command("modprobe", "aufs").Run() 151 152 if rsystem.RunningInUserNS() { 153 return ErrAufsNested 154 } 155 156 f, err := os.Open("/proc/filesystems") 157 if err != nil { 158 return err 159 } 160 defer f.Close() 161 162 s := bufio.NewScanner(f) 163 for s.Scan() { 164 if strings.Contains(s.Text(), "aufs") { 165 return nil 166 } 167 } 168 return ErrAufsNotSupported 169 } 170 171 func (a *Driver) rootPath() string { 172 return a.root 173 } 174 175 func (*Driver) String() string { 176 return "aufs" 177 } 178 179 // Status returns current information about the filesystem such as root directory, number of directories mounted, etc. 180 func (a *Driver) Status() [][2]string { 181 ids, _ := loadIds(path.Join(a.rootPath(), "layers")) 182 return [][2]string{ 183 {"Root Dir", a.rootPath()}, 184 {"Backing Filesystem", backingFs}, 185 {"Dirs", fmt.Sprintf("%d", len(ids))}, 186 {"Dirperm1 Supported", fmt.Sprintf("%v", useDirperm())}, 187 } 188 } 189 190 // GetMetadata not implemented 191 func (a *Driver) GetMetadata(id string) (map[string]string, error) { 192 return nil, nil 193 } 194 195 // Exists returns true if the given id is registered with 196 // this driver 197 func (a *Driver) Exists(id string) bool { 198 if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil { 199 return false 200 } 201 return true 202 } 203 204 // CreateReadWrite creates a layer that is writable for use as a container 205 // file system. 206 func (a *Driver) CreateReadWrite(id, parent, mountLabel string, storageOpt map[string]string) error { 207 return a.Create(id, parent, mountLabel, storageOpt) 208 } 209 210 // Create three folders for each id 211 // mnt, layers, and diff 212 func (a *Driver) Create(id, parent, mountLabel string, storageOpt map[string]string) error { 213 214 if len(storageOpt) != 0 { 215 return fmt.Errorf("--storage-opt is not supported for aufs") 216 } 217 218 if err := a.createDirsFor(id); err != nil { 219 return err 220 } 221 // Write the layers metadata 222 f, err := os.Create(path.Join(a.rootPath(), "layers", id)) 223 if err != nil { 224 return err 225 } 226 defer f.Close() 227 228 if parent != "" { 229 ids, err := getParentIds(a.rootPath(), parent) 230 if err != nil { 231 return err 232 } 233 234 if _, err := fmt.Fprintln(f, parent); err != nil { 235 return err 236 } 237 for _, i := range ids { 238 if _, err := fmt.Fprintln(f, i); err != nil { 239 return err 240 } 241 } 242 } 243 244 return nil 245 } 246 247 // createDirsFor creates two directories for the given id. 248 // mnt and diff 249 func (a *Driver) createDirsFor(id string) error { 250 paths := []string{ 251 "mnt", 252 "diff", 253 } 254 255 rootUID, rootGID, err := idtools.GetRootUIDGID(a.uidMaps, a.gidMaps) 256 if err != nil { 257 return err 258 } 259 // Directory permission is 0755. 260 // The path of directories are <aufs_root_path>/mnt/<image_id> 261 // and <aufs_root_path>/diff/<image_id> 262 for _, p := range paths { 263 if err := idtools.MkdirAllAs(path.Join(a.rootPath(), p, id), 0755, rootUID, rootGID); err != nil { 264 return err 265 } 266 } 267 return nil 268 } 269 270 // Remove will unmount and remove the given id. 271 func (a *Driver) Remove(id string) error { 272 a.pathCacheLock.Lock() 273 mountpoint, exists := a.pathCache[id] 274 a.pathCacheLock.Unlock() 275 if !exists { 276 mountpoint = a.getMountpoint(id) 277 } 278 if err := a.unmount(mountpoint); err != nil { 279 // no need to return here, we can still try to remove since the `Rename` will fail below if still mounted 280 logrus.Debugf("aufs: error while unmounting %s: %v", mountpoint, err) 281 } 282 283 // Atomically remove each directory in turn by first moving it out of the 284 // way (so that docker doesn't find it anymore) before doing removal of 285 // the whole tree. 286 tmpMntPath := path.Join(a.mntPath(), fmt.Sprintf("%s-removing", id)) 287 if err := os.Rename(mountpoint, tmpMntPath); err != nil && !os.IsNotExist(err) { 288 return err 289 } 290 defer os.RemoveAll(tmpMntPath) 291 292 tmpDiffpath := path.Join(a.diffPath(), fmt.Sprintf("%s-removing", id)) 293 if err := os.Rename(a.getDiffPath(id), tmpDiffpath); err != nil && !os.IsNotExist(err) { 294 return err 295 } 296 defer os.RemoveAll(tmpDiffpath) 297 298 // Remove the layers file for the id 299 if err := os.Remove(path.Join(a.rootPath(), "layers", id)); err != nil && !os.IsNotExist(err) { 300 return err 301 } 302 303 a.pathCacheLock.Lock() 304 delete(a.pathCache, id) 305 a.pathCacheLock.Unlock() 306 return nil 307 } 308 309 // Get returns the rootfs path for the id. 310 // This will mount the dir at it's given path 311 func (a *Driver) Get(id, mountLabel string) (string, error) { 312 parents, err := a.getParentLayerPaths(id) 313 if err != nil && !os.IsNotExist(err) { 314 return "", err 315 } 316 317 a.pathCacheLock.Lock() 318 m, exists := a.pathCache[id] 319 a.pathCacheLock.Unlock() 320 321 if !exists { 322 m = a.getDiffPath(id) 323 if len(parents) > 0 { 324 m = a.getMountpoint(id) 325 } 326 } 327 328 // If a dir does not have a parent ( no layers )do not try to mount 329 // just return the diff path to the data 330 if len(parents) > 0 { 331 if err := a.mount(id, m, mountLabel, parents); err != nil { 332 return "", err 333 } 334 } 335 336 a.pathCacheLock.Lock() 337 a.pathCache[id] = m 338 a.pathCacheLock.Unlock() 339 return m, nil 340 } 341 342 // Put unmounts and updates list of active mounts. 343 func (a *Driver) Put(id string) error { 344 a.pathCacheLock.Lock() 345 m, exists := a.pathCache[id] 346 if !exists { 347 m = a.getMountpoint(id) 348 a.pathCache[id] = m 349 } 350 a.pathCacheLock.Unlock() 351 352 err := a.unmount(m) 353 if err != nil { 354 logrus.Debugf("Failed to unmount %s aufs: %v", id, err) 355 } 356 return err 357 } 358 359 // Diff produces an archive of the changes between the specified 360 // layer and its parent layer which may be "". 361 func (a *Driver) Diff(id, parent string) (archive.Archive, error) { 362 // AUFS doesn't need the parent layer to produce a diff. 363 return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{ 364 Compression: archive.Uncompressed, 365 ExcludePatterns: []string{archive.WhiteoutMetaPrefix + "*", "!" + archive.WhiteoutOpaqueDir}, 366 UIDMaps: a.uidMaps, 367 GIDMaps: a.gidMaps, 368 }) 369 } 370 371 type fileGetNilCloser struct { 372 storage.FileGetter 373 } 374 375 func (f fileGetNilCloser) Close() error { 376 return nil 377 } 378 379 // DiffGetter returns a FileGetCloser that can read files from the directory that 380 // contains files for the layer differences. Used for direct access for tar-split. 381 func (a *Driver) DiffGetter(id string) (graphdriver.FileGetCloser, error) { 382 p := path.Join(a.rootPath(), "diff", id) 383 return fileGetNilCloser{storage.NewPathFileGetter(p)}, nil 384 } 385 386 func (a *Driver) applyDiff(id string, diff archive.Reader) error { 387 return chrootarchive.UntarUncompressed(diff, path.Join(a.rootPath(), "diff", id), &archive.TarOptions{ 388 UIDMaps: a.uidMaps, 389 GIDMaps: a.gidMaps, 390 }) 391 } 392 393 // DiffSize calculates the changes between the specified id 394 // and its parent and returns the size in bytes of the changes 395 // relative to its base filesystem directory. 396 func (a *Driver) DiffSize(id, parent string) (size int64, err error) { 397 // AUFS doesn't need the parent layer to calculate the diff size. 398 return directory.Size(path.Join(a.rootPath(), "diff", id)) 399 } 400 401 // ApplyDiff extracts the changeset from the given diff into the 402 // layer with the specified id and parent, returning the size of the 403 // new layer in bytes. 404 func (a *Driver) ApplyDiff(id, parent string, diff archive.Reader) (size int64, err error) { 405 // AUFS doesn't need the parent id to apply the diff. 406 if err = a.applyDiff(id, diff); err != nil { 407 return 408 } 409 410 return a.DiffSize(id, parent) 411 } 412 413 // Changes produces a list of changes between the specified layer 414 // and its parent layer. If parent is "", then all changes will be ADD changes. 415 func (a *Driver) Changes(id, parent string) ([]archive.Change, error) { 416 // AUFS doesn't have snapshots, so we need to get changes from all parent 417 // layers. 418 layers, err := a.getParentLayerPaths(id) 419 if err != nil { 420 return nil, err 421 } 422 return archive.Changes(layers, path.Join(a.rootPath(), "diff", id)) 423 } 424 425 func (a *Driver) getParentLayerPaths(id string) ([]string, error) { 426 parentIds, err := getParentIds(a.rootPath(), id) 427 if err != nil { 428 return nil, err 429 } 430 layers := make([]string, len(parentIds)) 431 432 // Get the diff paths for all the parent ids 433 for i, p := range parentIds { 434 layers[i] = path.Join(a.rootPath(), "diff", p) 435 } 436 return layers, nil 437 } 438 439 func (a *Driver) mount(id string, target string, mountLabel string, layers []string) error { 440 a.Lock() 441 defer a.Unlock() 442 443 // If the id is mounted or we get an error return 444 if mounted, err := a.mounted(target); err != nil || mounted { 445 return err 446 } 447 448 rw := a.getDiffPath(id) 449 450 if err := a.aufsMount(layers, rw, target, mountLabel); err != nil { 451 return fmt.Errorf("error creating aufs mount to %s: %v", target, err) 452 } 453 return nil 454 } 455 456 func (a *Driver) unmount(mountPath string) error { 457 a.Lock() 458 defer a.Unlock() 459 460 if mounted, err := a.mounted(mountPath); err != nil || !mounted { 461 return err 462 } 463 if err := Unmount(mountPath); err != nil { 464 return err 465 } 466 return nil 467 } 468 469 func (a *Driver) mounted(mountpoint string) (bool, error) { 470 return graphdriver.Mounted(graphdriver.FsMagicAufs, mountpoint) 471 } 472 473 // Cleanup aufs and unmount all mountpoints 474 func (a *Driver) Cleanup() error { 475 var dirs []string 476 if err := filepath.Walk(a.mntPath(), func(path string, info os.FileInfo, err error) error { 477 if err != nil { 478 return err 479 } 480 if !info.IsDir() { 481 return nil 482 } 483 dirs = append(dirs, path) 484 return nil 485 }); err != nil { 486 return err 487 } 488 489 for _, m := range dirs { 490 if err := a.unmount(m); err != nil { 491 logrus.Debugf("aufs error unmounting %s: %s", stringid.TruncateID(m), err) 492 } 493 } 494 return mountpk.Unmount(a.root) 495 } 496 497 func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err error) { 498 defer func() { 499 if err != nil { 500 Unmount(target) 501 } 502 }() 503 504 // Mount options are clipped to page size(4096 bytes). If there are more 505 // layers then these are remounted individually using append. 506 507 offset := 54 508 if useDirperm() { 509 offset += len("dirperm1") 510 } 511 b := make([]byte, syscall.Getpagesize()-len(mountLabel)-offset) // room for xino & mountLabel 512 bp := copy(b, fmt.Sprintf("br:%s=rw", rw)) 513 514 firstMount := true 515 i := 0 516 517 for { 518 for ; i < len(ro); i++ { 519 layer := fmt.Sprintf(":%s=ro+wh", ro[i]) 520 521 if firstMount { 522 if bp+len(layer) > len(b) { 523 break 524 } 525 bp += copy(b[bp:], layer) 526 } else { 527 data := label.FormatMountLabel(fmt.Sprintf("append%s", layer), mountLabel) 528 if err = mount("none", target, "aufs", syscall.MS_REMOUNT, data); err != nil { 529 return 530 } 531 } 532 } 533 534 if firstMount { 535 opts := "dio,xino=/dev/shm/aufs.xino" 536 if useDirperm() { 537 opts += ",dirperm1" 538 } 539 data := label.FormatMountLabel(fmt.Sprintf("%s,%s", string(b[:bp]), opts), mountLabel) 540 if err = mount("none", target, "aufs", 0, data); err != nil { 541 return 542 } 543 firstMount = false 544 } 545 546 if i == len(ro) { 547 break 548 } 549 } 550 551 return 552 } 553 554 // useDirperm checks dirperm1 mount option can be used with the current 555 // version of aufs. 556 func useDirperm() bool { 557 enableDirpermLock.Do(func() { 558 base, err := ioutil.TempDir("", "docker-aufs-base") 559 if err != nil { 560 logrus.Errorf("error checking dirperm1: %v", err) 561 return 562 } 563 defer os.RemoveAll(base) 564 565 union, err := ioutil.TempDir("", "docker-aufs-union") 566 if err != nil { 567 logrus.Errorf("error checking dirperm1: %v", err) 568 return 569 } 570 defer os.RemoveAll(union) 571 572 opts := fmt.Sprintf("br:%s,dirperm1,xino=/dev/shm/aufs.xino", base) 573 if err := mount("none", union, "aufs", 0, opts); err != nil { 574 return 575 } 576 enableDirperm = true 577 if err := Unmount(union); err != nil { 578 logrus.Errorf("error checking dirperm1: failed to unmount %v", err) 579 } 580 }) 581 return enableDirperm 582 }