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