From: Andre Noll Date: Sun, 26 Apr 2009 19:05:18 +0000 (+0200) Subject: Merge branch 'master' into next X-Git-Tag: v0.3.5~61^2~6 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=7ad440cc721a097ecff7aa3f38f22806c644a497;hp=b27f3e8dd53af7209626a9f0e98eb4770602c2e7 Merge branch 'master' into next --- diff --git a/afs.c b/afs.c index 2ebc0089..72e2490e 100644 --- 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); } diff --git a/command.c b/command.c index 229ec5c6..1ca54da9 100644 --- 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; diff --git a/server.c b/server.c index 79e67818..9bf6c3f8 100644 --- 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();