From 4d1276ba85ccb1b386bfa6373915f351ccc1fdc1 Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 5 Dec 2013 22:22:55 +0100 Subject: [PATCH] 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 (github: alexlarsson) asdfljk Upstream-commit: 886f650d9b2133fb61e7cc5b0bb7795246852026 Component: engine --- .../engine/graphdriver/devmapper/driver.go | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/components/engine/graphdriver/devmapper/driver.go b/components/engine/graphdriver/devmapper/driver.go index 0bf5fb24e1..dae712b9b5 100644 --- a/components/engine/graphdriver/devmapper/driver.go +++ b/components/engine/graphdriver/devmapper/driver.go @@ -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 {