devicemapper: 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 active devicemapper devices and free resources related to them. Docker-DCO-1.1-Signed-off-by: Alexander Larsson <alexl@redhat.com> (github: alexlarsson) asdfljk Upstream-commit: 886f650d9b2133fb61e7cc5b0bb7795246852026 Component: engine
This commit is contained in:
@@ -5,8 +5,10 @@ package devmapper
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/dotcloud/docker/graphdriver"
|
||||
"github.com/dotcloud/docker/utils"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"sync"
|
||||
)
|
||||
|
||||
func init() {
|
||||
@@ -20,7 +22,9 @@ func init() {
|
||||
|
||||
type Driver struct {
|
||||
*DeviceSet
|
||||
home string
|
||||
home string
|
||||
sync.Mutex // Protects concurrent modification to active
|
||||
active map[string]int
|
||||
}
|
||||
|
||||
var Init = func(home string) (graphdriver.Driver, error) {
|
||||
@@ -31,6 +35,7 @@ var Init = func(home string) (graphdriver.Driver, error) {
|
||||
d := &Driver{
|
||||
DeviceSet: deviceSet,
|
||||
home: home,
|
||||
active: make(map[string]int),
|
||||
}
|
||||
return d, nil
|
||||
}
|
||||
@@ -82,6 +87,14 @@ func (d *Driver) Create(id, parent string) error {
|
||||
}
|
||||
|
||||
func (d *Driver) Remove(id string) error {
|
||||
// Protect the d.active from concurrent access
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
if d.active[id] != 0 {
|
||||
utils.Errorf("Warning: removing active id %s\n", id)
|
||||
}
|
||||
|
||||
mp := path.Join(d.home, "mnt", id)
|
||||
if err := d.unmount(id, mp); err != nil {
|
||||
return err
|
||||
@@ -90,14 +103,36 @@ func (d *Driver) Remove(id string) error {
|
||||
}
|
||||
|
||||
func (d *Driver) Get(id string) (string, error) {
|
||||
// Protect the d.active from concurrent access
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
count := d.active[id]
|
||||
|
||||
mp := path.Join(d.home, "mnt", id)
|
||||
if err := d.mount(id, mp); err != nil {
|
||||
return "", err
|
||||
if count == 0 {
|
||||
if err := d.mount(id, mp); err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
d.active[id] = count + 1
|
||||
|
||||
return path.Join(mp, "rootfs"), nil
|
||||
}
|
||||
|
||||
func (d *Driver) Put(id string) {
|
||||
// Protect the d.active from concurrent access
|
||||
d.Lock()
|
||||
defer d.Unlock()
|
||||
|
||||
if count := d.active[id]; count > 1 {
|
||||
d.active[id] = count - 1
|
||||
} else {
|
||||
mp := path.Join(d.home, "mnt", id)
|
||||
d.unmount(id, mp)
|
||||
delete(d.active, id)
|
||||
}
|
||||
}
|
||||
|
||||
func (d *Driver) mount(id, mountPoint string) error {
|
||||
|
||||
Reference in New Issue
Block a user