Merge branch 'master' into next
authorAndre Noll <maan@systemlinux.org>
Sun, 26 Apr 2009 19:05:18 +0000 (21:05 +0200)
committerAndre Noll <maan@systemlinux.org>
Sun, 26 Apr 2009 19:05:18 +0000 (21:05 +0200)
afs.c
command.c
server.c

diff --git a/afs.c b/afs.c
index 2ebc008..72e2490 100644 (file)
--- a/afs.c
+++ b/afs.c
@@ -776,7 +776,7 @@ static void signal_pre_select(struct sched *s, struct task *t)
        para_fd_set(st->fd, &s->rfds, &s->max_fileno);
 }
 
-static void signal_post_select(struct sched *s, struct task *t)
+static void afs_signal_post_select(struct sched *s, struct task *t)
 {
        struct signal_task *st = container_of(t, struct signal_task, task);
        if (getppid() == 1) {
@@ -813,7 +813,7 @@ static void register_signal_task(void)
        para_install_sighandler(SIGHUP);
 
        st->task.pre_select = signal_pre_select;
-       st->task.post_select = signal_post_select;
+       st->task.post_select = afs_signal_post_select;
        sprintf(st->task.status, "signal task");
        register_task(&st->task);
 }
index 229ec5c..1ca54da 100644 (file)
--- a/command.c
+++ b/command.c
@@ -791,8 +791,6 @@ __noreturn void handle_connect(int fd, const char *peername)
        ret = cmd->handler(fd, argc, argv);
        mutex_lock(mmd_mutex);
        mmd->num_commands++;
-       free(mmd->afd.afhi.info_string);
-       free(mmd->afd.afhi.chunk_table);
        mutex_unlock(mmd_mutex);
        if (ret >= 0)
                goto out;
index 79e6781..9bf6c3f 100644 (file)
--- a/server.c
+++ b/server.c
@@ -291,15 +291,32 @@ static void signal_post_select(struct sched *s, struct task *t)
                        if (pid != mmd->afs_pid)
                                continue;
                        PARA_EMERG_LOG("fatal: afs died\n");
-                       goto genocide;
+                       kill(0, SIGTERM);
+                       goto cleanup;
                }
                break;
        /* die on sigint/sigterm. Kill all children too. */
        case SIGINT:
        case SIGTERM:
                PARA_EMERG_LOG("terminating on signal %d\n", st->signum);
-genocide:
                kill(0, SIGTERM);
+               /*
+                * We must wait for afs because afs catches SIGINT/SIGTERM.
+                * Before reacting to the signal, afs might want to use the
+                * shared memory area and the mmd mutex.  If we destroy this
+                * mutex too early and afs tries to lock the shared memory
+                * area, the call to mutex_lock() will fail and terminate the
+                * afs process. This leads to dirty osl tables.
+                *
+                * There's no such problem with the other children of the
+                * server process (the command handlers) as these reset their
+                * SIGINT/SIGTERM handlers to the default action, i.e.  these
+                * processes get killed immediately by the above kill().
+                */
+               PARA_INFO_LOG("waiting for afs (pid %d) to die\n",
+                       (int)mmd->afs_pid);
+               waitpid(mmd->afs_pid, NULL, 0);
+cleanup:
                free(mmd->afd.afhi.chunk_table);
                free(mmd->afd.afhi.info_string);
                close_listed_fds();
@@ -342,6 +359,8 @@ static void command_post_select(struct sched *s, struct task *t)
        int new_fd, ret, i;
        char *peer_name;
        pid_t child_pid;
+       uint32_t *chunk_table;
+       char *info_string;
 
        if (!FD_ISSET(sct->listen_fd, &s->rfds))
                return;
@@ -354,6 +373,16 @@ static void command_post_select(struct sched *s, struct task *t)
        mmd->num_connects++;
        mmd->active_connections++;
        random();
+       /* The chunk table and the info_string are pointers located in the
+        * mmd struct that point to dynamically allocated memory that must be
+        * freed by the parent and the child. However, as the mmd struct is in
+        * a shared memory area, there's no guarantee that after the fork these
+        * pointers are still valid in child context. As these two pointers are
+        * not used in the child anyway, we save them to local variables and
+        * free the memory via that copy in the child.
+        */
+       info_string = mmd->afd.afhi.info_string;
+       chunk_table = mmd->afd.afhi.chunk_table;
        child_pid = fork();
        if (child_pid < 0) {
                ret = -ERRNO_TO_PARA_ERROR(errno);
@@ -364,6 +393,9 @@ static void command_post_select(struct sched *s, struct task *t)
                /* parent keeps accepting connections */
                return;
        }
+       /* mmd might already have changed at this point */
+       free(info_string);
+       free(chunk_table);
        alarm(ALARM_TIMEOUT);
        close_listed_fds();
        para_signal_shutdown();