@@ -7227,6 +7227,7 @@ M: Denis Efremov <efremov@linux.com>
L: linux-block@vger.kernel.org
S: Odd Fixes
F: drivers/block/floppy.c
+F: tools/testing/selftests/floppy/
FLYSKY FSIA6B RC RECEIVER
M: Markus Koch <markus@notsyncing.net>
new file mode 100644
@@ -0,0 +1,5 @@
+init
+cpio_list
+initrd
+
+empty
new file mode 100644
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0
+CFLAGS := -static -I../../../../usr/include
+
+TEST_PROGS := run_empty.sh
+TEST_GEN_FILES := init empty
+TEST_FILES := lib.sh
+
+include ../lib.mk
+
+EXTRA_CLEAN := initrd cpio_list
new file mode 100644
@@ -0,0 +1 @@
+CONFIG_BLK_DEV_FD=y
new file mode 100644
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <fcntl.h>
+#include <unistd.h>
+#include "../kselftest_harness.h"
+
+FIXTURE(floppy) {
+ const char *dev;
+ int fd;
+};
+
+FIXTURE_VARIANT(floppy) {
+ int flags;
+};
+
+/*
+ * See ff06db1efb2a ("floppy: fix open(O_ACCMODE) for ioctl-only open")
+ * fdutils use O_ACCMODE for probing and ioctl-only open
+ */
+FIXTURE_VARIANT_ADD(floppy, ACCMODE) {
+ .flags = O_ACCMODE,
+};
+
+FIXTURE_VARIANT_ADD(floppy, NACCMODE) {
+ .flags = O_ACCMODE|O_NDELAY,
+};
+
+FIXTURE_VARIANT_ADD(floppy, NRD) {
+ .flags = O_RDONLY|O_NDELAY,
+};
+
+FIXTURE_VARIANT_ADD(floppy, NWR) {
+ .flags = O_WRONLY|O_NDELAY,
+};
+
+FIXTURE_VARIANT_ADD(floppy, NRDWR) {
+ .flags = O_RDWR|O_NDELAY,
+};
+
+FIXTURE_SETUP(floppy)
+{
+ self->dev = "/dev/fd0";
+ if (access(self->dev, F_OK))
+ ksft_exit_skip("No floppy device found\n");
+};
+
+FIXTURE_TEARDOWN(floppy)
+{
+ ASSERT_EQ(close(self->fd), 0);
+}
+
+TEST_F(floppy, open)
+{
+ self->fd = open(self->dev, variant->flags);
+ ASSERT_GT(self->fd, 0);
+}
+
+TEST_HARNESS_MAIN
new file mode 100644
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/reboot.h>
+
+__attribute__((noreturn)) static void poweroff(void)
+{
+ fflush(stdout);
+ fflush(stderr);
+ reboot(RB_POWER_OFF);
+ sleep(10);
+ fprintf(stderr, "\nFailed to power off\n");
+ exit(1);
+}
+
+static void panic(const char *what)
+{
+ fprintf(stderr, "\nPANIC %s: %s\n", what, strerror(errno));
+ poweroff();
+}
+
+int main(int argc, char *argv[])
+{
+ pid_t pid;
+
+ pid = fork();
+ if (pid == -1)
+ panic("fork");
+ else if (pid == 0) {
+ execl("/test", "test", NULL);
+ panic("exec");
+ }
+ if (waitpid(pid, NULL, 0) < 0)
+ panic("waitpid");
+
+ poweroff();
+ return 1;
+}
new file mode 100644
@@ -0,0 +1,57 @@
+# SPDX-License-Identifier: GPL-2.0
+
+TOP_DIR="$(realpath "$(dirname "$0")"/../../../../)"
+
+QEMU=qemu-system-x86_64
+KERNEL="$TOP_DIR"/arch/x86/boot/bzImage
+INITRD=initrd
+
+gen_cpio_list() {
+ echo "file /init init 755 0 0" > cpio_list
+ echo "file /test $1 755 0 0" >> cpio_list
+ echo "dir /dev 755 0 0" >> cpio_list
+ echo "nod /dev/console 644 0 0 c 5 1" >> cpio_list
+ echo "nod /dev/fd0 666 0 0 b 2 0" >> cpio_list
+ echo "dir /mnt 755 0 0" >> cpio_list
+}
+
+gen_initrd() {
+ "$TOP_DIR"/usr/gen_initramfs.sh -o initrd ./cpio_list
+}
+
+get_selftest_log() {
+ perl -ne '$begin = $_ =~ /^TAP version/ unless $begin;
+ if ($begin && !$end) {
+ $_ =~ s/^\s+|\s+$|\[.+//g;
+ print($_ . "\n") if $_;
+ }
+ $end = $_ =~ /^# Totals:/ unless $end;'
+}
+
+run_qemu() {
+ $QEMU -enable-kvm -nodefaults -nographic \
+ -kernel "$KERNEL" -initrd "$INITRD" \
+ -append "console=ttyS0 earlyprintk=serial" \
+ -serial stdio -monitor none -no-reboot "$@"
+}
+
+run_qemu_debug() {
+ run_qemu "$@"
+}
+
+run_qemu_nodebug() {
+ run_qemu "$@" | get_selftest_log
+}
+
+detect_debug() {
+ if [ "x$1" = "x" ]; then
+ run=run_qemu_nodebug
+ else
+ run=run_qemu_debug
+ fi
+}
+
+run_qemu_empty() {
+ detect_debug "$1"
+ $run -drive index=0,if=floppy
+}
new file mode 100755
@@ -0,0 +1,16 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+
+set -e
+
+source "$(dirname $0)"/lib.sh
+
+while getopts d flag; do
+ case "${flag}" in
+ d) debug=1;;
+ esac
+done
+
+gen_cpio_list empty
+gen_initrd empty
+run_qemu_empty $debug
Add basic tests for O_NDELAY and O_ACCMODE open of an empty floppy device. "empty" test works under assumption that there is no disk in "/dev/fd0". It's possible to run it on a real hardware. "run_empty.sh" automates the testing process by creating a minimal initrd image with "init" and "test" binaries and running the kernel in QEMU. The tests cover these regressions: - commit f2791e7eadf4 ("Revert "floppy: refactor open() flags handling"") - commit ff06db1efb2a ("floppy: fix open(O_ACCMODE) for ioctl-only open") Signed-off-by: Denis Efremov <efremov@linux.com> --- MAINTAINERS | 1 + tools/testing/selftests/floppy/.gitignore | 5 ++ tools/testing/selftests/floppy/Makefile | 10 ++++ tools/testing/selftests/floppy/config | 1 + tools/testing/selftests/floppy/empty.c | 58 +++++++++++++++++++++ tools/testing/selftests/floppy/init.c | 43 +++++++++++++++ tools/testing/selftests/floppy/lib.sh | 57 ++++++++++++++++++++ tools/testing/selftests/floppy/run_empty.sh | 16 ++++++ 8 files changed, 191 insertions(+) create mode 100644 tools/testing/selftests/floppy/.gitignore create mode 100644 tools/testing/selftests/floppy/Makefile create mode 100644 tools/testing/selftests/floppy/config create mode 100644 tools/testing/selftests/floppy/empty.c create mode 100644 tools/testing/selftests/floppy/init.c create mode 100644 tools/testing/selftests/floppy/lib.sh create mode 100755 tools/testing/selftests/floppy/run_empty.sh