From 009ee16beff4f6d3607fa251019908cc72ce0a34 Mon Sep 17 00:00:00 2001 From: Michael Crosby Date: Mon, 2 May 2016 15:44:20 -0700 Subject: [PATCH] Restore ref count Signed-off-by: Michael Crosby --- daemon/graphdriver/counter.go | 59 +++++++++++++++---- daemon/graphdriver/devmapper/driver.go | 18 +++--- daemon/graphdriver/overlay/overlay.go | 33 ++++------- daemon/graphdriver/zfs/zfs.go | 14 ++--- libcontainerd/client_liverestore_linux.go | 2 - libcontainerd/client_shutdownrestore_linux.go | 41 ------------- 6 files changed, 75 insertions(+), 92 deletions(-) delete mode 100644 libcontainerd/client_shutdownrestore_linux.go diff --git a/daemon/graphdriver/counter.go b/daemon/graphdriver/counter.go index 572fc9be47..8440a457ea 100644 --- a/daemon/graphdriver/counter.go +++ b/daemon/graphdriver/counter.go @@ -1,32 +1,69 @@ package graphdriver -import "sync" +import ( + "sync" + + "github.com/docker/docker/pkg/mount" +) + +type minfo struct { + check bool + count int +} // RefCounter is a generic counter for use by graphdriver Get/Put calls type RefCounter struct { - counts map[string]int + counts map[string]*minfo mu sync.Mutex } // NewRefCounter returns a new RefCounter func NewRefCounter() *RefCounter { - return &RefCounter{counts: make(map[string]int)} + return &RefCounter{counts: make(map[string]*minfo)} } // Increment increaes the ref count for the given id and returns the current count -func (c *RefCounter) Increment(id string) int { +func (c *RefCounter) Increment(path string) int { c.mu.Lock() - c.counts[id]++ - count := c.counts[id] + m := c.counts[path] + if m == nil { + m = &minfo{check: true} + c.counts[path] = m + } + // if we are checking this path for the first time check to make sure + // if it was already mounted on the system and make sure we have a correct ref + // count if it is mounted as it is in use. + if !m.check { + m.check = true + mntd, _ := mount.Mounted(path) + if mntd { + m.count++ + } + } + m.count++ c.mu.Unlock() - return count + return m.count } // Decrement decreases the ref count for the given id and returns the current count -func (c *RefCounter) Decrement(id string) int { +func (c *RefCounter) Decrement(path string) int { c.mu.Lock() - c.counts[id]-- - count := c.counts[id] + m := c.counts[path] + if m == nil { + m = &minfo{check: true} + c.counts[path] = m + } + // if we are checking this path for the first time check to make sure + // if it was already mounted on the system and make sure we have a correct ref + // count if it is mounted as it is in use. + if !m.check { + m.check = true + mntd, _ := mount.Mounted(path) + if mntd { + m.count++ + } + } + m.count-- c.mu.Unlock() - return count + return m.count } diff --git a/daemon/graphdriver/devmapper/driver.go b/daemon/graphdriver/devmapper/driver.go index 7cd90e924a..85a28b59ed 100644 --- a/daemon/graphdriver/devmapper/driver.go +++ b/daemon/graphdriver/devmapper/driver.go @@ -160,35 +160,35 @@ func (d *Driver) Remove(id string) error { // Get mounts a device with given id into the root filesystem func (d *Driver) Get(id, mountLabel string) (string, error) { mp := path.Join(d.home, "mnt", id) - if count := d.ctr.Increment(id); count > 1 { + if count := d.ctr.Increment(mp); count > 1 { return mp, nil } uid, gid, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { - d.ctr.Decrement(id) + d.ctr.Decrement(mp) return "", err } // Create the target directories if they don't exist if err := idtools.MkdirAllAs(path.Join(d.home, "mnt"), 0755, uid, gid); err != nil && !os.IsExist(err) { - d.ctr.Decrement(id) + d.ctr.Decrement(mp) return "", err } if err := idtools.MkdirAs(mp, 0755, uid, gid); err != nil && !os.IsExist(err) { - d.ctr.Decrement(id) + d.ctr.Decrement(mp) return "", err } // Mount the device if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil { - d.ctr.Decrement(id) + d.ctr.Decrement(mp) return "", err } rootFs := path.Join(mp, "rootfs") if err := idtools.MkdirAllAs(rootFs, 0755, uid, gid); err != nil && !os.IsExist(err) { - d.ctr.Decrement(id) + d.ctr.Decrement(mp) d.DeviceSet.UnmountDevice(id, mp) return "", err } @@ -198,7 +198,7 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { // Create an "id" file with the container/image id in it to help reconstruct this in case // of later problems if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil { - d.ctr.Decrement(id) + d.ctr.Decrement(mp) d.DeviceSet.UnmountDevice(id, mp) return "", err } @@ -209,10 +209,10 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { // Put unmounts a device and removes it. func (d *Driver) Put(id string) error { - if count := d.ctr.Decrement(id); count > 0 { + mp := path.Join(d.home, "mnt", id) + if count := d.ctr.Decrement(mp); count > 0 { return nil } - mp := path.Join(d.home, "mnt", id) err := d.DeviceSet.UnmountDevice(id, mp) if err != nil { logrus.Errorf("devmapper: Error unmounting device %s: %s", id, err) diff --git a/daemon/graphdriver/overlay/overlay.go b/daemon/graphdriver/overlay/overlay.go index a03a5acea6..6cb597fa13 100644 --- a/daemon/graphdriver/overlay/overlay.go +++ b/daemon/graphdriver/overlay/overlay.go @@ -340,6 +340,10 @@ func (d *Driver) Get(id string, mountLabel string) (string, error) { if _, err := os.Stat(dir); err != nil { return "", err } + mergedDir := path.Join(dir, "merged") + if count := d.ctr.Increment(mergedDir); count > 1 { + return mergedDir, nil + } // If id has a root, just return it rootDir := path.Join(dir, "root") @@ -357,40 +361,24 @@ func (d *Driver) Get(id string, mountLabel string) (string, error) { lowerDir := path.Join(d.dir(string(lowerID)), "root") upperDir := path.Join(dir, "upper") workDir := path.Join(dir, "work") - mergedDir := path.Join(dir, "merged") - - if count := d.ctr.Increment(id); count > 1 { - return mergedDir, nil - } opts := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", lowerDir, upperDir, workDir) - // if it's mounted already, just return - mounted, err := d.mounted(mergedDir) - if err != nil { - d.ctr.Decrement(id) - return "", err - } - if mounted { - d.ctr.Decrement(id) - return mergedDir, nil - } - if err := syscall.Mount("overlay", mergedDir, "overlay", 0, label.FormatMountLabel(opts, mountLabel)); err != nil { - d.ctr.Decrement(id) + d.ctr.Decrement(mergedDir) return "", fmt.Errorf("error creating overlay mount to %s: %v", mergedDir, err) } // chown "workdir/work" to the remapped root UID/GID. Overlay fs inside a // user namespace requires this to move a directory from lower to upper. rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { - d.ctr.Decrement(id) + d.ctr.Decrement(mergedDir) syscall.Unmount(mergedDir, 0) return "", err } if err := os.Chown(path.Join(workDir, "work"), rootUID, rootGID); err != nil { - d.ctr.Decrement(id) + d.ctr.Decrement(mergedDir) syscall.Unmount(mergedDir, 0) return "", err } @@ -408,13 +396,14 @@ func (d *Driver) mounted(dir string) (bool, error) { // Put unmounts the mount path created for the give id. func (d *Driver) Put(id string) error { - if count := d.ctr.Decrement(id); count > 0 { - return nil - } d.pathCacheLock.Lock() mountpoint, exists := d.pathCache[id] d.pathCacheLock.Unlock() + if count := d.ctr.Decrement(mountpoint); count > 0 { + return nil + } + if !exists { logrus.Debugf("Put on a non-mounted device %s", id) // but it might be still here diff --git a/daemon/graphdriver/zfs/zfs.go b/daemon/graphdriver/zfs/zfs.go index ffde8a545f..1ce71a68d1 100644 --- a/daemon/graphdriver/zfs/zfs.go +++ b/daemon/graphdriver/zfs/zfs.go @@ -307,7 +307,7 @@ func (d *Driver) Remove(id string) error { // Get returns the mountpoint for the given id after creating the target directories if necessary. func (d *Driver) Get(id, mountLabel string) (string, error) { mountpoint := d.mountPath(id) - if count := d.ctr.Increment(id); count > 1 { + if count := d.ctr.Increment(mountpoint); count > 1 { return mountpoint, nil } @@ -317,17 +317,17 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps) if err != nil { - d.ctr.Decrement(id) + d.ctr.Decrement(mountpoint) return "", err } // Create the target directories if they don't exist if err := idtools.MkdirAllAs(mountpoint, 0755, rootUID, rootGID); err != nil { - d.ctr.Decrement(id) + d.ctr.Decrement(mountpoint) return "", err } if err := mount.Mount(filesystem, mountpoint, "zfs", options); err != nil { - d.ctr.Decrement(id) + d.ctr.Decrement(mountpoint) return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err) } @@ -335,7 +335,7 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { // permissions instead of the remapped root uid:gid (if user namespaces are enabled): if err := os.Chown(mountpoint, rootUID, rootGID); err != nil { mount.Unmount(mountpoint) - d.ctr.Decrement(id) + d.ctr.Decrement(mountpoint) return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err) } @@ -344,10 +344,10 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { // Put removes the existing mountpoint for the given id if it exists. func (d *Driver) Put(id string) error { - if count := d.ctr.Decrement(id); count > 0 { + mountpoint := d.mountPath(id) + if count := d.ctr.Decrement(mountpoint); count > 0 { return nil } - mountpoint := d.mountPath(id) mounted, err := graphdriver.Mounted(graphdriver.FsMagicZfs, mountpoint) if err != nil || !mounted { return err diff --git a/libcontainerd/client_liverestore_linux.go b/libcontainerd/client_liverestore_linux.go index 2d6c2b257f..83b1a96fd4 100644 --- a/libcontainerd/client_liverestore_linux.go +++ b/libcontainerd/client_liverestore_linux.go @@ -1,5 +1,3 @@ -// +build experimental - package libcontainerd import ( diff --git a/libcontainerd/client_shutdownrestore_linux.go b/libcontainerd/client_shutdownrestore_linux.go deleted file mode 100644 index 52ea2a6180..0000000000 --- a/libcontainerd/client_shutdownrestore_linux.go +++ /dev/null @@ -1,41 +0,0 @@ -// +build !experimental - -package libcontainerd - -import ( - "syscall" - "time" - - "github.com/Sirupsen/logrus" -) - -func (clnt *client) Restore(containerID string, options ...CreateOption) error { - w := clnt.getOrCreateExitNotifier(containerID) - defer w.close() - cont, err := clnt.getContainerdContainer(containerID) - if err == nil && cont.Status != "stopped" { - clnt.lock(cont.Id) - container := clnt.newContainer(cont.BundlePath) - container.systemPid = systemPid(cont) - clnt.appendContainer(container) - clnt.unlock(cont.Id) - - if err := clnt.Signal(containerID, int(syscall.SIGTERM)); err != nil { - logrus.Errorf("error sending sigterm to %v: %v", containerID, err) - } - select { - case <-time.After(10 * time.Second): - if err := clnt.Signal(containerID, int(syscall.SIGKILL)); err != nil { - logrus.Errorf("error sending sigkill to %v: %v", containerID, err) - } - select { - case <-time.After(2 * time.Second): - case <-w.wait(): - return nil - } - case <-w.wait(): - return nil - } - } - return clnt.setExited(containerID) -}