The reason flock03 currently fails on both Linux 2.4 and 2.5 is because
it's wrong ;-) I suspect the test author didn't understand flock locks --
they're very different from POSIX locks. flocks are associated with a
file descriptor, but the child process was opening a new file descriptor
and expecting to be able to unlock it. That won't work; you have to
pass the file descriptor to the child from the parent.
This patch does just that. I'm not sure it's exactly what the author
wanted to achieve. I've added the flock06 test too which tests that
flocks on two fds on the same file do conflict with each other.
flock03 still fails. This is due to a real bug in both Linux 2.4 and 2.5.
Andrea's kernel picked up the fix, but Marcelo has declined it. I hope
to fix it properly in 2.5 in the next couple of weeks.
diff -urpN ltp-20030206/testcases/kernel/syscalls/flock/flock03.c ltp-20030206-willy/testcases/kernel/syscalls/flock/flock03.c
--- ltp-20030206/testcases/kernel/syscalls/flock/flock03.c 2003-01-27 16:30:31.000000000 -0600
+++ ltp-20030206-willy/testcases/kernel/syscalls/flock/flock03.c 2003-02-27 15:10:49.000000000 -0600
@@ -74,14 +74,13 @@
void setup(void);
void cleanup(void);
-void childfunc(void);
+void childfunc(int);
char *TCID = "flock03"; /* Test program identifier */
int TST_TOTAL = 3; /* Total number of test cases */
extern int Tst_count;
char filename[100];
-int fd; /* for opening the temporary file */
int main(int argc, char **argv)
{
@@ -89,6 +88,7 @@ int main(int argc, char **argv)
char *msg; /* message returned from parse_opts */
pid_t pid;
int status;
+ int fd; /* for opening the temporary file */
/* parse standard options */
@@ -107,18 +107,19 @@ int main(int argc, char **argv)
/* reset Tst_count in case we are looping */
Tst_count = 0;
+ /* PARENT */
+ fd = open(filename, O_RDWR);
+ if(fd == -1)
+ tst_brkm(TFAIL, cleanup, "parent failed to open the"
+ "file, errno %d", errno);
+
pid = fork();
if(pid == -1)
tst_brkm(TFAIL, cleanup, "fork() failed, errno %d",
errno);
if(pid == 0)
- childfunc();
+ childfunc(fd);
- /* PARENT */
- fd = open(filename, O_RDWR);
- if(fd == -1)
- tst_brkm(TFAIL, cleanup, "parent failed to open the"
- "file, errno %d", errno);
TEST(flock(fd, LOCK_EX | LOCK_NB));
if(TEST_RETURN != 0)
tst_resm(TFAIL, "Parent: Initial attempt to flock() failed, "
@@ -143,33 +144,39 @@ int main(int argc, char **argv)
}
-void childfunc(void )
+void childfunc(int fd)
{
+ int fd2;
/* give the parent a chance to lock the file */
sleep(2);
- fd = open(filename, O_RDWR);
- if(fd == -1)
+ fd2 = open(filename, O_RDWR);
+ if(fd2 == -1)
tst_brkm(TFAIL, cleanup, "child failed to open the"
"file, errno %d", errno);
- if(flock(fd, LOCK_EX | LOCK_NB) != -1)
+ if(flock(fd2, LOCK_EX | LOCK_NB) != -1)
tst_resm(TFAIL, "Child: The file was not already locked");
TEST(flock(fd, LOCK_UN));
+ /* XXX: LOCK_UN does not return an error if there was nothing to
+ * unlock.
+ */
if(TEST_RETURN == -1)
tst_resm(TFAIL, "Child: Unable to unlock file locked by parent, "
"errno %d", TEST_ERRNO);
else
tst_resm(TPASS, "Child: Unlocked file locked by parent");
- TEST(flock(fd, LOCK_EX | LOCK_NB));
+ TEST(flock(fd2, LOCK_EX | LOCK_NB));
if(TEST_RETURN == -1)
tst_resm(TFAIL, "Child: Unable to relock file after unlocking, "
"errno %d", TEST_ERRNO);
else
tst_resm(TPASS, "Child: flock after unlocking passed");
+ close(fd2);
+
tst_exit();
/* NOT REACHED */
return;
@@ -182,6 +189,7 @@ void childfunc(void )
*/
void setup(void)
{
+ int fd;
/* capture signals */
tst_sig(FORK, DEF_HANDLER, cleanup);
diff -urpN ltp-20030206/testcases/kernel/syscalls/flock/flock06.c ltp-20030206-willy/testcases/kernel/syscalls/flock/flock06.c
--- ltp-20030206/testcases/kernel/syscalls/flock/flock06.c 1969-12-31 18:00:00.000000000 -0600
+++ ltp-20030206-willy/testcases/kernel/syscalls/flock/flock06.c 2003-02-27 15:08:45.000000000 -0600
@@ -0,0 +1,206 @@
+/*
+ *
+ * Copyright (c) Matthew Wilcox for Hewlett Packard 2003
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will 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 to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/**********************************************************
+ *
+ * TEST IDENTIFIER : flock06
+ *
+ * EXECUTED BY : anyone
+ *
+ * TEST TITLE : Error condition test for flock(2)
+ *
+ * TEST CASE TOTAL : 1
+ *
+ * AUTHOR : Matthew Wilcox <willy@...>
+ *
+ * SIGNALS
+ * Uses SIGUSR1 to pause before test if option set.
+ * (See the parse_opts(3) man page).
+ *
+ * DESCRIPTION
+ * This test verifies that flock locks held on one fd conflict with
+ * flock locks held on a different fd.
+ *
+ * Test:
+ * The process opens two file descriptors on the same file.
+ * It acquires an exclusive flock on the first descriptor,
+ * checks that attempting to acquire an flock on the second
+ * descriptor fails. Then it removes the first descriptor's
+ * lock and attempts to acquire an exclusive lock on the
+ * second descriptor.
+ *
+ * USAGE: <for command-line>
+ * flock06 [-c n] [-e] [-i n] [-I x] [-P x] [-t] [-h] [-f] [-p]
+ * where, -c n : Run n copies concurrently
+ * -f : Turn off functional testing
+ * -e : Turn on errno logging
+ * -h : Show help screen
+ * -i n : Execute test n times
+ * -I x : Execute test for x seconds
+ * -p : Pause for SIGUSR1 before starting
+ * -P x : Pause for x seconds between iterations
+ * -t : Turn on syscall timing
+ *
+ ****************************************************************/
+
+
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/wait.h>
+#include "test.h"
+#include "usctest.h"
+
+void setup(void);
+void cleanup(void);
+
+
+char *TCID = "flock06"; /* Test program identifier */
+int TST_TOTAL = 3; /* Total number of test cases */
+extern int Tst_count;
+char filename[100];
+
+int main(int argc, char **argv)
+{
+ int lc; /* loop counter */
+ char *msg; /* message returned from parse_opts */
+
+ /* parse standard options */
+ if ((msg = parse_opts(argc, argv, (option_t *)NULL, NULL)) !=
+ (char *) NULL) {
+ tst_brkm(TBROK, cleanup, "OPTION PARSING ERROR - %s", msg);
+ /*NOTREACHED*/
+ }
+
+ setup();
+
+ /* The following loop checks looping state if -i option given */
+
+ for (lc = 0; TEST_LOOPING(lc); lc++) {
+ int fd1, fd2;
+
+ /* reset Tst_count in case we are looping */
+ Tst_count = 0;
+
+ fd1 = open(filename, O_RDWR);
+ if (fd1 == -1)
+ tst_brkm(TFAIL, cleanup, "failed to open the"
+ "file, errno %d", errno);
+
+ TEST(flock(fd1, LOCK_EX | LOCK_NB));
+ if (TEST_RETURN != 0)
+ tst_resm(TFAIL, "First attempt to flock() failed, "
+ "errno %d",TEST_ERRNO);
+ else
+ tst_resm(TPASS, "First attempt to flock() passed");
+
+ fd2 = open(filename, O_RDWR);
+ if (fd2 == -1)
+ tst_brkm(TFAIL, cleanup, "failed to open the"
+ "file, errno %d", errno);
+
+ TEST(flock(fd2, LOCK_EX | LOCK_NB));
+ if (TEST_RETURN == -1)
+ tst_resm(TPASS, "Second attempt to flock() denied");
+ else
+ tst_resm(TFAIL, "Second attempt to flock() succeeded!");
+
+ TEST(flock(fd1, LOCK_UN));
+ if (TEST_RETURN == -1)
+ tst_resm(TFAIL, "Failed to unlock fd1, errno %d",
+ TEST_ERRNO);
+ else
+ tst_resm(TPASS, "Unlocked fd1");
+
+ TEST(flock(fd2, LOCK_EX | LOCK_NB));
+ if (TEST_RETURN == -1)
+ tst_resm(TFAIL, "Third attempt to flock() denied!");
+ else
+ tst_resm(TPASS, "Third attempt to flock() succeeded");
+
+ }/* End of TEST_LOOPING */
+
+ cleanup();
+
+ return 0;
+
+}
+
+
+/*
+ * setup()
+ * performs all ONE TIME setup for this test
+ */
+void setup(void)
+{
+ int fd;
+ /* capture signals */
+ tst_sig(FORK, DEF_HANDLER, cleanup);
+
+ /* Pause if that option was specified
+ * TEST_PAUSE contains the code to fork the test with the -i option.
+ * You want to make sure you do this before you create your temporary
+ * directory.
+ */
+ TEST_PAUSE;
+
+ /* Create a unique temporary directory and chdir() to it. */
+ tst_tmpdir();
+
+ sprintf(filename, "flock06.%d", getpid());
+
+ /* creating temporary file */
+ fd = creat(filename, 0666);
+ if (fd < 0) {
+ tst_resm(TFAIL, "creating a new file failed");
+
+ TEST_CLEANUP;
+
+ /* Removing temp dir */
+ tst_rmdir();
+
+ /* exit with return code appropriate for result */
+ tst_exit();
+ }
+}
+
+/*
+ * cleanup()
+ * performs all ONE TIME cleanup for this test at
+ * completion or premature exit
+ */
+void cleanup(void)
+{
+ /*
+ * print timing stats if that option was specified.
+ * print errno log if that option was specified.
+ */
+ TEST_CLEANUP;
+
+ unlink(filename);
+ tst_rmdir();
+
+ /* exit with return code appropriate for results */
+ tst_exit();
+ /*NOTREACHED*/
+}
--
"It's not Hollywood. War is real, war is primarily not about defeat or
victory, it is about death. I've seen thousands and thousands of dead bodies.
Do you think I want to have an academic debate on this subject?" -- Robert Fisk
|