Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
L
lxc
Project
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Chen Yisong
lxc
Commits
3f76bcd6
Unverified
Commit
3f76bcd6
authored
Apr 19, 2019
by
Christian Brauner
Committed by
GitHub
Apr 19, 2019
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #2944 from brauner/lxc/stable-3.0
cgfsng: backport new cgroup handling logic
parents
bccf738c
1e04bb71
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
544 additions
and
335 deletions
+544
-335
configure.ac
configure.ac
+3
-3
attach.c
src/lxc/attach.c
+8
-7
cgfsng.c
src/lxc/cgroups/cgfsng.c
+410
-270
cgroup.c
src/lxc/cgroups/cgroup.c
+11
-6
cgroup.h
src/lxc/cgroups/cgroup.h
+22
-3
criu.c
src/lxc/criu.c
+3
-3
freezer.c
src/lxc/freezer.c
+17
-11
initutils.c
src/lxc/initutils.c
+1
-1
lxc.h
src/lxc/lxc.h
+4
-2
lxccontainer.c
src/lxc/lxccontainer.c
+32
-13
start.c
src/lxc/start.c
+31
-14
cgpath.c
src/tests/cgpath.c
+2
-2
No files found.
configure.ac
View file @
3f76bcd6
...
...
@@ -489,7 +489,7 @@ AC_ARG_WITH([cgroup-pattern],
[AC_HELP_STRING(
[--with-cgroup-pattern=pattern],
[pattern for container cgroups]
)], [], [with_cgroup_pattern=['lxc/%n']])
)], [], [with_cgroup_pattern=['lxc
.payload
/%n']])
# Container log path. By default, use $lxcpath.
AC_MSG_CHECKING([Whether to place logfiles in container config path])
...
...
@@ -721,8 +721,8 @@ AX_CHECK_COMPILE_FLAG([-fasynchronous-unwind-tables], [CFLAGS="$CFLAGS -fasynchr
AX_CHECK_COMPILE_FLAG([-pipe], [CFLAGS="$CFLAGS -pipe"],,[-Werror])
AX_CHECK_COMPILE_FLAG([-fexceptions], [CFLAGS="$CFLAGS -fexceptions"],,[-Werror])
AX_CHECK_LINK_FLAG([-z relro], [LD
LAGS="$LD
LAGS -z relro"],,[])
AX_CHECK_LINK_FLAG([-z now], [LD
LAGS="$LD
LAGS -z now"],,[])
AX_CHECK_LINK_FLAG([-z relro], [LD
FLAGS="$LDF
LAGS -z relro"],,[])
AX_CHECK_LINK_FLAG([-z now], [LD
FLAGS="$LDF
LAGS -z now"],,[])
CFLAGS="$CFLAGS -Wvla -std=gnu11"
if test "x$enable_werror" = "xyes"; then
...
...
src/lxc/attach.c
View file @
3f76bcd6
...
...
@@ -126,7 +126,7 @@ static struct lxc_proc_context_info *lxc_proc_get_context_info(pid_t pid)
static
inline
void
lxc_proc_close_ns_fd
(
struct
lxc_proc_context_info
*
ctx
)
{
for
(
int
i
=
0
;
i
<
LXC_NS_MAX
;
i
++
)
{
__do_close_prot_errno
int
fd
=
move_fd
(
ctx
->
ns_fd
[
i
]);
__do_close_prot_errno
int
fd
ATTR_UNUSED
=
move_fd
(
ctx
->
ns_fd
[
i
]);
}
}
...
...
@@ -689,8 +689,8 @@ struct attach_clone_payload {
static
void
lxc_put_attach_clone_payload
(
struct
attach_clone_payload
*
p
)
{
__do_close_prot_errno
int
ipc_socket
=
p
->
ipc_socket
;
__do_close_prot_errno
int
terminal_slave_fd
=
p
->
terminal_slave_fd
;
__do_close_prot_errno
int
ipc_socket
ATTR_UNUSED
=
p
->
ipc_socket
;
__do_close_prot_errno
int
terminal_slave_fd
ATTR_UNUSED
=
p
->
terminal_slave_fd
;
if
(
p
->
init_ctx
)
{
lxc_proc_put_context_info
(
p
->
init_ctx
);
...
...
@@ -700,7 +700,7 @@ static void lxc_put_attach_clone_payload(struct attach_clone_payload *p)
static
int
attach_child_main
(
struct
attach_clone_payload
*
payload
)
{
int
fd
,
lsm_fd
,
ret
;
int
lsm_fd
,
ret
;
uid_t
new_uid
;
gid_t
new_gid
;
uid_t
ns_root_uid
=
0
;
...
...
@@ -893,10 +893,11 @@ static int attach_child_main(struct attach_clone_payload *payload)
if
(
options
->
stderr_fd
>
STDERR_FILENO
)
close
(
options
->
stderr_fd
);
/* Try to remove FD_CLOEXEC flag from stdin/stdout/stderr, but also
/*
* Try to remove FD_CLOEXEC flag from stdin/stdout/stderr, but also
* here, ignore errors.
*/
for
(
fd
=
STDIN_FILENO
;
fd
<=
STDERR_FILENO
;
fd
++
)
{
for
(
int
fd
=
STDIN_FILENO
;
fd
<=
STDERR_FILENO
;
fd
++
)
{
ret
=
fd_cloexec
(
fd
,
false
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to clear FD_CLOEXEC from file descriptor %d"
,
fd
);
...
...
@@ -1217,7 +1218,7 @@ int lxc_attach(const char *name, const char *lxcpath,
if
(
options
->
attach_flags
&
LXC_ATTACH_MOVE_TO_CGROUP
)
{
struct
cgroup_ops
*
cgroup_ops
;
cgroup_ops
=
cgroup_init
(
NULL
);
cgroup_ops
=
cgroup_init
(
conf
);
if
(
!
cgroup_ops
)
goto
on_error
;
...
...
src/lxc/cgroups/cgfsng.c
View file @
3f76bcd6
...
...
@@ -232,10 +232,11 @@ static void append_line(char **dest, size_t oldlen, char *new, size_t newlen)
/* Slurp in a whole file */
static
char
*
read_file
(
const
char
*
fnam
)
{
FILE
*
f
;
char
*
line
=
NULL
,
*
buf
=
NULL
;
size_t
len
=
0
,
fulllen
=
0
;
__do_free
char
*
line
=
NULL
;
__do_fclose
FILE
*
f
=
NULL
;
int
linelen
;
char
*
buf
=
NULL
;
size_t
len
=
0
,
fulllen
=
0
;
f
=
fopen
(
fnam
,
"r"
);
if
(
!
f
)
...
...
@@ -244,8 +245,6 @@ static char *read_file(const char *fnam)
append_line
(
&
buf
,
fulllen
,
line
,
linelen
);
fulllen
+=
linelen
;
}
fclose
(
f
);
free
(
line
);
return
buf
;
}
...
...
@@ -381,12 +380,14 @@ static ssize_t get_max_cpus(char *cpulist)
#define __ISOL_CPUS "/sys/devices/system/cpu/isolated"
static
bool
cg_legacy_filter_and_set_cpus
(
char
*
path
,
bool
am_initialized
)
{
__do_free
char
*
cpulist
=
NULL
,
*
fpath
=
NULL
,
*
isolcpus
=
NULL
,
*
posscpus
=
NULL
;
__do_free
uint32_t
*
isolmask
=
NULL
,
*
possmask
=
NULL
;
int
ret
;
ssize_t
i
;
char
*
lastslash
,
*
fpath
,
oldv
;
char
oldv
;
char
*
lastslash
;
ssize_t
maxisol
=
0
,
maxposs
=
0
;
char
*
cpulist
=
NULL
,
*
isolcpus
=
NULL
,
*
posscpus
=
NULL
;
uint32_t
*
isolmask
=
NULL
,
*
possmask
=
NULL
;
bool
bret
=
false
,
flipped_bit
=
false
;
lastslash
=
strrchr
(
path
,
'/'
);
...
...
@@ -400,58 +401,58 @@ static bool cg_legacy_filter_and_set_cpus(char *path, bool am_initialized)
posscpus
=
read_file
(
fpath
);
if
(
!
posscpus
)
{
SYSERROR
(
"Failed to read file
\"
%s
\"
"
,
fpath
);
goto
on_error
;
return
false
;
}
/* Get maximum number of cpus found in possible cpuset. */
maxposs
=
get_max_cpus
(
posscpus
);
if
(
maxposs
<
0
||
maxposs
>=
INT_MAX
-
1
)
goto
on_error
;
return
false
;
if
(
!
file_exists
(
__ISOL_CPUS
))
{
/* This system doesn't expose isolated cpus. */
DEBUG
(
"The path
\"
"
__ISOL_CPUS
"
\"
to read isolated cpus from does not exist"
);
cpulist
=
posscpus
;
/* No isolated cpus but we weren't already initialized by
* someone. We should simply copy the parents cpuset.cpus
* values.
*/
if
(
!
am_initialized
)
{
DEBUG
(
"Copying cpu settings of parent cgroup"
);
cpulist
=
posscpus
;
goto
copy_parent
;
}
/* No isolated cpus but we were already initialized by someone.
* Nothing more to do for us.
*/
goto
on_success
;
return
true
;
}
isolcpus
=
read_file
(
__ISOL_CPUS
);
if
(
!
isolcpus
)
{
SYSERROR
(
"Failed to read file
\"
"
__ISOL_CPUS
"
\"
"
);
goto
on_error
;
return
false
;
}
if
(
!
isdigit
(
isolcpus
[
0
]))
{
TRACE
(
"No isolated cpus detected"
);
cpulist
=
posscpus
;
/* No isolated cpus but we weren't already initialized by
* someone. We should simply copy the parents cpuset.cpus
* values.
*/
if
(
!
am_initialized
)
{
DEBUG
(
"Copying cpu settings of parent cgroup"
);
cpulist
=
posscpus
;
goto
copy_parent
;
}
/* No isolated cpus but we were already initialized by someone.
* Nothing more to do for us.
*/
goto
on_success
;
return
true
;
}
/* Get maximum number of cpus found in isolated cpuset. */
maxisol
=
get_max_cpus
(
isolcpus
);
if
(
maxisol
<
0
||
maxisol
>=
INT_MAX
-
1
)
goto
on_error
;
return
false
;
if
(
maxposs
<
maxisol
)
maxposs
=
maxisol
;
...
...
@@ -460,13 +461,13 @@ static bool cg_legacy_filter_and_set_cpus(char *path, bool am_initialized)
possmask
=
lxc_cpumask
(
posscpus
,
maxposs
);
if
(
!
possmask
)
{
ERROR
(
"Failed to create cpumask for possible cpus"
);
goto
on_error
;
return
false
;
}
isolmask
=
lxc_cpumask
(
isolcpus
,
maxposs
);
if
(
!
isolmask
)
{
ERROR
(
"Failed to create cpumask for isolated cpus"
);
goto
on_error
;
return
false
;
}
for
(
i
=
0
;
i
<=
maxposs
;
i
++
)
{
...
...
@@ -479,41 +480,28 @@ static bool cg_legacy_filter_and_set_cpus(char *path, bool am_initialized)
if
(
!
flipped_bit
)
{
DEBUG
(
"No isolated cpus present in cpuset"
);
goto
on_success
;
return
true
;
}
DEBUG
(
"Removed isolated cpus from cpuset"
);
cpulist
=
lxc_cpumask_to_cpulist
(
possmask
,
maxposs
);
if
(
!
cpulist
)
{
ERROR
(
"Failed to create cpu list"
);
goto
on_error
;
return
false
;
}
copy_parent:
*
lastslash
=
oldv
;
free
(
fpath
);
fpath
=
must_make_path
(
path
,
"cpuset.cpus"
,
NULL
);
ret
=
lxc_write_to_file
(
fpath
,
cpulist
,
strlen
(
cpulist
),
false
,
0666
);
if
(
cpulist
==
posscpus
)
cpulist
=
NULL
;
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to write cpu list to
\"
%s
\"
"
,
fpath
);
goto
on_error
;
return
false
;
}
on_success:
bret
=
true
;
on_error:
free
(
fpath
);
free
(
isolcpus
);
free
(
isolmask
);
if
(
posscpus
!=
cpulist
)
free
(
posscpus
);
free
(
possmask
);
free
(
cpulist
);
return
bret
;
return
true
;
}
/* Copy contents of parent(@path)/@file to @path/@file */
...
...
@@ -534,13 +522,17 @@ static bool copy_parent_file(char *path, char *file)
*
lastslash
=
'\0'
;
parent_path
=
must_make_path
(
path
,
file
,
NULL
);
len
=
lxc_read_from_file
(
parent_path
,
NULL
,
0
);
if
(
len
<=
0
)
goto
on_error
;
if
(
len
<=
0
)
{
SYSERROR
(
"Failed to determine buffer size"
);
return
false
;
}
value
=
must_realloc
(
NULL
,
len
+
1
);
ret
=
lxc_read_from_file
(
parent_path
,
value
,
len
);
if
(
ret
!=
len
)
goto
on_error
;
if
(
ret
!=
len
)
{
SYSERROR
(
"Failed to read from parent file
\"
%s
\"
"
,
parent_path
);
return
false
;
}
*
lastslash
=
oldv
;
child_path
=
must_make_path
(
path
,
file
,
NULL
);
...
...
@@ -548,10 +540,6 @@ static bool copy_parent_file(char *path, char *file)
if
(
ret
<
0
)
SYSERROR
(
"Failed to write
\"
%s
\"
to file
\"
%s
\"
"
,
value
,
child_path
);
return
ret
>=
0
;
on_error:
SYSERROR
(
"Failed to read file
\"
%s
\"
"
,
child_path
);
return
false
;
}
/* Initialize the cpuset hierarchy in first directory of @gname and set
...
...
@@ -561,9 +549,10 @@ on_error:
*/
static
bool
cg_legacy_handle_cpuset_hierarchy
(
struct
hierarchy
*
h
,
char
*
cgname
)
{
__do_free
char
*
cgpath
=
NULL
,
*
clonechildrenpath
=
NULL
;
int
ret
;
char
v
;
char
*
cgpath
,
*
clonechildrenpath
,
*
slash
;
char
*
slash
;
if
(
!
string_in_list
(
h
->
controllers
,
"cpuset"
))
return
true
;
...
...
@@ -582,61 +571,46 @@ static bool cg_legacy_handle_cpuset_hierarchy(struct hierarchy *h, char *cgname)
if
(
ret
<
0
)
{
if
(
errno
!=
EEXIST
)
{
SYSERROR
(
"Failed to create directory
\"
%s
\"
"
,
cgpath
);
free
(
cgpath
);
return
false
;
}
}
clonechildrenpath
=
must_make_path
(
cgpath
,
"cgroup.clone_children"
,
NULL
);
clonechildrenpath
=
must_make_path
(
cgpath
,
"cgroup.clone_children"
,
NULL
);
/* unified hierarchy doesn't have clone_children */
if
(
!
file_exists
(
clonechildrenpath
))
{
free
(
clonechildrenpath
);
free
(
cgpath
);
if
(
!
file_exists
(
clonechildrenpath
))
return
true
;
}
ret
=
lxc_read_from_file
(
clonechildrenpath
,
&
v
,
1
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to read file
\"
%s
\"
"
,
clonechildrenpath
);
free
(
clonechildrenpath
);
free
(
cgpath
);
return
false
;
}
/* Make sure any isolated cpus are removed from cpuset.cpus. */
if
(
!
cg_legacy_filter_and_set_cpus
(
cgpath
,
v
==
'1'
))
{
SYSERROR
(
"Failed to remove isolated cpus"
);
free
(
clonechildrenpath
);
free
(
cgpath
);
return
false
;
}
/* Already set for us by someone else. */
if
(
v
==
'1'
)
{
DEBUG
(
"
\"
cgroup.clone_children
\"
was already set to
\"
1
\"
"
);
free
(
clonechildrenpath
);
free
(
cgpath
);
return
true
;
}
/* copy parent's settings */
if
(
!
copy_parent_file
(
cgpath
,
"cpuset.mems"
))
{
SYSERROR
(
"Failed to copy
\"
cpuset.mems
\"
settings"
);
free
(
cgpath
);
free
(
clonechildrenpath
);
return
false
;
}
free
(
cgpath
);
ret
=
lxc_write_to_file
(
clonechildrenpath
,
"1"
,
1
,
false
,
0666
);
if
(
ret
<
0
)
{
/* Set clone_children so children inherit our settings */
SYSERROR
(
"Failed to write 1 to
\"
%s
\"
"
,
clonechildrenpath
);
free
(
clonechildrenpath
);
return
false
;
}
free
(
clonechildrenpath
);
return
true
;
}
...
...
@@ -725,7 +699,7 @@ static char **cg_hybrid_get_controllers(char **klist, char **nlist, char *line,
* for legacy hierarchies.
*/
int
i
;
char
*
dup
,
*
p2
,
*
tok
;
char
*
p2
,
*
tok
;
char
*
p
=
line
,
*
sep
=
","
;
char
**
aret
=
NULL
;
...
...
@@ -753,19 +727,18 @@ static char **cg_hybrid_get_controllers(char **klist, char **nlist, char *line,
*
p2
=
'\0'
;
if
(
type
==
CGROUP_SUPER_MAGIC
)
{
__do_free
char
*
dup
=
NULL
;
/* strdup() here for v1 hierarchies. Otherwise
* lxc_iterate_parts() will destroy mountpoints such as
* "/sys/fs/cgroup/cpu,cpuacct".
*/
dup
=
strdup
(
p
);
dup
=
must_copy_string
(
p
);
if
(
!
dup
)
return
NULL
;
lxc_iterate_parts
(
tok
,
dup
,
sep
)
{
lxc_iterate_parts
(
tok
,
dup
,
sep
)
must_append_controller
(
klist
,
nlist
,
&
aret
,
tok
);
}
free
(
dup
);
}
*
p2
=
' '
;
...
...
@@ -784,7 +757,8 @@ static char **cg_unified_make_empty_controller(void)
static
char
**
cg_unified_get_controllers
(
const
char
*
file
)
{
char
*
buf
,
*
tok
;
__do_free
char
*
buf
=
NULL
;
char
*
tok
;
char
*
sep
=
"
\t\n
"
;
char
**
aret
=
NULL
;
...
...
@@ -801,7 +775,6 @@ static char **cg_unified_get_controllers(const char *file)
aret
[
newentry
]
=
copy
;
}
free
(
buf
);
return
aret
;
}
...
...
@@ -816,7 +789,9 @@ static struct hierarchy *add_hierarchy(struct hierarchy ***h, char **clist, char
new
->
mountpoint
=
mountpoint
;
new
->
container_base_path
=
container_base_path
;
new
->
container_full_path
=
NULL
;
new
->
monitor_full_path
=
NULL
;
new
->
version
=
type
;
new
->
cgroup2_chown
=
NULL
;
newentry
=
append_null_to_list
((
void
***
)
h
);
(
*
h
)[
newentry
]
=
new
;
...
...
@@ -876,7 +851,8 @@ static char *copy_to_eol(char *p)
*/
static
bool
controller_in_clist
(
char
*
cgline
,
char
*
c
)
{
char
*
tok
,
*
eol
,
*
tmp
;
__do_free
char
*
tmp
=
NULL
;
char
*
tok
,
*
eol
;
size_t
len
;
eol
=
strchr
(
cgline
,
':'
);
...
...
@@ -888,14 +864,10 @@ static bool controller_in_clist(char *cgline, char *c)
memcpy
(
tmp
,
cgline
,
len
);
tmp
[
len
]
=
'\0'
;
lxc_iterate_parts
(
tok
,
tmp
,
","
)
{
if
(
strcmp
(
tok
,
c
)
==
0
)
{
free
(
tmp
);
lxc_iterate_parts
(
tok
,
tmp
,
","
)
if
(
strcmp
(
tok
,
c
)
==
0
)
return
true
;
}
}
free
(
tmp
);
return
false
;
}
...
...
@@ -946,8 +918,8 @@ static void must_append_string(char ***list, char *entry)
static
int
get_existing_subsystems
(
char
***
klist
,
char
***
nlist
)
{
FILE
*
f
;
char
*
line
=
NULL
;
__do_free
char
*
line
=
NULL
;
__do_fclose
FILE
*
f
=
NULL
;
size_t
len
=
0
;
f
=
fopen
(
"/proc/self/cgroup"
,
"r"
);
...
...
@@ -985,8 +957,6 @@ static int get_existing_subsystems(char ***klist, char ***nlist)
}
}
free
(
line
);
fclose
(
f
);
return
0
;
}
...
...
@@ -1108,6 +1078,9 @@ __cgfsng_ops static void cgfsng_payload_destroy(struct cgroup_ops *ops,
int
ret
;
struct
generic_userns_exec_data
wrap
;
if
(
!
ops
->
hierarchies
)
return
;
wrap
.
origuid
=
0
;
wrap
.
container_cgroup
=
ops
->
container_cgroup
;
wrap
.
hierarchies
=
ops
->
hierarchies
;
...
...
@@ -1124,12 +1097,85 @@ __cgfsng_ops static void cgfsng_payload_destroy(struct cgroup_ops *ops,
}
}
__cgfsng_ops
static
void
cgfsng_monitor_destroy
(
struct
cgroup_ops
*
ops
,
struct
lxc_handler
*
handler
)
{
int
len
;
struct
lxc_conf
*
conf
=
handler
->
conf
;
char
pidstr
[
INTTYPE_TO_STRLEN
(
pid_t
)];
if
(
!
ops
->
hierarchies
)
return
;
len
=
snprintf
(
pidstr
,
sizeof
(
pidstr
),
"%d"
,
handler
->
monitor_pid
);
if
(
len
<
0
||
(
size_t
)
len
>=
sizeof
(
pidstr
))
return
;
for
(
int
i
=
0
;
ops
->
hierarchies
[
i
];
i
++
)
{
__do_free
char
*
pivot_path
=
NULL
;
int
ret
;
char
*
chop
;
char
pivot_cgroup
[]
=
PIVOT_CGROUP
;
struct
hierarchy
*
h
=
ops
->
hierarchies
[
i
];
if
(
!
h
->
monitor_full_path
)
continue
;
if
(
conf
&&
conf
->
cgroup_meta
.
dir
)
pivot_path
=
must_make_path
(
h
->
mountpoint
,
h
->
container_base_path
,
conf
->
cgroup_meta
.
dir
,
PIVOT_CGROUP
,
"cgroup.procs"
,
NULL
);
else
pivot_path
=
must_make_path
(
h
->
mountpoint
,
h
->
container_base_path
,
PIVOT_CGROUP
,
"cgroup.procs"
,
NULL
);
chop
=
strrchr
(
pivot_path
,
'/'
);
if
(
chop
)
*
chop
=
'\0'
;
/*
* Make sure not to pass in the ro string literal PIVOT_CGROUP
* here.
*/
if
(
!
cg_legacy_handle_cpuset_hierarchy
(
h
,
pivot_cgroup
))
{
WARN
(
"Failed to handle legacy cpuset controller"
);
continue
;
}
ret
=
mkdir_p
(
pivot_path
,
0755
);
if
(
ret
<
0
&&
errno
!=
EEXIST
)
{
SYSWARN
(
"Failed to create cgroup
\"
%s
\"\n
"
,
pivot_path
);
continue
;
}
if
(
chop
)
*
chop
=
'/'
;
/* Move ourselves into the pivot cgroup to delete our own
* cgroup.
*/
ret
=
lxc_write_to_file
(
pivot_path
,
pidstr
,
len
,
false
,
0666
);
if
(
ret
!=
0
)
{
SYSWARN
(
"Failed to move monitor %s to
\"
%s
\"\n
"
,
pidstr
,
pivot_path
);
continue
;
}
ret
=
recursive_destroy
(
h
->
monitor_full_path
);
if
(
ret
<
0
)
WARN
(
"Failed to destroy
\"
%s
\"
"
,
h
->
monitor_full_path
);
}
}
static
bool
cg_unified_create_cgroup
(
struct
hierarchy
*
h
,
char
*
cgname
)
{
__do_free
char
*
add_controllers
=
NULL
,
*
cgroup
=
NULL
;
size_t
i
,
parts_len
;
char
**
it
;
size_t
full_len
=
0
;
char
*
add_controllers
=
NULL
,
*
cgroup
=
NULL
;
char
**
parts
=
NULL
;
bool
bret
=
false
;
...
...
@@ -1170,12 +1216,11 @@ static bool cg_unified_create_cgroup(struct hierarchy *h, char *cgname)
cgroup
=
must_make_path
(
h
->
mountpoint
,
h
->
container_base_path
,
NULL
);
for
(
i
=
0
;
i
<
parts_len
;
i
++
)
{
int
ret
;
char
*
target
;
__do_free
char
*
target
=
NULL
;
cgroup
=
must_append_path
(
cgroup
,
parts
[
i
],
NULL
);
target
=
must_make_path
(
cgroup
,
"cgroup.subtree_control"
,
NULL
);
ret
=
lxc_write_to_file
(
target
,
add_controllers
,
full_len
,
false
,
0666
);
free
(
target
);
if
(
ret
<
0
)
{
SYSERROR
(
"Could not enable
\"
%s
\"
controllers in the "
"unified cgroup
\"
%s
\"
"
,
add_controllers
,
cgroup
);
...
...
@@ -1187,8 +1232,6 @@ static bool cg_unified_create_cgroup(struct hierarchy *h, char *cgname)
on_error:
lxc_free_array
((
void
**
)
parts
,
free
);
free
(
add_controllers
);
free
(
cgroup
);
return
bret
;
}
...
...
@@ -1200,9 +1243,9 @@ static int mkdir_eexist_on_last(const char *dir, mode_t mode)
orig_len
=
strlen
(
dir
);
do
{
__do_free
char
*
makeme
;
int
ret
;
size_t
cur_len
;
char
*
makeme
;
dir
=
tmp
+
strspn
(
tmp
,
"/"
);
tmp
=
dir
+
strcspn
(
dir
,
"/"
);
...
...
@@ -1217,18 +1260,34 @@ static int mkdir_eexist_on_last(const char *dir, mode_t mode)
if
(
ret
<
0
)
{
if
((
errno
!=
EEXIST
)
||
(
orig_len
==
cur_len
))
{
SYSERROR
(
"Failed to create directory
\"
%s
\"
"
,
makeme
);
free
(
makeme
);
return
-
1
;
}
}
free
(
makeme
);
}
while
(
tmp
!=
dir
);
return
0
;
}
static
bool
create_path_for_hierarchy
(
struct
hierarchy
*
h
,
char
*
cgname
)
static
bool
monitor_create_path_for_hierarchy
(
struct
hierarchy
*
h
,
char
*
cgname
)
{
int
ret
;
if
(
!
cg_legacy_handle_cpuset_hierarchy
(
h
,
cgname
))
{
ERROR
(
"Failed to handle legacy cpuset controller"
);
return
false
;
}
h
->
monitor_full_path
=
must_make_path
(
h
->
mountpoint
,
h
->
container_base_path
,
cgname
,
NULL
);
ret
=
mkdir_eexist_on_last
(
h
->
monitor_full_path
,
0755
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to create cgroup
\"
%s
\"
"
,
h
->
monitor_full_path
);
return
false
;
}
return
cg_unified_create_cgroup
(
h
,
cgname
);
}
static
bool
container_create_path_for_hierarchy
(
struct
hierarchy
*
h
,
char
*
cgname
)
{
int
ret
;
...
...
@@ -1247,38 +1306,111 @@ static bool create_path_for_hierarchy(struct hierarchy *h, char *cgname)
return
cg_unified_create_cgroup
(
h
,
cgname
);
}
static
void
remove_path_for_hierarchy
(
struct
hierarchy
*
h
,
char
*
cgname
)
static
void
remove_path_for_hierarchy
(
struct
hierarchy
*
h
,
char
*
cgname
,
bool
monitor
)
{
int
ret
;
char
*
full_path
;
if
(
monitor
)
full_path
=
h
->
monitor_full_path
;
else
full_path
=
h
->
container_full_path
;
ret
=
rmdir
(
h
->
container_
full_path
);
ret
=
rmdir
(
full_path
);
if
(
ret
<
0
)
SYSERROR
(
"Failed to rmdir(
\"
%s
\"
) from failed creation attempt"
,
h
->
container_full_path
);
SYSERROR
(
"Failed to rmdir(
\"
%s
\"
) from failed creation attempt"
,
full_path
);
free
(
full_path
);
if
(
monitor
)
h
->
monitor_full_path
=
NULL
;
else
h
->
container_full_path
=
NULL
;
}
free
(
h
->
container_full_path
);
h
->
container_full_path
=
NULL
;
__cgfsng_ops
static
inline
bool
cgfsng_monitor_create
(
struct
cgroup_ops
*
ops
,
struct
lxc_handler
*
handler
)
{
__do_free
char
*
monitor_cgroup
=
NULL
;
char
*
offset
,
*
tmp
;
int
i
,
idx
=
0
;
size_t
len
;
struct
lxc_conf
*
conf
=
handler
->
conf
;
if
(
!
conf
)
return
false
;
if
(
!
ops
->
hierarchies
)
return
true
;
if
(
conf
->
cgroup_meta
.
dir
)
tmp
=
lxc_string_join
(
"/"
,
(
const
char
*
[]){
conf
->
cgroup_meta
.
dir
,
ops
->
monitor_pattern
,
handler
->
name
,
NULL
},
false
);
else
tmp
=
must_make_path
(
ops
->
monitor_pattern
,
handler
->
name
,
NULL
);
if
(
!
tmp
)
return
false
;
len
=
strlen
(
tmp
)
+
5
;
/* leave room for -NNN\0 */
monitor_cgroup
=
must_realloc
(
tmp
,
len
);
offset
=
monitor_cgroup
+
len
-
5
;
*
offset
=
0
;
do
{
if
(
idx
)
{
int
ret
=
snprintf
(
offset
,
5
,
"-%d"
,
idx
);
if
(
ret
<
0
||
(
size_t
)
ret
>=
5
)
return
false
;
}
for
(
i
=
0
;
ops
->
hierarchies
[
i
];
i
++
)
{
if
(
!
monitor_create_path_for_hierarchy
(
ops
->
hierarchies
[
i
],
monitor_cgroup
))
{
ERROR
(
"Failed to create cgroup
\"
%s
\"
"
,
ops
->
hierarchies
[
i
]
->
monitor_full_path
);
for
(
int
j
=
0
;
j
<
i
;
j
++
)
remove_path_for_hierarchy
(
ops
->
hierarchies
[
j
],
monitor_cgroup
,
true
);
idx
++
;
break
;
}
}
}
while
(
ops
->
hierarchies
[
i
]
&&
idx
>
0
&&
idx
<
1000
);
if
(
idx
==
1000
)
return
false
;
INFO
(
"The monitor process uses
\"
%s
\"
as cgroup"
,
monitor_cgroup
);
return
true
;
}
/* Try to create the same cgroup in all hierarchies. Start with cgroup_pattern;
* next cgroup_pattern-1, -2, ..., -999.
*/
__cgfsng_ops
static
bool
cgfsng_payload_create
(
struct
cgroup_ops
*
ops
,
struct
lxc_handler
*
handler
)
__cgfsng_ops
static
inline
bool
cgfsng_payload_create
(
struct
cgroup_ops
*
ops
,
struct
lxc_handler
*
handler
)
{
__do_free
char
*
container_cgroup
=
NULL
,
*
tmp
=
NULL
;
int
i
;
size_t
len
;
char
*
container_cgroup
,
*
offset
,
*
tmp
;
char
*
offset
;
int
idx
=
0
;
struct
lxc_conf
*
conf
=
handler
->
conf
;
if
(
ops
->
container_cgroup
)
{
WARN
(
"cgfsng_create called a second time: %s"
,
ops
->
container_cgroup
);
if
(
ops
->
container_cgroup
)
return
false
;
}
if
(
!
conf
)
return
false
;
if
(
!
ops
->
hierarchies
)
return
true
;
if
(
conf
->
cgroup_meta
.
dir
)
tmp
=
lxc_string_join
(
"/"
,
(
const
char
*
[]){
conf
->
cgroup_meta
.
dir
,
handler
->
name
,
NULL
},
false
);
else
...
...
@@ -1291,78 +1423,81 @@ __cgfsng_ops static bool cgfsng_payload_create(struct cgroup_ops *ops,
len
=
strlen
(
tmp
)
+
5
;
/* leave room for -NNN\0 */
container_cgroup
=
must_realloc
(
NULL
,
len
);
(
void
)
strlcpy
(
container_cgroup
,
tmp
,
len
);
free
(
tmp
);
offset
=
container_cgroup
+
len
-
5
;
again:
if
(
idx
==
1000
)
{
ERROR
(
"Too many conflicting cgroup names"
);
goto
out_free
;
}
if
(
idx
)
{
int
ret
;
ret
=
snprintf
(
offset
,
5
,
"-%d"
,
idx
);
if
(
ret
<
0
||
(
size_t
)
ret
>=
5
)
{
FILE
*
f
=
fopen
(
"/dev/null"
,
"w"
);
if
(
f
)
{
fprintf
(
f
,
"Workaround for GCC7 bug: "
"https://gcc.gnu.org/bugzilla/"
"show_bug.cgi?id=78969"
);
fclose
(
f
);
}
do
{
if
(
idx
)
{
int
ret
=
snprintf
(
offset
,
5
,
"-%d"
,
idx
);
if
(
ret
<
0
||
(
size_t
)
ret
>=
5
)
return
false
;
}
}
for
(
i
=
0
;
ops
->
hierarchies
[
i
];
i
++
)
{
if
(
!
create_path_for_hierarchy
(
ops
->
hierarchies
[
i
],
container_cgroup
))
{
int
j
;
ERROR
(
"Failed to create cgroup
\"
%s
\"
"
,
ops
->
hierarchies
[
i
]
->
container_full_path
);
for
(
j
=
0
;
j
<
i
;
j
++
)
remove_path_for_hierarchy
(
ops
->
hierarchies
[
j
],
container_cgroup
);
idx
++
;
goto
again
;
for
(
i
=
0
;
ops
->
hierarchies
[
i
];
i
++
)
{
if
(
!
container_create_path_for_hierarchy
(
ops
->
hierarchies
[
i
],
container_cgroup
))
{
ERROR
(
"Failed to create cgroup
\"
%s
\"
"
,
ops
->
hierarchies
[
i
]
->
container_full_path
);
for
(
int
j
=
0
;
j
<
i
;
j
++
)
remove_path_for_hierarchy
(
ops
->
hierarchies
[
j
],
container_cgroup
,
false
);
idx
++
;
break
;
}
}
}
}
while
(
ops
->
hierarchies
[
i
]
&&
idx
>
0
&&
idx
<
1000
);
ops
->
container_cgroup
=
container_cgroup
;
if
(
idx
==
1000
)
return
false
;
INFO
(
"The container process uses
\"
%s
\"
as cgroup"
,
container_cgroup
);
ops
->
container_cgroup
=
move_ptr
(
container_cgroup
);
return
true
;
out_free:
free
(
container_cgroup
);
return
false
;
}
__cgfsng_ops
static
bool
cgfsng_payload_enter
(
struct
cgroup_ops
*
ops
,
pid_t
pid
)
__cgfsng_ops
static
bool
__do_cgroup_enter
(
struct
cgroup_ops
*
ops
,
pid_t
pid
,
bool
monitor
)
{
int
len
;
char
pidstr
[
INTTYPE_TO_STRLEN
(
pid_t
)];
if
(
!
ops
->
hierarchies
)
return
true
;
len
=
snprintf
(
pidstr
,
sizeof
(
pidstr
),
"%d"
,
pid
);
if
(
len
<
0
||
(
size_t
)
len
>=
sizeof
(
pidstr
))
return
false
;
for
(
int
i
=
0
;
ops
->
hierarchies
[
i
];
i
++
)
{
int
ret
;
char
*
fullpath
;
__do_free
char
*
path
=
NULL
;
fullpath
=
must_make_path
(
ops
->
hierarchies
[
i
]
->
container_full_path
,
"cgroup.procs"
,
NULL
);
ret
=
lxc_write_to_file
(
fullpath
,
pidstr
,
len
,
false
,
0666
);
if
(
monitor
)
path
=
must_make_path
(
ops
->
hierarchies
[
i
]
->
monitor_full_path
,
"cgroup.procs"
,
NULL
);
else
path
=
must_make_path
(
ops
->
hierarchies
[
i
]
->
container_full_path
,
"cgroup.procs"
,
NULL
);
ret
=
lxc_write_to_file
(
path
,
pidstr
,
len
,
false
,
0666
);
if
(
ret
!=
0
)
{
SYSERROR
(
"Failed to enter cgroup
\"
%s
\"
"
,
fullpath
);
free
(
fullpath
);
SYSERROR
(
"Failed to enter cgroup
\"
%s
\"
"
,
path
);
return
false
;
}
free
(
fullpath
);
}
return
true
;
}
__cgfsng_ops
static
bool
cgfsng_monitor_enter
(
struct
cgroup_ops
*
ops
,
pid_t
pid
)
{
return
__do_cgroup_enter
(
ops
,
pid
,
true
);
}
static
bool
cgfsng_payload_enter
(
struct
cgroup_ops
*
ops
,
pid_t
pid
)
{
return
__do_cgroup_enter
(
ops
,
pid
,
false
);
}
static
int
chowmod
(
char
*
path
,
uid_t
chown_uid
,
gid_t
chown_gid
,
mode_t
chmod_mode
)
{
...
...
@@ -1423,7 +1558,7 @@ static int chown_cgroup_wrapper(void *data)
destuid
=
0
;
for
(
i
=
0
;
arg
->
hierarchies
[
i
];
i
++
)
{
char
*
fullpath
;
__do_free
char
*
fullpath
=
NULL
;
char
*
path
=
arg
->
hierarchies
[
i
]
->
container_full_path
;
ret
=
chowmod
(
path
,
destuid
,
nsgid
,
0775
);
...
...
@@ -1440,23 +1575,18 @@ static int chown_cgroup_wrapper(void *data)
if
(
arg
->
hierarchies
[
i
]
->
version
==
CGROUP_SUPER_MAGIC
)
{
fullpath
=
must_make_path
(
path
,
"tasks"
,
NULL
);
(
void
)
chowmod
(
fullpath
,
destuid
,
nsgid
,
0664
);
free
(
fullpath
);
}
fullpath
=
must_make_path
(
path
,
"cgroup.procs"
,
NULL
);
(
void
)
chowmod
(
fullpath
,
destuid
,
nsgid
,
0664
);
free
(
fullpath
);
if
(
arg
->
hierarchies
[
i
]
->
version
!=
CGROUP2_SUPER_MAGIC
)
continue
;
fullpath
=
must_make_path
(
path
,
"cgroup.subtree_control"
,
NULL
);
(
void
)
chowmod
(
fullpath
,
destuid
,
nsgid
,
0664
);
free
(
fullpath
);
fullpath
=
must_make_path
(
path
,
"cgroup.threads"
,
NULL
);
(
void
)
chowmod
(
fullpath
,
destuid
,
nsgid
,
0664
);
free
(
fullpath
);
for
(
char
**
p
=
arg
->
hierarchies
[
i
]
->
cgroup2_chown
;
p
&&
*
p
;
p
++
)
{
fullpath
=
must_make_path
(
path
,
*
p
,
NULL
);
(
void
)
chowmod
(
fullpath
,
destuid
,
nsgid
,
0664
);
}
}
return
0
;
...
...
@@ -1470,6 +1600,9 @@ __cgfsng_ops static bool cgfsng_chown(struct cgroup_ops *ops,
if
(
lxc_list_empty
(
&
conf
->
id_map
))
return
true
;
if
(
!
ops
->
hierarchies
)
return
true
;
wrap
.
origuid
=
geteuid
();
wrap
.
path
=
NULL
;
wrap
.
hierarchies
=
ops
->
hierarchies
;
...
...
@@ -1501,8 +1634,8 @@ static int cg_legacy_mount_controllers(int type, struct hierarchy *h,
char
*
controllerpath
,
char
*
cgpath
,
const
char
*
container_cgroup
)
{
__do_free
char
*
sourcepath
=
NULL
;
int
ret
,
remount_flags
;
char
*
sourcepath
;
int
flags
=
MS_BIND
;
if
(
type
==
LXC_AUTO_CGROUP_RO
||
type
==
LXC_AUTO_CGROUP_MIXED
)
{
...
...
@@ -1535,7 +1668,6 @@ static int cg_legacy_mount_controllers(int type, struct hierarchy *h,
ret
=
mount
(
sourcepath
,
cgpath
,
"cgroup"
,
flags
,
NULL
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to mount
\"
%s
\"
onto
\"
%s
\"
"
,
h
->
controllers
[
0
],
cgpath
);
free
(
sourcepath
);
return
-
1
;
}
INFO
(
"Mounted
\"
%s
\"
onto
\"
%s
\"
"
,
h
->
controllers
[
0
],
cgpath
);
...
...
@@ -1546,13 +1678,11 @@ static int cg_legacy_mount_controllers(int type, struct hierarchy *h,
ret
=
mount
(
sourcepath
,
cgpath
,
"cgroup"
,
remount_flags
,
NULL
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to remount
\"
%s
\"
ro"
,
cgpath
);
free
(
sourcepath
);
return
-
1
;
}
INFO
(
"Remounted %s read-only"
,
cgpath
);
}
free
(
sourcepath
);
INFO
(
"Completed second stage cgroup automounts for
\"
%s
\"
"
,
cgpath
);
return
0
;
}
...
...
@@ -1567,7 +1697,7 @@ static int __cg_mount_direct(int type, struct hierarchy *h,
const
char
*
controllerpath
)
{
int
ret
;
char
*
controllers
=
NULL
;
__do_free
char
*
controllers
=
NULL
;
char
*
fstype
=
"cgroup2"
;
unsigned
long
flags
=
0
;
...
...
@@ -1587,7 +1717,6 @@ static int __cg_mount_direct(int type, struct hierarchy *h,
}
ret
=
mount
(
"cgroup"
,
controllerpath
,
fstype
,
flags
,
controllers
);
free
(
controllers
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to mount
\"
%s
\"
with cgroup filesystem type %s"
,
controllerpath
,
fstype
);
return
-
1
;
...
...
@@ -1616,10 +1745,13 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
struct
lxc_handler
*
handler
,
const
char
*
root
,
int
type
)
{
__do_free
char
*
tmpfspath
=
NULL
;
int
i
,
ret
;
char
*
tmpfspath
=
NULL
;
bool
has_cgns
=
false
,
retval
=
false
,
wants_force_mount
=
false
;
if
(
!
ops
->
hierarchies
)
return
true
;
if
((
type
&
LXC_AUTO_CGROUP_MASK
)
==
0
)
return
true
;
...
...
@@ -1653,7 +1785,7 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
goto
on_error
;
for
(
i
=
0
;
ops
->
hierarchies
[
i
];
i
++
)
{
char
*
controllerpath
,
*
path2
;
__do_free
char
*
controllerpath
=
NULL
,
*
path2
=
NULL
;
struct
hierarchy
*
h
=
ops
->
hierarchies
[
i
];
char
*
controller
=
strrchr
(
h
->
mountpoint
,
'/'
);
...
...
@@ -1662,15 +1794,12 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
controller
++
;
controllerpath
=
must_make_path
(
tmpfspath
,
controller
,
NULL
);
if
(
dir_exists
(
controllerpath
))
{
free
(
controllerpath
);
if
(
dir_exists
(
controllerpath
))
continue
;
}
ret
=
mkdir
(
controllerpath
,
0755
);
if
(
ret
<
0
)
{
SYSERROR
(
"Error creating cgroup path: %s"
,
controllerpath
);
free
(
controllerpath
);
goto
on_error
;
}
...
...
@@ -1680,7 +1809,6 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
* need to mount the cgroups manually.
*/
ret
=
cg_mount_in_cgroup_namespace
(
type
,
h
,
controllerpath
);
free
(
controllerpath
);
if
(
ret
<
0
)
goto
on_error
;
...
...
@@ -1688,45 +1816,35 @@ __cgfsng_ops static bool cgfsng_mount(struct cgroup_ops *ops,
}
ret
=
cg_mount_cgroup_full
(
type
,
h
,
controllerpath
);
if
(
ret
<
0
)
{
free
(
controllerpath
);
if
(
ret
<
0
)
goto
on_error
;
}
if
(
!
cg_mount_needs_subdirs
(
type
))
{
free
(
controllerpath
);
if
(
!
cg_mount_needs_subdirs
(
type
))
continue
;
}
path2
=
must_make_path
(
controllerpath
,
h
->
container_base_path
,
ops
->
container_cgroup
,
NULL
);
ret
=
mkdir_p
(
path2
,
0755
);
if
(
ret
<
0
)
{
free
(
controllerpath
);
free
(
path2
);
if
(
ret
<
0
)
goto
on_error
;
}
ret
=
cg_legacy_mount_controllers
(
type
,
h
,
controllerpath
,
path2
,
ops
->
container_cgroup
);
free
(
controllerpath
);
free
(
path2
);
if
(
ret
<
0
)
goto
on_error
;
}
retval
=
true
;
on_error:
free
(
tmpfspath
);
return
retval
;
}
static
int
recursive_count_nrtasks
(
char
*
dirname
)
{
__do_free
char
*
path
=
NULL
;
__do_closedir
DIR
*
dir
=
NULL
;
struct
dirent
*
direntp
;
DIR
*
dir
;
int
count
=
0
,
ret
;
char
*
path
;
dir
=
opendir
(
dirname
);
if
(
!
dir
)
...
...
@@ -1742,52 +1860,47 @@ static int recursive_count_nrtasks(char *dirname)
path
=
must_make_path
(
dirname
,
direntp
->
d_name
,
NULL
);
if
(
lstat
(
path
,
&
mystat
))
goto
next
;
continue
;
if
(
!
S_ISDIR
(
mystat
.
st_mode
))
goto
next
;
continue
;
count
+=
recursive_count_nrtasks
(
path
);
next:
free
(
path
);
}
path
=
must_make_path
(
dirname
,
"cgroup.procs"
,
NULL
);
ret
=
lxc_count_file_lines
(
path
);
if
(
ret
!=
-
1
)
count
+=
ret
;
free
(
path
);
(
void
)
closedir
(
dir
);
return
count
;
}
__cgfsng_ops
static
int
cgfsng_nrtasks
(
struct
cgroup_ops
*
ops
)
{
__do_free
char
*
path
=
NULL
;
int
count
;
char
*
path
;
if
(
!
ops
->
container_cgroup
||
!
ops
->
hierarchies
)
return
-
1
;
path
=
must_make_path
(
ops
->
hierarchies
[
0
]
->
container_full_path
,
NULL
);
count
=
recursive_count_nrtasks
(
path
);
free
(
path
);
return
count
;
}
/* Only root needs to escape to the cgroup of its init. */
__cgfsng_ops
static
bool
cgfsng_escape
(
const
struct
cgroup_ops
*
ops
)
__cgfsng_ops
static
bool
cgfsng_escape
(
const
struct
cgroup_ops
*
ops
,
struct
lxc_conf
*
conf
)
{
int
i
;
if
(
geteuid
())
if
(
geteuid
()
||
!
ops
->
hierarchies
)
return
true
;
for
(
i
=
0
;
ops
->
hierarchies
[
i
];
i
++
)
{
int
ret
;
char
*
fullpath
;
__do_free
char
*
fullpath
=
NULL
;
fullpath
=
must_make_path
(
ops
->
hierarchies
[
i
]
->
mountpoint
,
ops
->
hierarchies
[
i
]
->
container_base_path
,
...
...
@@ -1795,10 +1908,8 @@ __cgfsng_ops static bool cgfsng_escape(const struct cgroup_ops *ops)
ret
=
lxc_write_to_file
(
fullpath
,
"0"
,
2
,
false
,
0666
);
if
(
ret
!=
0
)
{
SYSERROR
(
"Failed to escape to cgroup
\"
%s
\"
"
,
fullpath
);
free
(
fullpath
);
return
false
;
}
free
(
fullpath
);
}
return
true
;
...
...
@@ -1806,9 +1917,12 @@ __cgfsng_ops static bool cgfsng_escape(const struct cgroup_ops *ops)
__cgfsng_ops
static
int
cgfsng_num_hierarchies
(
struct
cgroup_ops
*
ops
)
{
int
i
;
int
i
=
0
;
for
(
i
=
0
;
ops
->
hierarchies
[
i
];
i
++
)
if
(
!
ops
->
hierarchies
)
return
0
;
for
(;
ops
->
hierarchies
[
i
];
i
++
)
;
return
i
;
...
...
@@ -1818,6 +1932,9 @@ __cgfsng_ops static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n, c
{
int
i
;
if
(
!
ops
->
hierarchies
)
return
false
;
/* sanity check n */
for
(
i
=
0
;
i
<
n
;
i
++
)
if
(
!
ops
->
hierarchies
[
i
])
...
...
@@ -1837,7 +1954,7 @@ __cgfsng_ops static bool cgfsng_get_hierarchies(struct cgroup_ops *ops, int n, c
__cgfsng_ops
static
bool
cgfsng_unfreeze
(
struct
cgroup_ops
*
ops
)
{
int
ret
;
char
*
fullpath
;
__do_free
char
*
fullpath
=
NULL
;
struct
hierarchy
*
h
;
h
=
get_hierarchy
(
ops
,
"freezer"
);
...
...
@@ -1846,7 +1963,6 @@ __cgfsng_ops static bool cgfsng_unfreeze(struct cgroup_ops *ops)
fullpath
=
must_make_path
(
h
->
container_full_path
,
"freezer.state"
,
NULL
);
ret
=
lxc_write_to_file
(
fullpath
,
THAWED
,
THAWED_LEN
,
false
,
0666
);
free
(
fullpath
);
if
(
ret
<
0
)
return
false
;
...
...
@@ -1891,10 +2007,11 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name,
const
char
*
lxcpath
,
const
char
*
pidstr
,
size_t
pidstr_len
,
const
char
*
controller
)
{
__do_free
char
*
base_path
=
NULL
,
*
container_cgroup
=
NULL
,
*
full_path
=
NULL
;
int
ret
;
size_t
len
;
int
fret
=
-
1
,
idx
=
0
;
char
*
base_path
=
NULL
,
*
container_cgroup
=
NULL
,
*
full_path
=
NULL
;
container_cgroup
=
lxc_cmd_get_cgroup_path
(
name
,
lxcpath
,
controller
);
/* not running */
...
...
@@ -1911,8 +2028,6 @@ static int __cg_unified_attach(const struct hierarchy *h, const char *name,
if
(
ret
==
0
)
goto
on_success
;
free
(
full_path
);
len
=
strlen
(
base_path
)
+
STRLITERALLEN
(
"/lxc-1000"
)
+
STRLITERALLEN
(
"/cgroup-procs"
);
full_path
=
must_realloc
(
NULL
,
len
+
1
);
...
...
@@ -1946,10 +2061,6 @@ on_success:
fret
=
0
;
on_error:
free
(
base_path
);
free
(
container_cgroup
);
free
(
full_path
);
return
fret
;
}
...
...
@@ -1959,12 +2070,15 @@ __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name,
int
i
,
len
,
ret
;
char
pidstr
[
INTTYPE_TO_STRLEN
(
pid_t
)];
if
(
!
ops
->
hierarchies
)
return
true
;
len
=
snprintf
(
pidstr
,
sizeof
(
pidstr
),
"%d"
,
pid
);
if
(
len
<
0
||
(
size_t
)
len
>=
sizeof
(
pidstr
))
return
false
;
for
(
i
=
0
;
ops
->
hierarchies
[
i
];
i
++
)
{
char
*
path
;
__do_free
char
*
path
=
NULL
;
char
*
fullpath
=
NULL
;
struct
hierarchy
*
h
=
ops
->
hierarchies
[
i
];
...
...
@@ -1983,14 +2097,11 @@ __cgfsng_ops static bool cgfsng_attach(struct cgroup_ops *ops, const char *name,
continue
;
fullpath
=
build_full_cgpath_from_monitorpath
(
h
,
path
,
"cgroup.procs"
);
free
(
path
);
ret
=
lxc_write_to_file
(
fullpath
,
pidstr
,
len
,
false
,
0666
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to attach %d to %s"
,
(
int
)
pid
,
fullpath
);
free
(
fullpath
);
return
false
;
}
free
(
fullpath
);
}
return
true
;
...
...
@@ -2004,8 +2115,9 @@ __cgfsng_ops static int cgfsng_get(struct cgroup_ops *ops, const char *filename,
char
*
value
,
size_t
len
,
const
char
*
name
,
const
char
*
lxcpath
)
{
__do_free
char
*
controller
;
char
*
p
,
*
path
;
__do_free
char
*
path
=
NULL
;
__do_free
char
*
controller
=
NULL
;
char
*
p
;
struct
hierarchy
*
h
;
int
ret
=
-
1
;
...
...
@@ -2021,13 +2133,11 @@ __cgfsng_ops static int cgfsng_get(struct cgroup_ops *ops, const char *filename,
h
=
get_hierarchy
(
ops
,
controller
);
if
(
h
)
{
char
*
fullpath
;
__do_free
char
*
fullpath
=
NULL
;
fullpath
=
build_full_cgpath_from_monitorpath
(
h
,
path
,
filename
);
ret
=
lxc_read_from_file
(
fullpath
,
value
,
len
);
free
(
fullpath
);
}
free
(
path
);
return
ret
;
}
...
...
@@ -2040,8 +2150,9 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops,
const
char
*
filename
,
const
char
*
value
,
const
char
*
name
,
const
char
*
lxcpath
)
{
__do_free
char
*
controller
;
char
*
p
,
*
path
;
__do_free
char
*
path
=
NULL
;
__do_free
char
*
controller
=
NULL
;
char
*
p
;
struct
hierarchy
*
h
;
int
ret
=
-
1
;
...
...
@@ -2057,13 +2168,11 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops,
h
=
get_hierarchy
(
ops
,
controller
);
if
(
h
)
{
char
*
fullpath
;
__do_free
char
*
fullpath
=
NULL
;
fullpath
=
build_full_cgpath_from_monitorpath
(
h
,
path
,
filename
);
ret
=
lxc_write_to_file
(
fullpath
,
value
,
strlen
(
value
),
false
,
0666
);
free
(
fullpath
);
}
free
(
path
);
return
ret
;
}
...
...
@@ -2077,8 +2186,9 @@ __cgfsng_ops static int cgfsng_set(struct cgroup_ops *ops,
*/
static
int
convert_devpath
(
const
char
*
invalue
,
char
*
dest
)
{
__do_free
char
*
path
=
NULL
;
int
n_parts
;
char
*
p
,
*
path
,
type
;
char
*
p
,
type
;
unsigned
long
minor
,
major
;
struct
stat
sb
;
int
ret
=
-
EINVAL
;
...
...
@@ -2142,7 +2252,6 @@ static int convert_devpath(const char *invalue, char *dest)
ret
=
0
;
out:
free
(
path
);
return
ret
;
}
...
...
@@ -2152,8 +2261,9 @@ out:
static
int
cg_legacy_set_data
(
struct
cgroup_ops
*
ops
,
const
char
*
filename
,
const
char
*
value
)
{
__do_free
char
*
controller
;
char
*
fullpath
,
*
p
;
__do_free
char
*
controller
=
NULL
;
__do_free
char
*
fullpath
=
NULL
;
char
*
p
;
/* "b|c <2^64-1>:<2^64-1> r|w|m" = 47 chars max */
char
converted_value
[
50
];
struct
hierarchy
*
h
;
...
...
@@ -2183,7 +2293,6 @@ static int cg_legacy_set_data(struct cgroup_ops *ops, const char *filename,
fullpath
=
must_make_path
(
h
->
container_full_path
,
filename
,
NULL
);
ret
=
lxc_write_to_file
(
fullpath
,
value
,
strlen
(
value
),
false
,
0666
);
free
(
fullpath
);
return
ret
;
}
...
...
@@ -2191,13 +2300,17 @@ static bool __cg_legacy_setup_limits(struct cgroup_ops *ops,
struct
lxc_list
*
cgroup_settings
,
bool
do_devices
)
{
struct
lxc_list
*
iterator
,
*
next
,
*
sorted_cgroup_settings
;
__do_free
struct
lxc_list
*
sorted_cgroup_settings
=
NULL
;
struct
lxc_list
*
iterator
,
*
next
;
struct
lxc_cgroup
*
cg
;
bool
ret
=
false
;
if
(
lxc_list_empty
(
cgroup_settings
))
return
true
;
if
(
!
ops
->
hierarchies
)
return
false
;
sorted_cgroup_settings
=
sort_cgroup_settings
(
cgroup_settings
);
if
(
!
sorted_cgroup_settings
)
return
false
;
...
...
@@ -2228,7 +2341,7 @@ out:
lxc_list_del
(
iterator
);
free
(
iterator
);
}
free
(
sorted_cgroup_settings
);
return
ret
;
}
...
...
@@ -2245,13 +2358,12 @@ static bool __cg_unified_setup_limits(struct cgroup_ops *ops,
return
false
;
lxc_list_for_each
(
iterator
,
cgroup_settings
)
{
__do_free
char
*
fullpath
=
NULL
;
int
ret
;
char
*
fullpath
;
struct
lxc_cgroup
*
cg
=
iterator
->
elem
;
fullpath
=
must_make_path
(
h
->
container_full_path
,
cg
->
subsystem
,
NULL
);
ret
=
lxc_write_to_file
(
fullpath
,
cg
->
value
,
strlen
(
cg
->
value
),
false
,
0666
);
free
(
fullpath
);
if
(
ret
<
0
)
{
SYSERROR
(
"Failed to set
\"
%s
\"
to
\"
%s
\"
"
,
cg
->
subsystem
,
cg
->
value
);
...
...
@@ -2305,24 +2417,51 @@ static bool cgroup_use_wants_controllers(const struct cgroup_ops *ops,
return
true
;
}
static
void
cg_unified_delegate
(
char
***
delegate
)
{
__do_free
char
*
tmp
=
NULL
;
int
idx
;
char
*
standard
[]
=
{
"cgroup.subtree_control"
,
"cgroup.threads"
,
NULL
};
tmp
=
read_file
(
"/sys/kernel/cgroup/delegate"
);
if
(
!
tmp
)
{
for
(
char
**
p
=
standard
;
p
&&
*
p
;
p
++
)
{
idx
=
append_null_to_list
((
void
***
)
delegate
);
(
*
delegate
)[
idx
]
=
must_copy_string
(
*
p
);
}
}
else
{
char
*
token
;
lxc_iterate_parts
(
token
,
tmp
,
"
\t\n
"
)
{
/*
* We always need to chown this for both cgroup and
* cgroup2.
*/
if
(
strcmp
(
token
,
"cgroup.procs"
)
==
0
)
continue
;
idx
=
append_null_to_list
((
void
***
)
delegate
);
(
*
delegate
)[
idx
]
=
must_copy_string
(
token
);
}
}
}
/* At startup, parse_hierarchies finds all the info we need about cgroup
* mountpoints and current cgroups, and stores it in @d.
*/
static
bool
cg_hybrid_init
(
struct
cgroup_ops
*
ops
)
static
bool
cg_hybrid_init
(
struct
cgroup_ops
*
ops
,
bool
relative
,
bool
unprivileged
)
{
__do_free
char
*
basecginfo
=
NULL
;
__do_free
char
*
line
=
NULL
;
__do_fclose
FILE
*
f
=
NULL
;
int
ret
;
char
*
basecginfo
;
bool
will_escape
;
FILE
*
f
;
size_t
len
=
0
;
char
*
line
=
NULL
;
char
**
klist
=
NULL
,
**
nlist
=
NULL
;
/* Root spawned containers escape the current cgroup, so use init's
* cgroups as our base in that case.
*/
will_escape
=
(
geteuid
()
==
0
);
if
(
will_escape
)
if
(
!
relative
&&
(
geteuid
()
==
0
))
basecginfo
=
read_file
(
"/proc/1/cgroup"
);
else
basecginfo
=
read_file
(
"/proc/self/cgroup"
);
...
...
@@ -2332,14 +2471,12 @@ static bool cg_hybrid_init(struct cgroup_ops *ops)
ret
=
get_existing_subsystems
(
&
klist
,
&
nlist
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to retrieve available legacy cgroup controllers"
);
free
(
basecginfo
);
return
false
;
}
f
=
fopen
(
"/proc/self/mountinfo"
,
"r"
);
if
(
!
f
)
{
ERROR
(
"Failed to open
\"
/proc/self/mountinfo
\"
"
);
free
(
basecginfo
);
return
false
;
}
...
...
@@ -2425,8 +2562,11 @@ static bool cg_hybrid_init(struct cgroup_ops *ops)
goto
next
;
new
=
add_hierarchy
(
&
ops
->
hierarchies
,
controller_list
,
mountpoint
,
base_cgroup
,
type
);
if
(
type
==
CGROUP2_SUPER_MAGIC
&&
!
ops
->
unified
)
if
(
type
==
CGROUP2_SUPER_MAGIC
&&
!
ops
->
unified
)
{
if
(
unprivileged
)
cg_unified_delegate
(
&
new
->
cgroup2_chown
);
ops
->
unified
=
new
;
}
continue
;
...
...
@@ -2439,11 +2579,6 @@ static bool cg_hybrid_init(struct cgroup_ops *ops)
free_string_list
(
klist
);
free_string_list
(
nlist
);
free
(
basecginfo
);
fclose
(
f
);
free
(
line
);
TRACE
(
"Writable cgroup hierarchies:"
);
lxc_cgfsng_print_hierarchies
(
ops
);
...
...
@@ -2473,14 +2608,13 @@ static int cg_is_pure_unified(void)
}
/* Get current cgroup from /proc/self/cgroup for the cgroupfs v2 hierarchy. */
static
char
*
cg_unified_get_current_cgroup
(
void
)
static
char
*
cg_unified_get_current_cgroup
(
bool
relative
)
{
char
*
basecginfo
,
*
base_cgroup
;
bool
will_escape
;
__do_free
char
*
basecginfo
=
NULL
;
char
*
base_cgroup
;
char
*
copy
=
NULL
;
will_escape
=
(
geteuid
()
==
0
);
if
(
will_escape
)
if
(
!
relative
&&
(
geteuid
()
==
0
))
basecginfo
=
read_file
(
"/proc/1/cgroup"
);
else
basecginfo
=
read_file
(
"/proc/self/cgroup"
);
...
...
@@ -2497,19 +2631,20 @@ static char *cg_unified_get_current_cgroup(void)
goto
cleanup_on_err
;
cleanup_on_err:
free
(
basecginfo
);
if
(
copy
)
trim
(
copy
);
return
copy
;
}
static
int
cg_unified_init
(
struct
cgroup_ops
*
ops
)
static
int
cg_unified_init
(
struct
cgroup_ops
*
ops
,
bool
relative
,
bool
unprivileged
)
{
__do_free
char
*
subtree_path
=
NULL
;
int
ret
;
char
*
mountpoint
;
char
**
delegatable
;
struct
hierarchy
*
new
;
char
*
base_cgroup
=
NULL
;
ret
=
cg_is_pure_unified
();
...
...
@@ -2519,7 +2654,7 @@ static int cg_unified_init(struct cgroup_ops *ops)
if
(
ret
!=
CGROUP2_SUPER_MAGIC
)
return
0
;
base_cgroup
=
cg_unified_get_current_cgroup
();
base_cgroup
=
cg_unified_get_current_cgroup
(
relative
);
if
(
!
base_cgroup
)
return
-
EINVAL
;
prune_init_scope
(
base_cgroup
);
...
...
@@ -2544,39 +2679,41 @@ static int cg_unified_init(struct cgroup_ops *ops)
* controllers per container.
*/
new
=
add_hierarchy
(
&
ops
->
hierarchies
,
delegatable
,
mountpoint
,
base_cgroup
,
CGROUP2_SUPER_MAGIC
);
if
(
!
unprivileged
)
cg_unified_delegate
(
&
new
->
cgroup2_chown
);
ops
->
cgroup_layout
=
CGROUP_LAYOUT_UNIFIED
;
ops
->
unified
=
add_hierarchy
(
&
ops
->
hierarchies
,
delegatable
,
mountpoint
,
base_cgroup
,
CGROUP2_SUPER_MAGIC
);
ops
->
unified
=
new
;
return
CGROUP2_SUPER_MAGIC
;
}
static
bool
cg_init
(
struct
cgroup_ops
*
ops
)
static
bool
cg_init
(
struct
cgroup_ops
*
ops
,
struct
lxc_conf
*
conf
)
{
int
ret
;
const
char
*
tmp
;
bool
relative
=
false
;
tmp
=
lxc_global_config_value
(
"lxc.cgroup.use"
);
if
(
tmp
)
{
char
*
chop
,
*
cur
,
*
pin
;
__do_free
char
*
pin
=
NULL
;
char
*
chop
,
*
cur
;
pin
=
must_copy_string
(
tmp
);
chop
=
pin
;
lxc_iterate_parts
(
cur
,
chop
,
","
)
{
lxc_iterate_parts
(
cur
,
chop
,
","
)
must_append_string
(
&
ops
->
cgroup_use
,
cur
);
}
free
(
pin
);
}
ret
=
cg_unified_init
(
ops
);
ret
=
cg_unified_init
(
ops
,
relative
,
!
lxc_list_empty
(
&
conf
->
id_map
)
);
if
(
ret
<
0
)
return
false
;
if
(
ret
==
CGROUP2_SUPER_MAGIC
)
return
true
;
return
cg_hybrid_init
(
ops
);
return
cg_hybrid_init
(
ops
,
relative
,
!
lxc_list_empty
(
&
conf
->
id_map
)
);
}
__cgfsng_ops
static
bool
cgfsng_data_init
(
struct
cgroup_ops
*
ops
)
...
...
@@ -2591,11 +2728,12 @@ __cgfsng_ops static bool cgfsng_data_init(struct cgroup_ops *ops)
return
false
;
}
ops
->
cgroup_pattern
=
must_copy_string
(
cgroup_pattern
);
ops
->
monitor_pattern
=
MONITOR_CGROUP
;
return
true
;
}
struct
cgroup_ops
*
cgfsng_ops_init
(
void
)
struct
cgroup_ops
*
cgfsng_ops_init
(
struct
lxc_conf
*
conf
)
{
struct
cgroup_ops
*
cgfsng_ops
;
...
...
@@ -2606,14 +2744,16 @@ struct cgroup_ops *cgfsng_ops_init(void)
memset
(
cgfsng_ops
,
0
,
sizeof
(
struct
cgroup_ops
));
cgfsng_ops
->
cgroup_layout
=
CGROUP_LAYOUT_UNKNOWN
;
if
(
!
cg_init
(
cgfsng_ops
))
{
if
(
!
cg_init
(
cgfsng_ops
,
conf
))
{
free
(
cgfsng_ops
);
return
NULL
;
}
cgfsng_ops
->
data_init
=
cgfsng_data_init
;
cgfsng_ops
->
destroy
=
cgfsng_payload_destroy
;
cgfsng_ops
->
destroy
=
cgfsng_payload_destroy
;
cgfsng_ops
->
payload_destroy
=
cgfsng_payload_destroy
;
cgfsng_ops
->
monitor_destroy
=
cgfsng_monitor_destroy
;
cgfsng_ops
->
monitor_create
=
cgfsng_monitor_create
;
cgfsng_ops
->
monitor_enter
=
cgfsng_monitor_enter
;
cgfsng_ops
->
payload_create
=
cgfsng_payload_create
;
cgfsng_ops
->
payload_enter
=
cgfsng_payload_enter
;
cgfsng_ops
->
escape
=
cgfsng_escape
;
...
...
src/lxc/cgroups/cgroup.c
View file @
3f76bcd6
...
...
@@ -38,13 +38,13 @@
lxc_log_define
(
cgroup
,
lxc
);
extern
struct
cgroup_ops
*
cgfsng_ops_init
(
void
);
extern
struct
cgroup_ops
*
cgfsng_ops_init
(
struct
lxc_conf
*
conf
);
struct
cgroup_ops
*
cgroup_init
(
struct
lxc_
handler
*
handler
)
struct
cgroup_ops
*
cgroup_init
(
struct
lxc_
conf
*
conf
)
{
struct
cgroup_ops
*
cgroup_ops
;
cgroup_ops
=
cgfsng_ops_init
();
cgroup_ops
=
cgfsng_ops_init
(
conf
);
if
(
!
cgroup_ops
)
{
ERROR
(
"Failed to initialize cgroup driver"
);
return
NULL
;
...
...
@@ -82,15 +82,20 @@ void cgroup_exit(struct cgroup_ops *ops)
free
(
ops
->
container_cgroup
);
for
(
it
=
ops
->
hierarchies
;
it
&&
*
it
;
it
++
)
{
char
**
ctrlr
;
char
**
p
;
for
(
ctrlr
=
(
*
it
)
->
controllers
;
ctrlr
&&
*
ctrlr
;
ctrlr
++
)
free
(
*
ctrlr
);
for
(
p
=
(
*
it
)
->
controllers
;
p
&&
*
p
;
p
++
)
free
(
*
p
);
free
((
*
it
)
->
controllers
);
for
(
p
=
(
*
it
)
->
cgroup2_chown
;
p
&&
*
p
;
p
++
)
free
(
*
p
);
free
((
*
it
)
->
cgroup2_chown
);
free
((
*
it
)
->
mountpoint
);
free
((
*
it
)
->
container_base_path
);
free
((
*
it
)
->
container_full_path
);
free
((
*
it
)
->
monitor_full_path
);
free
(
*
it
);
}
free
(
ops
->
hierarchies
);
...
...
src/lxc/cgroups/cgroup.h
View file @
3f76bcd6
...
...
@@ -28,6 +28,10 @@
#include <stddef.h>
#include <sys/types.h>
#define PAYLOAD_CGROUP "lxc.payload"
#define MONITOR_CGROUP "lxc.monitor"
#define PIVOT_CGROUP "lxc.pivot"
struct
lxc_handler
;
struct
lxc_conf
;
struct
lxc_list
;
...
...
@@ -65,6 +69,9 @@ typedef enum {
* @container_full_path
* - The full path to the containers cgroup.
*
* @monitor_full_path
* - The full path to the monitor's cgroup.
*
* @version
* - legacy hierarchy
* If the hierarchy is a legacy hierarchy this will be set to
...
...
@@ -74,10 +81,16 @@ typedef enum {
* CGROUP2_SUPER_MAGIC.
*/
struct
hierarchy
{
/*
* cgroup2 only: what files need to be chowned to delegate a cgroup to
* an unprivileged user.
*/
char
**
cgroup2_chown
;
char
**
controllers
;
char
*
mountpoint
;
char
*
container_base_path
;
char
*
container_full_path
;
char
*
monitor_full_path
;
int
version
;
};
...
...
@@ -93,6 +106,9 @@ struct cgroup_ops {
char
*
cgroup_pattern
;
char
*
container_cgroup
;
/* Static memory, do not free.*/
const
char
*
monitor_pattern
;
/* @hierarchies
* - A NULL-terminated array of struct hierarchy, one per legacy
* hierarchy. No duplicates. First sufficient, writeable mounted
...
...
@@ -124,11 +140,14 @@ struct cgroup_ops {
cgroup_layout_t
cgroup_layout
;
bool
(
*
data_init
)(
struct
cgroup_ops
*
ops
);
void
(
*
destroy
)(
struct
cgroup_ops
*
ops
,
struct
lxc_handler
*
handler
);
void
(
*
payload_destroy
)(
struct
cgroup_ops
*
ops
,
struct
lxc_handler
*
handler
);
void
(
*
monitor_destroy
)(
struct
cgroup_ops
*
ops
,
struct
lxc_handler
*
handler
);
bool
(
*
monitor_create
)(
struct
cgroup_ops
*
ops
,
struct
lxc_handler
*
handler
);
bool
(
*
monitor_enter
)(
struct
cgroup_ops
*
ops
,
pid_t
pid
);
bool
(
*
payload_create
)(
struct
cgroup_ops
*
ops
,
struct
lxc_handler
*
handler
);
bool
(
*
payload_enter
)(
struct
cgroup_ops
*
ops
,
pid_t
pid
);
const
char
*
(
*
get_cgroup
)(
struct
cgroup_ops
*
ops
,
const
char
*
controller
);
bool
(
*
escape
)(
const
struct
cgroup_ops
*
ops
);
bool
(
*
escape
)(
const
struct
cgroup_ops
*
ops
,
struct
lxc_conf
*
conf
);
int
(
*
num_hierarchies
)(
struct
cgroup_ops
*
ops
);
bool
(
*
get_hierarchies
)(
struct
cgroup_ops
*
ops
,
int
n
,
char
***
out
);
int
(
*
set
)(
struct
cgroup_ops
*
ops
,
const
char
*
filename
,
...
...
@@ -146,7 +165,7 @@ struct cgroup_ops {
int
(
*
nrtasks
)(
struct
cgroup_ops
*
ops
);
};
extern
struct
cgroup_ops
*
cgroup_init
(
struct
lxc_
handler
*
handler
);
extern
struct
cgroup_ops
*
cgroup_init
(
struct
lxc_
conf
*
conf
);
extern
void
cgroup_exit
(
struct
cgroup_ops
*
ops
);
extern
void
prune_init_scope
(
char
*
cg
);
...
...
src/lxc/criu.c
View file @
3f76bcd6
...
...
@@ -194,7 +194,7 @@ static void exec_criu(struct cgroup_ops *cgroup_ops, struct lxc_conf *conf,
* /actual/ root cgroup so that lxcfs thinks criu has enough rights to
* see all cgroups.
*/
if
(
!
cgroup_ops
->
escape
(
cgroup_ops
))
{
if
(
!
cgroup_ops
->
escape
(
cgroup_ops
,
conf
))
{
ERROR
(
"failed to escape cgroups"
);
return
;
}
...
...
@@ -969,7 +969,7 @@ static void do_restore(struct lxc_container *c, int status_pipe, struct migrate_
if
(
lxc_init
(
c
->
name
,
handler
)
<
0
)
goto
out
;
cgroup_ops
=
cgroup_init
(
NULL
);
cgroup_ops
=
cgroup_init
(
c
->
lxc_conf
);
if
(
!
cgroup_ops
)
goto
out_fini_handler
;
handler
->
cgroup_ops
=
cgroup_ops
;
...
...
@@ -1268,7 +1268,7 @@ static bool do_dump(struct lxc_container *c, char *mode, struct migrate_opts *op
close
(
criuout
[
0
]);
cgroup_ops
=
cgroup_init
(
NULL
);
cgroup_ops
=
cgroup_init
(
c
->
lxc_conf
);
if
(
!
cgroup_ops
)
{
ERROR
(
"failed to cgroup_init()"
);
_exit
(
EXIT_FAILURE
);
...
...
src/lxc/freezer.c
View file @
3f76bcd6
...
...
@@ -45,35 +45,41 @@
lxc_log_define
(
freezer
,
lxc
);
static
int
do_freeze_thaw
(
bool
freeze
,
const
char
*
name
,
const
char
*
lxcpath
)
static
int
do_freeze_thaw
(
bool
freeze
,
struct
lxc_conf
*
conf
,
const
char
*
name
,
const
char
*
lxcpath
)
{
int
ret
;
char
v
[
100
];
struct
cgroup_ops
*
cgroup_ops
;
const
char
*
state
=
freeze
?
"FROZEN"
:
"THAWED"
;
size_t
state_len
=
6
;
const
char
*
state
;
size_t
state_len
;
lxc_state_t
new_state
=
freeze
?
FROZEN
:
THAWED
;
cgroup_ops
=
cgroup_init
(
NULL
);
state
=
lxc_state2str
(
new_state
);
state_len
=
strlen
(
state
);
cgroup_ops
=
cgroup_init
(
conf
);
if
(
!
cgroup_ops
)
return
-
1
;
ret
=
cgroup_ops
->
set
(
cgroup_ops
,
"freezer.state"
,
state
,
name
,
lxcpath
);
if
(
ret
<
0
)
{
cgroup_exit
(
cgroup_ops
);
ERROR
(
"Failed to freeze %s"
,
name
);
ERROR
(
"Failed to %s %s"
,
(
new_state
==
FROZEN
?
"freeze"
:
"unfreeze"
),
name
);
return
-
1
;
}
for
(;;)
{
ret
=
cgroup_ops
->
get
(
cgroup_ops
,
"freezer.state"
,
v
,
sizeof
(
v
),
name
,
lxcpath
);
ret
=
cgroup_ops
->
get
(
cgroup_ops
,
"freezer.state"
,
v
,
sizeof
(
v
),
name
,
lxcpath
);
if
(
ret
<
0
)
{
cgroup_exit
(
cgroup_ops
);
ERROR
(
"Failed to get freezer state of %s"
,
name
);
return
-
1
;
}
v
[
99
]
=
'\0'
;
v
[
sizeof
(
v
)
-
1
]
=
'\0'
;
v
[
lxc_char_right_gc
(
v
,
strlen
(
v
))]
=
'\0'
;
ret
=
strncmp
(
v
,
state
,
state_len
);
...
...
@@ -88,14 +94,14 @@ static int do_freeze_thaw(bool freeze, const char *name, const char *lxcpath)
}
}
int
lxc_freeze
(
const
char
*
name
,
const
char
*
lxcpath
)
int
lxc_freeze
(
struct
lxc_conf
*
conf
,
const
char
*
name
,
const
char
*
lxcpath
)
{
lxc_cmd_serve_state_clients
(
name
,
lxcpath
,
FREEZING
);
lxc_monitor_send_state
(
name
,
FREEZING
,
lxcpath
);
return
do_freeze_thaw
(
true
,
name
,
lxcpath
);
return
do_freeze_thaw
(
true
,
conf
,
name
,
lxcpath
);
}
int
lxc_unfreeze
(
const
char
*
name
,
const
char
*
lxcpath
)
int
lxc_unfreeze
(
struct
lxc_conf
*
conf
,
const
char
*
name
,
const
char
*
lxcpath
)
{
return
do_freeze_thaw
(
false
,
name
,
lxcpath
);
return
do_freeze_thaw
(
false
,
conf
,
name
,
lxcpath
);
}
src/lxc/initutils.c
View file @
3f76bcd6
...
...
@@ -105,7 +105,7 @@ const char *lxc_global_config_value(const char *option_name)
sprintf
(
user_config_path
,
"%s/.config/lxc/lxc.conf"
,
user_home
);
sprintf
(
user_default_config_path
,
"%s/.config/lxc/default.conf"
,
user_home
);
sprintf
(
user_lxc_path
,
"%s/.local/share/lxc/"
,
user_home
);
user_cgroup_pattern
=
strdup
(
"lxc/%n"
);
user_cgroup_pattern
=
strdup
(
"lxc
.payload
/%n"
);
}
else
{
user_config_path
=
strdup
(
LXC_GLOBAL_CONF
);
...
...
src/lxc/lxc.h
View file @
3f76bcd6
...
...
@@ -82,14 +82,16 @@ extern int lxc_monitor_close(int fd);
* @name : the container name
* Returns 0 on success, < 0 otherwise
*/
extern
int
lxc_freeze
(
const
char
*
name
,
const
char
*
lxcpath
);
extern
int
lxc_freeze
(
struct
lxc_conf
*
conf
,
const
char
*
name
,
const
char
*
lxcpath
);
/*
* Unfreeze all previously frozen tasks.
* @name : the name of the container
* Return 0 on success, < 0 otherwise
*/
extern
int
lxc_unfreeze
(
const
char
*
name
,
const
char
*
lxcpath
);
extern
int
lxc_unfreeze
(
struct
lxc_conf
*
conf
,
const
char
*
name
,
const
char
*
lxcpath
);
/*
* Retrieve the container state
...
...
src/lxc/lxccontainer.c
View file @
3f76bcd6
...
...
@@ -503,14 +503,14 @@ WRAP_API(bool, lxcapi_is_running)
static
bool
do_lxcapi_freeze
(
struct
lxc_container
*
c
)
{
int
ret
;
lxc_state_t
s
;
if
(
!
c
)
if
(
!
c
||
!
c
->
lxc_conf
)
return
false
;
ret
=
lxc_freez
e
(
c
->
name
,
c
->
config_path
);
if
(
ret
<
0
)
return
false
;
s
=
lxc_getstat
e
(
c
->
name
,
c
->
config_path
);
if
(
s
!=
FROZEN
)
return
lxc_freeze
(
c
->
lxc_conf
,
c
->
name
,
c
->
config_path
)
==
0
;
return
true
;
}
...
...
@@ -519,14 +519,14 @@ WRAP_API(bool, lxcapi_freeze)
static
bool
do_lxcapi_unfreeze
(
struct
lxc_container
*
c
)
{
int
ret
;
lxc_state_t
s
;
if
(
!
c
)
if
(
!
c
||
!
c
->
lxc_conf
)
return
false
;
ret
=
lxc_unfreez
e
(
c
->
name
,
c
->
config_path
);
if
(
ret
<
0
)
return
false
;
s
=
lxc_getstat
e
(
c
->
name
,
c
->
config_path
);
if
(
s
==
FROZEN
)
return
lxc_unfreeze
(
c
->
lxc_conf
,
c
->
name
,
c
->
config_path
)
==
0
;
return
true
;
}
...
...
@@ -2192,6 +2192,9 @@ static inline bool enter_net_ns(struct lxc_container *c)
{
pid_t
pid
=
do_lxcapi_init_pid
(
c
);
if
(
pid
<
0
)
return
false
;
if
((
geteuid
()
!=
0
||
(
c
->
lxc_conf
&&
!
lxc_list_empty
(
&
c
->
lxc_conf
->
id_map
)))
&&
(
access
(
"/proc/self/ns/user"
,
F_OK
)
==
0
))
if
(
!
switch_to_ns
(
pid
,
"user"
))
...
...
@@ -3241,7 +3244,7 @@ static bool do_lxcapi_set_cgroup_item(struct lxc_container *c, const char *subsy
if
(
is_stopped
(
c
))
return
false
;
cgroup_ops
=
cgroup_init
(
NULL
);
cgroup_ops
=
cgroup_init
(
c
->
lxc_conf
);
if
(
!
cgroup_ops
)
return
false
;
...
...
@@ -3265,7 +3268,7 @@ static int do_lxcapi_get_cgroup_item(struct lxc_container *c, const char *subsys
if
(
is_stopped
(
c
))
return
-
1
;
cgroup_ops
=
cgroup_init
(
NULL
);
cgroup_ops
=
cgroup_init
(
c
->
lxc_conf
);
if
(
!
cgroup_ops
)
return
-
1
;
...
...
@@ -4601,6 +4604,7 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
struct
stat
st
;
char
value
[
LXC_MAX_BUFFER
];
const
char
*
p
;
pid_t
init_pid
;
/* make sure container is running */
if
(
!
do_lxcapi_is_running
(
c
))
{
...
...
@@ -4627,7 +4631,13 @@ static bool add_remove_device_node(struct lxc_container *c, const char *src_path
if
(
ret
<
0
||
ret
>=
LXC_MAX_BUFFER
)
return
false
;
if
(
!
do_add_remove_node
(
do_lxcapi_init_pid
(
c
),
p
,
add
,
&
st
))
init_pid
=
do_lxcapi_init_pid
(
c
);
if
(
init_pid
<
0
)
{
ERROR
(
"Failed to get init pid"
);
return
false
;
}
if
(
!
do_add_remove_node
(
init_pid
,
p
,
add
,
&
st
))
return
false
;
/* add or remove device to/from cgroup access list */
...
...
@@ -4697,6 +4707,11 @@ static bool do_lxcapi_attach_interface(struct lxc_container *c,
}
init_pid
=
do_lxcapi_init_pid
(
c
);
if
(
init_pid
<
0
)
{
ERROR
(
"Failed to get init pid"
);
goto
err
;
}
ret
=
lxc_netdev_move_by_name
(
ifname
,
init_pid
,
dst_ifname
);
if
(
ret
)
goto
err
;
...
...
@@ -4742,6 +4757,10 @@ static bool do_lxcapi_detach_interface(struct lxc_container *c,
pid_t
init_pid
;
init_pid
=
do_lxcapi_init_pid
(
c
);
if
(
init_pid
<
0
)
{
ERROR
(
"Failed to get init pid"
);
_exit
(
EXIT_FAILURE
);
}
if
(
!
switch_to_ns
(
init_pid
,
"net"
))
{
ERROR
(
"Failed to enter network namespace"
);
_exit
(
EXIT_FAILURE
);
...
...
src/lxc/start.c
View file @
3f76bcd6
...
...
@@ -885,7 +885,7 @@ int lxc_init(const char *name, struct lxc_handler *handler)
}
TRACE
(
"Chowned console"
);
handler
->
cgroup_ops
=
cgroup_init
(
handler
);
handler
->
cgroup_ops
=
cgroup_init
(
handler
->
conf
);
if
(
!
handler
->
cgroup_ops
)
{
ERROR
(
"Failed to initialize cgroup driver"
);
goto
out_delete_terminal
;
...
...
@@ -895,6 +895,10 @@ int lxc_init(const char *name, struct lxc_handler *handler)
INFO
(
"Container
\"
%s
\"
is initialized"
,
name
);
return
0
;
out_destroy_cgroups:
handler
->
cgroup_ops
->
payload_destroy
(
handler
->
cgroup_ops
,
handler
);
handler
->
cgroup_ops
->
monitor_destroy
(
handler
->
cgroup_ops
,
handler
);
out_delete_terminal:
lxc_terminal_delete
(
&
handler
->
conf
->
console
);
...
...
@@ -985,7 +989,8 @@ void lxc_fini(const char *name, struct lxc_handler *handler)
while
(
namespace_count
--
)
free
(
namespaces
[
namespace_count
]);
cgroup_ops
->
destroy
(
cgroup_ops
,
handler
);
cgroup_ops
->
payload_destroy
(
cgroup_ops
,
handler
);
cgroup_ops
->
monitor_destroy
(
cgroup_ops
,
handler
);
if
(
handler
->
conf
->
reboot
==
REBOOT_NONE
)
{
/* For all new state clients simply close the command socket.
...
...
@@ -1599,16 +1604,12 @@ static int lxc_spawn(struct lxc_handler *handler)
ret
=
socketpair
(
AF_UNIX
,
SOCK_STREAM
|
SOCK_CLOEXEC
,
0
,
handler
->
data_sock
);
if
(
ret
<
0
)
{
lxc_sync_fini
(
handler
);
return
-
1
;
}
if
(
ret
<
0
)
goto
out_sync_fini
;
ret
=
resolve_clone_flags
(
handler
);
if
(
ret
<
0
)
{
lxc_sync_fini
(
handler
);
return
-
1
;
}
if
(
ret
<
0
)
goto
out_sync_fini
;
if
(
handler
->
ns_clone_flags
&
CLONE_NEWNET
)
{
if
(
!
lxc_list_empty
(
&
conf
->
network
))
{
...
...
@@ -1621,8 +1622,7 @@ static int lxc_spawn(struct lxc_handler *handler)
ret
=
lxc_find_gateway_addresses
(
handler
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to find gateway addresses"
);
lxc_sync_fini
(
handler
);
return
-
1
;
goto
out_sync_fini
;
}
/* That should be done before the clone because we will
...
...
@@ -1631,8 +1631,7 @@ static int lxc_spawn(struct lxc_handler *handler)
ret
=
lxc_create_network_priv
(
handler
);
if
(
ret
<
0
)
{
ERROR
(
"Failed to create the network"
);
lxc_sync_fini
(
handler
);
return
-
1
;
goto
out_delete_net
;
}
}
}
...
...
@@ -1891,6 +1890,8 @@ out_delete_net:
out_abort:
lxc_abort
(
name
,
handler
);
out_sync_fini:
lxc_sync_fini
(
handler
);
if
(
handler
->
pinfd
>=
0
)
{
close
(
handler
->
pinfd
);
...
...
@@ -1906,6 +1907,7 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
{
int
ret
,
status
;
struct
lxc_conf
*
conf
=
handler
->
conf
;
struct
cgroup_ops
*
cgroup_ops
;
ret
=
lxc_init
(
name
,
handler
);
if
(
ret
<
0
)
{
...
...
@@ -1915,9 +1917,23 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
handler
->
ops
=
ops
;
handler
->
data
=
data
;
handler
->
daemonize
=
daemonize
;
cgroup_ops
=
handler
->
cgroup_ops
;
if
(
!
attach_block_device
(
handler
->
conf
))
{
ERROR
(
"Failed to attach block device"
);
ret
=
-
1
;
goto
out_fini_nonet
;
}
if
(
!
cgroup_ops
->
monitor_create
(
cgroup_ops
,
handler
))
{
ERROR
(
"Failed to create monitor cgroup"
);
ret
=
-
1
;
goto
out_fini_nonet
;
}
if
(
!
cgroup_ops
->
monitor_enter
(
cgroup_ops
,
handler
->
monitor_pid
))
{
ERROR
(
"Failed to enter monitor cgroup"
);
ret
=
-
1
;
goto
out_fini_nonet
;
}
...
...
@@ -1962,6 +1978,7 @@ int __lxc_start(const char *name, struct lxc_handler *handler,
if
(
!
handler
->
init_died
&&
handler
->
pid
>
0
)
{
ERROR
(
"Child process is not killed"
);
ret
=
-
1
;
goto
out_abort
;
}
...
...
src/tests/cgpath.c
View file @
3f76bcd6
...
...
@@ -59,7 +59,7 @@ static int test_running_container(const char *lxcpath,
char
value
[
NAME_MAX
],
value_save
[
NAME_MAX
];
struct
cgroup_ops
*
cgroup_ops
;
sprintf
(
relpath
,
"%s/%s"
,
group
?
group
:
"lxc"
,
name
);
sprintf
(
relpath
,
"%s/%s"
,
group
?
group
:
"lxc
.payload
"
,
name
);
if
((
c
=
lxc_container_new
(
name
,
lxcpath
))
==
NULL
)
{
TSTERR
(
"container %s couldn't instantiate"
,
name
);
...
...
@@ -80,7 +80,7 @@ static int test_running_container(const char *lxcpath,
goto
err3
;
}
cgroup_ops
=
cgroup_init
(
NULL
);
cgroup_ops
=
cgroup_init
(
c
->
lxc_conf
);
if
(
!
cgroup_ops
)
goto
err3
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment