Skip to content

Commit 70ab151

Browse files
tjungblufuweid
authored andcommitted
Add basic XFS powerfailure tests
This also introduces mkfs options, in case we need to accomodate for non-default parameters here in the future. Signed-off-by: Thomas Jungblut <tjungblu@redhat.com> (cherry picked from commit c27eedc) Signed-off-by: Wei Fu <fuweid89@gmail.com>
1 parent 0719297 commit 70ab151

File tree

4 files changed

+102
-33
lines changed

4 files changed

+102
-33
lines changed

.github/workflows/robustness_test.yaml

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ jobs:
1212
with:
1313
go-version: ${{ steps.goversion.outputs.goversion }}
1414
- run: |
15+
set -euo pipefail
16+
sudo apt-get install -y dmsetup xfsprogs
17+
1518
make gofail-enable
1619
# build bbolt with failpoint
1720
go install ./cmd/bbolt

tests/dmflakey/dmflakey.go

+12-6
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ const (
9090
// The device-mapper device will be /dev/mapper/$flakeyDevice. And the filesystem
9191
// image will be created at $dataStorePath/$flakeyDevice.img. By default, the
9292
// device is available for 2 minutes and size is 10 GiB.
93-
func InitFlakey(flakeyDevice, dataStorePath string, fsType FSType) (_ Flakey, retErr error) {
93+
func InitFlakey(flakeyDevice, dataStorePath string, fsType FSType, mkfsOpt string) (_ Flakey, retErr error) {
9494
imgPath := filepath.Join(dataStorePath, fmt.Sprintf("%s.img", flakeyDevice))
95-
if err := createEmptyFSImage(imgPath, fsType); err != nil {
95+
if err := createEmptyFSImage(imgPath, fsType, mkfsOpt); err != nil {
9696
return nil, err
9797
}
9898
defer func() {
@@ -276,7 +276,7 @@ func (f *flakey) Teardown() error {
276276

277277
// createEmptyFSImage creates empty filesystem on dataStorePath folder with
278278
// default size - 10 GiB.
279-
func createEmptyFSImage(imgPath string, fsType FSType) error {
279+
func createEmptyFSImage(imgPath string, fsType FSType, mkfsOpt string) error {
280280
if err := validateFSType(fsType); err != nil {
281281
return err
282282
}
@@ -308,10 +308,16 @@ func createEmptyFSImage(imgPath string, fsType FSType) error {
308308
imgPath, defaultImgSize, err)
309309
}
310310

311-
output, err := exec.Command(mkfs, imgPath).CombinedOutput()
311+
args := []string{imgPath}
312+
if mkfsOpt != "" {
313+
splitArgs := strings.Split(mkfsOpt, " ")
314+
args = append(splitArgs, imgPath)
315+
}
316+
317+
output, err := exec.Command(mkfs, args...).CombinedOutput()
312318
if err != nil {
313-
return fmt.Errorf("failed to mkfs.%s on %s (out: %s): %w",
314-
fsType, imgPath, string(output), err)
319+
return fmt.Errorf("failed to mkfs on %s (%s %v) (out: %s): %w",
320+
imgPath, mkfs, args, string(output), err)
315321
}
316322
return nil
317323
}

tests/dmflakey/dmflakey_test.go

+23-19
Original file line numberDiff line numberDiff line change
@@ -26,31 +26,35 @@ func TestMain(m *testing.M) {
2626
}
2727

2828
func TestBasic(t *testing.T) {
29-
tmpDir := t.TempDir()
29+
for _, fsType := range []FSType{FSTypeEXT4, FSTypeXFS} {
30+
t.Run(string(fsType), func(t *testing.T) {
31+
tmpDir := t.TempDir()
3032

31-
flakey, err := InitFlakey("go-dmflakey", tmpDir, FSTypeEXT4)
32-
require.NoError(t, err, "init flakey")
33-
defer func() {
34-
assert.NoError(t, flakey.Teardown())
35-
}()
33+
flakey, err := InitFlakey("go-dmflakey", tmpDir, fsType, "")
34+
require.NoError(t, err, "init flakey")
35+
defer func() {
36+
assert.NoError(t, flakey.Teardown())
37+
}()
3638

37-
target := filepath.Join(tmpDir, "root")
38-
require.NoError(t, os.MkdirAll(target, 0600))
39+
target := filepath.Join(tmpDir, "root")
40+
require.NoError(t, os.MkdirAll(target, 0600))
3941

40-
require.NoError(t, mount(target, flakey.DevicePath(), ""))
41-
defer func() {
42-
assert.NoError(t, unmount(target))
43-
}()
42+
require.NoError(t, mount(target, flakey.DevicePath(), ""))
43+
defer func() {
44+
assert.NoError(t, unmount(target))
45+
}()
4446

45-
file := filepath.Join(target, "test")
46-
assert.NoError(t, writeFile(file, []byte("hello, world"), 0600, true))
47+
file := filepath.Join(target, "test")
48+
assert.NoError(t, writeFile(file, []byte("hello, world"), 0600, true))
4749

48-
assert.NoError(t, unmount(target))
50+
assert.NoError(t, unmount(target))
4951

50-
assert.NoError(t, flakey.Teardown())
52+
assert.NoError(t, flakey.Teardown())
53+
})
54+
}
5155
}
5256

53-
func TestDropWrites(t *testing.T) {
57+
func TestDropWritesExt4(t *testing.T) {
5458
flakey, root := initFlakey(t, FSTypeEXT4)
5559

5660
// commit=1000 is to delay commit triggered by writeback thread
@@ -82,7 +86,7 @@ func TestDropWrites(t *testing.T) {
8286
assert.True(t, errors.Is(err, os.ErrNotExist))
8387
}
8488

85-
func TestErrorWrites(t *testing.T) {
89+
func TestErrorWritesExt4(t *testing.T) {
8690
flakey, root := initFlakey(t, FSTypeEXT4)
8791

8892
// commit=1000 is to delay commit triggered by writeback thread
@@ -114,7 +118,7 @@ func initFlakey(t *testing.T, fsType FSType) (_ Flakey, root string) {
114118
target := filepath.Join(tmpDir, "root")
115119
require.NoError(t, os.MkdirAll(target, 0600))
116120

117-
flakey, err := InitFlakey("go-dmflakey", tmpDir, FSTypeEXT4)
121+
flakey, err := InitFlakey("go-dmflakey", tmpDir, fsType, "")
118122
require.NoError(t, err, "init flakey")
119123

120124
t.Cleanup(func() {

tests/robustness/powerfailure_test.go

+64-8
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ var panicFailpoints = []string{
3535
"unmapError",
3636
}
3737

38-
// TestRestartFromPowerFailure is to test data after unexpected power failure.
39-
func TestRestartFromPowerFailure(t *testing.T) {
38+
// TestRestartFromPowerFailureExt4 is to test data after unexpected power failure on ext4.
39+
func TestRestartFromPowerFailureExt4(t *testing.T) {
4040
for _, tc := range []struct {
4141
name string
4242
du time.Duration
@@ -78,13 +78,69 @@ func TestRestartFromPowerFailure(t *testing.T) {
7878
},
7979
} {
8080
t.Run(tc.name, func(t *testing.T) {
81-
doPowerFailure(t, tc.du, tc.fsMountOpt, tc.useFailpoint)
81+
doPowerFailure(t, tc.du, dmflakey.FSTypeEXT4, "", tc.fsMountOpt, tc.useFailpoint)
8282
})
8383
}
8484
}
8585

86-
func doPowerFailure(t *testing.T, du time.Duration, fsMountOpt string, useFailpoint bool) {
87-
flakey := initFlakeyDevice(t, strings.Replace(t.Name(), "/", "_", -1), dmflakey.FSTypeEXT4, fsMountOpt)
86+
func TestRestartFromPowerFailureXFS(t *testing.T) {
87+
for _, tc := range []struct {
88+
name string
89+
mkfsOpt string
90+
fsMountOpt string
91+
useFailpoint bool
92+
}{
93+
{
94+
name: "xfs_no_opts",
95+
mkfsOpt: "",
96+
fsMountOpt: "",
97+
useFailpoint: true,
98+
},
99+
{
100+
name: "lazy-log",
101+
mkfsOpt: "-l lazy-count=1",
102+
fsMountOpt: "",
103+
useFailpoint: true,
104+
},
105+
{
106+
name: "odd-allocsize",
107+
mkfsOpt: "",
108+
fsMountOpt: "allocsize=" + fmt.Sprintf("%d", 4096*5),
109+
useFailpoint: true,
110+
},
111+
{
112+
name: "nolargeio",
113+
mkfsOpt: "",
114+
fsMountOpt: "nolargeio",
115+
useFailpoint: true,
116+
},
117+
{
118+
name: "odd-alignment",
119+
mkfsOpt: "-d sunit=1024,swidth=1024",
120+
fsMountOpt: "noalign",
121+
useFailpoint: true,
122+
},
123+
{
124+
name: "openshift-sno-options",
125+
mkfsOpt: "-m bigtime=1,finobt=1,rmapbt=0,reflink=1 -i sparse=1 -l lazy-count=1",
126+
// openshift also supplies seclabel,relatime,prjquota on RHEL, but that's not supported on our CI
127+
// prjquota is only unsupported on our ARM runners.
128+
// You can find more information in either the man page with `man xfs` or `man mkfs.xfs`.
129+
// Also refer to https://man7.org/linux/man-pages/man8/mkfs.xfs.8.html.
130+
fsMountOpt: "rw,attr2,inode64,logbufs=8,logbsize=32k",
131+
useFailpoint: true,
132+
},
133+
} {
134+
t.Run(tc.name, func(t *testing.T) {
135+
t.Logf("mkfs opts: %s", tc.mkfsOpt)
136+
t.Logf("mount opts: %s", tc.fsMountOpt)
137+
doPowerFailure(t, 5*time.Second, dmflakey.FSTypeXFS, tc.mkfsOpt, tc.fsMountOpt, tc.useFailpoint)
138+
})
139+
}
140+
}
141+
142+
func doPowerFailure(t *testing.T, du time.Duration, fsType dmflakey.FSType, mkfsOpt string, fsMountOpt string, useFailpoint bool) {
143+
flakey := initFlakeyDevice(t, strings.Replace(t.Name(), "/", "_", -1), fsType, mkfsOpt, fsMountOpt)
88144
root := flakey.RootFS()
89145

90146
dbPath := filepath.Join(root, "boltdb")
@@ -185,10 +241,10 @@ type FlakeyDevice interface {
185241
}
186242

187243
// initFlakeyDevice returns FlakeyDevice instance with a given filesystem.
188-
func initFlakeyDevice(t *testing.T, name string, fsType dmflakey.FSType, mntOpt string) FlakeyDevice {
244+
func initFlakeyDevice(t *testing.T, name string, fsType dmflakey.FSType, mkfsOpt string, mntOpt string) FlakeyDevice {
189245
imgDir := t.TempDir()
190246

191-
flakey, err := dmflakey.InitFlakey(name, imgDir, fsType)
247+
flakey, err := dmflakey.InitFlakey(name, imgDir, fsType, mkfsOpt)
192248
require.NoError(t, err, "init flakey %s", name)
193249
t.Cleanup(func() {
194250
assert.NoError(t, flakey.Teardown())
@@ -239,7 +295,7 @@ func (f *flakeyT) PowerFailure(mntOpt string) error {
239295
}
240296

241297
if err := unix.Mount(f.DevicePath(), f.rootDir, string(f.Filesystem()), 0, mntOpt); err != nil {
242-
return fmt.Errorf("failed to mount rootfs %s: %w", f.rootDir, err)
298+
return fmt.Errorf("failed to mount rootfs %s (%s): %w", f.rootDir, mntOpt, err)
243299
}
244300
return nil
245301
}

0 commit comments

Comments
 (0)