Re: [PATCHv2] generic: add fcntl corner cases tests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Feb 09, 2024 at 07:43:10PM +0800, Zorro Lang wrote:
> On Thu, Feb 08, 2024 at 11:35:06PM -0600, Steve French wrote:
> > Could you forward the changeset for this so we could try it?
> 
> Hi Steve,
> 
> Thanks for your reply. Sure, there's a temporary branch "patches-in-queue",
> you can get it by:
>   # git clone -b patches-in-queue git://git.kernel.org/pub/scm/fs/xfs/xfstests-dev.git
> 
> Then you can see a generic/740 test case in it, run it on cifs. I tested
> with cifs 3.11, and wrote the /etc/samba/smb.conf as:
>   [TEST_dev]
>   path = $dir
>   writable = yes
>   ea support = yes
>   strict allocate = yes
> And set:
>   MOUNT_OPTIONS="-o vers=3.11,mfsymlinks,username=root,password=xxxxxxxxxx"
>   TEST_FS_MOUNT_OPTS="-o vers=3.11,mfsymlinks,username=root,password=xxxxxxxx"
> 
> I'm not sure if it's a cifs issue, Alexander writes this case for gfs2, it
> works for other fs, but blocked (until kill it manually) on cifs. So hope
> to get some suggestions from cifs list.

Hi Steve,

Any feedback about this? Just to make sure if it's a cifs bug or a case issue.

Thanks,
Zorro

> 
> Thanks,
> Zorro
> 
> > 
> > On Thu, Feb 8, 2024 at 11:26 PM Zorro Lang <zlang@xxxxxxxxxx> wrote:
> > >
> > > On Mon, Sep 25, 2023 at 04:18:27PM -0400, Alexander Aring wrote:
> > > > This patch adds fcntl corner cases that was being used to confirm issues
> > > > on a GFS2 filesystem. The GFS2 filesystem has it's own ->lock()
> > > > implementation and in those corner cases issues was being found and
> > > > fixed.
> > > >
> > > > Signed-off-by: Alexander Aring <aahringo@xxxxxxxxxx>
> > > > ---
> > >
> > > Hi Alexander,
> > >
> > > This test case directly hang on CIFS testing. Actually it's not a
> > > real hang, the fcntl_lock_corner_tests process can be killed, but
> > > before killing it manually, it was blocked there.
> > >
> > > Please check if it's a case issue or cifs bug, or it's not suitable
> > > for cifs? I'll try to delay this patch merging to next release,
> > > leave some time to have a discission. CC cifs list to get more
> > > reviewing.
> > >
> > > Thanks,
> > > Zorro
> > >
> > > FSTYP         -- cifs
> > > PLATFORM      -- Linux/ppc64le ibm-xxx-xxx-xxxx 6.8.0-rc3+ #1 SMP Wed Feb  7 01:38:35 EST 2024
> > > MKFS_OPTIONS  -- //xxx-xxx-xx-xxxx.xxxx.xxx.com/SCRATCH_dev
> > > MOUNT_OPTIONS -- -o vers=3.11,mfsymlinks,username=root,password=redhat -o context=system_u:object_r:root_t:s0 //xxx-xxx-xx-xxxx.xxxx.xxx.com/SCRATCH_dev /mnt/xfstests/scratch/cifs-client
> > >
> > > generic/740
> > > ...
> > > ...
> > >
> > > # ps axu|grep fcntl
> > > root     1138909  0.0  0.0   5056     0 ?        S    Feb07   0:00 /var/lib/xfstests/src/fcntl_lock_corner_tests /mnt/xfstests/test/cifs-client/testfile
> > > root     1138910  0.0  0.0  21760     0 ?        Sl   Feb07   0:00 /var/lib/xfstests/src/fcntl_lock_corner_tests /mnt/xfstests/test/cifs-client/testfile
> > > # cat /proc/1138909/stack
> > > [<0>] 0xc00000008d068a00
> > > [<0>] __switch_to+0x13c/0x228
> > > [<0>] do_wait+0x15c/0x224
> > > [<0>] kernel_wait4+0xb8/0x2c8
> > > [<0>] system_call_exception+0x134/0x390
> > > [<0>] system_call_vectored_common+0x15c/0x2ec
> > > # cat /proc/1138910/stack
> > > [<0>] 0xc00000008de94400
> > > [<0>] __switch_to+0x13c/0x228
> > > [<0>] futex_wait_queue+0xa8/0x134
> > > [<0>] __futex_wait+0xb4/0x15c
> > > [<0>] futex_wait+0x94/0x150
> > > [<0>] do_futex+0xe8/0x374
> > > [<0>] sys_futex+0xa4/0x234
> > > [<0>] system_call_exception+0x134/0x390
> > > [<0>] system_call_vectored_common+0x15c/0x2ec
> > >
> > > # strace -p 1138909
> > > strace: Process 1138909 attached
> > > wait4(-1,
> > > (nothing more output)
> > > strace: Process 1138909 detached
> > > ^C <detached ...>
> > > # strace -p 1138910
> > > strace: Process 1138910 attached
> > > futex(0x7fff97a8f110, FUTEX_WAIT_BITSET|FUTEX_CLOCK_REALTIME, 1138912, NULL, FUTEX_BITSET_MATCH_ANY
> > > (nothing more output)
> > > ^Cstrace: Process 1138910 detached
> > >  <detached ...>
> > >
> > >
> > > > changes since v2:
> > > > - move fcntl tests into one fcntl c file
> > > > - remove ofd and same owner tests, should be reflected by only one test
> > > > - simplify commit message (remove testname out of it)
> > > > - add error messages in fcntl.c to give more information if an error
> > > >   occur
> > > >
> > > >  src/Makefile          |   3 +-
> > > >  src/fcntl.c           | 322 ++++++++++++++++++++++++++++++++++++++++++
> > > >  tests/generic/732     |  32 +++++
> > > >  tests/generic/732.out |   2 +
> > > >  4 files changed, 358 insertions(+), 1 deletion(-)
> > > >  create mode 100644 src/fcntl.c
> > > >  create mode 100755 tests/generic/732
> > > >  create mode 100644 tests/generic/732.out
> > > >
> > > > diff --git a/src/Makefile b/src/Makefile
> > > > index 2815f919..67f936d3 100644
> > > > --- a/src/Makefile
> > > > +++ b/src/Makefile
> > > > @@ -19,7 +19,8 @@ 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 rewinddir-test
> > > > +     t_mmap_cow_memory_failure fake-dump-rootino dio-buf-fault rewinddir-test \
> > > > +     fcntl
> > > >
> > > >  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.c b/src/fcntl.c
> > > > new file mode 100644
> > > > index 00000000..8e375357
> > > > --- /dev/null
> > > > +++ b/src/fcntl.c
> > > > @@ -0,0 +1,322 @@
> > > > +// SPDX-License-Identifier: GPL-2.0+
> > > > +/* Copyright (c) 2023 Alexander Aring.  All Rights Reserved.
> > > > + */
> > > > +
> > > > +#include <pthread.h>
> > > > +#include <unistd.h>
> > > > +#include <string.h>
> > > > +#include <limits.h>
> > > > +#include <stdlib.h>
> > > > +#include <errno.h>
> > > > +#include <fcntl.h>
> > > > +#include <stdio.h>
> > > > +#include <wait.h>
> > > > +
> > > > +static char filename[PATH_MAX + 1];
> > > > +static int fd;
> > > > +
> > > > +static void usage(char *name, const char *msg)
> > > > +{
> > > > +     printf("Fatal: %s\nUsage:\n"
> > > > +            "%s <file for fcntl>\n", msg, name);
> > > > +     _exit(1);
> > > > +}
> > > > +
> > > > +static void *do_equal_file_lock_thread(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) {
> > > > +            perror("fcntl");
> > > > +            _exit(1);
> > > > +       }
> > > > +
> > > > +       return NULL;
> > > > +}
> > > > +
> > > > +static void do_test_equal_file_lock(void)
> > > > +{
> > > > +     struct flock fl;
> > > > +     pthread_t t[2];
> > > > +     int pid, rv;
> > > > +
> > > > +     fl.l_type = F_WRLCK;
> > > > +     fl.l_whence = SEEK_SET;
> > > > +     fl.l_start = 0L;
> > > > +     fl.l_len = 1L;
> > > > +
> > > > +     /* acquire range 0-0 */
> > > > +     rv = fcntl(fd, F_SETLK, &fl);
> > > > +     if (rv == -1) {
> > > > +            perror("fcntl");
> > > > +             _exit(1);
> > > > +     }
> > > > +
> > > > +     pid = fork();
> > > > +     if (pid == 0) {
> > > > +             rv = pthread_create(&t[0], NULL, do_equal_file_lock_thread, NULL);
> > > > +             if (rv != 0) {
> > > > +                     fprintf(stderr, "failed to create pthread\n");
> > > > +                     _exit(1);
> > > > +             }
> > > > +
> > > > +             rv = pthread_create(&t[1], NULL, do_equal_file_lock_thread, NULL);
> > > > +             if (rv != 0) {
> > > > +                     fprintf(stderr, "failed to create pthread\n");
> > > > +                     _exit(1);
> > > > +             }
> > > > +
> > > > +             pthread_join(t[0], NULL);
> > > > +             pthread_join(t[1], NULL);
> > > > +
> > > > +             _exit(0);
> > > > +     }
> > > > +
> > > > +     /* wait until threads block on 0-0 */
> > > > +     sleep(3);
> > > > +
> > > > +     fl.l_type = F_UNLCK;
> > > > +     fl.l_start = 0;
> > > > +     fl.l_len = 1;
> > > > +     rv = fcntl(fd, F_SETLK, &fl);
> > > > +     if (rv == -1) {
> > > > +             perror("fcntl");
> > > > +             _exit(1);
> > > > +     }
> > > > +
> > > > +     sleep(3);
> > > > +
> > > > +     /* check if the ->lock() implementation got the
> > > > +      * right locks granted 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) {
> > > > +             fprintf(stderr, "deadlock, pthread not cleaned up correctly\n");
> > > > +             _exit(1);
> > > > +     }
> > > > +
> > > > +     wait(NULL);
> > > > +}
> > > > +
> > > > +static void catch_alarm(int num) { }
> > > > +
> > > > +static void do_test_signal_interrupt_child(int *pfd)
> > > > +{
> > > > +     struct sigaction act;
> > > > +     unsigned char m;
> > > > +     struct flock fl;
> > > > +     int rv;
> > > > +
> > > > +     fl.l_type = F_WRLCK;
> > > > +     fl.l_whence = SEEK_SET;
> > > > +     fl.l_start = 1;
> > > > +     fl.l_len = 1;
> > > > +
> > > > +     rv = fcntl(fd, F_SETLK, &fl);
> > > > +     if (rv == -1) {
> > > > +             perror("fcntl");
> > > > +             _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_type = F_WRLCK;
> > > > +     fl.l_whence = SEEK_SET;
> > > > +     fl.l_start = 0;
> > > > +     fl.l_len = 1;
> > > > +
> > > > +     /* interrupt SETLKW by signal in 3 secs */
> > > > +     alarm(3);
> > > > +     rv = fcntl(fd, F_SETLKW, &fl);
> > > > +     if (rv == 0) {
> > > > +             fprintf(stderr, "fcntl interrupt successful but should fail with EINTR\n");
> > > > +             _exit(1);
> > > > +     }
> > > > +
> > > > +     /* synchronize to move parent to test region 1-1 */
> > > > +     write(pfd[1], &m, sizeof(m));
> > > > +
> > > > +     /* keep child alive */
> > > > +     read(pfd[1], &m, sizeof(m));
> > > > +}
> > > > +
> > > > +static void do_test_signal_interrupt(void)
> > > > +{
> > > > +     struct flock fl;
> > > > +     unsigned char m;
> > > > +     int pid, rv;
> > > > +     int pfd[2];
> > > > +
> > > > +     rv = pipe(pfd);
> > > > +     if (rv == -1) {
> > > > +             perror("pipe");
> > > > +             _exit(1);
> > > > +     }
> > > > +
> > > > +     fl.l_type = F_WRLCK;
> > > > +     fl.l_whence = SEEK_SET;
> > > > +     fl.l_start = 0;
> > > > +     fl.l_len = 1;
> > > > +
> > > > +     rv = fcntl(fd, F_SETLK, &fl);
> > > > +     if (rv == -1) {
> > > > +             perror("fcntl");
> > > > +             _exit(1);
> > > > +     }
> > > > +
> > > > +     pid = fork();
> > > > +     if (pid == 0) {
> > > > +             do_test_signal_interrupt_child(pfd);
> > > > +             _exit(0);
> > > > +     }
> > > > +
> > > > +     /* wait until child writes */
> > > > +     read(pfd[0], &m, sizeof(m));
> > > > +
> > > > +     fl.l_type = F_WRLCK;
> > > > +     fl.l_whence = SEEK_SET;
> > > > +     fl.l_start = 1;
> > > > +     fl.l_len = 1;
> > > > +     /* 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.
> > > > +      */
> > > > +     rv = fcntl(fd, F_SETLK, &fl);
> > > > +     if (rv == 0) {
> > > > +             fprintf(stderr, "fcntl trylock successful but should fail because child still acquires region\n");
> > > > +             _exit(1);
> > > > +     }
> > > > +
> > > > +     write(pfd[0], &m, sizeof(m));
> > > > +
> > > > +     wait(NULL);
> > > > +
> > > > +     close(pfd[0]);
> > > > +     close(pfd[1]);
> > > > +
> > > > +     /* cleanup everything */
> > > > +     fl.l_type = F_UNLCK;
> > > > +     fl.l_whence = SEEK_SET;
> > > > +     fl.l_start = 0;
> > > > +     fl.l_len = 2;
> > > > +     rv = fcntl(fd, F_SETLK, &fl);
> > > > +     if (rv == -1) {
> > > > +             perror("fcntl");
> > > > +             _exit(1);
> > > > +     }
> > > > +}
> > > > +
> > > > +static void do_test_kill_child(void)
> > > > +{
> > > > +     struct flock fl;
> > > > +     int rv;
> > > > +
> > > > +     fl.l_type = F_WRLCK;
> > > > +     fl.l_whence = SEEK_SET;
> > > > +     fl.l_start = 0;
> > > > +     fl.l_len = 1;
> > > > +
> > > > +     rv = fcntl(fd, F_SETLKW, &fl);
> > > > +     if (rv == -1) {
> > > > +             perror("fcntl");
> > > > +             _exit(1);
> > > > +     }
> > > > +}
> > > > +
> > > > +static void do_test_kill(void)
> > > > +{
> > > > +     struct flock fl;
> > > > +     int pid_to_kill;
> > > > +     int rv;
> > > > +
> > > > +     fl.l_type = F_WRLCK;
> > > > +     fl.l_whence = SEEK_SET;
> > > > +     fl.l_start = 0;
> > > > +     fl.l_len = 1;
> > > > +
> > > > +     rv = fcntl(fd, F_SETLK, &fl);
> > > > +     if (rv == -1) {
> > > > +             perror("fcntl");
> > > > +             _exit(1);
> > > > +     }
> > > > +
> > > > +     pid_to_kill = fork();
> > > > +     if (pid_to_kill == 0) {
> > > > +             do_test_kill_child();
> > > > +             _exit(0);
> > > > +     }
> > > > +
> > > > +     /* wait until child blocks */
> > > > +     sleep(3);
> > > > +
> > > > +     kill(pid_to_kill, SIGKILL);
> > > > +
> > > > +     /* wait until Linux did plock cleanup */
> > > > +     sleep(3);
> > > > +
> > > > +     fl.l_type = F_UNLCK;
> > > > +     fl.l_whence = SEEK_SET;
> > > > +     fl.l_start = 0;
> > > > +     fl.l_len = 1;
> > > > +
> > > > +     /* cleanup parent lock */
> > > > +     rv = fcntl(fd, F_SETLK, &fl);
> > > > +     if (rv == -1) {
> > > > +             perror("fcntl");
> > > > +             _exit(1);
> > > > +     }
> > > > +
> > > > +     fl.l_type = F_WRLCK;
> > > > +     fl.l_whence = SEEK_SET;
> > > > +     fl.l_start = 0;
> > > > +     fl.l_len = 1;
> > > > +
> > > > +     /* check if the child still holds the lock
> > > > +      * and killing the child was not cleaning
> > > > +      * up locks.
> > > > +      */
> > > > +     rv = fcntl(fd, F_SETLK, &fl);
> > > > +     if ((rv == -1 && errno == EAGAIN)) {
> > > > +             fprintf(stderr, "fcntl trylock failed but should be successful because killing child should cleanup acquired lock\n");
> > > > +             _exit(1);
> > > > +     }
> > > > +}
> > > > +
> > > > +int main(int argc, char * const argv[])
> > > > +{
> > > > +     if (optind != argc - 1)
> > > > +             usage(argv[0], "<file for fcntl> is mandatory to tell the file where to run fcntl() on it");
> > > > +
> > > > +     strncpy(filename, argv[1], PATH_MAX);
> > > > +
> > > > +     fd = open(filename, O_RDWR | O_CREAT, 0700);
> > > > +     if (fd == -1) {
> > > > +             perror("open");
> > > > +             _exit(1);
> > > > +     }
> > > > +
> > > > +     /* test to have to equal struct file_lock requests in ->lock() */
> > > > +     do_test_equal_file_lock();
> > > > +     /* test to interrupt F_SETLKW by a signal and cleanup only canceled the pending interrupted request */
> > > > +     do_test_signal_interrupt();
> > > > +     /* test if cleanup is correct if a child gets killed while being blocked in F_SETLKW */
> > > > +     do_test_kill();
> > > > +
> > > > +     close(fd);
> > > > +
> > > > +     return 0;
> > > > +}
> > > > diff --git a/tests/generic/732 b/tests/generic/732
> > > > new file mode 100755
> > > > index 00000000..d77f9fc2
> > > > --- /dev/null
> > > > +++ b/tests/generic/732
> > > > @@ -0,0 +1,32 @@
> > > > +#! /bin/bash
> > > > +# SPDX-License-Identifier: GPL-2.0
> > > > +# Copyright (c) 2023 Alexander Aring.  All Rights Reserved.
> > > > +#
> > > > +# FS QA Test 732
> > > > +#
> > > > +# This tests performs some fcntl() corner cases. See fcntl test
> > > > +# program for more details.
> > > > +#
> > > > +. ./common/preamble
> > > > +_begin_fstest auto
> > > > +
> > > > +# Import common functions.
> > > > +. ./common/filter
> > > > +
> > > > +# real QA test starts here
> > > > +
> > > > +# Modify as appropriate.
> > > > +_supported_fs generic
> > > > +_require_test
> > > > +_require_test_program fcntl
> > > > +
> > > > +echo "Silence is golden"
> > > > +
> > > > +$here/src/fcntl $TEST_DIR/testfile
> > > > +if [ $? -ne 0 ]
> > > > +then
> > > > +     exit
> > > > +fi
> > > > +
> > > > +status=0
> > > > +exit
> > > > diff --git a/tests/generic/732.out b/tests/generic/732.out
> > > > new file mode 100644
> > > > index 00000000..451f82ce
> > > > --- /dev/null
> > > > +++ b/tests/generic/732.out
> > > > @@ -0,0 +1,2 @@
> > > > +QA output created by 732
> > > > +Silence is golden
> > > > --
> > > > 2.31.1
> > > >
> > >
> > >
> > 
> > 
> > -- 
> > Thanks,
> > 
> > Steve
> > 




[Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux