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