1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

zfs: improve performance by using legacy mounts

instead of let zfs automaticly mount datasets, mount them on demand using mount(2).
This speed up this graph driver in 2 ways:
- less zfs processes needed to start a container
- /proc/mounts get smaller, so zfs userspace tools has less to read (which can
  a significant amount of data as the number of layer grows)

This ways it can be also ensured that the correct mountpoint is always used.

Signed-off-by: Jörg Thalheim <joerg@higgsboson.tk>
This commit is contained in:
Jörg Thalheim 2015-04-16 14:05:43 +02:00
parent ee00f07ea6
commit 11e9167a6b

View file

@ -179,20 +179,15 @@ func (d *Driver) Status() [][2]string {
}
}
func cloneFilesystem(id, parent, mountpoint string) error {
parentDataset, err := zfs.GetDataset(parent)
if err != nil {
return err
}
func cloneFilesystem(name, parentName string) error {
snapshotName := fmt.Sprintf("%d", time.Now().Nanosecond())
parentDataset := zfs.Dataset{Name: parentName}
snapshot, err := parentDataset.Snapshot(snapshotName /*recursive */, false)
if err != nil {
return err
}
_, err = snapshot.Clone(id, map[string]string{
"mountpoint": mountpoint,
})
_, err = snapshot.Clone(name, map[string]string{"mountpoint": "legacy"})
if err != nil {
snapshot.Destroy(zfs.DestroyDeferDeletion)
return err
@ -204,52 +199,73 @@ func (d *Driver) ZfsPath(id string) string {
return d.options.fsName + "/" + id
}
func (d *Driver) MountPath(id string) string {
return path.Join(d.options.mountPath, "graph", id)
}
func (d *Driver) Create(id string, parent string) error {
datasetName := d.ZfsPath(id)
dataset, err := zfs.GetDataset(datasetName)
err := d.create(id, parent)
if err == nil {
// cleanup existing dataset from an aborted build
err := dataset.Destroy(zfs.DestroyRecursiveClones)
if err != nil {
log.Warnf("[zfs] failed to destroy dataset '%s': %v", dataset.Name, err)
return nil
}
} else if zfsError, ok := err.(*zfs.Error); ok {
if !strings.HasSuffix(zfsError.Stderr, "dataset does not exist\n") {
if zfsError, ok := err.(*zfs.Error); ok {
if !strings.HasSuffix(zfsError.Stderr, "dataset already exists\n") {
return err
}
// aborted build -> cleanup
} else {
return err
}
mountPoint := path.Join(d.options.mountPath, "graph", id)
if parent == "" {
_, err := zfs.CreateFilesystem(datasetName, map[string]string{
"mountpoint": mountPoint,
})
dataset := zfs.Dataset{Name: d.ZfsPath(id)}
if err := dataset.Destroy(zfs.DestroyRecursiveClones); err != nil {
return err
}
return cloneFilesystem(datasetName, d.ZfsPath(parent), mountPoint)
// retry
return d.create(id, parent)
}
func (d *Driver) create(id, parent string) error {
name := d.ZfsPath(id)
if parent == "" {
mountoptions := map[string]string{"mountpoint": "legacy"}
_, err := zfs.CreateFilesystem(name, mountoptions)
return err
}
return cloneFilesystem(name, d.ZfsPath(parent))
}
func (d *Driver) Remove(id string) error {
dataset, err := zfs.GetDataset(d.ZfsPath(id))
if dataset == nil {
return err
}
dataset := zfs.Dataset{Name: d.ZfsPath(id)}
return dataset.Destroy(zfs.DestroyRecursive)
}
func (d *Driver) Get(id, mountLabel string) (string, error) {
dataset, err := zfs.GetDataset(d.ZfsPath(id))
if err != nil {
mountpoint := d.MountPath(id)
filesystem := d.ZfsPath(id)
log.Debugf(`[zfs] mount("%s", "%s", "%s")`, filesystem, mountpoint, mountLabel)
// Create the target directories if they don't exist
if err := os.MkdirAll(mountpoint, 0755); err != nil && !os.IsExist(err) {
return "", err
}
return dataset.Mountpoint, nil
err := mount.Mount(filesystem, mountpoint, "zfs", mountLabel)
if err != nil {
return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err)
}
return mountpoint, nil
}
func (d *Driver) Put(id string) error {
// FS is already mounted
mountpoint := d.MountPath(id)
log.Debugf(`[zfs] unmount("%s")`, mountpoint)
if err := mount.Unmount(mountpoint); err != nil {
return fmt.Errorf("error unmounting to %s: %v", mountpoint, err)
}
return nil
}