All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] generic: Add a test for basic F_SETLEASE functionality
@ 2019-08-27 12:35 Jeff Layton
  2019-08-27 20:28 ` J. Bruce Fields
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Jeff Layton @ 2019-08-27 12:35 UTC (permalink / raw)
  To: fstests; +Cc: amir73il, bfields

Add a new test that verifies that F_SETLEASE works as expected. The
parent opens a file and sets a lease on it and then forks. The child
then does a (possibly) conflicting open. We then verify that we get
signals as expected.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 src/Makefile          |   2 +-
 src/t_setlease.c      | 157 ++++++++++++++++++++++++++++++++++++++++++
 tests/generic/566     |  54 +++++++++++++++
 tests/generic/566.out |   1 +
 tests/generic/group   |   1 +
 5 files changed, 214 insertions(+), 1 deletion(-)
 create mode 100644 src/t_setlease.c
 create mode 100755 tests/generic/566
 create mode 100644 tests/generic/566.out

diff --git a/src/Makefile b/src/Makefile
index c4fcf370431f..11190afa3603 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -28,7 +28,7 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
 	attr-list-by-handle-cursor-test listxattr dio-interleaved t_dir_type \
 	dio-invalidate-cache stat_test t_encrypted_d_revalidate \
 	attr_replace_test swapon mkswap t_attr_corruption t_open_tmpfiles \
-	fscrypt-crypt-util bulkstat_null_ocount
+	fscrypt-crypt-util bulkstat_null_ocount t_setlease
 
 SUBDIRS = log-writes perf
 
diff --git a/src/t_setlease.c b/src/t_setlease.c
new file mode 100644
index 000000000000..81d46b6a6cd4
--- /dev/null
+++ b/src/t_setlease.c
@@ -0,0 +1,157 @@
+/*
+ * t_setlease.c: test basic F_SETLEASE functionality
+ *
+ * Open file, set lease on it. Then fork off children that open the file with
+ * different openflags. Ensure we get signals as expected.
+ *
+ * Copyright (c) 2019: Jeff Layton <jlayton@redhat.com>
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static volatile bool signalled;
+
+struct leasetest {
+	int	openflags;
+	int	leasetype;
+	int	conf_openflags;
+	bool	expect_signal;
+};
+
+static struct leasetest testcase[] = {
+	{ O_RDONLY, F_RDLCK, O_RDONLY, false },
+	{ O_RDONLY, F_RDLCK, O_WRONLY, true },
+	{ O_WRONLY, F_WRLCK, O_RDONLY, true },
+	{ O_WRONLY, F_WRLCK, O_WRONLY, true },
+};
+
+static void usage()
+{
+	printf("Usage: t_setlease <filename>\n");
+}
+
+static void lease_break(int signum)
+{
+	if (signum == SIGIO)
+		signalled = true;
+}
+
+/* Open/create a file, set up signal handler and set lease on file. */
+static int setlease(const char *fname, int openflags, int leasetype)
+{
+	int fd, ret;
+
+	fd = open(fname, openflags | O_CREAT, 0644);
+	if (fd < 0) {
+		perror("open");
+		return -errno;
+	}
+
+	ret = fcntl(fd, F_SETLEASE, leasetype);
+	if (ret) {
+		perror("setlease");
+		return -errno;
+	}
+	return fd;
+}
+
+static int open_conflict(const char *fname, int openflags)
+{
+	int fd;
+
+	fd = open(fname, openflags);
+	if (fd < 0) {
+		perror("open");
+		return -errno;
+	}
+	close(fd);
+	return 0;
+}
+
+static int simple_lease_break(const char *fname, struct leasetest *test)
+{
+	int fd, ret, status;
+	pid_t pid, exited;
+
+	signalled = false;
+	fd = setlease(fname, test->openflags, test->leasetype);
+	if (fd < 0)
+		return fd;
+
+	pid = fork();
+	if (pid < 0) {
+		return -errno;
+	} else if (pid == 0) {
+		/* child */
+		close(fd);
+		int ret = open_conflict(fname, test->conf_openflags);
+		exit(ret ? 1 : 0);
+	}
+
+	/* parent */
+	while (!signalled) {
+		/* Break out if child exited */
+		exited = waitpid(pid, &status, WNOHANG);
+		if (exited)
+			break;
+		usleep(1000);
+	}
+
+	fcntl(fd, F_SETLEASE, F_UNLCK);
+	close(fd);
+
+	/* If it didn't already exit, then wait now */
+	if (!exited)
+		waitpid(pid, &status, 0);
+
+	if (!WIFEXITED(status)) {
+		ret = 1;
+	} else {
+		ret = WEXITSTATUS(status);
+		if (test->expect_signal != signalled)
+			ret = 1;
+	}
+
+	return ret;
+}
+
+int main(int argc, char **argv)
+{
+	int ret, i;
+	char *fname;
+	struct sigaction sa = { .sa_handler = lease_break };
+
+	if (argc < 2) {
+		usage();
+		return 1;
+	}
+
+	fname = argv[1];
+
+	ret = sigaction(SIGIO, &sa, NULL);
+	if (ret) {
+		perror("sigaction");
+		return -1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(testcase); ++i) {
+		struct leasetest *t = &testcase[i];
+
+		ret = simple_lease_break(fname, t);
+		if (ret) {
+			fprintf(stderr, "Test failure: openflags=%d leasetype=%d conf_openflags=%d expect_signal=%d\n", t->openflags, t->leasetype, t->conf_openflags, t->expect_signal);
+			exit(1);
+		}
+	}
+	return 0;
+}
diff --git a/tests/generic/566 b/tests/generic/566
new file mode 100755
index 000000000000..abf4f6dd743a
--- /dev/null
+++ b/tests/generic/566
@@ -0,0 +1,54 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2019 YOUR NAME HERE.  All Rights Reserved.
+#
+# FS QA Test 566
+#
+# Test basic F_SETLEASE functionality. Call the t_setlease program which
+# opens a file and sets a lease on it, and then forks a child to open the
+# same file with various openflags and verify that we get signals as expected.
+#
+# Note that kernels that lack 387e3746d01c (locks: eliminate false positive
+# conflicts for write lease) will fail this test as tasks that have the file
+# open for write are unable to get a F_WRLCK lease.
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+# Modify as appropriate.
+_supported_fs generic
+_supported_os Linux
+_require_test
+
+# if error
+testfile=$TEST_DIR/t_setlease-testfile
+$here/src/t_setlease $testfile
+
+# optional stuff if your test has verbose output to help resolve problems
+#echo
+#echo "If failure, check $seqres.full (this) and $seqres.full.ok (reference)"
+
+# success, all done
+status=0
+exit
diff --git a/tests/generic/566.out b/tests/generic/566.out
new file mode 100644
index 000000000000..9cd099b9d317
--- /dev/null
+++ b/tests/generic/566.out
@@ -0,0 +1 @@
+QA output created by 566
diff --git a/tests/generic/group b/tests/generic/group
index 2e4a6f79276b..57f85f619f3b 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -568,3 +568,4 @@
 563 auto quick
 564 auto quick copy_range
 565 auto quick copy_range
+566 auto quick locks
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH] generic: Add a test for basic F_SETLEASE functionality
  2019-08-27 12:35 [PATCH] generic: Add a test for basic F_SETLEASE functionality Jeff Layton
@ 2019-08-27 20:28 ` J. Bruce Fields
  2019-08-31 17:18 ` Eryu Guan
  2019-09-04 12:48 ` [PATCH v2] " Jeff Layton
  2 siblings, 0 replies; 6+ messages in thread
From: J. Bruce Fields @ 2019-08-27 20:28 UTC (permalink / raw)
  To: Jeff Layton; +Cc: fstests, amir73il

On Tue, Aug 27, 2019 at 08:35:37AM -0400, Jeff Layton wrote:
> Add a new test that verifies that F_SETLEASE works as expected. The
> parent opens a file and sets a lease on it and then forks. The child
> then does a (possibly) conflicting open. We then verify that we get
> signals as expected.

I've been using tests of my own for this.  Looks like your tests cover
the same cases as mine with less code.  So, looks good to me, thanks!

--b.

> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  src/Makefile          |   2 +-
>  src/t_setlease.c      | 157 ++++++++++++++++++++++++++++++++++++++++++
>  tests/generic/566     |  54 +++++++++++++++
>  tests/generic/566.out |   1 +
>  tests/generic/group   |   1 +
>  5 files changed, 214 insertions(+), 1 deletion(-)
>  create mode 100644 src/t_setlease.c
>  create mode 100755 tests/generic/566
>  create mode 100644 tests/generic/566.out
> 
> diff --git a/src/Makefile b/src/Makefile
> index c4fcf370431f..11190afa3603 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -28,7 +28,7 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
>  	attr-list-by-handle-cursor-test listxattr dio-interleaved t_dir_type \
>  	dio-invalidate-cache stat_test t_encrypted_d_revalidate \
>  	attr_replace_test swapon mkswap t_attr_corruption t_open_tmpfiles \
> -	fscrypt-crypt-util bulkstat_null_ocount
> +	fscrypt-crypt-util bulkstat_null_ocount t_setlease
>  
>  SUBDIRS = log-writes perf
>  
> diff --git a/src/t_setlease.c b/src/t_setlease.c
> new file mode 100644
> index 000000000000..81d46b6a6cd4
> --- /dev/null
> +++ b/src/t_setlease.c
> @@ -0,0 +1,157 @@
> +/*
> + * t_setlease.c: test basic F_SETLEASE functionality
> + *
> + * Open file, set lease on it. Then fork off children that open the file with
> + * different openflags. Ensure we get signals as expected.
> + *
> + * Copyright (c) 2019: Jeff Layton <jlayton@redhat.com>
> + */
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <signal.h>
> +#include <sys/wait.h>
> +
> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
> +
> +static volatile bool signalled;
> +
> +struct leasetest {
> +	int	openflags;
> +	int	leasetype;
> +	int	conf_openflags;
> +	bool	expect_signal;
> +};
> +
> +static struct leasetest testcase[] = {
> +	{ O_RDONLY, F_RDLCK, O_RDONLY, false },
> +	{ O_RDONLY, F_RDLCK, O_WRONLY, true },
> +	{ O_WRONLY, F_WRLCK, O_RDONLY, true },
> +	{ O_WRONLY, F_WRLCK, O_WRONLY, true },
> +};
> +
> +static void usage()
> +{
> +	printf("Usage: t_setlease <filename>\n");
> +}
> +
> +static void lease_break(int signum)
> +{
> +	if (signum == SIGIO)
> +		signalled = true;
> +}
> +
> +/* Open/create a file, set up signal handler and set lease on file. */
> +static int setlease(const char *fname, int openflags, int leasetype)
> +{
> +	int fd, ret;
> +
> +	fd = open(fname, openflags | O_CREAT, 0644);
> +	if (fd < 0) {
> +		perror("open");
> +		return -errno;
> +	}
> +
> +	ret = fcntl(fd, F_SETLEASE, leasetype);
> +	if (ret) {
> +		perror("setlease");
> +		return -errno;
> +	}
> +	return fd;
> +}
> +
> +static int open_conflict(const char *fname, int openflags)
> +{
> +	int fd;
> +
> +	fd = open(fname, openflags);
> +	if (fd < 0) {
> +		perror("open");
> +		return -errno;
> +	}
> +	close(fd);
> +	return 0;
> +}
> +
> +static int simple_lease_break(const char *fname, struct leasetest *test)
> +{
> +	int fd, ret, status;
> +	pid_t pid, exited;
> +
> +	signalled = false;
> +	fd = setlease(fname, test->openflags, test->leasetype);
> +	if (fd < 0)
> +		return fd;
> +
> +	pid = fork();
> +	if (pid < 0) {
> +		return -errno;
> +	} else if (pid == 0) {
> +		/* child */
> +		close(fd);
> +		int ret = open_conflict(fname, test->conf_openflags);
> +		exit(ret ? 1 : 0);
> +	}
> +
> +	/* parent */
> +	while (!signalled) {
> +		/* Break out if child exited */
> +		exited = waitpid(pid, &status, WNOHANG);
> +		if (exited)
> +			break;
> +		usleep(1000);
> +	}
> +
> +	fcntl(fd, F_SETLEASE, F_UNLCK);
> +	close(fd);
> +
> +	/* If it didn't already exit, then wait now */
> +	if (!exited)
> +		waitpid(pid, &status, 0);
> +
> +	if (!WIFEXITED(status)) {
> +		ret = 1;
> +	} else {
> +		ret = WEXITSTATUS(status);
> +		if (test->expect_signal != signalled)
> +			ret = 1;
> +	}
> +
> +	return ret;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int ret, i;
> +	char *fname;
> +	struct sigaction sa = { .sa_handler = lease_break };
> +
> +	if (argc < 2) {
> +		usage();
> +		return 1;
> +	}
> +
> +	fname = argv[1];
> +
> +	ret = sigaction(SIGIO, &sa, NULL);
> +	if (ret) {
> +		perror("sigaction");
> +		return -1;
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(testcase); ++i) {
> +		struct leasetest *t = &testcase[i];
> +
> +		ret = simple_lease_break(fname, t);
> +		if (ret) {
> +			fprintf(stderr, "Test failure: openflags=%d leasetype=%d conf_openflags=%d expect_signal=%d\n", t->openflags, t->leasetype, t->conf_openflags, t->expect_signal);
> +			exit(1);
> +		}
> +	}
> +	return 0;
> +}
> diff --git a/tests/generic/566 b/tests/generic/566
> new file mode 100755
> index 000000000000..abf4f6dd743a
> --- /dev/null
> +++ b/tests/generic/566
> @@ -0,0 +1,54 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2019 YOUR NAME HERE.  All Rights Reserved.
> +#
> +# FS QA Test 566
> +#
> +# Test basic F_SETLEASE functionality. Call the t_setlease program which
> +# opens a file and sets a lease on it, and then forks a child to open the
> +# same file with various openflags and verify that we get signals as expected.
> +#
> +# Note that kernels that lack 387e3746d01c (locks: eliminate false positive
> +# conflicts for write lease) will fail this test as tasks that have the file
> +# open for write are unable to get a F_WRLCK lease.
> +#
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +# Modify as appropriate.
> +_supported_fs generic
> +_supported_os Linux
> +_require_test
> +
> +# if error
> +testfile=$TEST_DIR/t_setlease-testfile
> +$here/src/t_setlease $testfile
> +
> +# optional stuff if your test has verbose output to help resolve problems
> +#echo
> +#echo "If failure, check $seqres.full (this) and $seqres.full.ok (reference)"
> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/generic/566.out b/tests/generic/566.out
> new file mode 100644
> index 000000000000..9cd099b9d317
> --- /dev/null
> +++ b/tests/generic/566.out
> @@ -0,0 +1 @@
> +QA output created by 566
> diff --git a/tests/generic/group b/tests/generic/group
> index 2e4a6f79276b..57f85f619f3b 100644
> --- a/tests/generic/group
> +++ b/tests/generic/group
> @@ -568,3 +568,4 @@
>  563 auto quick
>  564 auto quick copy_range
>  565 auto quick copy_range
> +566 auto quick locks
> -- 
> 2.21.0

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] generic: Add a test for basic F_SETLEASE functionality
  2019-08-27 12:35 [PATCH] generic: Add a test for basic F_SETLEASE functionality Jeff Layton
  2019-08-27 20:28 ` J. Bruce Fields
@ 2019-08-31 17:18 ` Eryu Guan
  2019-09-04 12:48 ` [PATCH v2] " Jeff Layton
  2 siblings, 0 replies; 6+ messages in thread
From: Eryu Guan @ 2019-08-31 17:18 UTC (permalink / raw)
  To: Jeff Layton; +Cc: fstests, amir73il, bfields

On Tue, Aug 27, 2019 at 08:35:37AM -0400, Jeff Layton wrote:
> Add a new test that verifies that F_SETLEASE works as expected. The
> parent opens a file and sets a lease on it and then forks. The child
> then does a (possibly) conflicting open. We then verify that we get
> signals as expected.
> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>

Thanks for the test! Looks good to me overall, some minor issues inline.

> ---
>  src/Makefile          |   2 +-
>  src/t_setlease.c      | 157 ++++++++++++++++++++++++++++++++++++++++++
>  tests/generic/566     |  54 +++++++++++++++
>  tests/generic/566.out |   1 +
>  tests/generic/group   |   1 +

Missing a .gitignore entry for the new binary file.

>  5 files changed, 214 insertions(+), 1 deletion(-)
>  create mode 100644 src/t_setlease.c
>  create mode 100755 tests/generic/566
>  create mode 100644 tests/generic/566.out
> 
> diff --git a/src/Makefile b/src/Makefile
> index c4fcf370431f..11190afa3603 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -28,7 +28,7 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
>  	attr-list-by-handle-cursor-test listxattr dio-interleaved t_dir_type \
>  	dio-invalidate-cache stat_test t_encrypted_d_revalidate \
>  	attr_replace_test swapon mkswap t_attr_corruption t_open_tmpfiles \
> -	fscrypt-crypt-util bulkstat_null_ocount
> +	fscrypt-crypt-util bulkstat_null_ocount t_setlease
>  
>  SUBDIRS = log-writes perf
>  
> diff --git a/src/t_setlease.c b/src/t_setlease.c
> new file mode 100644
> index 000000000000..81d46b6a6cd4
> --- /dev/null
> +++ b/src/t_setlease.c
> @@ -0,0 +1,157 @@
> +/*
> + * t_setlease.c: test basic F_SETLEASE functionality
> + *
> + * Open file, set lease on it. Then fork off children that open the file with
> + * different openflags. Ensure we get signals as expected.
> + *
> + * Copyright (c) 2019: Jeff Layton <jlayton@redhat.com>
> + */
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <stdbool.h>
> +#include <signal.h>
> +#include <sys/wait.h>
> +
> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
> +
> +static volatile bool signalled;
> +
> +struct leasetest {
> +	int	openflags;
> +	int	leasetype;
> +	int	conf_openflags;
> +	bool	expect_signal;
> +};
> +
> +static struct leasetest testcase[] = {
> +	{ O_RDONLY, F_RDLCK, O_RDONLY, false },
> +	{ O_RDONLY, F_RDLCK, O_WRONLY, true },
> +	{ O_WRONLY, F_WRLCK, O_RDONLY, true },
> +	{ O_WRONLY, F_WRLCK, O_WRONLY, true },
> +};
> +
> +static void usage()
> +{
> +	printf("Usage: t_setlease <filename>\n");
> +}
> +
> +static void lease_break(int signum)
> +{
> +	if (signum == SIGIO)
> +		signalled = true;
> +}
> +
> +/* Open/create a file, set up signal handler and set lease on file. */
> +static int setlease(const char *fname, int openflags, int leasetype)
> +{
> +	int fd, ret;
> +
> +	fd = open(fname, openflags | O_CREAT, 0644);
> +	if (fd < 0) {
> +		perror("open");
> +		return -errno;
> +	}
> +
> +	ret = fcntl(fd, F_SETLEASE, leasetype);
> +	if (ret) {
> +		perror("setlease");
> +		return -errno;
> +	}
> +	return fd;
> +}
> +
> +static int open_conflict(const char *fname, int openflags)
> +{
> +	int fd;
> +
> +	fd = open(fname, openflags);
> +	if (fd < 0) {
> +		perror("open");
> +		return -errno;
> +	}
> +	close(fd);
> +	return 0;
> +}
> +
> +static int simple_lease_break(const char *fname, struct leasetest *test)
> +{
> +	int fd, ret, status;
> +	pid_t pid, exited;
> +
> +	signalled = false;
> +	fd = setlease(fname, test->openflags, test->leasetype);
> +	if (fd < 0)
> +		return fd;
> +
> +	pid = fork();
> +	if (pid < 0) {
> +		return -errno;
> +	} else if (pid == 0) {
> +		/* child */
> +		close(fd);
> +		int ret = open_conflict(fname, test->conf_openflags);
> +		exit(ret ? 1 : 0);
> +	}
> +
> +	/* parent */
> +	while (!signalled) {
> +		/* Break out if child exited */
> +		exited = waitpid(pid, &status, WNOHANG);
> +		if (exited)
> +			break;
> +		usleep(1000);
> +	}
> +
> +	fcntl(fd, F_SETLEASE, F_UNLCK);

Check return value of this fcntl as well?

> +	close(fd);
> +
> +	/* If it didn't already exit, then wait now */
> +	if (!exited)
> +		waitpid(pid, &status, 0);
> +
> +	if (!WIFEXITED(status)) {
> +		ret = 1;
> +	} else {
> +		ret = WEXITSTATUS(status);
> +		if (test->expect_signal != signalled)
> +			ret = 1;
> +	}
> +
> +	return ret;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int ret, i;
> +	char *fname;
> +	struct sigaction sa = { .sa_handler = lease_break };
> +
> +	if (argc < 2) {
> +		usage();
> +		return 1;
> +	}
> +
> +	fname = argv[1];
> +
> +	ret = sigaction(SIGIO, &sa, NULL);
> +	if (ret) {
> +		perror("sigaction");
> +		return -1;
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(testcase); ++i) {
> +		struct leasetest *t = &testcase[i];
> +
> +		ret = simple_lease_break(fname, t);
> +		if (ret) {
> +			fprintf(stderr, "Test failure: openflags=%d leasetype=%d conf_openflags=%d expect_signal=%d\n", t->openflags, t->leasetype, t->conf_openflags, t->expect_signal);

This line is too long, wrap it?

> +			exit(1);
> +		}
> +	}
> +	return 0;
> +}
> diff --git a/tests/generic/566 b/tests/generic/566
> new file mode 100755
> index 000000000000..abf4f6dd743a
> --- /dev/null
> +++ b/tests/generic/566
> @@ -0,0 +1,54 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2019 YOUR NAME HERE.  All Rights Reserved.

Missing proper copyright here.

> +#
> +# FS QA Test 566
> +#
> +# Test basic F_SETLEASE functionality. Call the t_setlease program which
> +# opens a file and sets a lease on it, and then forks a child to open the
> +# same file with various openflags and verify that we get signals as expected.
> +#
> +# Note that kernels that lack 387e3746d01c (locks: eliminate false positive
> +# conflicts for write lease) will fail this test as tasks that have the file
> +# open for write are unable to get a F_WRLCK lease.
> +#
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks
> +. ./common/rc
> +. ./common/filter
> +
> +# remove previous $seqres.full before test
> +rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +# Modify as appropriate.
> +_supported_fs generic
> +_supported_os Linux
> +_require_test

_require_test_program "t_setlease"

> +
> +# if error

Seems not needed.

> +testfile=$TEST_DIR/t_setlease-testfile
> +$here/src/t_setlease $testfile
> +
> +# optional stuff if your test has verbose output to help resolve problems
> +#echo
> +#echo "If failure, check $seqres.full (this) and $seqres.full.ok (reference)"

These comments are not needed.

> +
> +# success, all done
> +status=0
> +exit
> diff --git a/tests/generic/566.out b/tests/generic/566.out
> new file mode 100644
> index 000000000000..9cd099b9d317
> --- /dev/null
> +++ b/tests/generic/566.out
> @@ -0,0 +1 @@
> +QA output created by 566

Need a "Silence is golden" output from test.

Thanks,
Eryu

> diff --git a/tests/generic/group b/tests/generic/group
> index 2e4a6f79276b..57f85f619f3b 100644
> --- a/tests/generic/group
> +++ b/tests/generic/group
> @@ -568,3 +568,4 @@
>  563 auto quick
>  564 auto quick copy_range
>  565 auto quick copy_range
> +566 auto quick locks
> -- 
> 2.21.0
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH v2] generic: Add a test for basic F_SETLEASE functionality
  2019-08-27 12:35 [PATCH] generic: Add a test for basic F_SETLEASE functionality Jeff Layton
  2019-08-27 20:28 ` J. Bruce Fields
  2019-08-31 17:18 ` Eryu Guan
@ 2019-09-04 12:48 ` Jeff Layton
  2019-09-04 16:52   ` Weiny, Ira
  2 siblings, 1 reply; 6+ messages in thread
From: Jeff Layton @ 2019-09-04 12:48 UTC (permalink / raw)
  To: fstests; +Cc: bfields, amir73il

Add a new test that verifies that F_SETLEASE works as expected. The
parent opens a file and sets a lease on it and then forks. The child
then does a (possibly) conflicting open. We then verify that we get
signals as expected.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
 .gitignore            |   1 +
 src/Makefile          |   2 +-
 src/t_setlease.c      | 165 ++++++++++++++++++++++++++++++++++++++++++
 tests/generic/566     |  51 +++++++++++++
 tests/generic/566.out |   2 +
 tests/generic/group   |   1 +
 6 files changed, 221 insertions(+), 1 deletion(-)
 create mode 100644 src/t_setlease.c
 create mode 100755 tests/generic/566
 create mode 100644 tests/generic/566.out

v2: address Eryu's comments

diff --git a/.gitignore b/.gitignore
index c8c815f91dd5..cc4c4c26ab98 100644
--- a/.gitignore
+++ b/.gitignore
@@ -141,6 +141,7 @@
 /src/t_readdir_1
 /src/t_readdir_2
 /src/t_rename_overwrite
+/src/t_setlease
 /src/t_stripealign
 /src/t_truncate_cmtime
 /src/t_truncate_self
diff --git a/src/Makefile b/src/Makefile
index c4fcf370431f..11190afa3603 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -28,7 +28,7 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize preallo_rw_pattern_reader \
 	attr-list-by-handle-cursor-test listxattr dio-interleaved t_dir_type \
 	dio-invalidate-cache stat_test t_encrypted_d_revalidate \
 	attr_replace_test swapon mkswap t_attr_corruption t_open_tmpfiles \
-	fscrypt-crypt-util bulkstat_null_ocount
+	fscrypt-crypt-util bulkstat_null_ocount t_setlease
 
 SUBDIRS = log-writes perf
 
diff --git a/src/t_setlease.c b/src/t_setlease.c
new file mode 100644
index 000000000000..030ffaf454df
--- /dev/null
+++ b/src/t_setlease.c
@@ -0,0 +1,165 @@
+/*
+ * t_setlease.c: test basic F_SETLEASE functionality
+ *
+ * Open file, set lease on it. Then fork off children that open the file with
+ * different openflags. Ensure we get signals as expected.
+ *
+ * Copyright (c) 2019: Jeff Layton <jlayton@redhat.com>
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+static volatile bool signalled;
+
+struct leasetest {
+	int	openflags;
+	int	leasetype;
+	int	conf_openflags;
+	bool	expect_signal;
+};
+
+static struct leasetest testcase[] = {
+	{ O_RDONLY, F_RDLCK, O_RDONLY, false },
+	{ O_RDONLY, F_RDLCK, O_WRONLY, true },
+	{ O_WRONLY, F_WRLCK, O_RDONLY, true },
+	{ O_WRONLY, F_WRLCK, O_WRONLY, true },
+};
+
+static void usage()
+{
+	printf("Usage: t_setlease <filename>\n");
+}
+
+static void lease_break(int signum)
+{
+	if (signum == SIGIO)
+		signalled = true;
+}
+
+/* Open/create a file, set up signal handler and set lease on file. */
+static int setlease(const char *fname, int openflags, int leasetype)
+{
+	int fd, ret;
+
+	fd = open(fname, openflags | O_CREAT, 0644);
+	if (fd < 0) {
+		perror("open");
+		return -errno;
+	}
+
+	ret = fcntl(fd, F_SETLEASE, leasetype);
+	if (ret) {
+		perror("setlease");
+		return -errno;
+	}
+	return fd;
+}
+
+static int open_conflict(const char *fname, int openflags)
+{
+	int fd;
+
+	fd = open(fname, openflags);
+	if (fd < 0) {
+		perror("open");
+		return -errno;
+	}
+	close(fd);
+	return 0;
+}
+
+static int simple_lease_break(const char *fname, struct leasetest *test)
+{
+	int fd, ret, status;
+	pid_t pid, exited;
+
+	signalled = false;
+	fd = setlease(fname, test->openflags, test->leasetype);
+	if (fd < 0)
+		return fd;
+
+	pid = fork();
+	if (pid < 0) {
+		return -errno;
+	} else if (pid == 0) {
+		/* child */
+		close(fd);
+		ret = open_conflict(fname, test->conf_openflags);
+		exit(ret ? 1 : 0);
+	}
+
+	/* parent */
+	while (!signalled) {
+		/* Break out if child exited */
+		exited = waitpid(pid, &status, WNOHANG);
+		if (exited)
+			break;
+		usleep(1000);
+	}
+
+	ret = fcntl(fd, F_SETLEASE, F_UNLCK);
+	if (ret) {
+		perror("F_UNLCK");
+		return ret;
+	}
+
+	close(fd);
+
+	/* If it didn't already exit, then wait now */
+	if (!exited)
+		waitpid(pid, &status, 0);
+
+	if (!WIFEXITED(status)) {
+		ret = 1;
+	} else {
+		ret = WEXITSTATUS(status);
+		if (test->expect_signal != signalled)
+			ret = 1;
+	}
+
+	return ret;
+}
+
+int main(int argc, char **argv)
+{
+	int ret, i;
+	char *fname;
+	struct sigaction sa = { .sa_handler = lease_break };
+
+	if (argc < 2) {
+		usage();
+		return 1;
+	}
+
+	fname = argv[1];
+
+	ret = sigaction(SIGIO, &sa, NULL);
+	if (ret) {
+		perror("sigaction");
+		return -1;
+	}
+
+	for (i = 0; i < ARRAY_SIZE(testcase); ++i) {
+		struct leasetest *t = &testcase[i];
+
+		ret = simple_lease_break(fname, t);
+		if (ret) {
+			fprintf(stderr,
+				"Test failure: openflags=%d leasetype=%d conf_openflags=%d expect_signal=%d\n",
+				t->openflags, t->leasetype, t->conf_openflags,
+				t->expect_signal);
+			exit(1);
+		}
+	}
+	return 0;
+}
diff --git a/tests/generic/566 b/tests/generic/566
new file mode 100755
index 000000000000..f08cea833681
--- /dev/null
+++ b/tests/generic/566
@@ -0,0 +1,51 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2019 Jeff Layton.  All Rights Reserved.
+#
+# FS QA Test 566
+#
+# Test basic F_SETLEASE functionality. Call the t_setlease program which
+# opens a file and sets a lease on it, and then forks a child to open the
+# same file with various openflags and verify that we get signals as expected.
+#
+# Note that kernels that lack 387e3746d01c (locks: eliminate false positive
+# conflicts for write lease) will fail this test as tasks that have the file
+# open for write are unable to get a F_WRLCK lease.
+#
+seq=`basename $0`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+
+here=`pwd`
+tmp=/tmp/$$
+status=1	# failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+	cd /
+	rm -f $tmp.*
+}
+
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+
+# remove previous $seqres.full before test
+rm -f $seqres.full
+
+# real QA test starts here
+
+# Modify as appropriate.
+_supported_fs generic
+_supported_os Linux
+_require_test
+_require_test_program t_setlease
+
+testfile=$TEST_DIR/t_setlease-testfile
+$here/src/t_setlease $testfile
+
+# success, all done
+echo "Silence is golden"
+status=0
+exit
diff --git a/tests/generic/566.out b/tests/generic/566.out
new file mode 100644
index 000000000000..31df95af2378
--- /dev/null
+++ b/tests/generic/566.out
@@ -0,0 +1,2 @@
+QA output created by 566
+Silence is golden
diff --git a/tests/generic/group b/tests/generic/group
index 2e4a6f79276b..57f85f619f3b 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -568,3 +568,4 @@
 563 auto quick
 564 auto quick copy_range
 565 auto quick copy_range
+566 auto quick locks
-- 
2.21.0

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* RE: [PATCH v2] generic: Add a test for basic F_SETLEASE functionality
  2019-09-04 12:48 ` [PATCH v2] " Jeff Layton
@ 2019-09-04 16:52   ` Weiny, Ira
  2019-09-05  0:33     ` Jeff Layton
  0 siblings, 1 reply; 6+ messages in thread
From: Weiny, Ira @ 2019-09-04 16:52 UTC (permalink / raw)
  To: Jeff Layton, fstests; +Cc: bfields, amir73il

> Subject: [PATCH v2] generic: Add a test for basic F_SETLEASE functionality
> 
> Add a new test that verifies that F_SETLEASE works as expected. The parent
> opens a file and sets a lease on it and then forks. The child then does a
> (possibly) conflicting open. We then verify that we get signals as expected.

Jeff, does this mean you would rather go with this test vs the one I submitted?

https://www.spinics.net/lists/fstests/msg12449.html

Ira

> 
> Signed-off-by: Jeff Layton <jlayton@kernel.org>
> ---
>  .gitignore            |   1 +
>  src/Makefile          |   2 +-
>  src/t_setlease.c      | 165
> ++++++++++++++++++++++++++++++++++++++++++
>  tests/generic/566     |  51 +++++++++++++
>  tests/generic/566.out |   2 +
>  tests/generic/group   |   1 +
>  6 files changed, 221 insertions(+), 1 deletion(-)  create mode 100644
> src/t_setlease.c  create mode 100755 tests/generic/566  create mode 100644
> tests/generic/566.out
> 
> v2: address Eryu's comments
> 
> diff --git a/.gitignore b/.gitignore
> index c8c815f91dd5..cc4c4c26ab98 100644
> --- a/.gitignore
> +++ b/.gitignore
> @@ -141,6 +141,7 @@
>  /src/t_readdir_1
>  /src/t_readdir_2
>  /src/t_rename_overwrite
> +/src/t_setlease
>  /src/t_stripealign
>  /src/t_truncate_cmtime
>  /src/t_truncate_self
> diff --git a/src/Makefile b/src/Makefile index c4fcf370431f..11190afa3603
> 100644
> --- a/src/Makefile
> +++ b/src/Makefile
> @@ -28,7 +28,7 @@ LINUX_TARGETS = xfsctl bstat t_mtab getdevicesize
> preallo_rw_pattern_reader \
>  	attr-list-by-handle-cursor-test listxattr dio-interleaved t_dir_type \
>  	dio-invalidate-cache stat_test t_encrypted_d_revalidate \
>  	attr_replace_test swapon mkswap t_attr_corruption
> t_open_tmpfiles \
> -	fscrypt-crypt-util bulkstat_null_ocount
> +	fscrypt-crypt-util bulkstat_null_ocount t_setlease
> 
>  SUBDIRS = log-writes perf
> 
> diff --git a/src/t_setlease.c b/src/t_setlease.c new file mode 100644 index
> 000000000000..030ffaf454df
> --- /dev/null
> +++ b/src/t_setlease.c
> @@ -0,0 +1,165 @@
> +/*
> + * t_setlease.c: test basic F_SETLEASE functionality
> + *
> + * Open file, set lease on it. Then fork off children that open the
> +file with
> + * different openflags. Ensure we get signals as expected.
> + *
> + * Copyright (c) 2019: Jeff Layton <jlayton@redhat.com>  */ #include
> +<sys/types.h> #include <sys/stat.h> #include <errno.h> #include
> +<fcntl.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h>
> +#include <stdbool.h> #include <signal.h> #include <sys/wait.h>
> +
> +#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
> +
> +static volatile bool signalled;
> +
> +struct leasetest {
> +	int	openflags;
> +	int	leasetype;
> +	int	conf_openflags;
> +	bool	expect_signal;
> +};
> +
> +static struct leasetest testcase[] = {
> +	{ O_RDONLY, F_RDLCK, O_RDONLY, false },
> +	{ O_RDONLY, F_RDLCK, O_WRONLY, true },
> +	{ O_WRONLY, F_WRLCK, O_RDONLY, true },
> +	{ O_WRONLY, F_WRLCK, O_WRONLY, true }, };
> +
> +static void usage()
> +{
> +	printf("Usage: t_setlease <filename>\n"); }
> +
> +static void lease_break(int signum)
> +{
> +	if (signum == SIGIO)
> +		signalled = true;
> +}
> +
> +/* Open/create a file, set up signal handler and set lease on file. */
> +static int setlease(const char *fname, int openflags, int leasetype) {
> +	int fd, ret;
> +
> +	fd = open(fname, openflags | O_CREAT, 0644);
> +	if (fd < 0) {
> +		perror("open");
> +		return -errno;
> +	}
> +
> +	ret = fcntl(fd, F_SETLEASE, leasetype);
> +	if (ret) {
> +		perror("setlease");
> +		return -errno;
> +	}
> +	return fd;
> +}
> +
> +static int open_conflict(const char *fname, int openflags) {
> +	int fd;
> +
> +	fd = open(fname, openflags);
> +	if (fd < 0) {
> +		perror("open");
> +		return -errno;
> +	}
> +	close(fd);
> +	return 0;
> +}
> +
> +static int simple_lease_break(const char *fname, struct leasetest
> +*test) {
> +	int fd, ret, status;
> +	pid_t pid, exited;
> +
> +	signalled = false;
> +	fd = setlease(fname, test->openflags, test->leasetype);
> +	if (fd < 0)
> +		return fd;
> +
> +	pid = fork();
> +	if (pid < 0) {
> +		return -errno;
> +	} else if (pid == 0) {
> +		/* child */
> +		close(fd);
> +		ret = open_conflict(fname, test->conf_openflags);
> +		exit(ret ? 1 : 0);
> +	}
> +
> +	/* parent */
> +	while (!signalled) {
> +		/* Break out if child exited */
> +		exited = waitpid(pid, &status, WNOHANG);
> +		if (exited)
> +			break;
> +		usleep(1000);
> +	}
> +
> +	ret = fcntl(fd, F_SETLEASE, F_UNLCK);
> +	if (ret) {
> +		perror("F_UNLCK");
> +		return ret;
> +	}
> +
> +	close(fd);
> +
> +	/* If it didn't already exit, then wait now */
> +	if (!exited)
> +		waitpid(pid, &status, 0);
> +
> +	if (!WIFEXITED(status)) {
> +		ret = 1;
> +	} else {
> +		ret = WEXITSTATUS(status);
> +		if (test->expect_signal != signalled)
> +			ret = 1;
> +	}
> +
> +	return ret;
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int ret, i;
> +	char *fname;
> +	struct sigaction sa = { .sa_handler = lease_break };
> +
> +	if (argc < 2) {
> +		usage();
> +		return 1;
> +	}
> +
> +	fname = argv[1];
> +
> +	ret = sigaction(SIGIO, &sa, NULL);
> +	if (ret) {
> +		perror("sigaction");
> +		return -1;
> +	}
> +
> +	for (i = 0; i < ARRAY_SIZE(testcase); ++i) {
> +		struct leasetest *t = &testcase[i];
> +
> +		ret = simple_lease_break(fname, t);
> +		if (ret) {
> +			fprintf(stderr,
> +				"Test failure: openflags=%d leasetype=%d
> conf_openflags=%d expect_signal=%d\n",
> +				t->openflags, t->leasetype, t-
> >conf_openflags,
> +				t->expect_signal);
> +			exit(1);
> +		}
> +	}
> +	return 0;
> +}
> diff --git a/tests/generic/566 b/tests/generic/566 new file mode 100755
> index 000000000000..f08cea833681
> --- /dev/null
> +++ b/tests/generic/566
> @@ -0,0 +1,51 @@
> +#! /bin/bash
> +# SPDX-License-Identifier: GPL-2.0
> +# Copyright (c) 2019 Jeff Layton.  All Rights Reserved.
> +#
> +# FS QA Test 566
> +#
> +# Test basic F_SETLEASE functionality. Call the t_setlease program
> +which # opens a file and sets a lease on it, and then forks a child to
> +open the # same file with various openflags and verify that we get signals as
> expected.
> +#
> +# Note that kernels that lack 387e3746d01c (locks: eliminate false
> +positive # conflicts for write lease) will fail this test as tasks that
> +have the file # open for write are unable to get a F_WRLCK lease.
> +#
> +seq=`basename $0`
> +seqres=$RESULT_DIR/$seq
> +echo "QA output created by $seq"
> +
> +here=`pwd`
> +tmp=/tmp/$$
> +status=1	# failure is the default!
> +trap "_cleanup; exit \$status" 0 1 2 3 15
> +
> +_cleanup()
> +{
> +	cd /
> +	rm -f $tmp.*
> +}
> +
> +# get standard environment, filters and checks . ./common/rc .
> +./common/filter
> +
> +# remove previous $seqres.full before test rm -f $seqres.full
> +
> +# real QA test starts here
> +
> +# Modify as appropriate.
> +_supported_fs generic
> +_supported_os Linux
> +_require_test
> +_require_test_program t_setlease
> +
> +testfile=$TEST_DIR/t_setlease-testfile
> +$here/src/t_setlease $testfile
> +
> +# success, all done
> +echo "Silence is golden"
> +status=0
> +exit
> diff --git a/tests/generic/566.out b/tests/generic/566.out new file mode
> 100644 index 000000000000..31df95af2378
> --- /dev/null
> +++ b/tests/generic/566.out
> @@ -0,0 +1,2 @@
> +QA output created by 566
> +Silence is golden
> diff --git a/tests/generic/group b/tests/generic/group index
> 2e4a6f79276b..57f85f619f3b 100644
> --- a/tests/generic/group
> +++ b/tests/generic/group
> @@ -568,3 +568,4 @@
>  563 auto quick
>  564 auto quick copy_range
>  565 auto quick copy_range
> +566 auto quick locks
> --
> 2.21.0

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v2] generic: Add a test for basic F_SETLEASE functionality
  2019-09-04 16:52   ` Weiny, Ira
@ 2019-09-05  0:33     ` Jeff Layton
  0 siblings, 0 replies; 6+ messages in thread
From: Jeff Layton @ 2019-09-05  0:33 UTC (permalink / raw)
  To: Weiny, Ira, fstests; +Cc: bfields, amir73il

On Wed, 2019-09-04 at 16:52 +0000, Weiny, Ira wrote:
> > Subject: [PATCH v2] generic: Add a test for basic F_SETLEASE functionality
> > 
> > Add a new test that verifies that F_SETLEASE works as expected. The parent
> > opens a file and sets a lease on it and then forks. The child then does a
> > (possibly) conflicting open. We then verify that we get signals as expected.
> 
> Jeff, does this mean you would rather go with this test vs the one I submitted?
> 
> https://www.spinics.net/lists/fstests/msg12449.html
> 
> Ira
> 

No, actually...I'm sorry, I didn't notice your posting until just now.

I think your test (with the proposed changes) covers more cases and will
probably be more extensible later. I'll give it a more thorough review
tomorrow, but I expect we can just drop this patch and just go with your
tests.

Thanks,
-- 
Jeff Layton <jlayton@kernel.org>

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2019-09-05  0:33 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-27 12:35 [PATCH] generic: Add a test for basic F_SETLEASE functionality Jeff Layton
2019-08-27 20:28 ` J. Bruce Fields
2019-08-31 17:18 ` Eryu Guan
2019-09-04 12:48 ` [PATCH v2] " Jeff Layton
2019-09-04 16:52   ` Weiny, Ira
2019-09-05  0:33     ` Jeff Layton

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.