aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXiong Zhou <xzhou@redhat.com>2018-04-23 10:42:48 +0800
committerEryu Guan <guaneryu@gmail.com>2018-04-27 19:06:48 +0800
commit7bc26faa6b52a2035f659c90a2833a453a18bace (patch)
tree381c5998eb4095743c85e0af0805d52be594f2b3
parenta6f6336df750d37b06f572564cbe767cc4837bb5 (diff)
downloadxfstests-dev-7bc26faa6b52a2035f659c90a2833a453a18bace.tar.gz
generic: test record locks across execve in multithread process
POSIX requires that record locks are preserved across an execve(2). But currently the locks are released if process is multithreaded at the time that execve is called. As Jeff Layton wrote in his patch: " In that case, we'll end up unsharing the files_struct but the locks will still have their fl_owner set to the address of the old one. Eventually, when the other threads die and the last reference to the old files_struct is put, any POSIX locks get torn down since it looks like a close occurred on them. The result is that all of your open files will be intact with none of the locks you held before execve. " Add a new regression test for this particular case. [Eryu: rewrite commit log and test description] Signed-off-by: Xiong Zhou <xzhou@redhat.com> Reviewed-by: Eryu Guan <guaneryu@gmail.com> Signed-off-by: Eryu Guan <guaneryu@gmail.com>
-rw-r--r--.gitignore1
-rw-r--r--src/Makefile2
-rw-r--r--src/t_locks_execve.c77
-rwxr-xr-xtests/generic/48465
-rw-r--r--tests/generic/484.out2
-rw-r--r--tests/generic/group1
6 files changed, 147 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index 368d11c84a..192ca35e15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -121,6 +121,7 @@
/src/t_getcwd
/src/t_holes
/src/t_immutable
+/src/t_locks_execve
/src/t_mmap_cow_race
/src/t_mmap_dio
/src/t_mmap_fallocate
diff --git a/src/Makefile b/src/Makefile
index 0d3feae1ee..6ca5636639 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -15,7 +15,7 @@ TARGETS = dirstress fill fill2 getpagesize holes lstat64 \
holetest t_truncate_self t_mmap_dio af_unix t_mmap_stale_pmd \
t_mmap_cow_race t_mmap_fallocate fsync-err t_mmap_write_ro \
t_ext4_dax_journal_corruption t_ext4_dax_inline_corruption \
- t_ofd_locks
+ t_ofd_locks t_locks_execve
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/t_locks_execve.c b/src/t_locks_execve.c
new file mode 100644
index 0000000000..9ad2dc370d
--- /dev/null
+++ b/src/t_locks_execve.c
@@ -0,0 +1,77 @@
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+#include <stdio.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+static void err_exit(char *op, int errn)
+{
+ fprintf(stderr, "%s: %s\n", op, strerror(errn));
+ exit(errn);
+}
+
+void *thread_fn(void *arg)
+{
+ /* execve will release threads */
+ while(1) sleep(1);
+ return NULL;
+}
+
+struct flock fl = {
+ .l_type = F_WRLCK,
+ .l_whence = SEEK_SET,
+ .l_start = 0,
+ .l_len = 1,
+};
+
+static void checklock(int fd)
+{
+ if (fcntl(fd, F_GETLK, &fl) < 0)
+ err_exit("getlk", errno);
+ if (fl.l_type == F_UNLCK) {
+ printf("record lock is not preserved across execve(2)\n");
+ exit(1);
+ }
+ exit(0);
+}
+
+int main(int argc, char **argv)
+{
+ int fd, flags;
+ char fdstr[10];
+ char *newargv[] = { argv[0], argv[1], fdstr, NULL };
+ pthread_t th;
+
+ /* passing fd in argv[2] in execve */
+ if (argc == 3) {
+ fd = atoi(argv[2]);
+ checklock(fd);
+ exit(0);
+ }
+
+ fd = open(argv[1], O_WRONLY|O_CREAT, 0755);
+ if (fd < 0)
+ err_exit("open", errno);
+ if (fcntl(fd, F_SETLK, &fl) < 0)
+ err_exit("setlk", errno);
+
+ /* require multithread process to reproduce the issue */
+ pthread_create(&th, NULL, thread_fn, &fd);
+
+ if ((flags = fcntl(fd, F_GETFD)) < 0)
+ err_exit("getfd", errno);
+ flags &= ~FD_CLOEXEC;
+ if (fcntl(fd, F_SETFD, flags) < 0)
+ err_exit("setfd", errno);
+
+ snprintf(fdstr, sizeof(fdstr), "%d", fd);
+ execve(argv[0], newargv, NULL);
+
+ return 0;
+}
diff --git a/tests/generic/484 b/tests/generic/484
new file mode 100755
index 0000000000..1c2cd96244
--- /dev/null
+++ b/tests/generic/484
@@ -0,0 +1,65 @@
+#! /bin/bash
+# FS QA Test 484
+#
+# POSIX requires that record locks are preserved across an execve(2). But
+# there's bug that record locks are released if process is multithreaded at the
+# time that execve is called.
+#
+# Fixed by patch from Jeff Layton:
+# locks: change POSIX lock ownership on execve when files_struct is displaced
+#
+#-----------------------------------------------------------------------
+# Copyright (c) 2018 Red Hat Inc. All Rights Reserved.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it would be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+#-----------------------------------------------------------------------
+#
+
+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
+_supported_fs generic
+_supported_os Linux
+_require_test
+
+# prepare a 4k testfile in TEST_DIR
+$XFS_IO_PROG -f -c "pwrite -S 0xFF 0 4096" \
+ $TEST_DIR/t_lock_execve_file >> $seqres.full 2>&1
+
+$here/src/t_locks_execve $TEST_DIR/t_lock_execve_file
+
+# success, all done
+echo "Silence is golden"
+status=0
+exit
diff --git a/tests/generic/484.out b/tests/generic/484.out
new file mode 100644
index 0000000000..94f2f0bd73
--- /dev/null
+++ b/tests/generic/484.out
@@ -0,0 +1,2 @@
+QA output created by 484
+Silence is golden
diff --git a/tests/generic/group b/tests/generic/group
index ea8e51b35e..19be9267af 100644
--- a/tests/generic/group
+++ b/tests/generic/group
@@ -486,3 +486,4 @@
481 auto quick log metadata
482 auto metadata replay
483 auto quick log metadata
+484 auto quick