diff --git a/daemon/graphdriver/zfs/zfs.go b/daemon/graphdriver/zfs/zfs.go index 5cc10d2e26..28a94dd0b5 100644 --- a/daemon/graphdriver/zfs/zfs.go +++ b/daemon/graphdriver/zfs/zfs.go @@ -22,6 +22,12 @@ import ( "github.com/opencontainers/runc/libcontainer/label" ) +type activeMount struct { + count int + path string + mounted bool +} + type zfsOptions struct { fsName string mountPath string @@ -103,6 +109,7 @@ func Init(base string, opt []string, uidMaps, gidMaps []idtools.IDMap) (graphdri dataset: rootDataset, options: options, filesystemsCache: filesystemsCache, + active: make(map[string]*activeMount), uidMaps: uidMaps, gidMaps: gidMaps, } @@ -159,6 +166,7 @@ type Driver struct { options zfsOptions sync.Mutex // protects filesystem cache against concurrent access filesystemsCache map[string]bool + active map[string]*activeMount uidMaps []idtools.IDMap gidMaps []idtools.IDMap } @@ -294,6 +302,17 @@ 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) { + d.Lock() + defer d.Unlock() + + mnt := d.active[id] + if mnt != nil { + mnt.count++ + return mnt.path, nil + } + + mnt = &activeMount{count: 1} + mountpoint := d.mountPath(id) filesystem := d.zfsPath(id) options := label.FormatMountLabel("", mountLabel) @@ -316,17 +335,43 @@ func (d *Driver) Get(id, mountLabel string) (string, error) { if err := os.Chown(mountpoint, rootUID, rootGID); err != nil { return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err) } + mnt.path = mountpoint + mnt.mounted = true + d.active[id] = mnt return mountpoint, nil } // Put removes the existing mountpoint for the given id if it exists. func (d *Driver) Put(id string) error { - mountpoint := d.mountPath(id) - logrus.Debugf(`[zfs] unmount("%s")`, mountpoint) + d.Lock() + defer d.Unlock() - if err := mount.Unmount(mountpoint); err != nil { - return fmt.Errorf("error unmounting to %s: %v", mountpoint, err) + mnt := d.active[id] + if mnt == nil { + logrus.Debugf("[zfs] Put on a non-mounted device %s", id) + // but it might be still here + if d.Exists(id) { + err := mount.Unmount(d.mountPath(id)) + if err != nil { + logrus.Debugf("[zfs] Failed to unmount %s zfs fs: %v", id, err) + } + } + return nil + } + + mnt.count-- + if mnt.count > 0 { + return nil + } + + defer delete(d.active, id) + if mnt.mounted { + logrus.Debugf(`[zfs] unmount("%s")`, mnt.path) + + if err := mount.Unmount(mnt.path); err != nil { + return fmt.Errorf("error unmounting to %s: %v", mnt.path, err) + } } return nil }