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:
parent
b467f8b2ef
commit
d2b71b2660
7 changed files with 47 additions and 19 deletions
|
@ -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 {
|
||||||
|
if err := doCopyXattrs(srcPath, dstPath); err != nil {
|
||||||
return err
|
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
|
||||||
|
}
|
||||||
|
|
|
@ -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))
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
9
daemon/graphdriver/vfs/copy_linux.go
Normal file
9
daemon/graphdriver/vfs/copy_linux.go
Normal 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)
|
||||||
|
}
|
9
daemon/graphdriver/vfs/copy_unsupported.go
Normal file
9
daemon/graphdriver/vfs/copy_unsupported.go
Normal 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)
|
||||||
|
}
|
|
@ -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 {
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in a new issue