Have VFS graphdriver use accelerated in-kernel copy

This change makes the VFS graphdriver use the kernel-accelerated
(copy_file_range) mechanism of copying files, which is able to
leverage reflinks.

Signed-off-by: Sargun Dhillon <sargun@sargun.me>
This commit is contained in:
Sargun Dhillon 2017-11-21 10:29:27 -08:00
parent b467f8b2ef
commit d2b71b2660
7 changed files with 47 additions and 19 deletions

View file

@ -113,7 +113,9 @@ type fileID struct {
// DirCopy copies or hardlinks the contents of one directory to another, // DirCopy copies or hardlinks the contents of one directory to another,
// properly handling xattrs, and soft links // properly handling xattrs, and soft links
func DirCopy(srcDir, dstDir string, copyMode Mode) error { //
// Copying xattrs can be opted out of by passing false for copyXattrs.
func DirCopy(srcDir, dstDir string, copyMode Mode, copyXattrs bool) error {
copyWithFileRange := true copyWithFileRange := true
copyWithFileClone := true copyWithFileClone := true
// This is a map of source file inodes to dst file paths // This is a map of source file inodes to dst file paths
@ -206,16 +208,10 @@ func DirCopy(srcDir, dstDir string, copyMode Mode) error {
return err return err
} }
if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil { if copyXattrs {
return err if err := doCopyXattrs(srcPath, dstPath); err != nil {
} return err
}
// We need to copy this attribute if it appears in an overlay upper layer, as
// this function is used to copy those. It is set by overlay if a directory
// is removed and then re-created and should not inherit anything from the
// same dir in the lower dir.
if err := copyXattr(srcPath, dstPath, "trusted.overlay.opaque"); err != nil {
return err
} }
isSymlink := f.Mode()&os.ModeSymlink != 0 isSymlink := f.Mode()&os.ModeSymlink != 0
@ -246,3 +242,18 @@ func DirCopy(srcDir, dstDir string, copyMode Mode) error {
}) })
return err return err
} }
func doCopyXattrs(srcPath, dstPath string) error {
if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil {
return err
}
// We need to copy this attribute if it appears in an overlay upper layer, as
// this function is used to copy those. It is set by overlay if a directory
// is removed and then re-created and should not inherit anything from the
// same dir in the lower dir.
if err := copyXattr(srcPath, dstPath, "trusted.overlay.opaque"); err != nil {
return err
}
return nil
}

View file

@ -86,7 +86,7 @@ func TestCopyHardlink(t *testing.T) {
require.NoError(t, ioutil.WriteFile(srcFile1, []byte{}, 0777)) require.NoError(t, ioutil.WriteFile(srcFile1, []byte{}, 0777))
require.NoError(t, os.Link(srcFile1, srcFile2)) require.NoError(t, os.Link(srcFile1, srcFile2))
assert.NoError(t, DirCopy(srcDir, dstDir, Content)) assert.NoError(t, DirCopy(srcDir, dstDir, Content, false))
require.NoError(t, unix.Stat(srcFile1, &srcFile1FileInfo)) require.NoError(t, unix.Stat(srcFile1, &srcFile1FileInfo))
require.NoError(t, unix.Stat(srcFile2, &srcFile2FileInfo)) require.NoError(t, unix.Stat(srcFile2, &srcFile2FileInfo))

View file

@ -330,7 +330,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr
return err return err
} }
return copy.DirCopy(parentUpperDir, upperDir, copy.Content) return copy.DirCopy(parentUpperDir, upperDir, copy.Content, true)
} }
func (d *Driver) dir(id string) string { func (d *Driver) dir(id string) string {
@ -446,7 +446,7 @@ func (d *Driver) ApplyDiff(id string, parent string, diff io.Reader) (size int64
} }
}() }()
if err = copy.DirCopy(parentRootDir, tmpRootDir, copy.Hardlink); err != nil { if err = copy.DirCopy(parentRootDir, tmpRootDir, copy.Hardlink, true); err != nil {
return 0, err return 0, err
} }

View file

@ -0,0 +1,9 @@
// +build linux
package vfs
import "github.com/docker/docker/daemon/graphdriver/copy"
func dirCopy(srcDir, dstDir string) error {
return copy.DirCopy(srcDir, dstDir, copy.Content, false)
}

View file

@ -0,0 +1,9 @@
// +build !linux
package vfs
import "github.com/docker/docker/pkg/chrootarchive"
func dirCopy(srcDir, dstDir string) error {
return chrootarchive.NewArchiver(nil).CopyWithTar(srcDir, dstDir)
}

View file

@ -7,7 +7,6 @@ import (
"github.com/docker/docker/daemon/graphdriver" "github.com/docker/docker/daemon/graphdriver"
"github.com/docker/docker/daemon/graphdriver/quota" "github.com/docker/docker/daemon/graphdriver/quota"
"github.com/docker/docker/pkg/chrootarchive"
"github.com/docker/docker/pkg/containerfs" "github.com/docker/docker/pkg/containerfs"
"github.com/docker/docker/pkg/idtools" "github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/system"
@ -16,8 +15,8 @@ import (
) )
var ( var (
// CopyWithTar defines the copy method to use. // CopyDir defines the copy method to use.
CopyWithTar = chrootarchive.NewArchiver(nil).CopyWithTar CopyDir = dirCopy
) )
func init() { func init() {
@ -133,7 +132,7 @@ func (d *Driver) create(id, parent string, size uint64) error {
if err != nil { if err != nil {
return fmt.Errorf("%s: %s", parent, err) return fmt.Errorf("%s: %s", parent, err)
} }
return CopyWithTar(parentDir.Path(), dir) return CopyDir(parentDir.Path(), dir)
} }
func (d *Driver) dir(id string) string { func (d *Driver) dir(id string) string {

View file

@ -23,7 +23,7 @@ import (
func init() { func init() {
graphdriver.ApplyUncompressedLayer = archive.UnpackLayer graphdriver.ApplyUncompressedLayer = archive.UnpackLayer
defaultArchiver := archive.NewDefaultArchiver() defaultArchiver := archive.NewDefaultArchiver()
vfs.CopyWithTar = defaultArchiver.CopyWithTar vfs.CopyDir = defaultArchiver.CopyWithTar
} }
func newVFSGraphDriver(td string) (graphdriver.Driver, error) { func newVFSGraphDriver(td string) (graphdriver.Driver, error) {