mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 11:35:19 +00:00
util: Try to get limits from /proc
Calling prlimit() requires elevated privileges, specifically CAP_SYS_RESOURCE, and getrlimit() only works for the current process which is too limiting for our needs; /proc/$pid/limits, on the other hand, can be read by any process, so implement parsing that file as a fallback for when prlimit() fails. This is useful in containerized environments. Signed-off-by: Andrea Bolognani <abologna@redhat.com> Reviewed-by: Michal Privoznik <mprivozn@redhat.com>
This commit is contained in:
parent
cae268f7b9
commit
90fe839f8a
@ -757,6 +757,107 @@ virProcessSetRLimit(int resource,
|
||||
#endif /* WITH_SETRLIMIT */
|
||||
|
||||
#if WITH_GETRLIMIT
|
||||
static const char*
|
||||
virProcessLimitResourceToLabel(int resource)
|
||||
{
|
||||
switch (resource) {
|
||||
# if defined(RLIMIT_MEMLOCK)
|
||||
case RLIMIT_MEMLOCK:
|
||||
return "Max locked memory";
|
||||
# endif /* defined(RLIMIT_MEMLOCK) */
|
||||
|
||||
# if defined(RLIMIT_NPROC)
|
||||
case RLIMIT_NPROC:
|
||||
return "Max processes";
|
||||
# endif /* defined(RLIMIT_NPROC) */
|
||||
|
||||
# if defined(RLIMIT_NOFILE)
|
||||
case RLIMIT_NOFILE:
|
||||
return "Max open files";
|
||||
# endif /* defined(RLIMIT_NOFILE) */
|
||||
|
||||
# if defined(RLIMIT_CORE)
|
||||
case RLIMIT_CORE:
|
||||
return "Max core file size";
|
||||
# endif /* defined(RLIMIT_CORE) */
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
# if defined(__linux__)
|
||||
static int
|
||||
virProcessGetLimitFromProc(pid_t pid,
|
||||
int resource,
|
||||
struct rlimit *limit)
|
||||
{
|
||||
g_autofree char *procfile = NULL;
|
||||
g_autofree char *buf = NULL;
|
||||
g_auto(GStrv) lines = NULL;
|
||||
const char *label;
|
||||
size_t i;
|
||||
|
||||
if (!(label = virProcessLimitResourceToLabel(resource))) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
procfile = g_strdup_printf("/proc/%lld/limits", (long long)pid);
|
||||
|
||||
if (virFileReadAllQuiet(procfile, 2048, &buf) < 0) {
|
||||
/* virFileReadAllQuiet() already sets errno, so don't overwrite
|
||||
* that and return immediately instead */
|
||||
return -1;
|
||||
}
|
||||
|
||||
lines = g_strsplit(buf, "\n", 0);
|
||||
|
||||
for (i = 0; lines[i]; i++) {
|
||||
g_autofree char *softLimit = NULL;
|
||||
g_autofree char *hardLimit = NULL;
|
||||
char *line = lines[i];
|
||||
unsigned long long tmp;
|
||||
|
||||
if (!(line = STRSKIP(line, label)))
|
||||
continue;
|
||||
|
||||
if (sscanf(line, "%ms %ms %*s", &softLimit, &hardLimit) < 2)
|
||||
goto error;
|
||||
|
||||
if (STREQ(softLimit, "unlimited")) {
|
||||
limit->rlim_cur = RLIM_INFINITY;
|
||||
} else {
|
||||
if (virStrToLong_ull(softLimit, NULL, 10, &tmp) < 0)
|
||||
goto error;
|
||||
limit->rlim_cur = tmp;
|
||||
}
|
||||
if (STREQ(hardLimit, "unlimited")) {
|
||||
limit->rlim_max = RLIM_INFINITY;
|
||||
} else {
|
||||
if (virStrToLong_ull(hardLimit, NULL, 10, &tmp) < 0)
|
||||
goto error;
|
||||
limit->rlim_max = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
# else /* !defined(__linux__) */
|
||||
static int
|
||||
virProcessGetLimitFromProc(pid_t pid G_GNUC_UNUSED,
|
||||
int resource G_GNUC_UNUSED,
|
||||
struct rlimit *limit G_GNUC_UNUSED)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
# endif /* !defined(__linux__) */
|
||||
|
||||
static int
|
||||
virProcessGetLimit(pid_t pid,
|
||||
int resource,
|
||||
@ -768,6 +869,15 @@ virProcessGetLimit(pid_t pid,
|
||||
if (virProcessPrLimit(pid, resource, NULL, old_limit) == 0)
|
||||
return 0;
|
||||
|
||||
/* For whatever reason, using prlimit() on another process - even
|
||||
* when it's just to obtain the current limit rather than changing
|
||||
* it - requires CAP_SYS_RESOURCE, which we might not have in a
|
||||
* containerized environment; on the other hand, no particular
|
||||
* permission is needed to poke around /proc, so try that if going
|
||||
* through the syscall didn't work */
|
||||
if (virProcessGetLimitFromProc(pid, resource, old_limit) == 0)
|
||||
return 0;
|
||||
|
||||
if (same_process && virProcessGetRLimit(resource, old_limit) == 0)
|
||||
return 0;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user