aufs: Unmount inactive devices
This implements the new Put() operation such that Get()/Put() maintains a refcount for each ID, mounting only on first Get() and unmounting on the last Get(). This means we avoid littering the system with lots of mounts and free resources related to them. Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson) Upstream-commit: 5fe26ee426b9d748605c538829f30885462ad932 Component: engine
This commit is contained in:
@ -31,6 +31,7 @@ import (
|
||||
"os/exec"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@ -38,7 +39,9 @@ func init() {
|
||||
}
|
||||
|
||||
type Driver struct {
|
||||
root string
|
||||
root string
|
||||
sync.Mutex // Protects concurrent modification to active
|
||||
active map[string]int
|
||||
}
|
||||
|
||||
// New returns a new AUFS driver.
|
||||
@ -54,12 +57,17 @@ func Init(root string) (graphdriver.Driver, error) {
|
||||
"layers",
|
||||
}
|
||||
|
||||
a := &Driver{
|
||||
root: root,
|
||||
active: make(map[string]int),
|
||||
}
|
||||
|
||||
// Create the root aufs driver dir and return
|
||||
// if it already exists
|
||||
// If not populate the dir structure
|
||||
if err := os.MkdirAll(root, 0755); err != nil {
|
||||
if os.IsExist(err) {
|
||||
return &Driver{root}, nil
|
||||
return a, nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
@ -69,7 +77,7 @@ func Init(root string) (graphdriver.Driver, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &Driver{root}, nil
|
||||
return a, nil
|
||||
}
|
||||
|
||||
// Return a nil error if the kernel supports aufs
|
||||
@ -167,6 +175,14 @@ func (a *Driver) createDirsFor(id string) error {
|
||||
|
||||
// Unmount and remove the dir information
|
||||
func (a *Driver) Remove(id string) error {
|
||||
// Protect the a.active from concurrent access
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
|
||||
if a.active[id] != 0 {
|
||||
utils.Errorf("Warning: removing active id %s\n", id)
|
||||
}
|
||||
|
||||
// Make sure the dir is umounted first
|
||||
if err := a.unmount(id); err != nil {
|
||||
return err
|
||||
@ -210,19 +226,45 @@ func (a *Driver) Get(id string) (string, error) {
|
||||
ids = []string{}
|
||||
}
|
||||
|
||||
// Protect the a.active from concurrent access
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
|
||||
count := a.active[id]
|
||||
|
||||
// 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
|
||||
|
||||
if count == 0 {
|
||||
if err := a.mount(id); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
a.active[id] = count + 1
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (a *Driver) Put(id string) {
|
||||
// Protect the a.active from concurrent access
|
||||
a.Lock()
|
||||
defer a.Unlock()
|
||||
|
||||
if count := a.active[id]; count > 1 {
|
||||
a.active[id] = count - 1
|
||||
} else {
|
||||
ids, _ := getParentIds(a.rootPath(), id)
|
||||
// We only mounted if there are any parents
|
||||
if ids != nil && len(ids) > 0 {
|
||||
a.unmount(id)
|
||||
}
|
||||
delete(a.active, id)
|
||||
}
|
||||
}
|
||||
|
||||
// Returns an archive of the contents for the id
|
||||
|
||||
Reference in New Issue
Block a user