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 { func cloneFilesystem(name, parentName string) error {
parentDataset, err := zfs.GetDataset(parent)
if err != nil {
return err
}
snapshotName := fmt.Sprintf("%d", time.Now().Nanosecond()) snapshotName := fmt.Sprintf("%d", time.Now().Nanosecond())
parentDataset := zfs.Dataset{Name: parentName}
snapshot, err := parentDataset.Snapshot(snapshotName /*recursive */, false) snapshot, err := parentDataset.Snapshot(snapshotName /*recursive */, false)
if err != nil { if err != nil {
return err return err
} }
_, err = snapshot.Clone(id, map[string]string{ _, err = snapshot.Clone(name, map[string]string{"mountpoint": "legacy"})
"mountpoint": mountpoint,
})
if err != nil { if err != nil {
snapshot.Destroy(zfs.DestroyDeferDeletion) snapshot.Destroy(zfs.DestroyDeferDeletion)
return err return err
@ -204,52 +199,73 @@ func (d *Driver) ZfsPath(id string) string {
return d.options.fsName + "/" + id 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 { func (d *Driver) Create(id string, parent string) error {
datasetName := d.ZfsPath(id) err := d.create(id, parent)
dataset, err := zfs.GetDataset(datasetName)
if err == nil { if err == nil {
// cleanup existing dataset from an aborted build return nil
err := dataset.Destroy(zfs.DestroyRecursiveClones) }
if err != nil { if zfsError, ok := err.(*zfs.Error); ok {
log.Warnf("[zfs] failed to destroy dataset '%s': %v", dataset.Name, err) if !strings.HasSuffix(zfsError.Stderr, "dataset already exists\n") {
}
} else if zfsError, ok := err.(*zfs.Error); ok {
if !strings.HasSuffix(zfsError.Stderr, "dataset does not exist\n") {
return err return err
} }
// aborted build -> cleanup
} else { } else {
return err return err
} }
mountPoint := path.Join(d.options.mountPath, "graph", id) dataset := zfs.Dataset{Name: d.ZfsPath(id)}
if parent == "" { if err := dataset.Destroy(zfs.DestroyRecursiveClones); err != nil {
_, err := zfs.CreateFilesystem(datasetName, map[string]string{
"mountpoint": mountPoint,
})
return err 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 { func (d *Driver) Remove(id string) error {
dataset, err := zfs.GetDataset(d.ZfsPath(id)) dataset := zfs.Dataset{Name: d.ZfsPath(id)}
if dataset == nil {
return err
}
return dataset.Destroy(zfs.DestroyRecursive) return dataset.Destroy(zfs.DestroyRecursive)
} }
func (d *Driver) Get(id, mountLabel string) (string, error) { func (d *Driver) Get(id, mountLabel string) (string, error) {
dataset, err := zfs.GetDataset(d.ZfsPath(id)) mountpoint := d.MountPath(id)
if err != nil { 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 "", 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 { 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 return nil
} }