s4: torture: Ensure kernel oplock test can't hang in pause().
authorJeremy Allison <jra@samba.org>
Wed, 15 Nov 2017 18:12:06 +0000 (10:12 -0800)
committerJeremy Allison <jra@samba.org>
Thu, 16 Nov 2017 21:27:06 +0000 (22:27 +0100)
Use an alarm to break out of waiting for a signal.

BUG: https://bugzilla.samba.org/show_bug.cgi?id=13121

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Andreas Schneider <asn@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Thu Nov 16 22:27:06 CET 2017 on sn-devel-144

source4/torture/smb2/oplock.c

index 1830a017e8370601e25b72c27b1231fa42f8ca59..b6d9f842336c29cefaf4b6da515caa4a88687be2 100644 (file)
@@ -4817,6 +4817,17 @@ static void got_rt_break(int sig)
        got_break = 1;
 }
 
+static int got_alarm;
+
+/*
+ * Signal handler.
+ */
+
+static void got_alarm_fn(int sig)
+{
+       got_alarm = 1;
+}
+
 /*
  * Child process function.
  */
@@ -4835,6 +4846,13 @@ static int do_child_process(int pipefd, const char *name)
        if (ret == -1) {
                return 1;
        }
+       /* Set up a signal handler for SIGALRM. */
+       ZERO_STRUCT(act);
+       act.sa_handler = got_alarm_fn;
+       ret = sigaction(SIGALRM, &act, NULL);
+       if (ret == -1) {
+               return 1;
+       }
        /* Open the passed in file and get a kernel oplock. */
        fd = open(name, O_RDWR, 0666);
        if (fd == -1) {
@@ -4857,16 +4875,26 @@ static int do_child_process(int pipefd, const char *name)
                return 5;
        }
 
+       /* Ensure the pause doesn't hang forever. */
+       alarm(5);
+
        /* Wait for RT_SIGNAL_LEASE. */
        ret = pause();
        if (ret != -1 || errno != EINTR) {
                return 6;
        }
 
+       if (got_alarm == 1) {
+               return 10;
+       }
+
        if (got_break != 1) {
                return 7;
        }
 
+       /* Cancel any pending alarm. */
+       alarm(0);
+
        /* Force the server to wait for 3 seconds. */
        sleep(3);
 
@@ -4928,6 +4956,23 @@ static bool wait_for_child_oplock(struct torture_context *tctx,
 }
 #endif
 
+static void child_sig_term_handler(struct tevent_context *ev,
+                               struct tevent_signal *se,
+                               int signum,
+                               int count,
+                               void *siginfo,
+                               void *private_data)
+{
+       int *pstatus = (int *)private_data;
+       int status;
+       wait(&status);
+       if (WIFEXITED(status)) {
+               *pstatus = WEXITSTATUS(status);
+       } else {
+               *pstatus = status;
+       }
+}
+
 /*
  * Deal with a non-smbd process holding a kernel oplock.
  */
@@ -4944,6 +4989,8 @@ static bool test_smb2_kernel_oplocks8(struct torture_context *tctx,
        struct smb2_handle h1 = {{0}};
        struct smb2_handle h2 = {{0}};
        const char *localdir = torture_setting_string(tctx, "localdir", NULL);
+       struct tevent_signal *se = NULL;
+       int child_exit_code = -1;
        time_t start;
        time_t end;
 
@@ -4963,6 +5010,14 @@ static bool test_smb2_kernel_oplocks8(struct torture_context *tctx,
        smb2_util_close(tree, h1);
        ZERO_STRUCT(h1);
 
+       se = tevent_add_signal(tctx->ev,
+                               tctx,
+                               SIGCHLD,
+                               0,
+                               child_sig_term_handler,
+                               &child_exit_code);
+       torture_assert(tctx, se != NULL, "tevent_add_signal failed\n");
+
        /* Take the oplock locally in a sub-process. */
        ret = wait_for_child_oplock(tctx, localdir, fname);
        torture_assert_goto(tctx, ret = true, ret, done,
@@ -5013,6 +5068,18 @@ static bool test_smb2_kernel_oplocks8(struct torture_context *tctx,
                        "Error opening the file\n");
        h2 = io.out.file.handle;
 
+       /* Wait for the exit code from the child. */
+       while (child_exit_code == -1) {
+               int rval = tevent_loop_once(tctx->ev);
+               torture_assert(tctx, rval == 0, "tevent_loop_once error\n");
+       }
+
+       if (child_exit_code != 0) {
+               torture_comment(tctx, "Bad child exit code %d\n",
+                       child_exit_code);
+               ret = false;
+       }
+
 done:
        if (!smb2_util_handle_empty(h1)) {
                smb2_util_close(tree, h1);