diff mbox series

[2/2] selftests: add OFD lock tests

Message ID 20230621152214.2720319-3-stsp2@yandex.ru (mailing list archive)
State New
Headers show
Series v2: F_OFD_GETLK extension to read lock info | expand

Commit Message

stsp June 21, 2023, 3:22 p.m. UTC
Test the basic locking stuff on 2 fds: multiple read locks,
conflicts between read and write locks, use of len==0 for queries.
Also tests for F_UNLCK F_OFD_GETLK extension.

Signed-off-by: Stas Sergeev <stsp2@yandex.ru>

CC: Jeff Layton <jlayton@kernel.org>
CC: Chuck Lever <chuck.lever@oracle.com>
CC: Alexander Viro <viro@zeniv.linux.org.uk>
CC: Christian Brauner <brauner@kernel.org>
CC: linux-fsdevel@vger.kernel.org
CC: linux-kernel@vger.kernel.org
CC: Shuah Khan <shuah@kernel.org>
CC: linux-kselftest@vger.kernel.org
CC: linux-api@vger.kernel.org

---
 tools/testing/selftests/locking/Makefile   |   2 +
 tools/testing/selftests/locking/ofdlocks.c | 132 +++++++++++++++++++++
 2 files changed, 134 insertions(+)
 create mode 100644 tools/testing/selftests/locking/ofdlocks.c

Comments

Jeff Layton June 22, 2023, 11:48 a.m. UTC | #1
On Wed, 2023-06-21 at 20:22 +0500, Stas Sergeev wrote:
> Test the basic locking stuff on 2 fds: multiple read locks,
> conflicts between read and write locks, use of len==0 for queries.
> Also tests for F_UNLCK F_OFD_GETLK extension.
> 
> Signed-off-by: Stas Sergeev <stsp2@yandex.ru>
> 
> CC: Jeff Layton <jlayton@kernel.org>
> CC: Chuck Lever <chuck.lever@oracle.com>
> CC: Alexander Viro <viro@zeniv.linux.org.uk>
> CC: Christian Brauner <brauner@kernel.org>
> CC: linux-fsdevel@vger.kernel.org
> CC: linux-kernel@vger.kernel.org
> CC: Shuah Khan <shuah@kernel.org>
> CC: linux-kselftest@vger.kernel.org
> CC: linux-api@vger.kernel.org
> 
> ---
>  tools/testing/selftests/locking/Makefile   |   2 +
>  tools/testing/selftests/locking/ofdlocks.c | 132 +++++++++++++++++++++
>  2 files changed, 134 insertions(+)
>  create mode 100644 tools/testing/selftests/locking/ofdlocks.c
> 
> diff --git a/tools/testing/selftests/locking/Makefile b/tools/testing/selftests/locking/Makefile
> index 6e7761ab3536..a83ced1626de 100644
> --- a/tools/testing/selftests/locking/Makefile
> +++ b/tools/testing/selftests/locking/Makefile
> @@ -7,4 +7,6 @@ all:
>  
>  TEST_PROGS := ww_mutex.sh
>  
> +TEST_GEN_PROGS := ofdlocks
> +
>  include ../lib.mk

I'm not sure this really belongs in the "locking" directory. Given that
there is only the ww_mutex test in there, that's more for internal
synchronization mechanisms, I think.

Can you create a new "filelock" directory and drop this into there
instead?


> diff --git a/tools/testing/selftests/locking/ofdlocks.c b/tools/testing/selftests/locking/ofdlocks.c
> new file mode 100644
> index 000000000000..1ccb2b9b5ead
> --- /dev/null
> +++ b/tools/testing/selftests/locking/ofdlocks.c
> @@ -0,0 +1,132 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#define _GNU_SOURCE
> +#include <fcntl.h>
> +#include <assert.h>
> +#include <stdio.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include "../kselftest.h"
> +
> +static int lock_set(int fd, struct flock *fl)
> +{
> +	int ret;
> +
> +	fl->l_pid = 0;		// needed for OFD locks
> +	fl->l_whence = SEEK_SET;
> +	ret = fcntl(fd, F_OFD_SETLK, fl);
> +	if (ret)
> +		perror("fcntl()");
> +	return ret;
> +}
> +
> +static int lock_get(int fd, struct flock *fl)
> +{
> +	int ret;
> +
> +	fl->l_pid = 0;		// needed for OFD locks
> +	fl->l_whence = SEEK_SET;
> +	ret = fcntl(fd, F_OFD_GETLK, fl);
> +	if (ret)
> +		perror("fcntl()");
> +	return ret;
> +}
> +
> +int main(void)
> +{
> +	int rc;
> +	struct flock fl, fl2;
> +	int fd = open("/tmp/aa", O_RDWR | O_CREAT | O_EXCL, 0600);
> +	int fd2 = open("/tmp/aa", O_RDONLY);
> +
> +	unlink("aa");
> +	assert(fd != -1);
> +	assert(fd2 != -1);
> +	ksft_print_msg("[INFO] opened fds %i %i\n", fd, fd2);
> +
> +	/* Set some read lock */
> +	fl.l_type = F_RDLCK;
> +	fl.l_start = 5;
> +	fl.l_len = 3;
> +	rc = lock_set(fd, &fl);
> +	if (rc == 0) {
> +		ksft_print_msg
> +		    ("[SUCCESS] set OFD read lock on first fd\n");
> +	} else {
> +		ksft_print_msg("[FAIL] to set OFD read lock on first fd\n");
> +		return -1;
> +	}
> +	/* Make sure read locks do not conflict on different fds. */
> +	fl.l_type = F_RDLCK;
> +	fl.l_start = 5;
> +	fl.l_len = 1;
> +	rc = lock_get(fd2, &fl);
> +	if (rc != 0)
> +		return -1;
> +	if (fl.l_type != F_UNLCK) {
> +		ksft_print_msg("[FAIL] read locks conflicted\n");
> +		return -1;
> +	}
> +	/* Make sure read/write locks do conflict on different fds. */
> +	fl.l_type = F_WRLCK;
> +	fl.l_start = 5;
> +	fl.l_len = 1;
> +	rc = lock_get(fd2, &fl);
> +	if (rc != 0)
> +		return -1;
> +	if (fl.l_type != F_UNLCK) {
> +		ksft_print_msg
> +		    ("[SUCCESS] read and write locks conflicted\n");
> +	} else {
> +		ksft_print_msg
> +		    ("[SUCCESS] read and write locks not conflicted\n");
> +		return -1;
> +	}
> +	/* Get info about the lock on first fd. */
> +	fl.l_type = F_UNLCK;
> +	fl.l_start = 5;
> +	fl.l_len = 1;
> +	rc = lock_get(fd, &fl);
> +	if (rc != 0) {
> +		ksft_print_msg
> +		    ("[FAIL] F_OFD_GETLK with F_UNLCK not supported\n");
> +		return -1;
> +	}
> +	if (fl.l_type != F_UNLCK) {
> +		ksft_print_msg
> +		    ("[SUCCESS] F_UNLCK test returns: locked, type %i pid %i len %zi\n",
> +		     fl.l_type, fl.l_pid, fl.l_len);
> +	} else {
> +		ksft_print_msg
> +		    ("[FAIL] F_OFD_GETLK with F_UNLCK did not return lock info\n");
> +		return -1;
> +	}
> +	/* Try the same but by locking everything by len==0. */
> +	fl2.l_type = F_UNLCK;
> +	fl2.l_start = 0;
> +	fl2.l_len = 0;
> +	rc = lock_get(fd, &fl2);
> +	if (rc != 0) {
> +		ksft_print_msg
> +		    ("[FAIL] F_OFD_GETLK with F_UNLCK not supported\n");
> +		return -1;
> +	}
> +	if (memcmp(&fl, &fl2, sizeof(fl))) {
> +		ksft_print_msg
> +		    ("[FAIL] F_UNLCK test returns: locked, type %i pid %i len %zi\n",
> +		     fl.l_type, fl.l_pid, fl.l_len);
> +		return -1;
> +	}
> +	ksft_print_msg("[SUCCESS] F_UNLCK with len==0 returned the same\n");
> +	/* Get info about the lock on second fd - no locks on it. */
> +	fl.l_type = F_UNLCK;
> +	fl.l_start = 0;
> +	fl.l_len = 0;
> +	lock_get(fd2, &fl);
> +	if (fl.l_type != F_UNLCK) {
> +		ksft_print_msg
> +		    ("[FAIL] F_OFD_GETLK with F_UNLCK return lock info from another fd\n");
> +		return -1;
> +	}
> +	return 0;
> +}

I'm not opposed to adding a selftest here, but most filesystem testing
is done via xfstests:

    https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/

It would be better to add this test to the existing generic/478 test
that tests OFD locks. Can you patch that to add a test for the new
functionality?

Thanks,
stsp June 22, 2023, 4:40 p.m. UTC | #2
22.06.2023 16:48, Jeff Layton пишет:
> I'm not opposed to adding a selftest here, but most filesystem testing
> is done via xfstests:
>
>      https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/
>
> It would be better to add this test to the existing generic/478 test
> that tests OFD locks. Can you patch that to add a test for the new
> functionality?
I don't actually think its possible.
It seems like their script creates 2
t_ofd_locks processes, one for creating
the lock, one for testing it.
This is not our case.
To make it work our way, we'd probably
need to hack that test directly into
t_ofd_locks.c, so that it can set and test
from the same fd. And I don't know how
to even run these tests. :)
So I am really inclined to limit myself
with a kernel selftest.
stsp June 22, 2023, 4:54 p.m. UTC | #3
22.06.2023 16:48, Jeff Layton пишет:
> I'm not sure this really belongs in the "locking" directory. Given that
> there is only the ww_mutex test in there, that's more for internal
> synchronization mechanisms, I think.
>
> Can you create a new "filelock" directory and drop this into there
> instead?
Done and sent the v3.
Chuck Lever June 22, 2023, 4:58 p.m. UTC | #4
> On Jun 22, 2023, at 12:40 PM, stsp <stsp2@yandex.ru> wrote:
> 
> 22.06.2023 16:48, Jeff Layton пишет:
>> I'm not opposed to adding a selftest here, but most filesystem testing
>> is done via xfstests:
>> 
>>     https://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git/
>> 
>> It would be better to add this test to the existing generic/478 test
>> that tests OFD locks. Can you patch that to add a test for the new
>> functionality?

I agree with Jeff, this test needs to go in xfstests.


> I don't actually think its possible.
> It seems like their script creates 2
> t_ofd_locks processes, one for creating
> the lock, one for testing it.
> This is not our case.
> To make it work our way, we'd probably
> need to hack that test directly into
> t_ofd_locks.c, so that it can set and test
> from the same fd.

Or you could add a new test program.


> And I don't know how
> to even run these tests. :)
> So I am really inclined to limit myself
> with a kernel selftest.

IMO that's not a reason not to do this properly.

You should work with Jeff and the maintainer of
xfstests to make it happen.


--
Chuck Lever
stsp June 22, 2023, 5:05 p.m. UTC | #5
22.06.2023 21:58, Chuck Lever III пишет:
> IMO that's not a reason not to do this properly.
>
> You should work with Jeff and the maintainer of
> xfstests to make it happen.
But its not going to be in this patch-set
anyway, as its a different source tree...
So I should prepare it when this is merged,
or?
Chuck Lever June 22, 2023, 5:12 p.m. UTC | #6
> On Jun 22, 2023, at 1:05 PM, stsp <stsp2@yandex.ru> wrote:
> 
> 
> 22.06.2023 21:58, Chuck Lever III пишет:
>> IMO that's not a reason not to do this properly.
>> 
>> You should work with Jeff and the maintainer of
>> xfstests to make it happen.
> But its not going to be in this patch-set
> anyway, as its a different source tree...

If others agree with me, then please drop the selftests
patch from this series. There is a considerably higher
probability that the new test will be run frequently
by CI if it's in xfstests.


> So I should prepare it when this is merged,
> or?

I don't have a strong preference. A good choice is to
push the test before the kernel changes are merged.


--
Chuck Lever
stsp June 22, 2023, 5:31 p.m. UTC | #7
22.06.2023 22:12, Chuck Lever III пишет:
> I don't have a strong preference. A good choice is to
> push the test before the kernel changes are merged.
It will fail though w/o kernel changes.
So what exactly is the policy?
Frank Filz June 22, 2023, 5:34 p.m. UTC | #8
> > On Jun 22, 2023, at 1:05 PM, stsp <stsp2@yandex.ru> wrote:
> >
> >
> > 22.06.2023 21:58, Chuck Lever III пишет:
> >> IMO that's not a reason not to do this properly.
> >>
> >> You should work with Jeff and the maintainer of xfstests to make it
> >> happen.
> > But its not going to be in this patch-set anyway, as its a different
> > source tree...
> 
> If others agree with me, then please drop the selftests patch from this series.
> There is a considerably higher probability that the new test will be run frequently
> by CI if it's in xfstests.
> 
> 
> > So I should prepare it when this is merged, or?
> 
> I don't have a strong preference. A good choice is to push the test before the
> kernel changes are merged.

As an aside, an additional testing option for OFD locks is the multilock test tool that is in the nfs-ganesha project. In preparation to use OFD locks in Ganesha, I added them to multilock to check them out, and that incidentally also allows testing how the NFS client and server work when OFD locks are taken on a file from an NFS mount.

Frank
Dave Chinner June 22, 2023, 10:15 p.m. UTC | #9
On Thu, Jun 22, 2023 at 10:31:06PM +0500, stsp wrote:
> 
> 22.06.2023 22:12, Chuck Lever III пишет:
> > I don't have a strong preference. A good choice is to
> > push the test before the kernel changes are merged.
> It will fail though w/o kernel changes.
> So what exactly is the policy?

filesystem unit test functionality needs to be pushed into fstests
and/or ltp. The preference is the former, because just about every
filesystem developer and distro QA team is running this as part of
their every-day testing workflow.

fstests is written to probe whether the kernel supports a given
feature or not before testing it. It will _not_run() a test that
doesn't have the required kernel/fs/device support, and this is not
considered a test failure.

Yes, it means you have to also write the userspace feature probing
code, but that should be trivial to do because userspace already has
to be able to safely discover that this extension exists, right?

-Dave.
stsp Aug. 9, 2023, 7:56 a.m. UTC | #10
Hi,

22.06.2023 21:58, Chuck Lever III пишет:
> IMO that's not a reason not to do this properly.
>
> You should work with Jeff and the maintainer of
> xfstests to make it happen.
If only I knew who is that maintainer
and why he ignores all patches...

Can someone else please take a look at this:
https://www.spinics.net/lists/fstests/msg23115.html
and make a review/ack?
diff mbox series

Patch

diff --git a/tools/testing/selftests/locking/Makefile b/tools/testing/selftests/locking/Makefile
index 6e7761ab3536..a83ced1626de 100644
--- a/tools/testing/selftests/locking/Makefile
+++ b/tools/testing/selftests/locking/Makefile
@@ -7,4 +7,6 @@  all:
 
 TEST_PROGS := ww_mutex.sh
 
+TEST_GEN_PROGS := ofdlocks
+
 include ../lib.mk
diff --git a/tools/testing/selftests/locking/ofdlocks.c b/tools/testing/selftests/locking/ofdlocks.c
new file mode 100644
index 000000000000..1ccb2b9b5ead
--- /dev/null
+++ b/tools/testing/selftests/locking/ofdlocks.c
@@ -0,0 +1,132 @@ 
+// SPDX-License-Identifier: GPL-2.0
+
+#define _GNU_SOURCE
+#include <fcntl.h>
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "../kselftest.h"
+
+static int lock_set(int fd, struct flock *fl)
+{
+	int ret;
+
+	fl->l_pid = 0;		// needed for OFD locks
+	fl->l_whence = SEEK_SET;
+	ret = fcntl(fd, F_OFD_SETLK, fl);
+	if (ret)
+		perror("fcntl()");
+	return ret;
+}
+
+static int lock_get(int fd, struct flock *fl)
+{
+	int ret;
+
+	fl->l_pid = 0;		// needed for OFD locks
+	fl->l_whence = SEEK_SET;
+	ret = fcntl(fd, F_OFD_GETLK, fl);
+	if (ret)
+		perror("fcntl()");
+	return ret;
+}
+
+int main(void)
+{
+	int rc;
+	struct flock fl, fl2;
+	int fd = open("/tmp/aa", O_RDWR | O_CREAT | O_EXCL, 0600);
+	int fd2 = open("/tmp/aa", O_RDONLY);
+
+	unlink("aa");
+	assert(fd != -1);
+	assert(fd2 != -1);
+	ksft_print_msg("[INFO] opened fds %i %i\n", fd, fd2);
+
+	/* Set some read lock */
+	fl.l_type = F_RDLCK;
+	fl.l_start = 5;
+	fl.l_len = 3;
+	rc = lock_set(fd, &fl);
+	if (rc == 0) {
+		ksft_print_msg
+		    ("[SUCCESS] set OFD read lock on first fd\n");
+	} else {
+		ksft_print_msg("[FAIL] to set OFD read lock on first fd\n");
+		return -1;
+	}
+	/* Make sure read locks do not conflict on different fds. */
+	fl.l_type = F_RDLCK;
+	fl.l_start = 5;
+	fl.l_len = 1;
+	rc = lock_get(fd2, &fl);
+	if (rc != 0)
+		return -1;
+	if (fl.l_type != F_UNLCK) {
+		ksft_print_msg("[FAIL] read locks conflicted\n");
+		return -1;
+	}
+	/* Make sure read/write locks do conflict on different fds. */
+	fl.l_type = F_WRLCK;
+	fl.l_start = 5;
+	fl.l_len = 1;
+	rc = lock_get(fd2, &fl);
+	if (rc != 0)
+		return -1;
+	if (fl.l_type != F_UNLCK) {
+		ksft_print_msg
+		    ("[SUCCESS] read and write locks conflicted\n");
+	} else {
+		ksft_print_msg
+		    ("[SUCCESS] read and write locks not conflicted\n");
+		return -1;
+	}
+	/* Get info about the lock on first fd. */
+	fl.l_type = F_UNLCK;
+	fl.l_start = 5;
+	fl.l_len = 1;
+	rc = lock_get(fd, &fl);
+	if (rc != 0) {
+		ksft_print_msg
+		    ("[FAIL] F_OFD_GETLK with F_UNLCK not supported\n");
+		return -1;
+	}
+	if (fl.l_type != F_UNLCK) {
+		ksft_print_msg
+		    ("[SUCCESS] F_UNLCK test returns: locked, type %i pid %i len %zi\n",
+		     fl.l_type, fl.l_pid, fl.l_len);
+	} else {
+		ksft_print_msg
+		    ("[FAIL] F_OFD_GETLK with F_UNLCK did not return lock info\n");
+		return -1;
+	}
+	/* Try the same but by locking everything by len==0. */
+	fl2.l_type = F_UNLCK;
+	fl2.l_start = 0;
+	fl2.l_len = 0;
+	rc = lock_get(fd, &fl2);
+	if (rc != 0) {
+		ksft_print_msg
+		    ("[FAIL] F_OFD_GETLK with F_UNLCK not supported\n");
+		return -1;
+	}
+	if (memcmp(&fl, &fl2, sizeof(fl))) {
+		ksft_print_msg
+		    ("[FAIL] F_UNLCK test returns: locked, type %i pid %i len %zi\n",
+		     fl.l_type, fl.l_pid, fl.l_len);
+		return -1;
+	}
+	ksft_print_msg("[SUCCESS] F_UNLCK with len==0 returned the same\n");
+	/* Get info about the lock on second fd - no locks on it. */
+	fl.l_type = F_UNLCK;
+	fl.l_start = 0;
+	fl.l_len = 0;
+	lock_get(fd2, &fl);
+	if (fl.l_type != F_UNLCK) {
+		ksft_print_msg
+		    ("[FAIL] F_OFD_GETLK with F_UNLCK return lock info from another fd\n");
+		return -1;
+	}
+	return 0;
+}