Преглед изворни кода

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>
Jörg Thalheim пре 10 година
родитељ
комит
11e9167a6b
1 измењених фајлова са 46 додато и 30 уклоњено
  1. 46 30
      daemon/graphdriver/zfs/zfs.go

+ 46 - 30
daemon/graphdriver/zfs/zfs.go

@@ -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)
-		}
-	} else if zfsError, ok := err.(*zfs.Error); ok {
-		if !strings.HasSuffix(zfsError.Stderr, "dataset does not exist\n") {
+		return nil
+	}
+	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) Remove(id string) error {
-	dataset, err := zfs.GetDataset(d.ZfsPath(id))
-	if dataset == nil {
+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 := 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
 }