mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Restore ref count
Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
This commit is contained in:
parent
5f95750ab4
commit
009ee16bef
6 changed files with 75 additions and 92 deletions
|
@ -1,32 +1,69 @@
|
||||||
package graphdriver
|
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
|
// RefCounter is a generic counter for use by graphdriver Get/Put calls
|
||||||
type RefCounter struct {
|
type RefCounter struct {
|
||||||
counts map[string]int
|
counts map[string]*minfo
|
||||||
mu sync.Mutex
|
mu sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRefCounter returns a new RefCounter
|
// NewRefCounter returns a new RefCounter
|
||||||
func NewRefCounter() *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
|
// 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.mu.Lock()
|
||||||
c.counts[id]++
|
m := c.counts[path]
|
||||||
count := c.counts[id]
|
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()
|
c.mu.Unlock()
|
||||||
return count
|
return m.count
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrement decreases the ref count for the given id and returns the current 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.mu.Lock()
|
||||||
c.counts[id]--
|
m := c.counts[path]
|
||||||
count := c.counts[id]
|
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()
|
c.mu.Unlock()
|
||||||
return count
|
return m.count
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,35 +160,35 @@ func (d *Driver) Remove(id string) error {
|
||||||
// Get mounts a device with given id into the root filesystem
|
// Get mounts a device with given id into the root filesystem
|
||||||
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
||||||
mp := path.Join(d.home, "mnt", id)
|
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
|
return mp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
uid, gid, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
|
uid, gid, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.ctr.Decrement(id)
|
d.ctr.Decrement(mp)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the target directories if they don't exist
|
// 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) {
|
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
|
return "", err
|
||||||
}
|
}
|
||||||
if err := idtools.MkdirAs(mp, 0755, uid, gid); err != nil && !os.IsExist(err) {
|
if err := idtools.MkdirAs(mp, 0755, uid, gid); err != nil && !os.IsExist(err) {
|
||||||
d.ctr.Decrement(id)
|
d.ctr.Decrement(mp)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount the device
|
// Mount the device
|
||||||
if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil {
|
if err := d.DeviceSet.MountDevice(id, mp, mountLabel); err != nil {
|
||||||
d.ctr.Decrement(id)
|
d.ctr.Decrement(mp)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
rootFs := path.Join(mp, "rootfs")
|
rootFs := path.Join(mp, "rootfs")
|
||||||
if err := idtools.MkdirAllAs(rootFs, 0755, uid, gid); err != nil && !os.IsExist(err) {
|
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)
|
d.DeviceSet.UnmountDevice(id, mp)
|
||||||
return "", err
|
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
|
// Create an "id" file with the container/image id in it to help reconstruct this in case
|
||||||
// of later problems
|
// of later problems
|
||||||
if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil {
|
if err := ioutil.WriteFile(idFile, []byte(id), 0600); err != nil {
|
||||||
d.ctr.Decrement(id)
|
d.ctr.Decrement(mp)
|
||||||
d.DeviceSet.UnmountDevice(id, mp)
|
d.DeviceSet.UnmountDevice(id, mp)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -209,10 +209,10 @@ func (d *Driver) Get(id, mountLabel string) (string, error) {
|
||||||
|
|
||||||
// Put unmounts a device and removes it.
|
// Put unmounts a device and removes it.
|
||||||
func (d *Driver) Put(id string) error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
mp := path.Join(d.home, "mnt", id)
|
|
||||||
err := d.DeviceSet.UnmountDevice(id, mp)
|
err := d.DeviceSet.UnmountDevice(id, mp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logrus.Errorf("devmapper: Error unmounting device %s: %s", id, err)
|
logrus.Errorf("devmapper: Error unmounting device %s: %s", id, err)
|
||||||
|
|
|
@ -340,6 +340,10 @@ func (d *Driver) Get(id string, mountLabel string) (string, error) {
|
||||||
if _, err := os.Stat(dir); err != nil {
|
if _, err := os.Stat(dir); err != nil {
|
||||||
return "", err
|
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
|
// If id has a root, just return it
|
||||||
rootDir := path.Join(dir, "root")
|
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")
|
lowerDir := path.Join(d.dir(string(lowerID)), "root")
|
||||||
upperDir := path.Join(dir, "upper")
|
upperDir := path.Join(dir, "upper")
|
||||||
workDir := path.Join(dir, "work")
|
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)
|
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 {
|
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)
|
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
|
// 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.
|
// user namespace requires this to move a directory from lower to upper.
|
||||||
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
|
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.ctr.Decrement(id)
|
d.ctr.Decrement(mergedDir)
|
||||||
syscall.Unmount(mergedDir, 0)
|
syscall.Unmount(mergedDir, 0)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := os.Chown(path.Join(workDir, "work"), rootUID, rootGID); err != nil {
|
if err := os.Chown(path.Join(workDir, "work"), rootUID, rootGID); err != nil {
|
||||||
d.ctr.Decrement(id)
|
d.ctr.Decrement(mergedDir)
|
||||||
syscall.Unmount(mergedDir, 0)
|
syscall.Unmount(mergedDir, 0)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -408,13 +396,14 @@ func (d *Driver) mounted(dir string) (bool, error) {
|
||||||
|
|
||||||
// Put unmounts the mount path created for the give id.
|
// Put unmounts the mount path created for the give id.
|
||||||
func (d *Driver) Put(id string) error {
|
func (d *Driver) Put(id string) error {
|
||||||
if count := d.ctr.Decrement(id); count > 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
d.pathCacheLock.Lock()
|
d.pathCacheLock.Lock()
|
||||||
mountpoint, exists := d.pathCache[id]
|
mountpoint, exists := d.pathCache[id]
|
||||||
d.pathCacheLock.Unlock()
|
d.pathCacheLock.Unlock()
|
||||||
|
|
||||||
|
if count := d.ctr.Decrement(mountpoint); count > 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if !exists {
|
if !exists {
|
||||||
logrus.Debugf("Put on a non-mounted device %s", id)
|
logrus.Debugf("Put on a non-mounted device %s", id)
|
||||||
// but it might be still here
|
// but it might be still here
|
||||||
|
|
|
@ -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.
|
// Get returns the mountpoint for the given id after creating the target directories if necessary.
|
||||||
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
func (d *Driver) Get(id, mountLabel string) (string, error) {
|
||||||
mountpoint := d.mountPath(id)
|
mountpoint := d.mountPath(id)
|
||||||
if count := d.ctr.Increment(id); count > 1 {
|
if count := d.ctr.Increment(mountpoint); count > 1 {
|
||||||
return mountpoint, nil
|
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)
|
rootUID, rootGID, err := idtools.GetRootUIDGID(d.uidMaps, d.gidMaps)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.ctr.Decrement(id)
|
d.ctr.Decrement(mountpoint)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
// Create the target directories if they don't exist
|
// Create the target directories if they don't exist
|
||||||
if err := idtools.MkdirAllAs(mountpoint, 0755, rootUID, rootGID); err != nil {
|
if err := idtools.MkdirAllAs(mountpoint, 0755, rootUID, rootGID); err != nil {
|
||||||
d.ctr.Decrement(id)
|
d.ctr.Decrement(mountpoint)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := mount.Mount(filesystem, mountpoint, "zfs", options); err != nil {
|
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)
|
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):
|
// permissions instead of the remapped root uid:gid (if user namespaces are enabled):
|
||||||
if err := os.Chown(mountpoint, rootUID, rootGID); err != nil {
|
if err := os.Chown(mountpoint, rootUID, rootGID); err != nil {
|
||||||
mount.Unmount(mountpoint)
|
mount.Unmount(mountpoint)
|
||||||
d.ctr.Decrement(id)
|
d.ctr.Decrement(mountpoint)
|
||||||
return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err)
|
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.
|
// Put removes the existing mountpoint for the given id if it exists.
|
||||||
func (d *Driver) Put(id string) error {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
mountpoint := d.mountPath(id)
|
|
||||||
mounted, err := graphdriver.Mounted(graphdriver.FsMagicZfs, mountpoint)
|
mounted, err := graphdriver.Mounted(graphdriver.FsMagicZfs, mountpoint)
|
||||||
if err != nil || !mounted {
|
if err != nil || !mounted {
|
||||||
return err
|
return err
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
// +build experimental
|
|
||||||
|
|
||||||
package libcontainerd
|
package libcontainerd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
|
@ -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)
|
|
||||||
}
|
|
Loading…
Reference in a new issue