1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/aufs/aufs.go

276 lines
6.1 KiB
Go
Raw Normal View History

/*
aufs driver directory structure
.
layers // Metadata of layers
   1
   2
   3
diffs // Content of the layer
   1 // Contains layers that need to be mounted for the id
   2
   3
mnt // Mount points for the rw layers to be mounted
1
2
3
*/
package aufs
import (
"fmt"
2013-11-04 23:51:12 -05:00
"github.com/dotcloud/docker/archive"
"github.com/dotcloud/docker/graphdriver"
"github.com/dotcloud/docker/utils"
"log"
"os"
"os/exec"
"path"
)
2013-11-04 18:22:34 -05:00
func init() {
graphdriver.Register("aufs", Init)
}
type AufsDriver struct {
2013-11-04 23:51:12 -05:00
root string
}
// New returns a new AUFS driver.
// An error is returned if AUFS is not supported.
2013-11-04 18:22:34 -05:00
func Init(root string) (graphdriver.Driver, error) {
// Try to load the aufs kernel module
if err := exec.Command("modprobe", "aufs").Run(); err != nil {
return nil, err
}
paths := []string{
"mnt",
"diff",
"layers",
}
// Create the root aufs driver dir and return
// if it already exists
// If not populate the dir structure
aufsPath := path.Join(root, "aufs")
if err := os.Mkdir(aufsPath, 0755); err != nil {
if os.IsExist(err) {
return &AufsDriver{root}, nil
}
return nil, err
}
for _, p := range paths {
if err := os.MkdirAll(path.Join(aufsPath, p), 0755); err != nil {
return nil, err
}
}
2013-11-04 23:51:12 -05:00
return &AufsDriver{root}, nil
}
func (a *AufsDriver) rootPath() string {
return path.Join(a.root, "aufs")
}
func (a *AufsDriver) String() string {
return "aufs"
}
// Three folders are created for each id
// mnt, layers, and diff
func (a *AufsDriver) Create(id, parent string) error {
if err := a.createDirsFor(id); err != nil {
2013-11-04 23:51:12 -05:00
return err
}
// Write the layers metadata
f, err := os.Create(path.Join(a.rootPath(), "layers", id))
if err != nil {
2013-11-04 23:51:12 -05:00
return err
}
defer f.Close()
2013-11-04 23:51:12 -05:00
if parent != "" {
ids, err := getParentIds(a.rootPath(), parent)
if err != nil {
2013-11-04 23:51:12 -05:00
return err
}
fmt.Fprintln(f, parent)
for _, i := range ids {
fmt.Fprintln(f, i)
}
2013-11-04 23:51:12 -05:00
}
return nil
}
func (a *AufsDriver) createDirsFor(id string) error {
paths := []string{
"mnt",
"diff",
}
2013-11-04 23:51:12 -05:00
for _, p := range paths {
dir := path.Join(a.rootPath(), p, id)
if err := os.MkdirAll(dir, 0755); err != nil {
return err
}
2013-11-04 23:51:12 -05:00
}
return nil
}
2013-11-04 23:51:12 -05:00
// Unmount and remove the dir information
func (a *AufsDriver) Remove(id string) error {
// Make sure the dir is umounted first
mntPoint := path.Join(a.rootPath(), "mnt", id)
if err := a.unmount(mntPoint); err != nil {
2013-11-04 23:51:12 -05:00
return err
}
tmpDirs := []string{
"mnt",
"diff",
}
// Remove the dirs atomically
for _, p := range tmpDirs {
tmp := path.Join(os.TempDir(), p, id)
if err := os.MkdirAll(tmp, 0755); err != nil {
return err
}
realPath := path.Join(a.rootPath(), p, id)
if err := os.Rename(realPath, tmp); err != nil {
return err
}
defer os.RemoveAll(tmp)
}
// Remove the layers file for the id
return os.Remove(path.Join(a.rootPath(), "layers", id))
2013-11-04 23:51:12 -05:00
}
// Return the rootfs path for the id
// This will mount the dir at it's given path
func (a *AufsDriver) Get(id string) (string, error) {
ids, err := getParentIds(a.rootPath(), id)
if err != nil {
if !os.IsNotExist(err) {
return "", err
}
ids = []string{}
}
// If a dir does not have a parent ( no layers )do not try to mount
// just return the diff path to the data
out := path.Join(a.rootPath(), "diff", id)
if len(ids) > 0 {
out = path.Join(a.rootPath(), "mnt", id)
if err := a.mount(id); err != nil {
return "", err
}
}
return out, nil
}
// Returns an archive of the contents for the id
func (a *AufsDriver) Diff(id string) (archive.Archive, error) {
p, err := a.Get(id)
if err != nil {
return nil, err
}
return archive.Tar(p, archive.Uncompressed)
}
// Returns the size of the contents for the id
func (a *AufsDriver) DiffSize(id string) (int64, error) {
p, err := a.Get(id)
if err != nil {
return -1, err
}
return utils.TreeSize(p)
}
func (a *AufsDriver) Changes(id string) ([]archive.Change, error) {
return nil, nil
}
func (a *AufsDriver) mount(id string) error {
// If the id is mounted or we get an error return
if mounted, err := a.mounted(id); err != nil || mounted {
return err
}
parentIds, err := getParentIds(a.rootPath(), id)
if err != nil {
return err
}
if len(parentIds) == 0 {
return fmt.Errorf("Dir %s does not have any parent layers", id)
}
var (
target = path.Join(a.rootPath(), "mnt", id)
rw = path.Join(a.rootPath(), "diff", id)
layers = make([]string, len(parentIds))
)
// Get the diff paths for all the parent ids
for i, p := range parentIds {
layers[i] = path.Join(a.rootPath(), "diff", p)
}
if err := a.aufsMount(layers, rw, target); err != nil {
return err
}
return nil
}
func (a *AufsDriver) unmount(id string) error {
if mounted, err := a.mounted(id); err != nil || !mounted {
return err
}
target := path.Join(a.rootPath(), "mnt", id)
return Unmount(target)
}
func (a *AufsDriver) mounted(id string) (bool, error) {
target := path.Join(a.rootPath(), "mnt", id)
return Mounted(target)
2013-11-04 23:51:12 -05:00
}
// During cleanup aufs needs to unmount all mountpoints
2013-11-04 23:51:12 -05:00
func (a *AufsDriver) Cleanup() error {
ids, err := loadIds(path.Join(a.rootPath(), "layers"))
if err != nil {
return err
}
for _, id := range ids {
if err := a.unmount(id); err != nil {
return err
2013-11-04 23:51:12 -05:00
}
}
return nil
}
func (a *AufsDriver) aufsMount(ro []string, rw, target string) error {
rwBranch := fmt.Sprintf("%v=rw", rw)
roBranches := ""
for _, layer := range ro {
roBranches += fmt.Sprintf("%v=ro+wh:", layer)
}
branches := fmt.Sprintf("br:%v:%v,xino=/dev/shm/aufs.xino", rwBranch, roBranches)
//if error, try to load aufs kernel module
if err := mount("none", target, "aufs", 0, branches); err != nil {
log.Printf("Kernel does not support AUFS, trying to load the AUFS module with modprobe...")
if err := exec.Command("modprobe", "aufs").Run(); err != nil {
return fmt.Errorf("Unable to load the AUFS module")
}
log.Printf("...module loaded.")
if err := mount("none", target, "aufs", 0, branches); err != nil {
return fmt.Errorf("Unable to mount using aufs %s", err)
}
}
return nil
}