snapshots/blockfile: deflaky the testsuite

* Use direct-io mode to reduce IO.

* Add testViewHook helper to recovery the backing file since the ext4
  might need writable permission to handle recovery. If the backing file
  needs recovery and it's for View snapshot, the readonly mount will
  cause error.

* Use 8 MiB as capacity to reduce the IO.

Signed-off-by: Wei Fu <fuweid89@gmail.com>
This commit is contained in:
Wei Fu
2023-06-15 14:28:57 +00:00
parent 6dfb16f99a
commit 7de95cbc4c
2 changed files with 125 additions and 27 deletions

View File

@@ -26,9 +26,6 @@ import (
"testing"
"github.com/containerd/containerd/mount"
"github.com/containerd/continuity/fs"
"github.com/containerd/continuity/testutil/loopback"
"golang.org/x/sys/unix"
)
func setupSnapshotter(t *testing.T) ([]Opt, error) {
@@ -37,52 +34,94 @@ func setupSnapshotter(t *testing.T) ([]Opt, error) {
t.Skipf("Could not find mkfs.ext4: %v", err)
}
loopbackSize := int64(128 << 20) // 128 MB
loopbackSize := int64(8 << 20) // 8 MB
if os.Getpagesize() > 4096 {
loopbackSize = int64(650 << 20) // 650 MB
}
loop, err := loopback.New(loopbackSize)
scratch := filepath.Join(t.TempDir(), "scratch")
scratchDevFile, err := os.OpenFile(scratch, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0600)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to create %s: %w", scratch, err)
}
defer loop.Close()
if out, err := exec.Command(mkfs, loop.Device).CombinedOutput(); err != nil {
if err := scratchDevFile.Truncate(loopbackSize); err != nil {
scratchDevFile.Close()
return nil, fmt.Errorf("failed to resize %s file: %w", scratch, err)
}
if err := scratchDevFile.Sync(); err != nil {
scratchDevFile.Close()
return nil, fmt.Errorf("failed to sync %s file: %w", scratch, err)
}
scratchDevFile.Close()
if out, err := exec.Command(mkfs, scratch).CombinedOutput(); err != nil {
return nil, fmt.Errorf("failed to make ext4 filesystem (out: %q): %w", out, err)
}
// sync after a mkfs on the loopback before trying to mount the device
unix.Sync()
if err := testMount(t, loop.Device); err != nil {
return nil, err
}
defaultOpts := []string{"loop", "direct-io", "sync"}
scratch := filepath.Join(t.TempDir(), "scratch")
err = fs.CopyFile(scratch, loop.File)
if err != nil {
if err := testMount(t, scratch, defaultOpts); err != nil {
return nil, err
}
return []Opt{
WithScratchFile(scratch),
WithFSType("ext4"),
WithMountOptions([]string{"loop", "sync"}),
WithMountOptions(defaultOpts),
WithRecreateScratch(false), // reduce IO presure in CI
withViewHookHelper(testViewHook),
}, nil
}
func testMount(t *testing.T, device string) error {
func testMount(t *testing.T, scratchFile string, opts []string) error {
root, err := os.MkdirTemp(t.TempDir(), "")
if err != nil {
return err
}
defer os.RemoveAll(root)
if out, err := exec.Command("mount", device, root).CombinedOutput(); err != nil {
return fmt.Errorf("failed to mount device %s (out: %q): %w", device, out, err)
m := []mount.Mount{
{
Type: "ext4",
Source: scratchFile,
Options: opts,
},
}
if err := mount.All(m, root); err != nil {
return fmt.Errorf("failed to mount device %s: %w", scratchFile, err)
}
if err := os.Remove(filepath.Join(root, "lost+found")); err != nil {
return err
}
return mount.UnmountAll(root, unix.MNT_DETACH)
return mount.UnmountAll(root, 0)
}
func testViewHook(backingFile string, fsType string, defaultOpts []string) error {
root, err := os.MkdirTemp("", "blockfile-testViewHook-XXXX")
if err != nil {
return err
}
defer os.RemoveAll(root)
// FIXME(fuweid): Mount with rw to force fs to handle recover
mountOpts := []mount.Mount{
{
Type: fsType,
Source: backingFile,
Options: defaultOpts,
},
}
if err := mount.All(mountOpts, root); err != nil {
return fmt.Errorf("failed to mount device %s: %w", backingFile, err)
}
if err := mount.UnmountAll(root, 0); err != nil {
return fmt.Errorf("failed to unmount device %s: %w", backingFile, err)
}
return nil
}