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
d6337a5f
Unverified
Commit
d6337a5f
authored
Jan 31, 2018
by
Christian Brauner
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
cgroups: get controllers on the unified hierarchy
Signed-off-by:
Christian Brauner
<
christian.brauner@ubuntu.com
>
parent
2ddc6653
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
322 additions
and
98 deletions
+322
-98
cgfsng.c
src/lxc/cgroups/cgfsng.c
+312
-91
cgroup.h
src/lxc/cgroups/cgroup.h
+7
-0
cgroup_utils.c
src/lxc/cgroups/cgroup_utils.c
+3
-3
cgroup_utils.h
src/lxc/cgroups/cgroup_utils.h
+0
-4
No files found.
src/lxc/cgroups/cgfsng.c
View file @
d6337a5f
...
@@ -78,7 +78,7 @@ struct hierarchy {
...
@@ -78,7 +78,7 @@ struct hierarchy {
char
*
mountpoint
;
char
*
mountpoint
;
char
*
base_cgroup
;
char
*
base_cgroup
;
char
*
fullcgpath
;
char
*
fullcgpath
;
bool
is_cgroup_v2
;
int
version
;
};
};
/*
/*
...
@@ -98,14 +98,17 @@ struct cgfsng_handler_data {
...
@@ -98,14 +98,17 @@ struct cgfsng_handler_data {
char
*
name
;
/* container name */
char
*
name
;
/* container name */
/* per-container cgroup information */
/* per-container cgroup information */
struct
lxc_cgroup
cgroup_meta
;
struct
lxc_cgroup
cgroup_meta
;
cgroup_layout_t
cgroup_layout
;
};
};
/*
/*
* @hierarchies - a NULL-terminated array of struct hierarchy, one per
* @hierarchies - a NULL-terminated array of struct hierarchy, one per
*
hierarchy. No duplicates. First sufficient, writeable mounted
*
legacy hierarchy. No duplicates. First sufficient, writeable
* hierarchy wins
*
mounted
hierarchy wins
*/
*/
struct
hierarchy
**
hierarchies
;
struct
hierarchy
**
hierarchies
;
struct
hierarchy
*
unified
;
cgroup_layout_t
cgroup_layout
;
/*
/*
* @cgroup_use - a copy of the lxc.cgroup.use
* @cgroup_use - a copy of the lxc.cgroup.use
...
@@ -183,6 +186,7 @@ static bool string_in_list(char **list, const char *entry)
...
@@ -183,6 +186,7 @@ static bool string_in_list(char **list, const char *entry)
if
(
!
list
)
if
(
!
list
)
return
false
;
return
false
;
for
(
i
=
0
;
list
[
i
];
i
++
)
for
(
i
=
0
;
list
[
i
];
i
++
)
if
(
strcmp
(
list
[
i
],
entry
)
==
0
)
if
(
strcmp
(
list
[
i
],
entry
)
==
0
)
return
true
;
return
true
;
...
@@ -220,8 +224,6 @@ static void must_append_controller(char **klist, char **nlist, char ***clist, ch
...
@@ -220,8 +224,6 @@ static void must_append_controller(char **klist, char **nlist, char ***clist, ch
copy
=
must_copy_string
(
entry
);
copy
=
must_copy_string
(
entry
);
else
if
(
string_in_list
(
klist
,
entry
))
else
if
(
string_in_list
(
klist
,
entry
))
copy
=
must_copy_string
(
entry
);
copy
=
must_copy_string
(
entry
);
else
if
(
!
strcmp
(
entry
,
"cgroup2"
))
copy
=
must_copy_string
(
entry
);
else
else
copy
=
must_prefix_named
(
entry
);
copy
=
must_prefix_named
(
entry
);
...
@@ -250,10 +252,21 @@ struct hierarchy *get_hierarchy(const char *c)
...
@@ -250,10 +252,21 @@ struct hierarchy *get_hierarchy(const char *c)
if
(
!
hierarchies
)
if
(
!
hierarchies
)
return
NULL
;
return
NULL
;
for
(
i
=
0
;
hierarchies
[
i
];
i
++
)
{
for
(
i
=
0
;
hierarchies
[
i
];
i
++
)
{
if
(
!
c
)
{
/* This is the empty unified hierarchy. */
if
(
hierarchies
[
i
]
->
controllers
&&
!
hierarchies
[
i
]
->
controllers
[
0
])
return
hierarchies
[
i
];
return
NULL
;
}
if
(
string_in_list
(
hierarchies
[
i
]
->
controllers
,
c
))
if
(
string_in_list
(
hierarchies
[
i
]
->
controllers
,
c
))
return
hierarchies
[
i
];
return
hierarchies
[
i
];
}
}
return
NULL
;
return
NULL
;
}
}
...
@@ -278,7 +291,7 @@ static void append_line(char **dest, size_t oldlen, char *new, size_t newlen)
...
@@ -278,7 +291,7 @@ 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
(
char
*
fnam
)
static
char
*
read_file
(
c
onst
c
har
*
fnam
)
{
{
FILE
*
f
;
FILE
*
f
;
char
*
line
=
NULL
,
*
buf
=
NULL
;
char
*
line
=
NULL
,
*
buf
=
NULL
;
...
@@ -713,12 +726,14 @@ static bool controller_list_is_dup(struct hierarchy **hlist, char **clist)
...
@@ -713,12 +726,14 @@ static bool controller_list_is_dup(struct hierarchy **hlist, char **clist)
static
bool
controller_found
(
struct
hierarchy
**
hlist
,
char
*
entry
)
static
bool
controller_found
(
struct
hierarchy
**
hlist
,
char
*
entry
)
{
{
int
i
;
int
i
;
if
(
!
hlist
)
if
(
!
hlist
)
return
false
;
return
false
;
for
(
i
=
0
;
hlist
[
i
];
i
++
)
for
(
i
=
0
;
hlist
[
i
];
i
++
)
if
(
string_in_list
(
hlist
[
i
]
->
controllers
,
entry
))
if
(
string_in_list
(
hlist
[
i
]
->
controllers
,
entry
))
return
true
;
return
true
;
return
false
;
return
false
;
}
}
...
@@ -757,12 +772,13 @@ static bool all_controllers_found(void)
...
@@ -757,12 +772,13 @@ static bool all_controllers_found(void)
* options. But we simply assume that the mountpoint must be
* options. But we simply assume that the mountpoint must be
* /sys/fs/cgroup/controller-list
* /sys/fs/cgroup/controller-list
*/
*/
static
char
**
get_controllers
(
char
**
klist
,
char
**
nlist
,
char
*
line
,
int
type
)
static
char
**
get_controllers_on_hybrid_layout
(
char
**
klist
,
char
**
nlist
,
char
*
line
,
int
type
)
{
{
/* the fourth field is /sys/fs/cgroup/comma-delimited-controller-list */
/* the fourth field is /sys/fs/cgroup/comma-delimited-controller-list */
int
i
;
int
i
;
char
*
dup
,
*
p2
,
*
tok
;
char
*
dup
,
*
p2
,
*
tok
;
char
*
p
=
line
,
*
saveptr
=
NULL
;
char
*
p
=
line
,
*
saveptr
=
NULL
,
*
sep
=
","
;
char
**
aret
=
NULL
;
char
**
aret
=
NULL
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
for
(
i
=
0
;
i
<
4
;
i
++
)
{
...
@@ -778,6 +794,7 @@ static char **get_controllers(char **klist, char **nlist, char *line, int type)
...
@@ -778,6 +794,7 @@ static char **get_controllers(char **klist, char **nlist, char *line, int type)
CGFSNG_DEBUG
(
"Found hierarchy not under /sys/fs/cgroup:
\"
%s
\"\n
"
,
p
);
CGFSNG_DEBUG
(
"Found hierarchy not under /sys/fs/cgroup:
\"
%s
\"\n
"
,
p
);
return
NULL
;
return
NULL
;
}
}
p
+=
15
;
p
+=
15
;
p2
=
strchr
(
p
,
' '
);
p2
=
strchr
(
p
,
' '
);
if
(
!
p2
)
{
if
(
!
p2
)
{
...
@@ -786,30 +803,60 @@ static char **get_controllers(char **klist, char **nlist, char *line, int type)
...
@@ -786,30 +803,60 @@ static char **get_controllers(char **klist, char **nlist, char *line, int type)
}
}
*
p2
=
'\0'
;
*
p2
=
'\0'
;
/* cgroup v2 does not have separate mountpoints for controllers */
if
(
type
==
CGROUP_SUPER_MAGIC
)
{
if
(
type
==
CGROUP_V2
)
{
/* strdup() here for v1 hierarchies. Otherwise strtok_r() will
must_append_controller
(
klist
,
nlist
,
&
aret
,
"cgroup2"
);
* destroy mountpoints such as "/sys/fs/cgroup/cpu,cpuacct".
return
aret
;
*/
dup
=
strdup
(
p
);
if
(
!
dup
)
return
NULL
;
for
(
tok
=
strtok_r
(
dup
,
sep
,
&
saveptr
);
tok
;
tok
=
strtok_r
(
NULL
,
sep
,
&
saveptr
))
must_append_controller
(
klist
,
nlist
,
&
aret
,
tok
);
free
(
dup
);
}
}
*
p2
=
' '
;
return
aret
;
}
/* strdup() here for v1 hierarchies. Otherwise strtok_r() will destroy
static
char
**
cg_unified_make_empty_controller
(
void
)
* mountpoints such as "/sys/fs/cgroup/cpu,cpuacct".
{
*/
int
newentry
;
dup
=
strdup
(
p
);
char
**
aret
=
NULL
;
if
(
!
dup
)
newentry
=
append_null_to_list
((
void
***
)
&
aret
);
aret
[
newentry
]
=
NULL
;
return
aret
;
}
static
char
**
cg_unified_get_controllers
(
const
char
*
file
)
{
char
*
buf
,
*
tok
;
char
*
saveptr
=
NULL
,
*
sep
=
"
\t\n
"
;
char
**
aret
=
NULL
;
buf
=
read_file
(
file
);
if
(
!
buf
)
return
NULL
;
return
NULL
;
for
(
tok
=
strtok_r
(
dup
,
","
,
&
saveptr
);
tok
;
for
(
tok
=
strtok_r
(
buf
,
sep
,
&
saveptr
);
tok
;
tok
=
strtok_r
(
NULL
,
","
,
&
saveptr
))
{
tok
=
strtok_r
(
NULL
,
sep
,
&
saveptr
))
{
must_append_controller
(
klist
,
nlist
,
&
aret
,
tok
);
int
newentry
;
char
*
copy
;
newentry
=
append_null_to_list
((
void
***
)
&
aret
);
copy
=
must_copy_string
(
tok
);
aret
[
newentry
]
=
copy
;
}
}
free
(
dup
);
free
(
buf
);
return
aret
;
return
aret
;
}
}
/* Add a controller to our list of hierarchies */
static
struct
hierarchy
*
add_hierarchy
(
char
**
clist
,
char
*
mountpoint
,
static
void
add_controller
(
char
**
clist
,
char
*
mountpoint
,
char
*
base_cgroup
)
char
*
base_cgroup
,
int
type
)
{
{
struct
hierarchy
*
new
;
struct
hierarchy
*
new
;
int
newentry
;
int
newentry
;
...
@@ -819,26 +866,24 @@ static void add_controller(char **clist, char *mountpoint, char *base_cgroup)
...
@@ -819,26 +866,24 @@ static void add_controller(char **clist, char *mountpoint, char *base_cgroup)
new
->
mountpoint
=
mountpoint
;
new
->
mountpoint
=
mountpoint
;
new
->
base_cgroup
=
base_cgroup
;
new
->
base_cgroup
=
base_cgroup
;
new
->
fullcgpath
=
NULL
;
new
->
fullcgpath
=
NULL
;
new
->
version
=
type
;
/* record if this is the cgroup v2 hierarchy */
if
(
clist
&&
!
strcmp
(
*
clist
,
"cgroup2"
))
new
->
is_cgroup_v2
=
true
;
else
new
->
is_cgroup_v2
=
false
;
newentry
=
append_null_to_list
((
void
***
)
&
hierarchies
);
newentry
=
append_null_to_list
((
void
***
)
&
hierarchies
);
hierarchies
[
newentry
]
=
new
;
hierarchies
[
newentry
]
=
new
;
return
new
;
}
}
/*
/*
* Get a copy of the mountpoint from @line, which is a line from
* Get a copy of the mountpoint from @line, which is a line from
* /proc/self/mountinfo
* /proc/self/mountinfo
*/
*/
static
char
*
get_mountpoint
(
char
*
line
)
static
char
*
get_mountpoint
_on_hybrid_layout
(
char
*
line
)
{
{
int
i
;
int
i
;
char
*
p
=
line
,
*
sret
;
char
*
p
2
;
size_t
len
;
size_t
len
;
char
*
p
=
line
;
char
*
sret
=
NULL
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
for
(
i
=
0
;
i
<
4
;
i
++
)
{
p
=
strchr
(
p
,
' '
);
p
=
strchr
(
p
,
' '
);
...
@@ -846,7 +891,15 @@ static char *get_mountpoint(char *line)
...
@@ -846,7 +891,15 @@ static char *get_mountpoint(char *line)
return
NULL
;
return
NULL
;
p
++
;
p
++
;
}
}
/* we've already stuck a \0 after the mountpoint */
if
(
strncmp
(
p
,
"/sys/fs/cgroup/"
,
15
))
return
NULL
;
p2
=
strchr
(
p
+
15
,
' '
);
if
(
!
p2
)
return
NULL
;
*
p2
=
'\0'
;
len
=
strlen
(
p
);
len
=
strlen
(
p
);
sret
=
must_alloc
(
len
+
1
);
sret
=
must_alloc
(
len
+
1
);
memcpy
(
sret
,
p
,
len
);
memcpy
(
sret
,
p
,
len
);
...
@@ -893,10 +946,11 @@ static bool controller_in_clist(char *cgline, char *c)
...
@@ -893,10 +946,11 @@ static bool controller_in_clist(char *cgline, char *c)
tmp
[
len
]
=
'\0'
;
tmp
[
len
]
=
'\0'
;
for
(
tok
=
strtok_r
(
tmp
,
","
,
&
saveptr
);
tok
;
for
(
tok
=
strtok_r
(
tmp
,
","
,
&
saveptr
);
tok
;
tok
=
strtok_r
(
NULL
,
","
,
&
saveptr
))
{
tok
=
strtok_r
(
NULL
,
","
,
&
saveptr
))
{
if
(
strcmp
(
tok
,
c
)
==
0
)
if
(
strcmp
(
tok
,
c
)
==
0
)
return
true
;
return
true
;
}
}
return
false
;
return
false
;
}
}
...
@@ -904,24 +958,23 @@ static bool controller_in_clist(char *cgline, char *c)
...
@@ -904,24 +958,23 @@ static bool controller_in_clist(char *cgline, char *c)
* @basecginfo is a copy of /proc/$$/cgroup. Return the current
* @basecginfo is a copy of /proc/$$/cgroup. Return the current
* cgroup for @controller
* cgroup for @controller
*/
*/
static
char
*
get_current_cgroup
(
char
*
basecginfo
,
char
*
controller
)
static
char
*
get_current_cgroup
(
char
*
basecginfo
,
char
*
controller
,
int
type
)
{
{
char
*
p
=
basecginfo
;
char
*
p
=
basecginfo
;
bool
is_cgroup_v2
;
bool
is_cgroup_v2_base_cgroup
;
is_cgroup_v2
=
!
strcmp
(
controller
,
"cgroup2"
);
for
(;;)
{
while
(
true
)
{
bool
is_cgv2_base_cgroup
=
false
;
is_cgroup_v2_base_cgroup
=
false
;
/* cgroup v2 entry in "/proc/<pid>/cgroup": "0::/some/path" */
/* cgroup v2 entry in "/proc/<pid>/cgroup": "0::/some/path" */
if
(
is_cgroup_v2
&&
(
*
p
==
'0'
))
if
(
(
type
==
CGROUP2_SUPER_MAGIC
)
&&
(
*
p
==
'0'
))
is_cg
roup_
v2_base_cgroup
=
true
;
is_cgv2_base_cgroup
=
true
;
p
=
strchr
(
p
,
':'
);
p
=
strchr
(
p
,
':'
);
if
(
!
p
)
if
(
!
p
)
return
NULL
;
return
NULL
;
p
++
;
p
++
;
if
(
is_cgroup_v2_base_cgroup
||
controller_in_clist
(
p
,
controller
))
{
if
(
is_cgv2_base_cgroup
||
(
controller
&&
controller_in_clist
(
p
,
controller
)))
{
p
=
strchr
(
p
,
':'
);
p
=
strchr
(
p
,
':'
);
if
(
!
p
)
if
(
!
p
)
return
NULL
;
return
NULL
;
...
@@ -945,14 +998,16 @@ static void must_append_string(char ***list, char *entry)
...
@@ -945,14 +998,16 @@ static void must_append_string(char ***list, char *entry)
(
*
list
)[
newentry
]
=
copy
;
(
*
list
)[
newentry
]
=
copy
;
}
}
static
void
get_existing_subsystems
(
char
***
klist
,
char
***
nlist
)
static
int
get_existing_subsystems
(
char
***
klist
,
char
***
nlist
)
{
{
FILE
*
f
;
FILE
*
f
;
char
*
line
=
NULL
;
char
*
line
=
NULL
;
size_t
len
=
0
;
size_t
len
=
0
;
if
((
f
=
fopen
(
"/proc/self/cgroup"
,
"r"
))
==
NULL
)
f
=
fopen
(
"/proc/self/cgroup"
,
"r"
);
return
;
if
(
!
f
)
return
-
1
;
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
char
*
p
,
*
p2
,
*
tok
,
*
saveptr
=
NULL
;
char
*
p
,
*
p2
,
*
tok
,
*
saveptr
=
NULL
;
p
=
strchr
(
line
,
':'
);
p
=
strchr
(
line
,
':'
);
...
@@ -977,7 +1032,7 @@ static void get_existing_subsystems(char ***klist, char ***nlist)
...
@@ -977,7 +1032,7 @@ static void get_existing_subsystems(char ***klist, char ***nlist)
}
}
for
(
tok
=
strtok_r
(
p
,
","
,
&
saveptr
);
tok
;
for
(
tok
=
strtok_r
(
p
,
","
,
&
saveptr
);
tok
;
tok
=
strtok_r
(
NULL
,
","
,
&
saveptr
))
{
tok
=
strtok_r
(
NULL
,
","
,
&
saveptr
))
{
if
(
strncmp
(
tok
,
"name="
,
5
)
==
0
)
if
(
strncmp
(
tok
,
"name="
,
5
)
==
0
)
must_append_string
(
nlist
,
tok
);
must_append_string
(
nlist
,
tok
);
else
else
...
@@ -987,6 +1042,7 @@ static void get_existing_subsystems(char ***klist, char ***nlist)
...
@@ -987,6 +1042,7 @@ static void get_existing_subsystems(char ***klist, char ***nlist)
free
(
line
);
free
(
line
);
fclose
(
f
);
fclose
(
f
);
return
0
;
}
}
static
void
trim
(
char
*
s
)
static
void
trim
(
char
*
s
)
...
@@ -1054,82 +1110,125 @@ static void lxc_cgfsng_print_debuginfo(const struct cgfsng_handler_data *d)
...
@@ -1054,82 +1110,125 @@ static void lxc_cgfsng_print_debuginfo(const struct cgfsng_handler_data *d)
* At startup, parse_hierarchies finds all the info we need about
* At startup, parse_hierarchies finds all the info we need about
* cgroup mountpoints and current cgroups, and stores it in @d.
* cgroup mountpoints and current cgroups, and stores it in @d.
*/
*/
static
bool
parse_hierarchies
(
void
)
static
bool
cg_init_hybrid
(
void
)
{
{
int
ret
;
char
*
basecginfo
;
bool
will_escape
;
FILE
*
f
;
FILE
*
f
;
char
*
line
=
NULL
,
*
basecginfo
;
char
**
klist
=
NULL
,
**
nlist
=
NULL
;
size_t
len
=
0
;
size_t
len
=
0
;
char
*
line
=
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.
*/
*/
if
(
geteuid
())
will_escape
=
(
geteuid
()
==
0
);
basecginfo
=
read_file
(
"/proc/self/cgroup"
);
if
(
will_escape
)
else
basecginfo
=
read_file
(
"/proc/1/cgroup"
);
basecginfo
=
read_file
(
"/proc/1/cgroup"
);
else
basecginfo
=
read_file
(
"/proc/self/cgroup"
);
if
(
!
basecginfo
)
if
(
!
basecginfo
)
return
false
;
return
false
;
if
((
f
=
fopen
(
"/proc/self/mountinfo"
,
"r"
))
==
NULL
)
{
ret
=
get_existing_subsystems
(
&
klist
,
&
nlist
);
CGFSNG_DEBUG
(
"Failed to open
\"
/proc/self/mountinfo
\"\n
"
);
if
(
ret
<
0
)
{
CGFSNG_DEBUG
(
"Failed to retrieve available cgroup v1 controllers
\n
"
);
free
(
basecginfo
);
return
false
;
return
false
;
}
}
get_existing_subsystems
(
&
klist
,
&
nlist
);
f
=
fopen
(
"/proc/self/mountinfo"
,
"r"
);
if
(
!
f
)
{
CGFSNG_DEBUG
(
"Failed to open
\"
/proc/self/mountinfo
\"\n
"
);
return
false
;
}
if
(
lxc_cgfsng_debug
)
if
(
lxc_cgfsng_debug
)
lxc_cgfsng_print_basecg_debuginfo
(
basecginfo
,
klist
,
nlist
);
lxc_cgfsng_print_basecg_debuginfo
(
basecginfo
,
klist
,
nlist
);
/* we support simple cgroup mounts and lxcfs mounts */
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
while
(
getline
(
&
line
,
&
len
,
f
)
!=
-
1
)
{
char
**
controller_list
=
NULL
;
char
*
mountpoint
,
*
base_cgroup
;
bool
writeable
;
int
type
;
int
type
;
bool
writeable
;
struct
hierarchy
*
new
;
char
*
mountpoint
=
NULL
,
*
base_cgroup
=
NULL
;
char
**
controller_list
=
NULL
;
type
=
get_cgroup_version
(
line
);
type
=
get_cgroup_version
(
line
);
if
(
type
<
0
)
if
(
type
==
0
)
continue
;
continue
;
controller_list
=
get_controllers
(
klist
,
nlist
,
line
,
type
);
if
(
type
==
CGROUP2_SUPER_MAGIC
&&
unified
)
if
(
!
controller_list
)
continue
;
continue
;
if
(
controller_list_is_dup
(
hierarchies
,
controller_list
))
{
if
(
cgroup_layout
==
CGROUP_LAYOUT_UNKNOWN
)
{
free
(
controller_list
);
if
(
type
==
CGROUP2_SUPER_MAGIC
)
continue
;
cgroup_layout
=
CGROUP_LAYOUT_UNIFIED
;
else
if
(
type
==
CGROUP_SUPER_MAGIC
)
cgroup_layout
=
CGROUP_LAYOUT_LEGACY
;
}
else
if
(
cgroup_layout
==
CGROUP_LAYOUT_UNIFIED
)
{
if
(
type
==
CGROUP_SUPER_MAGIC
)
cgroup_layout
=
CGROUP_LAYOUT_HYBRID
;
}
else
if
(
cgroup_layout
==
CGROUP_LAYOUT_LEGACY
)
{
if
(
type
==
CGROUP2_SUPER_MAGIC
)
cgroup_layout
=
CGROUP_LAYOUT_HYBRID
;
}
}
mountpoint
=
get_mountpoint
(
line
);
controller_list
=
get_controllers_on_hybrid_layout
(
klist
,
nlist
,
line
,
type
);
if
(
!
controller_list
&&
type
==
CGROUP_SUPER_MAGIC
)
continue
;
if
(
type
==
CGROUP_SUPER_MAGIC
)
if
(
controller_list_is_dup
(
hierarchies
,
controller_list
))
goto
next
;
mountpoint
=
get_mountpoint_on_hybrid_layout
(
line
);
if
(
!
mountpoint
)
{
if
(
!
mountpoint
)
{
CGFSNG_DEBUG
(
"Failed parsing mountpoint from
\"
%s
\"\n
"
,
line
);
CGFSNG_DEBUG
(
"Failed parsing mountpoint from
\"
%s
\"\n
"
,
line
);
free_string_list
(
controller_list
);
goto
next
;
continue
;
}
}
base_cgroup
=
get_current_cgroup
(
basecginfo
,
controller_list
[
0
]);
if
(
type
==
CGROUP_SUPER_MAGIC
)
base_cgroup
=
get_current_cgroup
(
basecginfo
,
controller_list
[
0
],
CGROUP_SUPER_MAGIC
);
else
base_cgroup
=
get_current_cgroup
(
basecginfo
,
NULL
,
CGROUP2_SUPER_MAGIC
);
if
(
!
base_cgroup
)
{
if
(
!
base_cgroup
)
{
CGFSNG_DEBUG
(
"Failed to find current cgroup for controller
\"
%s
\"\n
"
,
controller_list
[
0
]);
CGFSNG_DEBUG
(
"Failed to find current cgroup
\n
"
);
free_string_list
(
controller_list
);
goto
next
;
free
(
mountpoint
);
continue
;
}
}
trim
(
base_cgroup
);
trim
(
base_cgroup
);
prune_init_scope
(
base_cgroup
);
prune_init_scope
(
base_cgroup
);
if
(
type
==
CGROUP
_V2
)
if
(
type
==
CGROUP
2_SUPER_MAGIC
)
writeable
=
test_writeable_v2
(
mountpoint
,
base_cgroup
);
writeable
=
test_writeable_v2
(
mountpoint
,
base_cgroup
);
else
else
writeable
=
test_writeable_v1
(
mountpoint
,
base_cgroup
);
writeable
=
test_writeable_v1
(
mountpoint
,
base_cgroup
);
if
(
!
writeable
)
{
if
(
!
writeable
)
free_string_list
(
controller_list
);
goto
next
;
free
(
mountpoint
);
free
(
base_cgroup
);
if
(
type
==
CGROUP2_SUPER_MAGIC
)
{
continue
;
char
*
cgv2_ctrl_path
;
cgv2_ctrl_path
=
must_make_path
(
mountpoint
,
base_cgroup
,
"cgroup.controllers"
,
NULL
);
controller_list
=
cg_unified_get_controllers
(
cgv2_ctrl_path
);
free
(
cgv2_ctrl_path
);
if
(
!
controller_list
)
controller_list
=
cg_unified_make_empty_controller
();
}
}
add_controller
(
controller_list
,
mountpoint
,
base_cgroup
);
new
=
add_hierarchy
(
controller_list
,
mountpoint
,
base_cgroup
,
type
);
if
(
type
==
CGROUP2_SUPER_MAGIC
&&
!
unified
)
unified
=
new
;
continue
;
next:
free_string_list
(
controller_list
);
free
(
mountpoint
);
free
(
base_cgroup
);
}
}
free_string_list
(
klist
);
free_string_list
(
klist
);
...
@@ -1154,9 +1253,106 @@ static bool parse_hierarchies(void)
...
@@ -1154,9 +1253,106 @@ static bool parse_hierarchies(void)
return
true
;
return
true
;
}
}
static
bool
collect_hierarchy_info
(
void
)
static
int
cg_is_pure_unified
(
void
)
{
int
ret
;
struct
statfs
fs
;
ret
=
statfs
(
"/sys/fs/cgroup"
,
&
fs
);
if
(
ret
<
0
)
return
-
ENOMEDIUM
;
if
(
is_fs_type
(
&
fs
,
CGROUP2_SUPER_MAGIC
))
return
CGROUP2_SUPER_MAGIC
;
return
0
;
}
/* Get current cgroup from /proc/self/cgroup for the cgroupfs v2 hierarchy. */
static
char
*
cg_get_current_cgroup_unified
(
void
)
{
{
char
*
basecginfo
;
char
*
base_cgroup
;
bool
will_escape
;
char
*
copy
=
NULL
;
will_escape
=
(
geteuid
()
==
0
);
if
(
will_escape
)
basecginfo
=
read_file
(
"/proc/1/cgroup"
);
else
basecginfo
=
read_file
(
"/proc/self/cgroup"
);
if
(
!
basecginfo
)
return
NULL
;
base_cgroup
=
strstr
(
basecginfo
,
"0::/"
);
if
(
!
base_cgroup
)
goto
cleanup_on_err
;
base_cgroup
=
base_cgroup
+
3
;
copy
=
copy_to_eol
(
base_cgroup
);
if
(
!
copy
)
goto
cleanup_on_err
;
cleanup_on_err:
free
(
basecginfo
);
if
(
copy
)
trim
(
copy
);
return
copy
;
}
static
int
cg_init_unified
(
void
)
{
int
ret
;
char
*
mountpoint
,
*
subtree_path
;
char
**
delegatable
;
char
*
base_cgroup
=
NULL
;
ret
=
cg_is_pure_unified
();
if
(
ret
==
-
ENOMEDIUM
)
return
-
ENOMEDIUM
;
if
(
ret
!=
CGROUP2_SUPER_MAGIC
)
return
0
;
base_cgroup
=
cg_get_current_cgroup_unified
();
if
(
!
base_cgroup
)
return
-
EINVAL
;
prune_init_scope
(
base_cgroup
);
/* We assume that we have already been given controllers to delegate
* further down the hierarchy. If not it is up to the user to delegate
* them to us.
*/
mountpoint
=
must_copy_string
(
"/sys/fs/cgroup"
);
subtree_path
=
must_make_path
(
mountpoint
,
base_cgroup
,
"cgroup.subtree_control"
,
NULL
);
delegatable
=
cg_unified_get_controllers
(
subtree_path
);
free
(
subtree_path
);
if
(
!
delegatable
)
delegatable
=
cg_unified_make_empty_controller
();
if
(
!
delegatable
[
0
])
CGFSNG_DEBUG
(
"No controllers are enabled for delegation
\n
"
);
/* TODO: If the user requested specific controllers via lxc.cgroup.use
* we should verify here. The reason I'm not doing it right is that I'm
* not convinced that lxc.cgroup.use will be the future since it is a
* global property. I much rather have an option that lets you request
* controllers per container.
*/
add_hierarchy
(
delegatable
,
mountpoint
,
base_cgroup
,
CGROUP2_SUPER_MAGIC
);
unified
=
hierarchies
[
0
];
cgroup_layout
=
CGROUP_LAYOUT_UNIFIED
;
return
CGROUP2_SUPER_MAGIC
;
}
static
bool
cg_init
(
void
)
{
int
ret
;
const
char
*
tmp
;
const
char
*
tmp
;
errno
=
0
;
errno
=
0
;
tmp
=
lxc_global_config_value
(
"lxc.cgroup.use"
);
tmp
=
lxc_global_config_value
(
"lxc.cgroup.use"
);
if
(
!
cgroup_use
&&
errno
!=
0
)
{
/* lxc.cgroup.use can be NULL */
if
(
!
cgroup_use
&&
errno
!=
0
)
{
/* lxc.cgroup.use can be NULL */
...
@@ -1165,7 +1361,14 @@ static bool collect_hierarchy_info(void)
...
@@ -1165,7 +1361,14 @@ static bool collect_hierarchy_info(void)
}
}
cgroup_use
=
must_copy_string
(
tmp
);
cgroup_use
=
must_copy_string
(
tmp
);
return
parse_hierarchies
();
ret
=
cg_init_unified
();
if
(
ret
<
0
)
return
false
;
if
(
ret
==
CGROUP2_SUPER_MAGIC
)
return
true
;
return
cg_init_hybrid
();
}
}
static
void
*
cgfsng_init
(
struct
lxc_handler
*
handler
)
static
void
*
cgfsng_init
(
struct
lxc_handler
*
handler
)
...
@@ -1196,6 +1399,16 @@ static void *cgfsng_init(struct lxc_handler *handler)
...
@@ -1196,6 +1399,16 @@ static void *cgfsng_init(struct lxc_handler *handler)
}
}
d
->
cgroup_pattern
=
must_copy_string
(
cgroup_pattern
);
d
->
cgroup_pattern
=
must_copy_string
(
cgroup_pattern
);
d
->
cgroup_layout
=
cgroup_layout
;
if
(
d
->
cgroup_layout
==
CGROUP_LAYOUT_LEGACY
)
TRACE
(
"Running with legacy cgroup layout"
);
else
if
(
d
->
cgroup_layout
==
CGROUP_LAYOUT_HYBRID
)
TRACE
(
"Running with hybrid cgroup layout"
);
else
if
(
d
->
cgroup_layout
==
CGROUP_LAYOUT_UNIFIED
)
TRACE
(
"Running with unified cgroup layout"
);
else
WARN
(
"Running with unknown cgroup layout"
);
if
(
lxc_cgfsng_debug
)
if
(
lxc_cgfsng_debug
)
lxc_cgfsng_print_debuginfo
(
d
);
lxc_cgfsng_print_debuginfo
(
d
);
...
@@ -1343,7 +1556,7 @@ struct cgroup_ops *cgfsng_ops_init(void)
...
@@ -1343,7 +1556,7 @@ struct cgroup_ops *cgfsng_ops_init(void)
if
(
getenv
(
"LXC_DEBUG_CGFSNG"
))
if
(
getenv
(
"LXC_DEBUG_CGFSNG"
))
lxc_cgfsng_debug
=
true
;
lxc_cgfsng_debug
=
true
;
if
(
!
c
ollect_hierarchy_info
())
if
(
!
c
g_init
())
return
NULL
;
return
NULL
;
return
&
cgfsng_ops
;
return
&
cgfsng_ops
;
...
@@ -1529,7 +1742,7 @@ static int chown_cgroup_wrapper(void *data)
...
@@ -1529,7 +1742,7 @@ static int chown_cgroup_wrapper(void *data)
WARN
(
"Error chmoding %s: %s"
,
path
,
strerror
(
errno
));
WARN
(
"Error chmoding %s: %s"
,
path
,
strerror
(
errno
));
free
(
fullpath
);
free
(
fullpath
);
if
(
!
hierarchies
[
i
]
->
is_cgroup_v2
)
if
(
hierarchies
[
i
]
->
version
!=
CGROUP2_SUPER_MAGIC
)
continue
;
continue
;
fullpath
=
must_make_path
(
path
,
"cgroup.subtree_control"
,
NULL
);
fullpath
=
must_make_path
(
path
,
"cgroup.subtree_control"
,
NULL
);
...
@@ -1679,7 +1892,7 @@ static int mount_cgroup_cgns_supported(int type, struct hierarchy *h, const char
...
@@ -1679,7 +1892,7 @@ static int mount_cgroup_cgns_supported(int type, struct hierarchy *h, const char
if
(
type
==
LXC_AUTO_CGROUP_RO
||
type
==
LXC_AUTO_CGROUP_FULL_RO
)
if
(
type
==
LXC_AUTO_CGROUP_RO
||
type
==
LXC_AUTO_CGROUP_FULL_RO
)
flags
|=
MS_RDONLY
;
flags
|=
MS_RDONLY
;
if
(
!
h
->
is_cgroup_v2
)
{
if
(
h
->
version
!=
CGROUP2_SUPER_MAGIC
)
{
controllers
=
lxc_string_join
(
","
,
(
const
char
**
)
h
->
controllers
,
false
);
controllers
=
lxc_string_join
(
","
,
(
const
char
**
)
h
->
controllers
,
false
);
if
(
!
controllers
)
if
(
!
controllers
)
return
-
ENOMEM
;
return
-
ENOMEM
;
...
@@ -1902,25 +2115,33 @@ static bool cgfsng_get_hierarchies(int n, char ***out)
...
@@ -1902,25 +2115,33 @@ static bool cgfsng_get_hierarchies(int n, char ***out)
#define THAWED "THAWED"
#define THAWED "THAWED"
#define THAWED_LEN (strlen(THAWED))
#define THAWED_LEN (strlen(THAWED))
/* TODO: If the unified cgroup hierarchy grows a freezer controller this needs
* to be adapted.
*/
static
bool
cgfsng_unfreeze
(
void
*
hdata
)
static
bool
cgfsng_unfreeze
(
void
*
hdata
)
{
{
int
ret
;
char
*
fullpath
;
char
*
fullpath
;
struct
hierarchy
*
h
=
get_hierarchy
(
"freezer"
)
;
struct
hierarchy
*
h
;
h
=
get_hierarchy
(
"freezer"
);
if
(
!
h
)
if
(
!
h
)
return
false
;
return
false
;
fullpath
=
must_make_path
(
h
->
fullcgpath
,
"freezer.state"
,
NULL
);
fullpath
=
must_make_path
(
h
->
fullcgpath
,
"freezer.state"
,
NULL
);
if
(
lxc_write_to_file
(
fullpath
,
THAWED
,
THAWED_LEN
,
false
)
!=
0
)
{
ret
=
lxc_write_to_file
(
fullpath
,
THAWED
,
THAWED_LEN
,
false
);
free
(
fullpath
);
return
false
;
}
free
(
fullpath
);
free
(
fullpath
);
if
(
ret
<
0
)
return
false
;
return
true
;
return
true
;
}
}
static
const
char
*
cgfsng_get_cgroup
(
void
*
hdata
,
const
char
*
subsystem
)
static
const
char
*
cgfsng_get_cgroup
(
void
*
hdata
,
const
char
*
subsystem
)
{
{
struct
hierarchy
*
h
=
get_hierarchy
(
subsystem
);
struct
hierarchy
*
h
;
h
=
get_hierarchy
(
subsystem
);
if
(
!
h
)
if
(
!
h
)
return
NULL
;
return
NULL
;
...
...
src/lxc/cgroups/cgroup.h
View file @
d6337a5f
...
@@ -33,6 +33,13 @@ struct lxc_conf;
...
@@ -33,6 +33,13 @@ struct lxc_conf;
struct
lxc_list
;
struct
lxc_list
;
typedef
enum
{
typedef
enum
{
CGROUP_LAYOUT_UNKNOWN
=
-
1
,
CGROUP_LAYOUT_LEGACY
=
0
,
CGROUP_LAYOUT_HYBRID
=
1
,
CGROUP_LAYOUT_UNIFIED
=
2
,
}
cgroup_layout_t
;
typedef
enum
{
CGFS
,
CGFS
,
CGMANAGER
,
CGMANAGER
,
CGFSNG
,
CGFSNG
,
...
...
src/lxc/cgroups/cgroup_utils.c
View file @
d6337a5f
...
@@ -35,12 +35,12 @@
...
@@ -35,12 +35,12 @@
int
get_cgroup_version
(
char
*
line
)
int
get_cgroup_version
(
char
*
line
)
{
{
if
(
is_cgroupfs_v1
(
line
))
if
(
is_cgroupfs_v1
(
line
))
return
CGROUP_
V1
;
return
CGROUP_
SUPER_MAGIC
;
if
(
is_cgroupfs_v2
(
line
))
if
(
is_cgroupfs_v2
(
line
))
return
CGROUP
_V2
;
return
CGROUP
2_SUPER_MAGIC
;
return
-
1
;
return
0
;
}
}
bool
is_cgroupfs_v1
(
char
*
line
)
bool
is_cgroupfs_v1
(
char
*
line
)
...
...
src/lxc/cgroups/cgroup_utils.h
View file @
d6337a5f
...
@@ -28,10 +28,6 @@
...
@@ -28,10 +28,6 @@
#include <stdbool.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdio.h>
#define CGROUP_V1 0
#define CGROUP_V2 1
#define LXCFS_CGROUP 2
/* Retrieve the cgroup version of a given entry from /proc/<pid>/mountinfo. */
/* Retrieve the cgroup version of a given entry from /proc/<pid>/mountinfo. */
extern
int
get_cgroup_version
(
char
*
line
);
extern
int
get_cgroup_version
(
char
*
line
);
...
...
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