diff mbox series

[1/5] fcntl40: test for owner values on classic posix lock

Message ID 20230530203707.2965684-2-aahringo@redhat.com
State Changes Requested
Headers show
Series fcntl: add more testcases | expand

Commit Message

Alexander Aring May 30, 2023, 8:37 p.m. UTC
This patch adds fcntl40 to test similar owner values for classical owner
locks. There was an issue been found in the gfs2 filesystem because
there can be collisions with identical owner values.

Signed-off-by: Alexander Aring <aahringo@redhat.com>
---
 testcases/kernel/syscalls/fcntl/.gitignore |   2 +
 testcases/kernel/syscalls/fcntl/Makefile   |   3 +
 testcases/kernel/syscalls/fcntl/fcntl40.c  | 188 +++++++++++++++++++++
 3 files changed, 193 insertions(+)
 create mode 100644 testcases/kernel/syscalls/fcntl/fcntl40.c

Comments

Petr Vorel June 21, 2023, 9:03 a.m. UTC | #1
Hi Alexander,

> This patch adds fcntl40 to test similar owner values for classical owner
> locks. There was an issue been found in the gfs2 filesystem because
> there can be collisions with identical owner values.

Thanks for your work!

...
> +++ b/testcases/kernel/syscalls/fcntl/fcntl40.c
> @@ -0,0 +1,188 @@
There is no SPDX and copyright, see other files:

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * Copyright (c) 2023 ...
 */

> +/*
NOTE: this should be /*\
to be able to get the description in our automatically generated documentation

https://github.com/linux-test-project/ltp/releases/download/20230516/metadata.20230516.html

> + * [Description]
> + * Tests gfs2 dlm posix op queue handling in the kernel.
> + * It is recommended to run watch -n 0.1 "dlm_tool plocks $LS"
> + * aside to monitor dlm plock handling.
> + *
> + * [How to use it]
> + * Call it with TMPDIR=/mnt ./fcntl40 where TMPDIR is a gfs2 mountpoint.
I wonder if we could check for GFS2_MAGIC (we'd need to add it to
include/tst_fs.h => 0x01161970) and quit the test with tst_brk(TCONF) if TMPDIR
is not on gfs2.

ATM we don't have any helper in struct tst_test, which would do it.

> + * Try it on other filesystems to compare results.
> + *
> + * [What's it doing]
nit: I'd replace this with [Algorithm].

...
> +void do_child(void)
This should be static (in all files).

make check (or make check-fcntl40) is your friend.

> +{
> +	pthread_t t1, t2;
> +
> +	SAFE_PTHREAD_CREATE(&t1, NULL, do_thread1, NULL);
> +	SAFE_PTHREAD_CREATE(&t2, NULL, do_thread2, NULL);
> +
> +	SAFE_PTHREAD_JOIN(t1, NULL);
> +	SAFE_PTHREAD_JOIN(t2, NULL);
> +
> +	tst_res(TPASS, "Child passed!");
> +}
> +
> +void do_parent(void)
This should also be static.

> +{
> +	struct flock fl = {
> +		.l_whence = SEEK_SET,
> +	};
> +
> +	/* wait for 1 seconds so thread2 lock 1-1 tries to acquires at first
> +	 * than thread1 lock 0-0 tries to acquired to have a specific waiting
> +	 * order in dlm posix handling.
> +	 */
> +	sleep(1);

I wonder if there could be some proactive check instead of sleep.
FYI we have undocumented TST_RETRY_FUNC() in C API.

> +	/* tell thread2 to call SETLKW for lock 0-0 */
> +	TST_CHECKPOINT_WAKE(1);
> +	/* wait 3 seconds for thread 1 and 2 being in waiting state */
> +	sleep(3);
> +
> +	/* unlock 0-1, should be successful */
> +	fl.l_type = F_UNLCK;
> +	fl.l_start = 1;
> +	fl.l_len = 1;
> +	tst_res(TINFO, "unlock region 1-1 thread2");
> +	SAFE_FCNTL(fd, F_SETLK, &fl);
> +
> +	/* wait until thread 2 got acquired and leave waiting */
> +	TST_CHECKPOINT_WAIT(2);
> +
> +	fl.l_start = 0;
> +	fl.l_len = 1;
> +	fl.l_type = F_UNLCK;
> +	tst_res(TINFO, "unlock region 0-0 thread2");
> +	SAFE_FCNTL(fd, F_SETLK, &fl);
> +}
> +
> +static void fcntl40_test(void)
> +{
> +	struct flock fl = {
> +		.l_type = F_WRLCK,
> +		.l_whence = SEEK_SET,
> +		.l_start = 0L,
> +		.l_len = 2L,
> +	};
> +	pid_t pid;
> +
> +	tst_res(TINFO, "parent lock region 0-1 - should be successful");
> +	SAFE_FCNTL(fd, F_SETLK, &fl);
> +	tst_res(TINFO, "parent region 0-1 locked");
> +
> +	pid = SAFE_FORK();
> +	if (pid == 0) {
> +		do_child();
> +		return;
> +	}
> +
> +	do_parent();
> +	wait(NULL);

waitpid() should be replaced by tst_reap_children(), see
https://github.com/linux-test-project/ltp/wiki/C-Test-API#18-doing-the-test-in-the-child-process

> +
> +	tst_res(TPASS, "Parent passed!");
There is TPASS in child, does it really need to be in the parent as well?
> +}
> +
> +static void setup(void)
> +{
> +	fd = SAFE_OPEN("filename", O_RDWR | O_CREAT, 0700);
> +}
> +
> +static void cleanup(void)
> +{
> +	if (fd > -1)
> +		SAFE_CLOSE(fd);
> +}
> +
> +static struct tst_test test = {
> +	.forks_child = 1,
> +	.needs_checkpoints = 1,
> +	.test_all = fcntl40_test,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +};
Alexander Aring June 30, 2023, 7:59 p.m. UTC | #2
Hi,

On Wed, Jun 21, 2023 at 5:10 AM Petr Vorel <pvorel@suse.cz> wrote:
>
> Hi Alexander,
>
> > This patch adds fcntl40 to test similar owner values for classical owner
> > locks. There was an issue been found in the gfs2 filesystem because
> > there can be collisions with identical owner values.
>
> Thanks for your work!
>
> ...
> > +++ b/testcases/kernel/syscalls/fcntl/fcntl40.c
> > @@ -0,0 +1,188 @@
> There is no SPDX and copyright, see other files:
>
> // SPDX-License-Identifier: GPL-2.0-or-later
> /*
>  * Copyright (c) 2023 ...
>  */
>
> > +/*
> NOTE: this should be /*\
> to be able to get the description in our automatically generated documentation
>
> https://github.com/linux-test-project/ltp/releases/download/20230516/metadata.20230516.html
>

ok

> > + * [Description]
> > + * Tests gfs2 dlm posix op queue handling in the kernel.
> > + * It is recommended to run watch -n 0.1 "dlm_tool plocks $LS"
> > + * aside to monitor dlm plock handling.
> > + *
> > + * [How to use it]
> > + * Call it with TMPDIR=/mnt ./fcntl40 where TMPDIR is a gfs2 mountpoint.
> I wonder if we could check for GFS2_MAGIC (we'd need to add it to
> include/tst_fs.h => 0x01161970) and quit the test with tst_brk(TCONF) if TMPDIR
> is not on gfs2.
>
> ATM we don't have any helper in struct tst_test, which would do it.
>

I will mention that gfs2 is only an example here. It becomes
interesting when a file system implements its own .lock() callback OR
if somebody wants to test file system core, when a filesystem does not
implement its own .lock().

> > + * Try it on other filesystems to compare results.
> > + *
> > + * [What's it doing]
> nit: I'd replace this with [Algorithm].
>

ok.

> ...
> > +void do_child(void)
> This should be static (in all files).
>
> make check (or make check-fcntl40) is your friend.
>

ok. Thanks for telling me about make check.

> > +{
> > +     pthread_t t1, t2;
> > +
> > +     SAFE_PTHREAD_CREATE(&t1, NULL, do_thread1, NULL);
> > +     SAFE_PTHREAD_CREATE(&t2, NULL, do_thread2, NULL);
> > +
> > +     SAFE_PTHREAD_JOIN(t1, NULL);
> > +     SAFE_PTHREAD_JOIN(t2, NULL);
> > +
> > +     tst_res(TPASS, "Child passed!");
> > +}
> > +
> > +void do_parent(void)
> This should also be static.
>

ok.

> > +{
> > +     struct flock fl = {
> > +             .l_whence = SEEK_SET,
> > +     };
> > +
> > +     /* wait for 1 seconds so thread2 lock 1-1 tries to acquires at first
> > +      * than thread1 lock 0-0 tries to acquired to have a specific waiting
> > +      * order in dlm posix handling.
> > +      */
> > +     sleep(1);
>
> I wonder if there could be some proactive check instead of sleep.
> FYI we have undocumented TST_RETRY_FUNC() in C API.
>

I try to look into it.

> > +     /* tell thread2 to call SETLKW for lock 0-0 */
> > +     TST_CHECKPOINT_WAKE(1);
> > +     /* wait 3 seconds for thread 1 and 2 being in waiting state */
> > +     sleep(3);
> > +
> > +     /* unlock 0-1, should be successful */
> > +     fl.l_type = F_UNLCK;
> > +     fl.l_start = 1;
> > +     fl.l_len = 1;
> > +     tst_res(TINFO, "unlock region 1-1 thread2");
> > +     SAFE_FCNTL(fd, F_SETLK, &fl);
> > +
> > +     /* wait until thread 2 got acquired and leave waiting */
> > +     TST_CHECKPOINT_WAIT(2);
> > +
> > +     fl.l_start = 0;
> > +     fl.l_len = 1;
> > +     fl.l_type = F_UNLCK;
> > +     tst_res(TINFO, "unlock region 0-0 thread2");
> > +     SAFE_FCNTL(fd, F_SETLK, &fl);
> > +}
> > +
> > +static void fcntl40_test(void)
> > +{
> > +     struct flock fl = {
> > +             .l_type = F_WRLCK,
> > +             .l_whence = SEEK_SET,
> > +             .l_start = 0L,
> > +             .l_len = 2L,
> > +     };
> > +     pid_t pid;
> > +
> > +     tst_res(TINFO, "parent lock region 0-1 - should be successful");
> > +     SAFE_FCNTL(fd, F_SETLK, &fl);
> > +     tst_res(TINFO, "parent region 0-1 locked");
> > +
> > +     pid = SAFE_FORK();
> > +     if (pid == 0) {
> > +             do_child();
> > +             return;
> > +     }
> > +
> > +     do_parent();
> > +     wait(NULL);
>
> waitpid() should be replaced by tst_reap_children(), see
> https://github.com/linux-test-project/ltp/wiki/C-Test-API#18-doing-the-test-in-the-child-process
>

ok. Thanks.

> > +
> > +     tst_res(TPASS, "Parent passed!");
> There is TPASS in child, does it really need to be in the parent as well?

no.

- Alex
Petr Vorel July 2, 2023, 7:18 p.m. UTC | #3
Hi Alex,

...
> > > + * [Description]
> > > + * Tests gfs2 dlm posix op queue handling in the kernel.
> > > + * It is recommended to run watch -n 0.1 "dlm_tool plocks $LS"
> > > + * aside to monitor dlm plock handling.
> > > + *
> > > + * [How to use it]
> > > + * Call it with TMPDIR=/mnt ./fcntl40 where TMPDIR is a gfs2 mountpoint.
> > I wonder if we could check for GFS2_MAGIC (we'd need to add it to
> > include/tst_fs.h => 0x01161970) and quit the test with tst_brk(TCONF) if TMPDIR
> > is not on gfs2.

> > ATM we don't have any helper in struct tst_test, which would do it.


> I will mention that gfs2 is only an example here. It becomes
> interesting when a file system implements its own .lock() callback OR
> if somebody wants to test file system core, when a filesystem does not
> implement its own .lock().

I see .lock is implemented in 9p, afs, ceph, cifs, ocfs2, orangefs, even NFS.
"file system core": do you mean VFS? Because that would be more usable than the
filesystems above (which are quite exotic).

...

Kind regards,
Petr
Petr Vorel July 2, 2023, 7:19 p.m. UTC | #4
Hi Alex,

...
> > > +     tst_res(TPASS, "Parent passed!");
> > There is TPASS in child, does it really need to be in the parent as well?

> no.

Thanks for info, let's skip it then in the parent.

Kind regards,
Petr
Alexander Aring July 5, 2023, 1:23 p.m. UTC | #5
Hi,

On Sun, Jul 2, 2023 at 3:18 PM Petr Vorel <pvorel@suse.cz> wrote:
>
> Hi Alex,
>
> ...
> > > > + * [Description]
> > > > + * Tests gfs2 dlm posix op queue handling in the kernel.
> > > > + * It is recommended to run watch -n 0.1 "dlm_tool plocks $LS"
> > > > + * aside to monitor dlm plock handling.
> > > > + *
> > > > + * [How to use it]
> > > > + * Call it with TMPDIR=/mnt ./fcntl40 where TMPDIR is a gfs2 mountpoint.
> > > I wonder if we could check for GFS2_MAGIC (we'd need to add it to
> > > include/tst_fs.h => 0x01161970) and quit the test with tst_brk(TCONF) if TMPDIR
> > > is not on gfs2.
>
> > > ATM we don't have any helper in struct tst_test, which would do it.
>
>
> > I will mention that gfs2 is only an example here. It becomes
> > interesting when a file system implements its own .lock() callback OR
> > if somebody wants to test file system core, when a filesystem does not
> > implement its own .lock().
>
> I see .lock is implemented in 9p, afs, ceph, cifs, ocfs2, orangefs, even NFS.
> "file system core": do you mean VFS? Because that would be more usable than the
> filesystems above (which are quite exotic).
>

It depends here what they are doing in .lock() - If they just call
locks_lock_file_wait() or similar helpers depending on the call, then
they don't do much different than what vfs is doing.
In case of gfs2/ocfs it is very special, it redirects their calls to
DLM and DLM has its own whole posix implementation behind it. We only
call locks_lock_file_wait() to keep the Linux bookkeeping in
/proc/locks.

What I am doing here is mostly trusting the Linux implementation and
comparing results from e.g. tmpfs with GFS2 and I found issues.

For now I trust the Linux implementation and check if we have a
different result here. I need to be very careful here because
GFS2/OCFS2 are cluster filesystems and the fcntl() interface was never
made for cluster filesystems. However I currently only test "one node"
locking and this should deliver the same results as tmpfs, etc.

- Alex
Petr Vorel July 7, 2023, 8:14 a.m. UTC | #6
> Hi,

> On Sun, Jul 2, 2023 at 3:18 PM Petr Vorel <pvorel@suse.cz> wrote:

> > Hi Alex,

> > ...
> > > > > + * [Description]
> > > > > + * Tests gfs2 dlm posix op queue handling in the kernel.
> > > > > + * It is recommended to run watch -n 0.1 "dlm_tool plocks $LS"
> > > > > + * aside to monitor dlm plock handling.
> > > > > + *
> > > > > + * [How to use it]
> > > > > + * Call it with TMPDIR=/mnt ./fcntl40 where TMPDIR is a gfs2 mountpoint.
> > > > I wonder if we could check for GFS2_MAGIC (we'd need to add it to
> > > > include/tst_fs.h => 0x01161970) and quit the test with tst_brk(TCONF) if TMPDIR
> > > > is not on gfs2.

> > > > ATM we don't have any helper in struct tst_test, which would do it.


> > > I will mention that gfs2 is only an example here. It becomes
> > > interesting when a file system implements its own .lock() callback OR
> > > if somebody wants to test file system core, when a filesystem does not
> > > implement its own .lock().

> > I see .lock is implemented in 9p, afs, ceph, cifs, ocfs2, orangefs, even NFS.
> > "file system core": do you mean VFS? Because that would be more usable than the
> > filesystems above (which are quite exotic).


> It depends here what they are doing in .lock() - If they just call
> locks_lock_file_wait() or similar helpers depending on the call, then
> they don't do much different than what vfs is doing.
> In case of gfs2/ocfs it is very special, it redirects their calls to
> DLM and DLM has its own whole posix implementation behind it. We only
> call locks_lock_file_wait() to keep the Linux bookkeeping in
> /proc/locks.

> What I am doing here is mostly trusting the Linux implementation and
> comparing results from e.g. tmpfs with GFS2 and I found issues.

> For now I trust the Linux implementation and check if we have a
> different result here. I need to be very careful here because
> GFS2/OCFS2 are cluster filesystems and the fcntl() interface was never
> made for cluster filesystems. However I currently only test "one node"
> locking and this should deliver the same results as tmpfs, etc.

Thanks for info.  I'm still not sure if this is useful only for gfs2/ocfs
and we should prepare block device with gfs2 or ocfs and test filesystem on it.
Or if it would be useful to test other filesystem implementation. In this latter
case we usually use .all_filesystems (we don't have proper docs for
.all_filesystems, the closest is [1]) and test is then run on various common
filesystems (see fs_type_whitelist[] in lib/tst_supported_fs_types.c), but in
that case gfs2 would be skipped (it's not a common filesystem).

In case preparing block device with gfs2 something like this might work:

static struct tst_test test = {
	...
	.dev_fs_type = "gfs2",
	.format_device = 1,
	.dev_fs_opts = (const char *const []){ "-t", "mycluster:mygfs2", "-p", "lock_dlm", "-j" , "2" , NULL},

Kind regards,
Petr

[1] https://github.com/linux-test-project/ltp/wiki/C-Test-API#113-filesystem-type-detection-and-skiplist

> - Alex
Alexander Aring July 7, 2023, 12:50 p.m. UTC | #7
Hi,

On Fri, Jul 7, 2023 at 4:14 AM Petr Vorel <pvorel@suse.cz> wrote:
>
> > Hi,
>
> > On Sun, Jul 2, 2023 at 3:18 PM Petr Vorel <pvorel@suse.cz> wrote:
>
> > > Hi Alex,
>
> > > ...
> > > > > > + * [Description]
> > > > > > + * Tests gfs2 dlm posix op queue handling in the kernel.
> > > > > > + * It is recommended to run watch -n 0.1 "dlm_tool plocks $LS"
> > > > > > + * aside to monitor dlm plock handling.
> > > > > > + *
> > > > > > + * [How to use it]
> > > > > > + * Call it with TMPDIR=/mnt ./fcntl40 where TMPDIR is a gfs2 mountpoint.
> > > > > I wonder if we could check for GFS2_MAGIC (we'd need to add it to
> > > > > include/tst_fs.h => 0x01161970) and quit the test with tst_brk(TCONF) if TMPDIR
> > > > > is not on gfs2.
>
> > > > > ATM we don't have any helper in struct tst_test, which would do it.
>
>
> > > > I will mention that gfs2 is only an example here. It becomes
> > > > interesting when a file system implements its own .lock() callback OR
> > > > if somebody wants to test file system core, when a filesystem does not
> > > > implement its own .lock().
>
> > > I see .lock is implemented in 9p, afs, ceph, cifs, ocfs2, orangefs, even NFS.
> > > "file system core": do you mean VFS? Because that would be more usable than the
> > > filesystems above (which are quite exotic).
>
>
> > It depends here what they are doing in .lock() - If they just call
> > locks_lock_file_wait() or similar helpers depending on the call, then
> > they don't do much different than what vfs is doing.
> > In case of gfs2/ocfs it is very special, it redirects their calls to
> > DLM and DLM has its own whole posix implementation behind it. We only
> > call locks_lock_file_wait() to keep the Linux bookkeeping in
> > /proc/locks.
>
> > What I am doing here is mostly trusting the Linux implementation and
> > comparing results from e.g. tmpfs with GFS2 and I found issues.
>
> > For now I trust the Linux implementation and check if we have a
> > different result here. I need to be very careful here because
> > GFS2/OCFS2 are cluster filesystems and the fcntl() interface was never
> > made for cluster filesystems. However I currently only test "one node"
> > locking and this should deliver the same results as tmpfs, etc.
>
> Thanks for info.  I'm still not sure if this is useful only for gfs2/ocfs
> and we should prepare block device with gfs2 or ocfs and test filesystem on it.
> Or if it would be useful to test other filesystem implementation. In this latter
> case we usually use .all_filesystems (we don't have proper docs for
> .all_filesystems, the closest is [1]) and test is then run on various common
> filesystems (see fs_type_whitelist[] in lib/tst_supported_fs_types.c), but in
> that case gfs2 would be skipped (it's not a common filesystem).
>
> In case preparing block device with gfs2 something like this might work:
>
> static struct tst_test test = {
>         ...
>         .dev_fs_type = "gfs2",
>         .format_device = 1,
>         .dev_fs_opts = (const char *const []){ "-t", "mycluster:mygfs2", "-p", "lock_dlm", "-j" , "2" , NULL},
>

Can I override this setting by some ENV because I actually want to run
it on a different filesystem which is using VFS posix lock
implementation, because as I said I want to compare the results.

- Alex
Petr Vorel July 7, 2023, 1:17 p.m. UTC | #8
> Hi,

> On Fri, Jul 7, 2023 at 4:14 AM Petr Vorel <pvorel@suse.cz> wrote:

> > > Hi,

> > > On Sun, Jul 2, 2023 at 3:18 PM Petr Vorel <pvorel@suse.cz> wrote:

> > > > Hi Alex,

> > > > ...
> > > > > > > + * [Description]
> > > > > > > + * Tests gfs2 dlm posix op queue handling in the kernel.
> > > > > > > + * It is recommended to run watch -n 0.1 "dlm_tool plocks $LS"
> > > > > > > + * aside to monitor dlm plock handling.
> > > > > > > + *
> > > > > > > + * [How to use it]
> > > > > > > + * Call it with TMPDIR=/mnt ./fcntl40 where TMPDIR is a gfs2 mountpoint.
> > > > > > I wonder if we could check for GFS2_MAGIC (we'd need to add it to
> > > > > > include/tst_fs.h => 0x01161970) and quit the test with tst_brk(TCONF) if TMPDIR
> > > > > > is not on gfs2.

> > > > > > ATM we don't have any helper in struct tst_test, which would do it.


> > > > > I will mention that gfs2 is only an example here. It becomes
> > > > > interesting when a file system implements its own .lock() callback OR
> > > > > if somebody wants to test file system core, when a filesystem does not
> > > > > implement its own .lock().

> > > > I see .lock is implemented in 9p, afs, ceph, cifs, ocfs2, orangefs, even NFS.
> > > > "file system core": do you mean VFS? Because that would be more usable than the
> > > > filesystems above (which are quite exotic).


> > > It depends here what they are doing in .lock() - If they just call
> > > locks_lock_file_wait() or similar helpers depending on the call, then
> > > they don't do much different than what vfs is doing.
> > > In case of gfs2/ocfs it is very special, it redirects their calls to
> > > DLM and DLM has its own whole posix implementation behind it. We only
> > > call locks_lock_file_wait() to keep the Linux bookkeeping in
> > > /proc/locks.

> > > What I am doing here is mostly trusting the Linux implementation and
> > > comparing results from e.g. tmpfs with GFS2 and I found issues.

> > > For now I trust the Linux implementation and check if we have a
> > > different result here. I need to be very careful here because
> > > GFS2/OCFS2 are cluster filesystems and the fcntl() interface was never
> > > made for cluster filesystems. However I currently only test "one node"
> > > locking and this should deliver the same results as tmpfs, etc.

> > Thanks for info.  I'm still not sure if this is useful only for gfs2/ocfs
> > and we should prepare block device with gfs2 or ocfs and test filesystem on it.
> > Or if it would be useful to test other filesystem implementation. In this latter
> > case we usually use .all_filesystems (we don't have proper docs for
> > .all_filesystems, the closest is [1]) and test is then run on various common
> > filesystems (see fs_type_whitelist[] in lib/tst_supported_fs_types.c), but in
> > that case gfs2 would be skipped (it's not a common filesystem).

> > In case preparing block device with gfs2 something like this might work:

> > static struct tst_test test = {
> >         ...
> >         .dev_fs_type = "gfs2",
> >         .format_device = 1,
> >         .dev_fs_opts = (const char *const []){ "-t", "mycluster:mygfs2", "-p", "lock_dlm", "-j" , "2" , NULL},


> Can I override this setting by some ENV because I actually want to run
> it on a different filesystem which is using VFS posix lock
> implementation, because as I said I want to compare the results.

Sure, there is LTP_DEV_FS_TYPE. But the point is to write test which will be
useful for the default scenario.

Kind regards,
Petr

> - Alex
diff mbox series

Patch

diff --git a/testcases/kernel/syscalls/fcntl/.gitignore b/testcases/kernel/syscalls/fcntl/.gitignore
index 10cb0995f..e558cfe83 100644
--- a/testcases/kernel/syscalls/fcntl/.gitignore
+++ b/testcases/kernel/syscalls/fcntl/.gitignore
@@ -74,3 +74,5 @@ 
 /fcntl38_64
 /fcntl39
 /fcntl39_64
+/fcntl40
+/fcntl40_64
diff --git a/testcases/kernel/syscalls/fcntl/Makefile b/testcases/kernel/syscalls/fcntl/Makefile
index df663a50a..c3196a527 100644
--- a/testcases/kernel/syscalls/fcntl/Makefile
+++ b/testcases/kernel/syscalls/fcntl/Makefile
@@ -12,6 +12,9 @@  fcntl34_64: LDLIBS += -lpthread
 fcntl36: LDLIBS += -lpthread
 fcntl36_64: LDLIBS += -lpthread
 
+fcntl40: LDLIBS += -lpthread
+fcntl40_64: LDLIBS += -lpthread
+
 include $(top_srcdir)/include/mk/testcases.mk
 include $(abs_srcdir)/../utils/newer_64.mk
 
diff --git a/testcases/kernel/syscalls/fcntl/fcntl40.c b/testcases/kernel/syscalls/fcntl/fcntl40.c
new file mode 100644
index 000000000..829685436
--- /dev/null
+++ b/testcases/kernel/syscalls/fcntl/fcntl40.c
@@ -0,0 +1,188 @@ 
+/*
+ * [Description]
+ * Tests gfs2 dlm posix op queue handling in the kernel.
+ * It is recommended to run watch -n 0.1 "dlm_tool plocks $LS"
+ * aside to monitor dlm plock handling.
+ *
+ * [How to use it]
+ * Call it with TMPDIR=/mnt ./fcntl40 where TMPDIR is a gfs2 mountpoint.
+ * Try it on other filesystems to compare results.
+ *
+ * [What's it doing]
+ *
+ * The test shows that we currently have problems with the operation lookup
+ * functionality [0] when we using threads. The owner value is the same for two
+ * locks being in WAITING state. dlm_controld "dlm_tool plocks $LS" will show
+ * it correctly that the specific lock is not in waiting anymore. The issue
+ * begins matching the right iter->done in the kernel at dev_write() see [0].
+ *
+ * What this test does is (using dlm_controld interval range interpretation):
+ *
+ * parent:
+ *
+ * 1. lock[0-1]
+ *
+ * child:
+ *
+ * thread1:
+ *
+ * 2. lockw[1-1] - important 1-1 at first because the order of WAITING state
+ *                 locks matters
+ *
+ * thread2:
+ *
+ * 3. lockw[0-0]
+ *
+ * parent:
+ *
+ * 4. unlock[1-1] - will give a iter->done = 1 in [0] for lock at 3. and the
+ *                  application results in a deadlock
+ * 5. unlock[0-0]
+ *
+ * We have this issue also with SETLK, GETLK - it's easier to reproduce
+ * with SETLKW because dev_write() is more controlable by doing unlocks.
+ *
+ * OFD (open filedescriptor locks) are also affected and should be able
+ * to reproduce with fork() only and not threads. The owner value of [0]
+ * depends on "struct file *" pointer in this case.
+ *
+ * [0] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/fs/dlm/plock.c?h=v6.3#n432
+ */
+
+#include <sys/wait.h>
+#include <pthread.h>
+
+#include "tst_safe_pthread.h"
+#include "tst_test.h"
+
+static int fd;
+
+static void *do_thread1(void *arg)
+{
+	const struct flock fl_0_0 = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 1L,
+	};
+	(void)arg;
+
+	tst_res(TINFO, "thread1 waits for thread2 to lock 1-1");
+	TST_CHECKPOINT_WAIT(1);
+
+	tst_res(TINFO, "thread1 lock region 0-0 - It should block");
+	SAFE_FCNTL(fd, F_SETLKW, &fl_0_0);
+	tst_res(TINFO, "lock region 0-0 acquired");
+
+	return NULL;
+}
+
+static void *do_thread2(void *arg)
+{
+	const struct flock fl_1_1 = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 1L,
+		.l_len = 1L,
+	};
+	(void)arg;
+
+	tst_res(TINFO, "thread1 lock region 1-1 - It should block");
+	SAFE_FCNTL(fd, F_SETLKW, &fl_1_1);
+	tst_res(TINFO, "lock region 1-1 acquired");
+
+	TST_CHECKPOINT_WAKE(2);
+
+	return NULL;
+}
+
+void do_child(void)
+{
+	pthread_t t1, t2;
+
+	SAFE_PTHREAD_CREATE(&t1, NULL, do_thread1, NULL);
+	SAFE_PTHREAD_CREATE(&t2, NULL, do_thread2, NULL);
+
+	SAFE_PTHREAD_JOIN(t1, NULL);
+	SAFE_PTHREAD_JOIN(t2, NULL);
+
+	tst_res(TPASS, "Child passed!");
+}
+
+void do_parent(void)
+{
+	struct flock fl = {
+		.l_whence = SEEK_SET,
+	};
+
+	/* wait for 1 seconds so thread2 lock 1-1 tries to acquires at first
+	 * than thread1 lock 0-0 tries to acquired to have a specific waiting
+	 * order in dlm posix handling.
+	 */
+	sleep(1);
+	/* tell thread2 to call SETLKW for lock 0-0 */
+	TST_CHECKPOINT_WAKE(1);
+	/* wait 3 seconds for thread 1 and 2 being in waiting state */
+	sleep(3);
+
+	/* unlock 0-1, should be successful */
+	fl.l_type = F_UNLCK;
+	fl.l_start = 1;
+	fl.l_len = 1;
+	tst_res(TINFO, "unlock region 1-1 thread2");
+	SAFE_FCNTL(fd, F_SETLK, &fl);
+
+	/* wait until thread 2 got acquired and leave waiting */
+	TST_CHECKPOINT_WAIT(2);
+
+	fl.l_start = 0;
+	fl.l_len = 1;
+	fl.l_type = F_UNLCK;
+	tst_res(TINFO, "unlock region 0-0 thread2");
+	SAFE_FCNTL(fd, F_SETLK, &fl);
+}
+
+static void fcntl40_test(void)
+{
+	struct flock fl = {
+		.l_type = F_WRLCK,
+		.l_whence = SEEK_SET,
+		.l_start = 0L,
+		.l_len = 2L,
+	};
+	pid_t pid;
+
+	tst_res(TINFO, "parent lock region 0-1 - should be successful");
+	SAFE_FCNTL(fd, F_SETLK, &fl);
+	tst_res(TINFO, "parent region 0-1 locked");
+
+	pid = SAFE_FORK();
+	if (pid == 0) {
+		do_child();
+		return;
+	}
+
+	do_parent();
+	wait(NULL);
+
+	tst_res(TPASS, "Parent passed!");
+}
+
+static void setup(void)
+{
+	fd = SAFE_OPEN("filename", O_RDWR | O_CREAT, 0700);
+}
+
+static void cleanup(void)
+{
+	if (fd > -1)
+		SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.forks_child = 1,
+	.needs_checkpoints = 1,
+	.test_all = fcntl40_test,
+	.setup = setup,
+	.cleanup = cleanup,
+};