mirror of
https://github.com/troglobit/finit.git
synced 2026-10-01 05:22:48 +07:00
Fix filesystems not unmounted at shutdown
Instead of unconditionally waiting 2 seconds for processes to die, check continuously for remaining processes, and break the loop when none remain. Turn PID 1 to a RT process with highest priority 99 during shutdown, this ensures it would not be preempted by other RT processes. Signed-off-by: Robert Andersson <robert.m.andersson@atlascopco.com> Signed-off-by: Mathias Thore <mathias.thore@atlascopco.com> Signed-off-by: Ming Liu <liu.ming50@gmail.com>
This commit is contained in:
@@ -71,6 +71,7 @@
|
|||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <string.h> /* strerror() */
|
#include <string.h> /* strerror() */
|
||||||
|
#include <sched.h>
|
||||||
#include <sys/reboot.h>
|
#include <sys/reboot.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#ifdef _LIBITE_LITE
|
#ifdef _LIBITE_LITE
|
||||||
@@ -172,7 +173,7 @@ void unmount_regular(void);
|
|||||||
*
|
*
|
||||||
* https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/
|
* https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/
|
||||||
*/
|
*/
|
||||||
void do_kill(int signo)
|
void do_iterate_proc(int (*callback)(int, int *), int *context)
|
||||||
{
|
{
|
||||||
DIR *dirp;
|
DIR *dirp;
|
||||||
|
|
||||||
@@ -191,6 +192,8 @@ void do_kill(int signo)
|
|||||||
pid = atoi(d->d_name);
|
pid = atoi(d->d_name);
|
||||||
if (!pid)
|
if (!pid)
|
||||||
continue;
|
continue;
|
||||||
|
if (pid == 1)
|
||||||
|
continue;
|
||||||
|
|
||||||
snprintf(file, sizeof(file), "/proc/%s/cmdline", d->d_name);
|
snprintf(file, sizeof(file), "/proc/%s/cmdline", d->d_name);
|
||||||
fp = fopen(file, "r");
|
fp = fopen(file, "r");
|
||||||
@@ -203,7 +206,10 @@ void do_kill(int signo)
|
|||||||
else if (file[0] == '@')
|
else if (file[0] == '@')
|
||||||
_d("Skipping %s ...", &file[1]);
|
_d("Skipping %s ...", &file[1]);
|
||||||
else
|
else
|
||||||
kill(pid, signo);
|
if (callback(pid, context)) {
|
||||||
|
print(0, "PID %d is still alive (%s)", pid, file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
@@ -211,8 +217,51 @@ void do_kill(int signo)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int kill_callback(int pid, int *context)
|
||||||
|
{
|
||||||
|
kill(pid, (int)context);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int status_callback(int pid, int *context)
|
||||||
|
{
|
||||||
|
*context = 1;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return value:
|
||||||
|
* 1 - at least one process remaining
|
||||||
|
* 0 - no processes remaining
|
||||||
|
*/
|
||||||
|
static int do_wait(int secs)
|
||||||
|
{
|
||||||
|
int has_proc;
|
||||||
|
int tmo = 250000;
|
||||||
|
int iterations = secs*1000*1000/tmo;
|
||||||
|
|
||||||
|
do {
|
||||||
|
do_usleep(tmo);
|
||||||
|
while (waitpid(-1, NULL, WNOHANG) > 0)
|
||||||
|
;
|
||||||
|
has_proc = 0;
|
||||||
|
iterations--;
|
||||||
|
do_iterate_proc(status_callback, &has_proc);
|
||||||
|
}
|
||||||
|
while (has_proc && iterations > 0);
|
||||||
|
|
||||||
|
return has_proc;
|
||||||
|
}
|
||||||
|
|
||||||
void do_shutdown(shutop_t op)
|
void do_shutdown(shutop_t op)
|
||||||
{
|
{
|
||||||
|
struct sched_param sched_param = { .sched_priority = 99 };
|
||||||
|
|
||||||
|
/*
|
||||||
|
* On a PREEMPT-RT system, Finit must run as the highest prioritized
|
||||||
|
* RT process to ensure it completes the shutdown sequence.
|
||||||
|
*/
|
||||||
|
sched_setscheduler(1, SCHED_RR, &sched_param);
|
||||||
|
|
||||||
if (sdown)
|
if (sdown)
|
||||||
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
|
run_interactive(sdown, "Calling shutdown hook: %s", sdown);
|
||||||
|
|
||||||
@@ -223,9 +272,10 @@ void do_shutdown(shutop_t op)
|
|||||||
* Tell remaining non-monitored processes to exit, give them
|
* Tell remaining non-monitored processes to exit, give them
|
||||||
* time to exit gracefully, 2 sec was customary, we go for 1.
|
* time to exit gracefully, 2 sec was customary, we go for 1.
|
||||||
*/
|
*/
|
||||||
do_kill(SIGTERM);
|
do_iterate_proc(kill_callback, (int*)SIGTERM);
|
||||||
do_sleep(1);
|
if (do_wait(1)) {
|
||||||
do_kill(SIGKILL);
|
do_iterate_proc(kill_callback, (int*)SIGKILL);
|
||||||
|
}
|
||||||
|
|
||||||
/* Exit plugins and API gracefully */
|
/* Exit plugins and API gracefully */
|
||||||
plugin_exit();
|
plugin_exit();
|
||||||
|
|||||||
+14
@@ -297,6 +297,20 @@ void do_sleep(unsigned int sec)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void do_usleep(unsigned int usec)
|
||||||
|
{
|
||||||
|
struct timespec deadline;
|
||||||
|
|
||||||
|
clock_gettime(CLOCK_MONOTONIC, &deadline);
|
||||||
|
|
||||||
|
deadline.tv_nsec += usec * 1000;
|
||||||
|
deadline.tv_sec += deadline.tv_nsec / 1000000000;
|
||||||
|
deadline.tv_nsec = deadline.tv_nsec % 1000000000;
|
||||||
|
|
||||||
|
while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &deadline, NULL) != 0 && errno == EINTR)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
/* Seconds since boot, from sysinfo() */
|
/* Seconds since boot, from sysinfo() */
|
||||||
long jiffies(void)
|
long jiffies(void)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ char *sig2str (int sig);
|
|||||||
char *code2str (int code);
|
char *code2str (int code);
|
||||||
|
|
||||||
void do_sleep (unsigned int sec);
|
void do_sleep (unsigned int sec);
|
||||||
|
void do_usleep (unsigned int usec);
|
||||||
long jiffies (void);
|
long jiffies (void);
|
||||||
char *uptime (long secs, char *buf, size_t len);
|
char *uptime (long secs, char *buf, size_t len);
|
||||||
char *memsz (uint64_t sz, char *buf, size_t len);
|
char *memsz (uint64_t sz, char *buf, size_t len);
|
||||||
|
|||||||
Reference in New Issue
Block a user