diff mbox series

[RFC,xfstests] generic: add fcntl corner cases tests

Message ID 20230809210228.2068122-1-aahringo@redhat.com (mailing list archive)
State New, archived
Headers show
Series [RFC,xfstests] generic: add fcntl corner cases tests | expand

Commit Message

Alexander Aring Aug. 9, 2023, 9:02 p.m. UTC
This patch adds generic 730 testcase. It will test on various fcntl()
corner cases that was making problems on a GFS2 filesystem. GFS2 has
it's own lock() implementation that has it's own posix lock
implementation behind it. There are testcases to find issues with struct
file_lock matches. Currently the Linux kernel does not have a unique
identifier per lock request to e.g. find the original lock request when
a complete handler of an async lock request comes back. The current way
is to use struct file_lock fields to fine the original lock request.
However there was issues being found that in some cases it wasn't an
unique match because multiple pending struct file_lock could have the
same state. To find issues the testcases fcntl_lock_equal_file_lock and
fcntl_lock_same_owner are introduced and their OFD variants.

Other test like fcntl_lock_kill_child tests cleanup routines when a
process blocking in F_SETLKW to wait the lock request getting granted
and the process gets killed.

A similar test is fcntl_lock_signal_interrupt which checks for
side-effects e.g. unlock all previous acquired locks when a blocking
F_SETLKW gets interrupted by a signal.

Signed-off-by: Alexander Aring <aahringo@redhat.com>
---
 src/Makefile                         |   5 +-
 src/fcntl_lock_equal_file_lock.c     | 140 +++++++++++++++++++++++
 src/fcntl_lock_equal_file_lock_ofd.c | 144 ++++++++++++++++++++++++
 src/fcntl_lock_kill_child.c          | 148 +++++++++++++++++++++++++
 src/fcntl_lock_same_owner.c          | 146 ++++++++++++++++++++++++
 src/fcntl_lock_same_owner_ofd.c      | 144 ++++++++++++++++++++++++
 src/fcntl_lock_signal_interrupt.c    | 159 +++++++++++++++++++++++++++
 tests/generic/730                    |  70 ++++++++++++
 tests/generic/730.out                |   2 +
 9 files changed, 957 insertions(+), 1 deletion(-)
 create mode 100644 src/fcntl_lock_equal_file_lock.c
 create mode 100644 src/fcntl_lock_equal_file_lock_ofd.c
 create mode 100644 src/fcntl_lock_kill_child.c
 create mode 100644 src/fcntl_lock_same_owner.c
 create mode 100644 src/fcntl_lock_same_owner_ofd.c
 create mode 100644 src/fcntl_lock_signal_interrupt.c
 create mode 100755 tests/generic/730
 create mode 100644 tests/generic/730.out
diff mbox series

Patch

diff --git a/src/Makefile b/src/Makefile
index 24cd4747..e633f748 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -19,7 +19,10 @@  TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
 	t_ofd_locks t_mmap_collision mmap-write-concurrent \
 	t_get_file_time t_create_short_dirs t_create_long_dirs t_enospc \
 	t_mmap_writev_overlap checkpoint_journal mmap-rw-fault allocstale \
-	t_mmap_cow_memory_failure fake-dump-rootino dio-buf-fault
+	t_mmap_cow_memory_failure fake-dump-rootino dio-buf-fault \
+	fcntl_lock_equal_file_lock fcntl_lock_equal_file_lock_ofd \
+	fcntl_lock_kill_child fcntl_lock_same_owner fcntl_lock_same_owner_ofd \
+	fcntl_lock_signal_interrupt
 
 LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
 	preallo_rw_pattern_writer ftrunc trunc fs_perms testx looptest \
diff --git a/src/fcntl_lock_equal_file_lock.c b/src/fcntl_lock_equal_file_lock.c
new file mode 100644
index 00000000..38b111c5
--- /dev/null
+++ b/src/fcntl_lock_equal_file_lock.c
@@ -0,0 +1,140 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This program tests fcntl() operations that have two
+ * of struct file_lock in the kernel in waiting state. Those
+ * two struct file_lock have exact the identitcal fields. Currently
+ * the Linux kernel matches lock requests by file_lock fields and not
+ * by an unique identifiers. There is a verifier to check if the
+ * posix locks got unlocked.
+ */
+
+#include <sys/wait.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+static const char *filename;
+static int fd;
+
+static void *do_equal_file_lock_thread0(void *arg)
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	int rv;
+
+	rv = fcntl(fd, F_SETLKW, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	return NULL;
+}
+
+static void *do_equal_file_lock_thread1(void *arg)
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	int rv;
+
+	rv = fcntl(fd, F_SETLKW, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	return NULL;
+}
+
+static void do_setup()
+{
+	fd = open(filename, O_RDWR | O_CREAT, 0700);
+	if (fd == -1)
+		_exit(1);
+}
+
+static void do_teardown()
+{
+	close(fd);
+}
+
+static void do_equal_file_lock()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	pthread_t t[2];
+	int pid, rv;
+
+	rv = fcntl(fd, F_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	pid = fork();
+	if (pid == 0) {
+		rv = pthread_create(&t[0], NULL, do_equal_file_lock_thread0, NULL);
+		if (rv != 0)
+			_exit(1);
+
+		rv = pthread_create(&t[1], NULL, do_equal_file_lock_thread1, NULL);
+		if (rv != 0)
+			_exit(1);
+
+		pthread_join(t[0], NULL);
+		pthread_join(t[1], NULL);
+
+		_exit(0);
+	}
+
+	/* wait threads should block */
+	sleep(3);
+
+	fl.l_type = F_UNLCK;
+	fl.l_start = 0;
+	fl.l_len = 1;
+	rv = fcntl(fd, F_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	sleep(3);
+
+	/* check if the lock() implementation got the
+	 * right locks because two waiter with the
+	 * same file_lock fields are waiting.
+	 */
+	fl.l_type = F_WRLCK;
+	rv = fcntl(fd, F_SETLK, &fl);
+	if (rv == -1 && errno == EAGAIN)
+		_exit(1);
+
+	wait(NULL);
+}
+
+static void usage(const char *argv0)
+{
+	fprintf(stderr, "Usage: %s {filename}\n", argv0);
+	_exit(1);
+}
+
+int main(int argc, const char *argv[])
+{
+	if (argc != 2)
+		usage(argv[0]);
+
+	filename = argv[1];
+
+	do_setup();
+	do_equal_file_lock();
+	do_teardown();
+
+	return 0;
+}
diff --git a/src/fcntl_lock_equal_file_lock_ofd.c b/src/fcntl_lock_equal_file_lock_ofd.c
new file mode 100644
index 00000000..a9f6b06b
--- /dev/null
+++ b/src/fcntl_lock_equal_file_lock_ofd.c
@@ -0,0 +1,144 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This program tests fcntl() operations that have two
+ * of struct file_lock in the kernel in waiting state. Those
+ * two struct file_lock have exact the identitcal fields. Currently
+ * the Linux kernel matches lock requests by file_lock fields and not
+ * by an unique identifiers. This does the same test as
+ * fcntl_lock_equal_file_lock does just with OFD posix locks.
+ * There is a verifier to check if the right posix locks got unlocked.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+
+static const char *filename;
+static int fd[2];
+
+static void do_setup()
+{
+	fd[0] = open(filename, O_RDWR | O_CREAT, 0700);
+	if (fd[0] == -1)
+		goto error;
+
+	fd[1] = open(filename, O_RDWR, 0700);
+	if (fd[1] == -1)
+		goto fd0;
+
+	return;
+
+fd0:
+	close(fd[0]);
+error:
+	_exit(1);
+}
+
+static void do_teardown()
+{
+	close(fd[0]);
+	close(fd[1]);
+}
+
+static void do_equal_file_lock_ofd_child0()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	int rv;
+
+	rv = fcntl(fd[1], F_OFD_SETLKW, &fl);
+	if (rv == -1)
+		_exit(1);
+}
+
+static void do_equal_file_lock_ofd_child1()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	int rv;
+
+	rv = fcntl(fd[1], F_OFD_SETLKW, &fl);
+	if (rv == -1)
+		_exit(1);
+}
+
+static void do_equal_file_lock_ofd()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	int pid, rv;
+
+	rv = fcntl(fd[0], F_OFD_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	pid = fork();
+	if (pid == 0) {
+		do_equal_file_lock_ofd_child0();
+		_exit(0);
+	}
+
+	pid = fork();
+	if (pid == 0) {
+		do_equal_file_lock_ofd_child1();
+		_exit(0);
+	}
+
+	/* wait childs should block */
+	sleep(3);
+
+	fl.l_type = F_UNLCK;
+	fl.l_start = 0;
+	fl.l_len = 1;
+	rv = fcntl(fd[0], F_OFD_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	sleep(3);
+
+	/* check if the lock() implementation got the
+	 * right locks because two waiter with the
+	 * same file_lock fields were waiting.
+	 */
+	fl.l_type = F_WRLCK;
+	rv = fcntl(fd[0], F_OFD_SETLK, &fl);
+	if (!(rv == -1 && errno == EAGAIN))
+		_exit(1);
+
+	wait(NULL);
+}
+
+static void usage(const char *argv0)
+{
+	fprintf(stderr, "Usage: %s {filename}\n", argv0);
+	_exit(1);
+}
+
+int main(int argc, const char *argv[])
+{
+	if (argc != 2)
+		usage(argv[0]);
+
+	filename = argv[1];
+
+	do_setup();
+	do_equal_file_lock_ofd();
+	do_teardown();
+
+	return 0;
+}
diff --git a/src/fcntl_lock_kill_child.c b/src/fcntl_lock_kill_child.c
new file mode 100644
index 00000000..60a992bb
--- /dev/null
+++ b/src/fcntl_lock_kill_child.c
@@ -0,0 +1,148 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This program tests fcntl() operations that have two
+ * fcntl() calls in waiting state in two different childs but the
+ * fl_owner value is the same because using OFD locks. One of the
+ * blocked childs get killed. There is a verifier at the end if
+ * the right posix lock got unlocked when killing the child.
+ *
+ */
+
+#include <sys/wait.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+
+static const char *filename;
+static int fd[2];
+
+static void do_setup()
+{
+	fd[0] = open(filename, O_RDWR | O_CREAT, 0700);
+	if (fd[0] == -1)
+		goto error;
+
+	fd[1] = open(filename, O_RDWR, 0700);
+	if (fd[1] == -1)
+		goto fd0;
+
+	return;
+
+fd0:
+	close(fd[0]);
+error:
+	_exit(1);
+}
+
+static void do_teardown()
+{
+	close(fd[0]);
+	close(fd[1]);
+}
+
+static void do_to_be_killed_child()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	int rv;
+
+	rv = fcntl(fd[1], F_OFD_SETLKW, &fl);
+	if (rv == -1)
+		_exit(1);
+}
+
+static void do_blocking_child()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 1L,
+		.l_len = 1L,
+	};
+	int rv;
+
+	rv = fcntl(fd[1], F_OFD_SETLKW, &fl);
+	if (rv == -1)
+		_exit(1);
+}
+
+static void do_kill_child_setlkw()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 2L,
+	};
+	int pid_to_kill, pid, rv;
+
+	rv = fcntl(fd[0], F_OFD_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	pid_to_kill = fork();
+	if (pid_to_kill == 0) {
+		do_to_be_killed_child();
+		_exit(0);
+	}
+
+	pid = fork();
+	if (pid == 0) {
+		do_blocking_child();
+		_exit(0);
+	}
+
+	/* wait childs should block */
+	sleep(3);
+
+	kill(pid_to_kill, SIGKILL);
+
+	/* wait until Linux did plock cleanup */
+
+	sleep(3);
+
+	/* check if the lock() implementation got the
+	 * right lock because two waiter with the
+	 * same fl_owner were waiting.
+	 */
+	fl.l_type = F_WRLCK;
+	rv = fcntl(fd[0], F_OFD_SETLK, &fl);
+	if ((rv == -1 && errno == EAGAIN))
+		_exit(1);
+
+	fl.l_type = F_UNLCK;
+	fl.l_start = 1;
+	fl.l_len = 1;
+	rv = fcntl(fd[0], F_OFD_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	wait(NULL);
+}
+
+static void usage(const char *argv0)
+{
+	fprintf(stderr, "Usage: %s {filename}\n", argv0);
+	_exit(1);
+}
+
+int main(int argc, const char *argv[])
+{
+	if (argc != 2)
+		usage(argv[0]);
+
+	filename = argv[1];
+
+	do_setup();
+	do_kill_child_setlkw();
+	do_teardown();
+
+	return 0;
+}
diff --git a/src/fcntl_lock_same_owner.c b/src/fcntl_lock_same_owner.c
new file mode 100644
index 00000000..071a3b49
--- /dev/null
+++ b/src/fcntl_lock_same_owner.c
@@ -0,0 +1,146 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This program tests fcntl() operations that have two
+ * fcntl() calls in waiting state in two different threads.
+ * Those fcntl() ends in a struct file_lock have the same fl_owner
+ * field. One fcntl() call gets granted, there will be a verifier
+ * going on if the right lock was granted.
+ */
+
+#include <sys/wait.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+
+static const char *filename;
+static int fd;
+
+static void *do_same_owner_thread0(void *arg)
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	int rv;
+
+	rv = fcntl(fd, F_SETLKW, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	return NULL;
+}
+
+static void *do_same_owner_thread1(void *arg)
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 1L,
+		.l_len = 1L,
+	};
+	int rv;
+
+	rv = fcntl(fd, F_SETLKW, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	return NULL;
+}
+
+static void do_setup()
+{
+	fd = open(filename, O_RDWR | O_CREAT, 0700);
+	if (fd == -1)
+		_exit(1);
+}
+
+static void do_teardown()
+{
+	close(fd);
+}
+
+static void do_same_owner()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 2L,
+	};
+	pthread_t t[2];
+	int pid, rv;
+
+	rv = fcntl(fd, F_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	pid = fork();
+	if (pid == 0) {
+		rv = pthread_create(&t[0], NULL, do_same_owner_thread0, NULL);
+		if (rv != 0)
+			_exit(1);
+
+		rv = pthread_create(&t[1], NULL, do_same_owner_thread1, NULL);
+		if (rv != 0)
+			_exit(1);
+
+		pthread_join(t[0], NULL);
+		pthread_join(t[1], NULL);
+
+		_exit(0);
+	}
+
+	/* wait threads should block */
+	sleep(3);
+
+	fl.l_type = F_UNLCK;
+	fl.l_start = 1;
+	fl.l_len = 1;
+	rv = fcntl(fd, F_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	sleep(3);
+
+	/* check if the lock() implementation got the
+	 * right lock because two waiter with the
+	 * same fl_owner were waiting.
+	 */
+	fl.l_type = F_WRLCK;
+	rv = fcntl(fd, F_SETLK, &fl);
+	if (!(rv == -1 && errno == EAGAIN))
+		_exit(1);
+
+	fl.l_type = F_UNLCK;
+	fl.l_start = 1;
+	fl.l_len = 1;
+	rv = fcntl(fd, F_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	wait(NULL);
+}
+
+static void usage(const char *argv0)
+{
+	fprintf(stderr, "Usage: %s {filename}\n", argv0);
+	_exit(1);
+}
+
+int main(int argc, const char *argv[])
+{
+	if (argc != 2)
+		usage(argv[0]);
+
+	filename = argv[1];
+
+	do_setup();
+	do_same_owner();
+	do_teardown();
+
+	return 0;
+}
diff --git a/src/fcntl_lock_same_owner_ofd.c b/src/fcntl_lock_same_owner_ofd.c
new file mode 100644
index 00000000..d5addfb5
--- /dev/null
+++ b/src/fcntl_lock_same_owner_ofd.c
@@ -0,0 +1,144 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This program tests fcntl() operations that have two
+ * fcntl() calls in waiting state in two different threads.
+ * Those fcntl() ends in a struct file_lock have the same fl_owner
+ * field. One fcntl() call gets granted, there will be a verifier
+ * going on if the right lock was granted.
+ *
+ * This test is the same like fcntl_lock_same_owner but using OFD
+ * locks.
+ */
+
+#include <sys/wait.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+
+static const char *filename;
+static int fd[2];
+
+static void do_setup()
+{
+	fd[0] = open(filename, O_RDWR | O_CREAT, 0700);
+	if (fd[0] == -1)
+		goto error;
+
+	fd[1] = open(filename, O_RDWR, 0700);
+	if (fd[1] == -1)
+		goto fd0;
+
+	return;
+
+fd0:
+	close(fd[0]);
+error:
+	_exit(1);
+}
+
+static void do_teardown()
+{
+	close(fd[0]);
+	close(fd[1]);
+}
+
+static void do_same_owner_ofd_child0()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	int rv;
+
+	rv = fcntl(fd[1], F_OFD_SETLKW, &fl);
+	if (rv == -1)
+		_exit(1);
+}
+
+static void do_same_owner_ofd_child1()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 1L,
+		.l_len = 1L,
+	};
+	int rv;
+
+	rv = fcntl(fd[1], F_OFD_SETLKW, &fl);
+	if (rv == -1)
+		_exit(1);
+}
+
+static void do_same_owner_ofd()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 2L,
+	};
+	int pid, rv;
+
+	rv = fcntl(fd[0], F_OFD_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	pid = fork();
+	if (pid == 0) {
+		do_same_owner_ofd_child0();
+		_exit(0);
+	}
+
+	pid = fork();
+	if (pid == 0) {
+		do_same_owner_ofd_child1();
+		_exit(0);
+	}
+
+	/* wait childs should block */
+	sleep(3);
+
+	fl.l_type = F_UNLCK;
+	fl.l_start = 1;
+	fl.l_len = 1;
+	rv = fcntl(fd[0], F_OFD_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	sleep(3);
+
+	/* check if the lock() implementation granted
+	 * the locks.
+	 */
+	fl.l_type = F_WRLCK;
+	rv = fcntl(fd[0], F_OFD_SETLK, &fl);
+	if (rv == -1 && errno == EAGAIN)
+		_exit(1);
+
+	wait(NULL);
+}
+
+static void usage(const char *argv0)
+{
+	fprintf(stderr, "Usage: %s {filename}\n", argv0);
+	_exit(1);
+}
+
+int main(int argc, const char *argv[])
+{
+	if (argc != 2)
+		usage(argv[0]);
+
+	filename = argv[1];
+
+	do_setup();
+	do_same_owner_ofd();
+	do_teardown();
+
+	return 0;
+}
diff --git a/src/fcntl_lock_signal_interrupt.c b/src/fcntl_lock_signal_interrupt.c
new file mode 100644
index 00000000..af3008f1
--- /dev/null
+++ b/src/fcntl_lock_signal_interrupt.c
@@ -0,0 +1,159 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * This program tests fcntl() operations in the child process
+ * that have one lock acquired and sitting in a blocked fcntl()
+ * F_SETLKW call to get granted. The blocked fcntl() call will be
+ * interrupted by a signal that will cancel the blocked fcntl() call.
+ * Afterwards there is a verifier that the previous lock which wasn't
+ * cancelled is still acquired by the child.
+ */
+
+#include <sys/wait.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+
+struct pipe_msg {
+	int rv;
+};
+
+static const char *filename;
+static int pfd[2];
+static int fd;
+
+static void do_setup()
+{
+	int rv;
+
+	rv = pipe(pfd);
+	if (rv == -1)
+		goto error;
+
+	fd = open(filename, O_RDWR | O_CREAT, 0700);
+	if (fd == -1)
+		goto pipe;
+
+	return;
+
+pipe:
+	close(pfd[0]);
+	close(pfd[1]);
+
+error:
+	_exit(1);
+}
+
+static void do_teardown()
+{
+	close(fd);
+
+	close(pfd[0]);
+	close(pfd[1]);
+}
+
+static void catch_alarm(int num) { }
+
+static void do_signal_interrupt_setlkw_child(void)
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 1L,
+		.l_len = 1L,
+	};
+	struct sigaction act;
+	struct pipe_msg msg;
+	int rv;
+
+	rv = fcntl(fd, F_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	memset(&act, 0, sizeof(act));
+	act.sa_handler = catch_alarm;
+	sigemptyset(&act.sa_mask);
+	sigaddset(&act.sa_mask, SIGALRM);
+	sigaction(SIGALRM, &act, NULL);
+
+	fl.l_start = 0;
+
+	/* interrupt SETLKW by signal in 3 secs */
+	alarm(3);
+	rv = fcntl(fd, F_SETLKW, &fl);
+	if (rv == -1 && errno == EINTR)
+		msg.rv = 0;
+	else
+		msg.rv = 1;
+
+	write(pfd[1], &msg, sizeof(msg));
+
+	/* keep child alive */
+	read(pfd[1], &msg, sizeof(msg));
+}
+
+static void do_signal_interrupt_setlkw()
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	struct pipe_msg msg;
+	int pid, rv;
+
+	rv = fcntl(fd, F_SETLK, &fl);
+	if (rv == -1)
+		_exit(1);
+
+	pid = fork();
+	if (pid == 0) {
+		do_signal_interrupt_setlkw_child();
+		_exit(0);
+	}
+
+	/* wait until child writes */
+	read(pfd[0], &msg, sizeof(msg));
+
+	fl.l_type = F_WRLCK;
+	fl.l_start = 1;
+	fl.l_len = 1;
+	rv = fcntl(fd, F_SETLK, &fl);
+	/* parent testing childs region, the child will think
+	 * it has region 1-1 locked because it was interrupted
+	 * by region 0-0. Due bugs the interruption also unlocked
+	 * region 1-1.
+	 */
+	if (rv == -1 && errno == EAGAIN)
+		rv = 0;
+	else
+		rv = 1;
+
+	write(pfd[0], &msg, sizeof(msg));
+
+	wait(NULL);
+	_exit(rv);
+}
+
+static void usage(const char *argv0)
+{
+	fprintf(stderr, "Usage: %s {filename}\n", argv0);
+	_exit(1);
+}
+
+int main(int argc, const char *argv[])
+{
+	if (argc != 2)
+		usage(argv[0]);
+
+	filename = argv[1];
+
+	do_setup();
+	do_signal_interrupt_setlkw();
+	do_teardown();
+
+	return 0;
+}
diff --git a/tests/generic/730 b/tests/generic/730
new file mode 100755
index 00000000..4a1e7f20
--- /dev/null
+++ b/tests/generic/730
@@ -0,0 +1,70 @@ 
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2023 Alexander Aring.  All Rights Reserved.
+#
+# FS QA Test 730
+#
+# This tests performs some fcntl() corner cases when
+# two waiter have the same or some (fl_owner) fields. In Linux
+# there exists no unique lock request identifier, some lock()
+# filesystem implementation does that over struct file_lock fields.
+# Other tests check for bad side-effects if a blocking F_SETLKW lock
+# request got interrupted or the process got killed.
+#
+. ./common/preamble
+_begin_fstest auto quick
+
+# Import common functions.
+. ./common/filter
+
+# real QA test starts here
+
+_supported_fs generic
+_require_test
+_require_test_program fcntl_lock_equal_file_lock
+_require_test_program fcntl_lock_equal_file_lock_ofd
+_require_test_program fcntl_lock_kill_child
+_require_test_program fcntl_lock_same_owner
+_require_test_program fcntl_lock_same_owner_ofd
+_require_test_program fcntl_lock_signal_interrupt
+
+echo "Silence is golden"
+
+$here/src/fcntl_lock_equal_file_lock $TEST_DIR/testfile
+if [ $? -ne 0 ]
+then
+	exit
+fi
+
+$here/src/fcntl_lock_equal_file_lock_ofd $TEST_DIR/testfile
+if [ $? -ne 0 ]
+then
+	exit
+fi
+
+$here/src/fcntl_lock_kill_child $TEST_DIR/testfile
+if [ $? -ne 0 ]
+then
+	exit
+fi
+
+$here/src/fcntl_lock_same_owner $TEST_DIR/testfile
+if [ $? -ne 0 ]
+then
+	exit
+fi
+
+$here/src/fcntl_lock_same_owner_ofd $TEST_DIR/testfile
+if [ $? -ne 0 ]
+then
+	exit
+fi
+
+$here/src/fcntl_lock_signal_interrupt $TEST_DIR/testfile
+if [ $? -ne 0 ]
+then
+	exit
+fi
+
+status=0
+exit
diff --git a/tests/generic/730.out b/tests/generic/730.out
new file mode 100644
index 00000000..50c3c832
--- /dev/null
+++ b/tests/generic/730.out
@@ -0,0 +1,2 @@ 
+QA output created by 730
+Silence is golden