github.com/adxhyt/docker@v1.4.2-0.20150117221845-467b7c821390/daemon/graphdriver/aufs/aufs.go (about) 1 /* 2 3 aufs driver directory structure 4 5 . 6 ├── layers // Metadata of layers 7 │ ├── 1 8 │ ├── 2 9 │ └── 3 10 ├── diff // Content of the layer 11 │ ├── 1 // Contains layers that need to be mounted for the id 12 │ ├── 2 13 │ └── 3 14 └── mnt // Mount points for the rw layers to be mounted 15 ├── 1 16 ├── 2 17 └── 3 18 19 */ 20 21 package aufs 22 23 import ( 24 "bufio" 25 "fmt" 26 "os" 27 "os/exec" 28 "path" 29 "strings" 30 "sync" 31 "syscall" 32 33 log "github.com/Sirupsen/logrus" 34 "github.com/docker/docker/daemon/graphdriver" 35 "github.com/docker/docker/pkg/archive" 36 "github.com/docker/docker/pkg/chrootarchive" 37 mountpk "github.com/docker/docker/pkg/mount" 38 "github.com/docker/docker/utils" 39 "github.com/docker/libcontainer/label" 40 ) 41 42 var ( 43 ErrAufsNotSupported = fmt.Errorf("AUFS was not found in /proc/filesystems") 44 incompatibleFsMagic = []graphdriver.FsMagic{ 45 graphdriver.FsMagicBtrfs, 46 graphdriver.FsMagicAufs, 47 } 48 backingFs = "<unknown>" 49 ) 50 51 func init() { 52 graphdriver.Register("aufs", Init) 53 } 54 55 type Driver struct { 56 root string 57 sync.Mutex // Protects concurrent modification to active 58 active map[string]int 59 } 60 61 // New returns a new AUFS driver. 62 // An error is returned if AUFS is not supported. 63 func Init(root string, options []string) (graphdriver.Driver, error) { 64 65 // Try to load the aufs kernel module 66 if err := supportsAufs(); err != nil { 67 return nil, graphdriver.ErrNotSupported 68 } 69 70 fsMagic, err := graphdriver.GetFSMagic(root) 71 if err != nil { 72 return nil, err 73 } 74 if fsName, ok := graphdriver.FsNames[fsMagic]; ok { 75 backingFs = fsName 76 } 77 78 for _, magic := range incompatibleFsMagic { 79 if fsMagic == magic { 80 return nil, graphdriver.ErrIncompatibleFS 81 } 82 } 83 84 paths := []string{ 85 "mnt", 86 "diff", 87 "layers", 88 } 89 90 a := &Driver{ 91 root: root, 92 active: make(map[string]int), 93 } 94 95 // Create the root aufs driver dir and return 96 // if it already exists 97 // If not populate the dir structure 98 if err := os.MkdirAll(root, 0755); err != nil { 99 if os.IsExist(err) { 100 return a, nil 101 } 102 return nil, err 103 } 104 105 if err := mountpk.MakePrivate(root); err != nil { 106 return nil, err 107 } 108 109 for _, p := range paths { 110 if err := os.MkdirAll(path.Join(root, p), 0755); err != nil { 111 return nil, err 112 } 113 } 114 return a, nil 115 } 116 117 // Return a nil error if the kernel supports aufs 118 // We cannot modprobe because inside dind modprobe fails 119 // to run 120 func supportsAufs() error { 121 // We can try to modprobe aufs first before looking at 122 // proc/filesystems for when aufs is supported 123 exec.Command("modprobe", "aufs").Run() 124 125 f, err := os.Open("/proc/filesystems") 126 if err != nil { 127 return err 128 } 129 defer f.Close() 130 131 s := bufio.NewScanner(f) 132 for s.Scan() { 133 if strings.Contains(s.Text(), "aufs") { 134 return nil 135 } 136 } 137 return ErrAufsNotSupported 138 } 139 140 func (a *Driver) rootPath() string { 141 return a.root 142 } 143 144 func (*Driver) String() string { 145 return "aufs" 146 } 147 148 func (a *Driver) Status() [][2]string { 149 ids, _ := loadIds(path.Join(a.rootPath(), "layers")) 150 return [][2]string{ 151 {"Root Dir", a.rootPath()}, 152 {"Backing Filesystem", backingFs}, 153 {"Dirs", fmt.Sprintf("%d", len(ids))}, 154 } 155 } 156 157 // Exists returns true if the given id is registered with 158 // this driver 159 func (a *Driver) Exists(id string) bool { 160 if _, err := os.Lstat(path.Join(a.rootPath(), "layers", id)); err != nil { 161 return false 162 } 163 return true 164 } 165 166 // Three folders are created for each id 167 // mnt, layers, and diff 168 func (a *Driver) Create(id, parent string) error { 169 if err := a.createDirsFor(id); err != nil { 170 return err 171 } 172 // Write the layers metadata 173 f, err := os.Create(path.Join(a.rootPath(), "layers", id)) 174 if err != nil { 175 return err 176 } 177 defer f.Close() 178 179 if parent != "" { 180 ids, err := getParentIds(a.rootPath(), parent) 181 if err != nil { 182 return err 183 } 184 185 if _, err := fmt.Fprintln(f, parent); err != nil { 186 return err 187 } 188 for _, i := range ids { 189 if _, err := fmt.Fprintln(f, i); err != nil { 190 return err 191 } 192 } 193 } 194 return nil 195 } 196 197 func (a *Driver) createDirsFor(id string) error { 198 paths := []string{ 199 "mnt", 200 "diff", 201 } 202 203 for _, p := range paths { 204 if err := os.MkdirAll(path.Join(a.rootPath(), p, id), 0755); err != nil { 205 return err 206 } 207 } 208 return nil 209 } 210 211 // Unmount and remove the dir information 212 func (a *Driver) Remove(id string) error { 213 // Protect the a.active from concurrent access 214 a.Lock() 215 defer a.Unlock() 216 217 if a.active[id] != 0 { 218 log.Errorf("Warning: removing active id %s", id) 219 } 220 221 // Make sure the dir is umounted first 222 if err := a.unmount(id); err != nil { 223 return err 224 } 225 tmpDirs := []string{ 226 "mnt", 227 "diff", 228 } 229 230 // Atomically remove each directory in turn by first moving it out of the 231 // way (so that docker doesn't find it anymore) before doing removal of 232 // the whole tree. 233 for _, p := range tmpDirs { 234 235 realPath := path.Join(a.rootPath(), p, id) 236 tmpPath := path.Join(a.rootPath(), p, fmt.Sprintf("%s-removing", id)) 237 if err := os.Rename(realPath, tmpPath); err != nil && !os.IsNotExist(err) { 238 return err 239 } 240 defer os.RemoveAll(tmpPath) 241 } 242 243 // Remove the layers file for the id 244 if err := os.Remove(path.Join(a.rootPath(), "layers", id)); err != nil && !os.IsNotExist(err) { 245 return err 246 } 247 return nil 248 } 249 250 // Return the rootfs path for the id 251 // This will mount the dir at it's given path 252 func (a *Driver) Get(id, mountLabel string) (string, error) { 253 ids, err := getParentIds(a.rootPath(), id) 254 if err != nil { 255 if !os.IsNotExist(err) { 256 return "", err 257 } 258 ids = []string{} 259 } 260 261 // Protect the a.active from concurrent access 262 a.Lock() 263 defer a.Unlock() 264 265 count := a.active[id] 266 267 // If a dir does not have a parent ( no layers )do not try to mount 268 // just return the diff path to the data 269 out := path.Join(a.rootPath(), "diff", id) 270 if len(ids) > 0 { 271 out = path.Join(a.rootPath(), "mnt", id) 272 273 if count == 0 { 274 if err := a.mount(id, mountLabel); err != nil { 275 return "", err 276 } 277 } 278 } 279 280 a.active[id] = count + 1 281 282 return out, nil 283 } 284 285 func (a *Driver) Put(id string) error { 286 // Protect the a.active from concurrent access 287 a.Lock() 288 defer a.Unlock() 289 290 if count := a.active[id]; count > 1 { 291 a.active[id] = count - 1 292 } else { 293 ids, _ := getParentIds(a.rootPath(), id) 294 // We only mounted if there are any parents 295 if ids != nil && len(ids) > 0 { 296 a.unmount(id) 297 } 298 delete(a.active, id) 299 } 300 return nil 301 } 302 303 // Diff produces an archive of the changes between the specified 304 // layer and its parent layer which may be "". 305 func (a *Driver) Diff(id, parent string) (archive.Archive, error) { 306 // AUFS doesn't need the parent layer to produce a diff. 307 return archive.TarWithOptions(path.Join(a.rootPath(), "diff", id), &archive.TarOptions{ 308 Compression: archive.Uncompressed, 309 ExcludePatterns: []string{".wh..wh.*"}, 310 }) 311 } 312 313 func (a *Driver) applyDiff(id string, diff archive.ArchiveReader) error { 314 return chrootarchive.Untar(diff, path.Join(a.rootPath(), "diff", id), nil) 315 } 316 317 // DiffSize calculates the changes between the specified id 318 // and its parent and returns the size in bytes of the changes 319 // relative to its base filesystem directory. 320 func (a *Driver) DiffSize(id, parent string) (size int64, err error) { 321 // AUFS doesn't need the parent layer to calculate the diff size. 322 return utils.TreeSize(path.Join(a.rootPath(), "diff", id)) 323 } 324 325 // ApplyDiff extracts the changeset from the given diff into the 326 // layer with the specified id and parent, returning the size of the 327 // new layer in bytes. 328 func (a *Driver) ApplyDiff(id, parent string, diff archive.ArchiveReader) (size int64, err error) { 329 // AUFS doesn't need the parent id to apply the diff. 330 if err = a.applyDiff(id, diff); err != nil { 331 return 332 } 333 334 return a.DiffSize(id, parent) 335 } 336 337 // Changes produces a list of changes between the specified layer 338 // and its parent layer. If parent is "", then all changes will be ADD changes. 339 func (a *Driver) Changes(id, parent string) ([]archive.Change, error) { 340 // AUFS doesn't have snapshots, so we need to get changes from all parent 341 // layers. 342 layers, err := a.getParentLayerPaths(id) 343 if err != nil { 344 return nil, err 345 } 346 return archive.Changes(layers, path.Join(a.rootPath(), "diff", id)) 347 } 348 349 func (a *Driver) getParentLayerPaths(id string) ([]string, error) { 350 parentIds, err := getParentIds(a.rootPath(), id) 351 if err != nil { 352 return nil, err 353 } 354 layers := make([]string, len(parentIds)) 355 356 // Get the diff paths for all the parent ids 357 for i, p := range parentIds { 358 layers[i] = path.Join(a.rootPath(), "diff", p) 359 } 360 return layers, nil 361 } 362 363 func (a *Driver) mount(id, mountLabel string) error { 364 // If the id is mounted or we get an error return 365 if mounted, err := a.mounted(id); err != nil || mounted { 366 return err 367 } 368 369 var ( 370 target = path.Join(a.rootPath(), "mnt", id) 371 rw = path.Join(a.rootPath(), "diff", id) 372 ) 373 374 layers, err := a.getParentLayerPaths(id) 375 if err != nil { 376 return err 377 } 378 379 if err := a.aufsMount(layers, rw, target, mountLabel); err != nil { 380 return err 381 } 382 return nil 383 } 384 385 func (a *Driver) unmount(id string) error { 386 if mounted, err := a.mounted(id); err != nil || !mounted { 387 return err 388 } 389 target := path.Join(a.rootPath(), "mnt", id) 390 return Unmount(target) 391 } 392 393 func (a *Driver) mounted(id string) (bool, error) { 394 target := path.Join(a.rootPath(), "mnt", id) 395 return mountpk.Mounted(target) 396 } 397 398 // During cleanup aufs needs to unmount all mountpoints 399 func (a *Driver) Cleanup() error { 400 ids, err := loadIds(path.Join(a.rootPath(), "layers")) 401 if err != nil { 402 return err 403 } 404 405 for _, id := range ids { 406 if err := a.unmount(id); err != nil { 407 log.Errorf("Unmounting %s: %s", utils.TruncateID(id), err) 408 } 409 } 410 411 return mountpk.Unmount(a.root) 412 } 413 414 func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err error) { 415 defer func() { 416 if err != nil { 417 Unmount(target) 418 } 419 }() 420 421 // Mount options are clipped to page size(4096 bytes). If there are more 422 // layers then these are remounted individually using append. 423 424 b := make([]byte, syscall.Getpagesize()-len(mountLabel)-50) // room for xino & mountLabel 425 bp := copy(b, fmt.Sprintf("br:%s=rw", rw)) 426 427 firstMount := true 428 i := 0 429 430 for { 431 for ; i < len(ro); i++ { 432 layer := fmt.Sprintf(":%s=ro+wh", ro[i]) 433 434 if firstMount { 435 if bp+len(layer) > len(b) { 436 break 437 } 438 bp += copy(b[bp:], layer) 439 } else { 440 data := label.FormatMountLabel(fmt.Sprintf("append%s", layer), mountLabel) 441 if err = mount("none", target, "aufs", MsRemount, data); err != nil { 442 return 443 } 444 } 445 } 446 447 if firstMount { 448 data := label.FormatMountLabel(fmt.Sprintf("%s,xino=/dev/shm/aufs.xino", string(b[:bp])), mountLabel) 449 if err = mount("none", target, "aufs", 0, data); err != nil { 450 return 451 } 452 firstMount = false 453 } 454 455 if i == len(ro) { 456 break 457 } 458 } 459 460 return 461 }