mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-27 11:13:50 +00:00
conf: implement resource limits
This adds lxc.limit.<name> options consisting of one or two colon separated numerical values (soft and optional hard limit). If only one number is specified it'll be used for both soft and hard limit. Additionally the word 'unlimited' can be used instead of numbers. Eg. lxc.limit.nofile = 30000:32768 lxc.limit.stack = unlimited Signed-off-by: Wolfgang Bumiller <w.bumiller@proxmox.com>
This commit is contained in:
parent
359f86f975
commit
c6d09e15c5
@ -639,7 +639,7 @@ AC_CHECK_DECLS([PR_SET_NO_NEW_PRIVS], [], [], [#include <sys/prctl.h>])
|
|||||||
AC_CHECK_DECLS([PR_GET_NO_NEW_PRIVS], [], [], [#include <sys/prctl.h>])
|
AC_CHECK_DECLS([PR_GET_NO_NEW_PRIVS], [], [], [#include <sys/prctl.h>])
|
||||||
|
|
||||||
# Check for some headers
|
# Check for some headers
|
||||||
AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/memfd.h sys/personality.h utmpx.h sys/timerfd.h])
|
AC_CHECK_HEADERS([sys/signalfd.h pty.h ifaddrs.h sys/memfd.h sys/personality.h utmpx.h sys/timerfd.h sys/resource.h])
|
||||||
|
|
||||||
# lookup major()/minor()/makedev()
|
# lookup major()/minor()/makedev()
|
||||||
AC_HEADER_MAJOR
|
AC_HEADER_MAJOR
|
||||||
|
@ -894,6 +894,11 @@ int lxc_attach(const char* name, const char* lxcpath, lxc_attach_exec_t exec_fun
|
|||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Setup resource limits */
|
||||||
|
if (!lxc_list_empty(&init_ctx->container->lxc_conf->limits) && setup_resource_limits(&init_ctx->container->lxc_conf->limits, pid)) {
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
/* Open /proc before setns() to the containers namespace so we
|
/* Open /proc before setns() to the containers namespace so we
|
||||||
* don't rely on any information from inside the container.
|
* don't rely on any information from inside the container.
|
||||||
*/
|
*/
|
||||||
|
122
src/lxc/conf.c
122
src/lxc/conf.c
@ -239,6 +239,11 @@ struct caps_opt {
|
|||||||
int value;
|
int value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct limit_opt {
|
||||||
|
char *name;
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The lxc_conf of the container currently being worked on in an
|
* The lxc_conf of the container currently being worked on in an
|
||||||
* API call
|
* API call
|
||||||
@ -371,6 +376,57 @@ static struct caps_opt caps_opt[] = {
|
|||||||
static struct caps_opt caps_opt[] = {};
|
static struct caps_opt caps_opt[] = {};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static struct limit_opt limit_opt[] = {
|
||||||
|
#ifdef RLIMIT_AS
|
||||||
|
{ "as", RLIMIT_AS },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_CORE
|
||||||
|
{ "core", RLIMIT_CORE },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_CPU
|
||||||
|
{ "cpu", RLIMIT_CPU },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_DATA
|
||||||
|
{ "data", RLIMIT_DATA },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_FSIZE
|
||||||
|
{ "fsize", RLIMIT_FSIZE },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_LOCKS
|
||||||
|
{ "locks", RLIMIT_LOCKS },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_MEMLOCK
|
||||||
|
{ "memlock", RLIMIT_MEMLOCK },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_MSGQUEUE
|
||||||
|
{ "msgqueue", RLIMIT_MSGQUEUE },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_NICE
|
||||||
|
{ "nice", RLIMIT_NICE },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_NOFILE
|
||||||
|
{ "nofile", RLIMIT_NOFILE },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_NPROC
|
||||||
|
{ "nproc", RLIMIT_NPROC },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_RSS
|
||||||
|
{ "rss", RLIMIT_RSS },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_RTPRIO
|
||||||
|
{ "rtprio", RLIMIT_RTPRIO },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_RTTIME
|
||||||
|
{ "rttime", RLIMIT_RTTIME },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_SIGPENDING
|
||||||
|
{ "sigpending", RLIMIT_SIGPENDING },
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_STACK
|
||||||
|
{ "stack", RLIMIT_STACK },
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
static int run_buffer(char *buffer)
|
static int run_buffer(char *buffer)
|
||||||
{
|
{
|
||||||
struct lxc_popen_FILE *f;
|
struct lxc_popen_FILE *f;
|
||||||
@ -2473,6 +2529,45 @@ static int setup_network(struct lxc_list *network)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int parse_resource(const char *res) {
|
||||||
|
size_t i;
|
||||||
|
int resid = -1;
|
||||||
|
|
||||||
|
for (i = 0; i < sizeof(limit_opt)/sizeof(limit_opt[0]); ++i) {
|
||||||
|
if (strcmp(res, limit_opt[i].name) == 0)
|
||||||
|
return limit_opt[i].value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* try to see if it's numeric, so the user may specify
|
||||||
|
* resources that the running kernel knows about but
|
||||||
|
* we don't */
|
||||||
|
if (lxc_safe_int(res, &resid) == 0)
|
||||||
|
return resid;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int setup_resource_limits(struct lxc_list *limits, pid_t pid) {
|
||||||
|
struct lxc_list *it;
|
||||||
|
struct lxc_limit *lim;
|
||||||
|
int resid;
|
||||||
|
|
||||||
|
lxc_list_for_each(it, limits) {
|
||||||
|
lim = it->elem;
|
||||||
|
|
||||||
|
resid = parse_resource(lim->resource);
|
||||||
|
if (resid < 0) {
|
||||||
|
ERROR("unknown resource %s", lim->resource);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prlimit(pid, resid, &lim->limit, NULL) != 0) {
|
||||||
|
ERROR("failed to set limit %s: %s", lim->resource, strerror(errno));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* try to move physical nics to the init netns */
|
/* try to move physical nics to the init netns */
|
||||||
void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
|
void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf)
|
||||||
{
|
{
|
||||||
@ -2559,6 +2654,7 @@ struct lxc_conf *lxc_conf_init(void)
|
|||||||
lxc_list_init(&new->includes);
|
lxc_list_init(&new->includes);
|
||||||
lxc_list_init(&new->aliens);
|
lxc_list_init(&new->aliens);
|
||||||
lxc_list_init(&new->environment);
|
lxc_list_init(&new->environment);
|
||||||
|
lxc_list_init(&new->limits);
|
||||||
for (i=0; i<NUM_LXC_HOOKS; i++)
|
for (i=0; i<NUM_LXC_HOOKS; i++)
|
||||||
lxc_list_init(&new->hooks[i]);
|
lxc_list_init(&new->hooks[i]);
|
||||||
lxc_list_init(&new->groups);
|
lxc_list_init(&new->groups);
|
||||||
@ -4178,6 +4274,31 @@ int lxc_clear_cgroups(struct lxc_conf *c, const char *key)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lxc_clear_limits(struct lxc_conf *c, const char *key)
|
||||||
|
{
|
||||||
|
struct lxc_list *it, *next;
|
||||||
|
bool all = false;
|
||||||
|
const char *k = NULL;
|
||||||
|
|
||||||
|
if (strcmp(key, "lxc.limit") == 0)
|
||||||
|
all = true;
|
||||||
|
else if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.")-1) == 0)
|
||||||
|
k = key + sizeof("lxc.limit.")-1;
|
||||||
|
else
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
lxc_list_for_each_safe(it, &c->limits, next) {
|
||||||
|
struct lxc_limit *lim = it->elem;
|
||||||
|
if (!all && strcmp(lim->resource, k) != 0)
|
||||||
|
continue;
|
||||||
|
lxc_list_del(it);
|
||||||
|
free(lim->resource);
|
||||||
|
free(lim);
|
||||||
|
free(it);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int lxc_clear_groups(struct lxc_conf *c)
|
int lxc_clear_groups(struct lxc_conf *c)
|
||||||
{
|
{
|
||||||
struct lxc_list *it,*next;
|
struct lxc_list *it,*next;
|
||||||
@ -4320,6 +4441,7 @@ void lxc_conf_free(struct lxc_conf *conf)
|
|||||||
lxc_clear_includes(conf);
|
lxc_clear_includes(conf);
|
||||||
lxc_clear_aliens(conf);
|
lxc_clear_aliens(conf);
|
||||||
lxc_clear_environment(conf);
|
lxc_clear_environment(conf);
|
||||||
|
lxc_clear_limits(conf, "lxc.limit");
|
||||||
free(conf);
|
free(conf);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +30,9 @@
|
|||||||
#include <net/if.h>
|
#include <net/if.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#if HAVE_SYS_RESOURCE_H
|
||||||
|
#include <sys/resource.h>
|
||||||
|
#endif
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
@ -149,6 +152,23 @@ struct lxc_cgroup {
|
|||||||
char *value;
|
char *value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if !HAVE_SYS_RESOURCE_H
|
||||||
|
# define RLIM_INFINITY ((unsigned long)-1)
|
||||||
|
struct rlimit {
|
||||||
|
unsigned long rlim_cur;
|
||||||
|
unsigned long rlim_max;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Defines a structure to configure resource limits to set via setrlimit().
|
||||||
|
* @resource : the resource name in lowercase without the RLIMIT_ prefix
|
||||||
|
* @limit : the limit to set
|
||||||
|
*/
|
||||||
|
struct lxc_limit {
|
||||||
|
char *resource;
|
||||||
|
struct rlimit limit;
|
||||||
|
};
|
||||||
|
|
||||||
enum idtype {
|
enum idtype {
|
||||||
ID_TYPE_UID,
|
ID_TYPE_UID,
|
||||||
ID_TYPE_GID
|
ID_TYPE_GID
|
||||||
@ -385,6 +405,9 @@ struct lxc_conf {
|
|||||||
|
|
||||||
/* Whether PR_SET_NO_NEW_PRIVS will be set for the container. */
|
/* Whether PR_SET_NO_NEW_PRIVS will be set for the container. */
|
||||||
bool no_new_privs;
|
bool no_new_privs;
|
||||||
|
|
||||||
|
/* RLIMIT_* limits */
|
||||||
|
struct lxc_list limits;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef HAVE_TLS
|
#ifdef HAVE_TLS
|
||||||
@ -428,6 +451,7 @@ extern int lxc_clear_hooks(struct lxc_conf *c, const char *key);
|
|||||||
extern int lxc_clear_idmaps(struct lxc_conf *c);
|
extern int lxc_clear_idmaps(struct lxc_conf *c);
|
||||||
extern int lxc_clear_groups(struct lxc_conf *c);
|
extern int lxc_clear_groups(struct lxc_conf *c);
|
||||||
extern int lxc_clear_environment(struct lxc_conf *c);
|
extern int lxc_clear_environment(struct lxc_conf *c);
|
||||||
|
extern int lxc_clear_limits(struct lxc_conf *c, const char *key);
|
||||||
extern int lxc_delete_autodev(struct lxc_handler *handler);
|
extern int lxc_delete_autodev(struct lxc_handler *handler);
|
||||||
|
|
||||||
extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
|
extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
|
||||||
@ -440,6 +464,8 @@ extern int do_rootfs_setup(struct lxc_conf *conf, const char *name,
|
|||||||
struct cgroup_process_info;
|
struct cgroup_process_info;
|
||||||
extern int lxc_setup(struct lxc_handler *handler);
|
extern int lxc_setup(struct lxc_handler *handler);
|
||||||
|
|
||||||
|
extern int setup_resource_limits(struct lxc_list *limits, pid_t pid);
|
||||||
|
|
||||||
extern void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf);
|
extern void lxc_restore_phys_nics_to_netns(int netnsfd, struct lxc_conf *conf);
|
||||||
|
|
||||||
extern int find_unmapped_nsuid(struct lxc_conf *conf, enum idtype idtype);
|
extern int find_unmapped_nsuid(struct lxc_conf *conf, enum idtype idtype);
|
||||||
|
@ -121,6 +121,7 @@ static int config_init_uid(const char *, const char *, struct lxc_conf *);
|
|||||||
static int config_init_gid(const char *, const char *, struct lxc_conf *);
|
static int config_init_gid(const char *, const char *, struct lxc_conf *);
|
||||||
static int config_ephemeral(const char *, const char *, struct lxc_conf *);
|
static int config_ephemeral(const char *, const char *, struct lxc_conf *);
|
||||||
static int config_no_new_privs(const char *, const char *, struct lxc_conf *);
|
static int config_no_new_privs(const char *, const char *, struct lxc_conf *);
|
||||||
|
static int config_limit(const char *, const char *, struct lxc_conf *);
|
||||||
|
|
||||||
static struct lxc_config_t config[] = {
|
static struct lxc_config_t config[] = {
|
||||||
|
|
||||||
@ -195,6 +196,7 @@ static struct lxc_config_t config[] = {
|
|||||||
{ "lxc.ephemeral", config_ephemeral },
|
{ "lxc.ephemeral", config_ephemeral },
|
||||||
{ "lxc.syslog", config_syslog },
|
{ "lxc.syslog", config_syslog },
|
||||||
{ "lxc.no_new_privs", config_no_new_privs },
|
{ "lxc.no_new_privs", config_no_new_privs },
|
||||||
|
{ "lxc.limit", config_limit },
|
||||||
};
|
};
|
||||||
|
|
||||||
struct signame {
|
struct signame {
|
||||||
@ -1580,6 +1582,110 @@ out:
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool parse_limit_value(const char **value, unsigned long *res) {
|
||||||
|
char *endptr = NULL;
|
||||||
|
|
||||||
|
if (strncmp(*value, "unlimited", sizeof("unlimited")-1) == 0) {
|
||||||
|
*res = RLIM_INFINITY;
|
||||||
|
*value += sizeof("unlimited")-1;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
*res = strtoul(*value, &endptr, 10);
|
||||||
|
if (errno || !endptr)
|
||||||
|
return false;
|
||||||
|
*value = endptr;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int config_limit(const char *key, const char *value,
|
||||||
|
struct lxc_conf *lxc_conf)
|
||||||
|
{
|
||||||
|
struct lxc_list *limlist = NULL;
|
||||||
|
struct lxc_limit *limelem = NULL;
|
||||||
|
struct lxc_list *iter;
|
||||||
|
struct rlimit limit;
|
||||||
|
unsigned long limit_value;
|
||||||
|
|
||||||
|
if (!value || strlen(value) == 0)
|
||||||
|
return lxc_clear_limits(lxc_conf, key);
|
||||||
|
|
||||||
|
if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.")-1) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
key += sizeof("lxc.limit.")-1;
|
||||||
|
|
||||||
|
/* soft limit comes first in the value */
|
||||||
|
if (!parse_limit_value(&value, &limit_value))
|
||||||
|
return -1;
|
||||||
|
limit.rlim_cur = limit_value;
|
||||||
|
|
||||||
|
/* skip spaces and a colon */
|
||||||
|
while (isspace(*value))
|
||||||
|
++value;
|
||||||
|
if (*value == ':')
|
||||||
|
++value;
|
||||||
|
else if (*value) /* any other character is an error here */
|
||||||
|
return -1;
|
||||||
|
while (isspace(*value))
|
||||||
|
++value;
|
||||||
|
|
||||||
|
/* optional hard limit */
|
||||||
|
if (*value) {
|
||||||
|
if (!parse_limit_value(&value, &limit_value))
|
||||||
|
return -1;
|
||||||
|
limit.rlim_max = limit_value;
|
||||||
|
/* check for trailing garbage */
|
||||||
|
while (isspace(*value))
|
||||||
|
++value;
|
||||||
|
if (*value)
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
/* a single value sets both hard and soft limit */
|
||||||
|
limit.rlim_max = limit.rlim_cur;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* find existing list element */
|
||||||
|
lxc_list_for_each(iter, &lxc_conf->limits) {
|
||||||
|
limelem = iter->elem;
|
||||||
|
if (!strcmp(key, limelem->resource)) {
|
||||||
|
limelem->limit = limit;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate list element */
|
||||||
|
limlist = malloc(sizeof(*limlist));
|
||||||
|
if (!limlist)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
limelem = malloc(sizeof(*limelem));
|
||||||
|
if (!limelem)
|
||||||
|
goto out;
|
||||||
|
memset(limelem, 0, sizeof(*limelem));
|
||||||
|
|
||||||
|
limelem->resource = strdup(key);
|
||||||
|
if (!limelem->resource)
|
||||||
|
goto out;
|
||||||
|
limelem->limit = limit;
|
||||||
|
|
||||||
|
limlist->elem = limelem;
|
||||||
|
|
||||||
|
lxc_list_add_tail(&lxc_conf->limits, limlist);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(limlist);
|
||||||
|
if (limelem) {
|
||||||
|
free(limelem->resource);
|
||||||
|
free(limelem);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc_conf)
|
static int config_idmap(const char *key, const char *value, struct lxc_conf *lxc_conf)
|
||||||
{
|
{
|
||||||
char *token = "lxc.id_map";
|
char *token = "lxc.id_map";
|
||||||
@ -2313,6 +2419,55 @@ static int lxc_get_cgroup_entry(struct lxc_conf *c, char *retv, int inlen,
|
|||||||
return fulllen;
|
return fulllen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If you ask for a specific value, i.e. lxc.limit.nofile, then just the value
|
||||||
|
* will be printed. If you ask for 'lxc.limit', then all limit entries will be
|
||||||
|
* printed, in 'lxc.limit.resource = value' format.
|
||||||
|
*/
|
||||||
|
static int lxc_get_limit_entry(struct lxc_conf *c, char *retv, int inlen,
|
||||||
|
const char *key)
|
||||||
|
{
|
||||||
|
int fulllen = 0, len;
|
||||||
|
int all = 0;
|
||||||
|
struct lxc_list *it;
|
||||||
|
|
||||||
|
if (!retv)
|
||||||
|
inlen = 0;
|
||||||
|
else
|
||||||
|
memset(retv, 0, inlen);
|
||||||
|
|
||||||
|
if (strcmp(key, "all") == 0)
|
||||||
|
all = 1;
|
||||||
|
|
||||||
|
lxc_list_for_each(it, &c->limits) {
|
||||||
|
char buf[LXC_NUMSTRLEN64*2+2]; /* 2 colon separated 64 bit integers or the word 'unlimited' */
|
||||||
|
int partlen;
|
||||||
|
struct lxc_limit *lim = it->elem;
|
||||||
|
|
||||||
|
if (lim->limit.rlim_cur == RLIM_INFINITY) {
|
||||||
|
memcpy(buf, "unlimited", sizeof("unlimited"));
|
||||||
|
partlen = sizeof("unlimited")-1;
|
||||||
|
} else {
|
||||||
|
partlen = sprintf(buf, "%lu", lim->limit.rlim_cur);
|
||||||
|
}
|
||||||
|
if (lim->limit.rlim_cur != lim->limit.rlim_max) {
|
||||||
|
if (lim->limit.rlim_max == RLIM_INFINITY) {
|
||||||
|
memcpy(buf+partlen, ":unlimited", sizeof(":unlimited"));
|
||||||
|
} else {
|
||||||
|
sprintf(buf+partlen, ":%lu", lim->limit.rlim_max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (all) {
|
||||||
|
strprint(retv, inlen, "lxc.limit.%s = %s\n", lim->resource, buf);
|
||||||
|
} else if (strcmp(lim->resource, key) == 0) {
|
||||||
|
strprint(retv, inlen, "%s", buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fulllen;
|
||||||
|
}
|
||||||
|
|
||||||
static int lxc_get_item_hooks(struct lxc_conf *c, char *retv, int inlen,
|
static int lxc_get_item_hooks(struct lxc_conf *c, char *retv, int inlen,
|
||||||
const char *key)
|
const char *key)
|
||||||
{
|
{
|
||||||
@ -2678,6 +2833,10 @@ int lxc_get_config_item(struct lxc_conf *c, const char *key, char *retv,
|
|||||||
v = c->syslog;
|
v = c->syslog;
|
||||||
else if (strcmp(key, "lxc.no_new_privs") == 0)
|
else if (strcmp(key, "lxc.no_new_privs") == 0)
|
||||||
return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
|
return lxc_get_conf_int(c, retv, inlen, c->no_new_privs);
|
||||||
|
else if (strcmp(key, "lxc.limit") == 0) // all limits
|
||||||
|
return lxc_get_limit_entry(c, retv, inlen, "all");
|
||||||
|
else if (strncmp(key, "lxc.limit.", 10) == 0) // specific limit
|
||||||
|
return lxc_get_limit_entry(c, retv, inlen, key + 10);
|
||||||
else return -1;
|
else return -1;
|
||||||
|
|
||||||
if (!v)
|
if (!v)
|
||||||
@ -2711,6 +2870,8 @@ int lxc_clear_config_item(struct lxc_conf *c, const char *key)
|
|||||||
return lxc_clear_environment(c);
|
return lxc_clear_environment(c);
|
||||||
else if (strncmp(key, "lxc.id_map", 10) == 0)
|
else if (strncmp(key, "lxc.id_map", 10) == 0)
|
||||||
return lxc_clear_idmaps(c);
|
return lxc_clear_idmaps(c);
|
||||||
|
else if (strncmp(key, "lxc.limit", 9) == 0)
|
||||||
|
return lxc_clear_limits(c, key);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1261,6 +1261,11 @@ static int lxc_spawn(struct lxc_handler *handler)
|
|||||||
if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_CONFIGURE))
|
if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_CONFIGURE))
|
||||||
goto out_delete_net;
|
goto out_delete_net;
|
||||||
|
|
||||||
|
if (!lxc_list_empty(&handler->conf->limits) && setup_resource_limits(&handler->conf->limits, handler->pid)) {
|
||||||
|
ERROR("failed to setup resource limits for '%s'", name);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (!cgroup_setup_limits(handler, true)) {
|
if (!cgroup_setup_limits(handler, true)) {
|
||||||
ERROR("Failed to setup the devices cgroup for container \"%s\".", name);
|
ERROR("Failed to setup the devices cgroup for container \"%s\".", name);
|
||||||
goto out_delete_net;
|
goto out_delete_net;
|
||||||
|
Loading…
Reference in New Issue
Block a user