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>
| ... | ... |
@@ -113,7 +113,9 @@ type fileID struct {
|
| 113 | 113 |
|
| 114 | 114 |
// DirCopy copies or hardlinks the contents of one directory to another, |
| 115 | 115 |
// properly handling xattrs, and soft links |
| 116 |
-func DirCopy(srcDir, dstDir string, copyMode Mode) error {
|
|
| 116 |
+// |
|
| 117 |
+// Copying xattrs can be opted out of by passing false for copyXattrs. |
|
| 118 |
+func DirCopy(srcDir, dstDir string, copyMode Mode, copyXattrs bool) error {
|
|
| 117 | 119 |
copyWithFileRange := true |
| 118 | 120 |
copyWithFileClone := true |
| 119 | 121 |
// This is a map of source file inodes to dst file paths |
| ... | ... |
@@ -206,16 +208,10 @@ func DirCopy(srcDir, dstDir string, copyMode Mode) error {
|
| 206 | 206 |
return err |
| 207 | 207 |
} |
| 208 | 208 |
|
| 209 |
- if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil {
|
|
| 210 |
- return err |
|
| 211 |
- } |
|
| 212 |
- |
|
| 213 |
- // We need to copy this attribute if it appears in an overlay upper layer, as |
|
| 214 |
- // this function is used to copy those. It is set by overlay if a directory |
|
| 215 |
- // is removed and then re-created and should not inherit anything from the |
|
| 216 |
- // same dir in the lower dir. |
|
| 217 |
- if err := copyXattr(srcPath, dstPath, "trusted.overlay.opaque"); err != nil {
|
|
| 218 |
- return err |
|
| 209 |
+ if copyXattrs {
|
|
| 210 |
+ if err := doCopyXattrs(srcPath, dstPath); err != nil {
|
|
| 211 |
+ return err |
|
| 212 |
+ } |
|
| 219 | 213 |
} |
| 220 | 214 |
|
| 221 | 215 |
isSymlink := f.Mode()&os.ModeSymlink != 0 |
| ... | ... |
@@ -246,3 +242,18 @@ func DirCopy(srcDir, dstDir string, copyMode Mode) error {
|
| 246 | 246 |
}) |
| 247 | 247 |
return err |
| 248 | 248 |
} |
| 249 |
+ |
|
| 250 |
+func doCopyXattrs(srcPath, dstPath string) error {
|
|
| 251 |
+ if err := copyXattr(srcPath, dstPath, "security.capability"); err != nil {
|
|
| 252 |
+ return err |
|
| 253 |
+ } |
|
| 254 |
+ |
|
| 255 |
+ // We need to copy this attribute if it appears in an overlay upper layer, as |
|
| 256 |
+ // this function is used to copy those. It is set by overlay if a directory |
|
| 257 |
+ // is removed and then re-created and should not inherit anything from the |
|
| 258 |
+ // same dir in the lower dir. |
|
| 259 |
+ if err := copyXattr(srcPath, dstPath, "trusted.overlay.opaque"); err != nil {
|
|
| 260 |
+ return err |
|
| 261 |
+ } |
|
| 262 |
+ return nil |
|
| 263 |
+} |
| ... | ... |
@@ -86,7 +86,7 @@ func TestCopyHardlink(t *testing.T) {
|
| 86 | 86 |
require.NoError(t, ioutil.WriteFile(srcFile1, []byte{}, 0777))
|
| 87 | 87 |
require.NoError(t, os.Link(srcFile1, srcFile2)) |
| 88 | 88 |
|
| 89 |
- assert.NoError(t, DirCopy(srcDir, dstDir, Content)) |
|
| 89 |
+ assert.NoError(t, DirCopy(srcDir, dstDir, Content, false)) |
|
| 90 | 90 |
|
| 91 | 91 |
require.NoError(t, unix.Stat(srcFile1, &srcFile1FileInfo)) |
| 92 | 92 |
require.NoError(t, unix.Stat(srcFile2, &srcFile2FileInfo)) |
| ... | ... |
@@ -330,7 +330,7 @@ func (d *Driver) Create(id, parent string, opts *graphdriver.CreateOpts) (retErr |
| 330 | 330 |
return err |
| 331 | 331 |
} |
| 332 | 332 |
|
| 333 |
- return copy.DirCopy(parentUpperDir, upperDir, copy.Content) |
|
| 333 |
+ return copy.DirCopy(parentUpperDir, upperDir, copy.Content, true) |
|
| 334 | 334 |
} |
| 335 | 335 |
|
| 336 | 336 |
func (d *Driver) dir(id string) string {
|
| ... | ... |
@@ -446,7 +446,7 @@ func (d *Driver) ApplyDiff(id string, parent string, diff io.Reader) (size int64 |
| 446 | 446 |
} |
| 447 | 447 |
}() |
| 448 | 448 |
|
| 449 |
- if err = copy.DirCopy(parentRootDir, tmpRootDir, copy.Hardlink); err != nil {
|
|
| 449 |
+ if err = copy.DirCopy(parentRootDir, tmpRootDir, copy.Hardlink, true); err != nil {
|
|
| 450 | 450 |
return 0, err |
| 451 | 451 |
} |
| 452 | 452 |
|
| ... | ... |
@@ -7,7 +7,6 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/docker/docker/daemon/graphdriver" |
| 9 | 9 |
"github.com/docker/docker/daemon/graphdriver/quota" |
| 10 |
- "github.com/docker/docker/pkg/chrootarchive" |
|
| 11 | 10 |
"github.com/docker/docker/pkg/containerfs" |
| 12 | 11 |
"github.com/docker/docker/pkg/idtools" |
| 13 | 12 |
"github.com/docker/docker/pkg/system" |
| ... | ... |
@@ -16,8 +15,8 @@ import ( |
| 16 | 16 |
) |
| 17 | 17 |
|
| 18 | 18 |
var ( |
| 19 |
- // CopyWithTar defines the copy method to use. |
|
| 20 |
- CopyWithTar = chrootarchive.NewArchiver(nil).CopyWithTar |
|
| 19 |
+ // CopyDir defines the copy method to use. |
|
| 20 |
+ CopyDir = dirCopy |
|
| 21 | 21 |
) |
| 22 | 22 |
|
| 23 | 23 |
func init() {
|
| ... | ... |
@@ -133,7 +132,7 @@ func (d *Driver) create(id, parent string, size uint64) error {
|
| 133 | 133 |
if err != nil {
|
| 134 | 134 |
return fmt.Errorf("%s: %s", parent, err)
|
| 135 | 135 |
} |
| 136 |
- return CopyWithTar(parentDir.Path(), dir) |
|
| 136 |
+ return CopyDir(parentDir.Path(), dir) |
|
| 137 | 137 |
} |
| 138 | 138 |
|
| 139 | 139 |
func (d *Driver) dir(id string) string {
|
| ... | ... |
@@ -23,7 +23,7 @@ import ( |
| 23 | 23 |
func init() {
|
| 24 | 24 |
graphdriver.ApplyUncompressedLayer = archive.UnpackLayer |
| 25 | 25 |
defaultArchiver := archive.NewDefaultArchiver() |
| 26 |
- vfs.CopyWithTar = defaultArchiver.CopyWithTar |
|
| 26 |
+ vfs.CopyDir = defaultArchiver.CopyWithTar |
|
| 27 | 27 |
} |
| 28 | 28 |
|
| 29 | 29 |
func newVFSGraphDriver(td string) (graphdriver.Driver, error) {
|