mirror of
git://sourceware.org/git/lvm2.git
synced 2025-01-03 05:18:29 +03:00
Add support for systemd socket handover for common daemon-server code and also add support for new OOM killer adjustment interface.
This code is already a part of dmeventd, but it's modified slightly to check sockets instead of FIFOs.
This commit is contained in:
parent
0650d875e8
commit
870353f9d1
@ -43,6 +43,7 @@ static int _pthread_create(pthread_t *t, void *(*fun)(void *), void *arg, int st
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static volatile sig_atomic_t _shutdown_requested = 0;
|
static volatile sig_atomic_t _shutdown_requested = 0;
|
||||||
|
static int _systemd_activation = 0;
|
||||||
|
|
||||||
static void _exit_handler(int sig __attribute__((unused)))
|
static void _exit_handler(int sig __attribute__((unused)))
|
||||||
{
|
{
|
||||||
@ -50,41 +51,148 @@ static void _exit_handler(int sig __attribute__((unused)))
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef linux
|
#ifdef linux
|
||||||
# define OOM_ADJ_FILE "/proc/self/oom_adj"
|
|
||||||
# include <stdio.h>
|
|
||||||
|
|
||||||
/* From linux/oom.h */
|
#include <stddef.h>
|
||||||
# define OOM_DISABLE (-17)
|
|
||||||
# define OOM_ADJUST_MIN (-16)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Protection against OOM killer if kernel supports it
|
* Kernel version 2.6.36 and higher has
|
||||||
|
* new OOM killer adjustment interface.
|
||||||
*/
|
*/
|
||||||
static int _set_oom_adj(int val)
|
# define OOM_ADJ_FILE_OLD "/proc/self/oom_adj"
|
||||||
|
# define OOM_ADJ_FILE "/proc/self/oom_score_adj"
|
||||||
|
|
||||||
|
/* From linux/oom.h */
|
||||||
|
/* Old interface */
|
||||||
|
# define OOM_DISABLE (-17)
|
||||||
|
# define OOM_ADJUST_MIN (-16)
|
||||||
|
/* New interface */
|
||||||
|
# define OOM_SCORE_ADJ_MIN (-1000)
|
||||||
|
|
||||||
|
/* Systemd on-demand activation support */
|
||||||
|
# define SD_LISTEN_PID_ENV_VAR_NAME "LISTEN_PID"
|
||||||
|
# define SD_LISTEN_FDS_ENV_VAR_NAME "LISTEN_FDS"
|
||||||
|
# define SD_LISTEN_FDS_START 3
|
||||||
|
# define SD_FD_SOCKET_SERVER SD_LISTEN_FDS_START
|
||||||
|
|
||||||
|
# include <stdio.h>
|
||||||
|
|
||||||
|
static int _set_oom_adj(const char *oom_adj_path, int val)
|
||||||
{
|
{
|
||||||
FILE *fp;
|
FILE *fp;
|
||||||
|
|
||||||
struct stat st;
|
if (!(fp = fopen(oom_adj_path, "w"))) {
|
||||||
|
perror("oom_adj: fopen failed");
|
||||||
if (stat(OOM_ADJ_FILE, &st) == -1) {
|
|
||||||
if (errno == ENOENT)
|
|
||||||
perror(OOM_ADJ_FILE " not found");
|
|
||||||
else
|
|
||||||
perror(OOM_ADJ_FILE ": stat failed");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(fp = fopen(OOM_ADJ_FILE, "w"))) {
|
|
||||||
perror(OOM_ADJ_FILE ": fopen failed");
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, "%i", val);
|
fprintf(fp, "%i", val);
|
||||||
if (fclose(fp))
|
|
||||||
perror(OOM_ADJ_FILE ": fclose failed");
|
if (dm_fclose(fp))
|
||||||
|
perror("oom_adj: fclose failed");
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Protection against OOM killer if kernel supports it
|
||||||
|
*/
|
||||||
|
static int _protect_against_oom_killer(void)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (stat(OOM_ADJ_FILE, &st) == -1) {
|
||||||
|
if (errno != ENOENT)
|
||||||
|
perror(OOM_ADJ_FILE ": stat failed");
|
||||||
|
|
||||||
|
/* Try old oom_adj interface as a fallback */
|
||||||
|
if (stat(OOM_ADJ_FILE_OLD, &st) == -1) {
|
||||||
|
if (errno == ENOENT)
|
||||||
|
perror(OOM_ADJ_FILE_OLD " not found");
|
||||||
|
else
|
||||||
|
perror(OOM_ADJ_FILE_OLD ": stat failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _set_oom_adj(OOM_ADJ_FILE_OLD, OOM_DISABLE) ||
|
||||||
|
_set_oom_adj(OOM_ADJ_FILE_OLD, OOM_ADJUST_MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _set_oom_adj(OOM_ADJ_FILE, OOM_SCORE_ADJ_MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
union sockaddr_union {
|
||||||
|
struct sockaddr sa;
|
||||||
|
struct sockaddr_un un;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int _handle_preloaded_socket(int fd, const char *path)
|
||||||
|
{
|
||||||
|
struct stat st_fd;
|
||||||
|
union sockaddr_union sockaddr;
|
||||||
|
int type = 0;
|
||||||
|
socklen_t len = sizeof(type);
|
||||||
|
size_t path_len = strlen(path);
|
||||||
|
|
||||||
|
if (fd < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (fstat(fd, &st_fd) < 0 || !S_ISSOCK(st_fd.st_mode))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0 ||
|
||||||
|
len != sizeof(type) || type != SOCK_STREAM)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
memset(&sockaddr, 0, sizeof(sockaddr));
|
||||||
|
len = sizeof(sockaddr);
|
||||||
|
if (getsockname(fd, &sockaddr.sa, &len) < 0 ||
|
||||||
|
len < sizeof(sa_family_t) ||
|
||||||
|
sockaddr.sa.sa_family != PF_UNIX)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!(len >= offsetof(struct sockaddr_un, sun_path) + path_len + 1 &&
|
||||||
|
memcmp(path, sockaddr.un.sun_path, path_len) == 0))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int _systemd_handover(struct daemon_state *ds)
|
||||||
|
{
|
||||||
|
const char *e;
|
||||||
|
char *p;
|
||||||
|
unsigned long env_pid, env_listen_fds;
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
/* LISTEN_PID must be equal to our PID! */
|
||||||
|
if (!(e = getenv(SD_LISTEN_PID_ENV_VAR_NAME)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
env_pid = strtoul(e, &p, 10);
|
||||||
|
if (errno || !p || *p || env_pid <= 0 ||
|
||||||
|
getpid() != (pid_t) env_pid)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* LISTEN_FDS must be 1 and the fd must be a socket! */
|
||||||
|
if (!(e = getenv(SD_LISTEN_FDS_ENV_VAR_NAME)))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
env_listen_fds = strtoul(e, &p, 10);
|
||||||
|
if (errno || !p || *p || env_listen_fds != 1)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Check and handle the socket passed in */
|
||||||
|
if ((r = _handle_preloaded_socket(SD_FD_SOCKET_SERVER, ds->socket_path)))
|
||||||
|
ds->socket_fd = SD_FD_SOCKET_SERVER;
|
||||||
|
|
||||||
|
out:
|
||||||
|
unsetenv(SD_LISTEN_PID_ENV_VAR_NAME);
|
||||||
|
unsetenv(SD_LISTEN_FDS_ENV_VAR_NAME);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int _open_socket(daemon_state s)
|
static int _open_socket(daemon_state s)
|
||||||
@ -192,8 +300,14 @@ static void _daemonise(void)
|
|||||||
else
|
else
|
||||||
fd = rlim.rlim_cur;
|
fd = rlim.rlim_cur;
|
||||||
|
|
||||||
for (--fd; fd >= 0; fd--)
|
for (--fd; fd >= 0; fd--) {
|
||||||
|
#ifdef linux
|
||||||
|
/* Do not close fds preloaded by systemd! */
|
||||||
|
if (_systemd_activation && fd == SD_FD_SOCKET_SERVER)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
close(fd);
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
if ((open("/dev/null", O_RDONLY) < 0) ||
|
if ((open("/dev/null", O_RDONLY) < 0) ||
|
||||||
(open("/dev/null", O_WRONLY) < 0) ||
|
(open("/dev/null", O_WRONLY) < 0) ||
|
||||||
@ -328,6 +442,10 @@ void daemon_start(daemon_state s)
|
|||||||
if (setenv("LANG", "C", 1))
|
if (setenv("LANG", "C", 1))
|
||||||
perror("Cannot set LANG to C");
|
perror("Cannot set LANG to C");
|
||||||
|
|
||||||
|
#ifdef linux
|
||||||
|
_systemd_activation = _systemd_handover(&s);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!s.foreground)
|
if (!s.foreground)
|
||||||
_daemonise();
|
_daemonise();
|
||||||
|
|
||||||
@ -354,11 +472,12 @@ void daemon_start(daemon_state s)
|
|||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
#ifdef linux
|
#ifdef linux
|
||||||
if (s.avoid_oom && !_set_oom_adj(OOM_DISABLE) && !_set_oom_adj(OOM_ADJUST_MIN))
|
/* Systemd has adjusted oom killer for us already */
|
||||||
syslog(LOG_ERR, "Failed to set oom_adj to protect against OOM killer");
|
if (s.avoid_oom && !_systemd_activation && !_protect_against_oom_killer())
|
||||||
|
syslog(LOG_ERR, "Failed to protect against OOM killer");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (s.socket_path) {
|
if (!_systemd_activation && s.socket_path) {
|
||||||
s.socket_fd = _open_socket(s);
|
s.socket_fd = _open_socket(s);
|
||||||
if (s.socket_fd < 0)
|
if (s.socket_fd < 0)
|
||||||
failed = 1;
|
failed = 1;
|
||||||
|
Loading…
Reference in New Issue
Block a user