
* 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>
128 lines
3.2 KiB
Go
128 lines
3.2 KiB
Go
//go:build !windows && !darwin
|
|
|
|
/*
|
|
Copyright The containerd Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package blockfile
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/containerd/containerd/mount"
|
|
)
|
|
|
|
func setupSnapshotter(t *testing.T) ([]Opt, error) {
|
|
mkfs, err := exec.LookPath("mkfs.ext4")
|
|
if err != nil {
|
|
t.Skipf("Could not find mkfs.ext4: %v", err)
|
|
}
|
|
|
|
loopbackSize := int64(8 << 20) // 8 MB
|
|
if os.Getpagesize() > 4096 {
|
|
loopbackSize = int64(650 << 20) // 650 MB
|
|
}
|
|
|
|
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, fmt.Errorf("failed to create %s: %w", scratch, err)
|
|
}
|
|
|
|
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)
|
|
}
|
|
|
|
defaultOpts := []string{"loop", "direct-io", "sync"}
|
|
|
|
if err := testMount(t, scratch, defaultOpts); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return []Opt{
|
|
WithScratchFile(scratch),
|
|
WithFSType("ext4"),
|
|
WithMountOptions(defaultOpts),
|
|
WithRecreateScratch(false), // reduce IO presure in CI
|
|
withViewHookHelper(testViewHook),
|
|
}, nil
|
|
}
|
|
|
|
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)
|
|
|
|
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, 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
|
|
}
|