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