github.com/daaku/docker@v1.5.0/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  }