Files
wenlxieandGleb Chesnokov 1429b611ce tests: Exercise a forking scst_user handler over scst_local
Extend the scst_user fault hook with a fork action: once armed, the
handler fork()s before its next scst_user ioctl, and the child only
sleeps, as a crash reporter, system() or popen() would. The new spec
reads LBA 0 first, so the handler's cached buffer holds known data,
then makes the handler fork. Afterwards READ CAPACITY(10) and (16),
reads and writes must return the right geometry and data.

The hook logs its success line only after the fault was applied, and
logs a failed fork() with its errno. The specs fail on that line and
require each fault's success line, so a failed fork() cannot pass as a
handler that forked.

Before Linux 5.9, the same boundary as dev_user_map_buf(), scst_user
keeps get_user_pages() and a handler that forks must use MADV_DONTFORK,
which fileio_tgt does not. There the hook applies MADV_DONTFORK to every
active data buffer before it forks and logs how many it protected. It
tracks the buffers from the handler's ALLOC_MEM and EXEC replies, and
restores MADV_DOFORK before the handler frees one. The spec requires
that line below 5.9 and its absence from 5.9, and the same correct
geometry and data on every kernel. So 5.9 and later test the pin
alone, and older kernels test the documented MADV_DONTFORK requirement.

Without pinned buffers SCST keeps reading the pre-fork page, and the
next READ CAPACITY reports the stale data block as its block length.
2026-10-20 08:43:01 +03:00

33 lines
788 B
Go

// SPDX-License-Identifier: GPL-2.0-only
package testhost
import "testing"
func TestKernelAtLeast(t *testing.T) {
for _, tc := range []struct {
release string
want bool
}{
{"5.9", true},
{"5.9.0-fork59", true},
{"5.9.16", true},
{"5.10.264", true},
{"6.17.13-kunit", true},
{"10.0.1", true},
{"5.8.18", false},
{"5.4.0-200-generic", false},
{"4.18.0-553.el8_10.x86_64", false},
{"4.20.1", false},
} {
got, err := KernelAtLeast(tc.release, 5, 9)
if err != nil || got != tc.want {
t.Errorf("KernelAtLeast(%q, 5, 9) = %t, %v; want %t", tc.release, got, err, tc.want)
}
}
for _, release := range []string{"", "5", "abc", "v5.9"} {
if _, err := KernelAtLeast(release, 5, 9); err == nil {
t.Errorf("accepted kernel release %q", release)
}
}
}