1
0
mirror of https://github.com/systemd/systemd synced 2025-10-04 11:14:45 +02:00

Compare commits

..

No commits in common. "4b252eaa316ae811f6523cde0028fc53ba29e6cf" and "e5f8ce13bbaf0d8b9ff597692c67fba0e38b4200" have entirely different histories.

8 changed files with 128 additions and 95 deletions

View File

@ -527,22 +527,41 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
return 0; return 0;
} }
static int controller_is_v1_accessible(const char *root, const char *controller) { static int controller_is_accessible(const char *controller) {
const char *cpath, *dn; int r;
assert(controller); assert(controller);
dn = controller_to_dirname(controller); /* Checks whether a specific controller is accessible,
cpath = strjoina("/sys/fs/cgroup/", dn); * i.e. its hierarchy mounted. In the unified hierarchy all
if (root) * controllers are considered accessible, except for the named
/* Also check that: * hierarchies */
* - possible subcgroup is created at root,
* - we can modify the hierarchy.
* "Leak" cpath on stack */
cpath = strjoina(cpath, root, "/cgroup.procs");
if (laccess(cpath, root ? W_OK : F_OK) < 0) if (!cg_controller_is_valid(controller))
return -errno; return -EINVAL;
r = cg_all_unified();
if (r < 0)
return r;
if (r > 0) {
/* We don't support named hierarchies if we are using
* the unified hierarchy. */
if (streq(controller, SYSTEMD_CGROUP_CONTROLLER))
return 0;
if (startswith(controller, "name="))
return -EOPNOTSUPP;
} else {
const char *cc, *dn;
dn = controller_to_dirname(controller);
cc = strjoina("/sys/fs/cgroup/", dn);
if (laccess(cc, F_OK) < 0)
return -errno;
}
return 0; return 0;
} }
@ -553,23 +572,10 @@ int cg_get_path_and_check(const char *controller, const char *path, const char *
assert(controller); assert(controller);
assert(fs); assert(fs);
if (!cg_controller_is_valid(controller)) /* Check if the specified controller is actually accessible */
return -EINVAL; r = controller_is_accessible(controller);
r = cg_all_unified();
if (r < 0) if (r < 0)
return r; return r;
if (r > 0) {
/* In the unified hierarchy all controllers are considered accessible,
* except for the named hierarchies */
if (startswith(controller, "name="))
return -EOPNOTSUPP;
} else {
/* Check if the specified controller is actually accessible */
r = controller_is_v1_accessible(NULL, controller);
if (r < 0)
return r;
}
return cg_get_path(controller, path, suffix, fs); return cg_get_path(controller, path, suffix, fs);
} }
@ -1886,7 +1892,7 @@ int cg_mask_from_string(const char *value, CGroupMask *ret) {
return 0; return 0;
} }
int cg_mask_supported_subtree(const char *root, CGroupMask *ret) { int cg_mask_supported(CGroupMask *ret) {
CGroupMask mask; CGroupMask mask;
int r; int r;
@ -1898,11 +1904,15 @@ int cg_mask_supported_subtree(const char *root, CGroupMask *ret) {
if (r < 0) if (r < 0)
return r; return r;
if (r > 0) { if (r > 0) {
_cleanup_free_ char *controllers = NULL, *path = NULL; _cleanup_free_ char *root = NULL, *controllers = NULL, *path = NULL;
/* In the unified hierarchy we can read the supported and accessible controllers from /* In the unified hierarchy we can read the supported and accessible controllers from
* the top-level cgroup attribute */ * the top-level cgroup attribute */
r = cg_get_root_path(&root);
if (r < 0)
return r;
r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, "cgroup.controllers", &path); r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, root, "cgroup.controllers", &path);
if (r < 0) if (r < 0)
return r; return r;
@ -1921,7 +1931,7 @@ int cg_mask_supported_subtree(const char *root, CGroupMask *ret) {
} else { } else {
CGroupController c; CGroupController c;
/* In the legacy hierarchy, we check which hierarchies are accessible. */ /* In the legacy hierarchy, we check which hierarchies are mounted. */
mask = 0; mask = 0;
for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) { for (c = 0; c < _CGROUP_CONTROLLER_MAX; c++) {
@ -1932,7 +1942,7 @@ int cg_mask_supported_subtree(const char *root, CGroupMask *ret) {
continue; continue;
n = cgroup_controller_to_string(c); n = cgroup_controller_to_string(c);
if (controller_is_v1_accessible(root, n) >= 0) if (controller_is_accessible(n) >= 0)
mask |= bit; mask |= bit;
} }
} }
@ -1941,17 +1951,6 @@ int cg_mask_supported_subtree(const char *root, CGroupMask *ret) {
return 0; return 0;
} }
int cg_mask_supported(CGroupMask *ret) {
_cleanup_free_ char *root = NULL;
int r;
r = cg_get_root_path(&root);
if (r < 0)
return r;
return cg_mask_supported_subtree(root, ret);
}
int cg_kernel_controllers(Set **ret) { int cg_kernel_controllers(Set **ret) {
_cleanup_set_free_free_ Set *controllers = NULL; _cleanup_set_free_free_ Set *controllers = NULL;
_cleanup_fclose_ FILE *f = NULL; _cleanup_fclose_ FILE *f = NULL;

View File

@ -260,7 +260,6 @@ int cg_slice_to_path(const char *unit, char **ret);
typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata); typedef const char* (*cg_migrate_callback_t)(CGroupMask mask, void *userdata);
int cg_mask_supported(CGroupMask *ret); int cg_mask_supported(CGroupMask *ret);
int cg_mask_supported_subtree(const char *root, CGroupMask *ret);
int cg_mask_from_string(const char *s, CGroupMask *ret); int cg_mask_from_string(const char *s, CGroupMask *ret);
int cg_mask_to_string(CGroupMask mask, char **ret); int cg_mask_to_string(CGroupMask mask, char **ret);

View File

@ -1880,6 +1880,10 @@ int unit_pick_cgroup_path(Unit *u) {
return 0; return 0;
} }
static int cg_v1_errno_to_log_level(int r) {
return r == -EROFS ? LOG_DEBUG : LOG_WARNING;
}
static int unit_update_cgroup( static int unit_update_cgroup(
Unit *u, Unit *u,
CGroupMask target_mask, CGroupMask target_mask,
@ -1937,16 +1941,30 @@ static int unit_update_cgroup(
* We perform migration also with whole slices for cases when users don't care about leave * We perform migration also with whole slices for cases when users don't care about leave
* granularity. Since delegated_mask is subset of target mask, we won't trim slice subtree containing * granularity. Since delegated_mask is subset of target mask, we won't trim slice subtree containing
* delegated units. * delegated units.
*
* If we're in an nspawn container and using legacy cgroups, the controller hierarchies are mounted
* read-only into the container. We skip migration/trim in this scenario since it would fail
* regardless with noisy "Read-only filesystem" warnings.
*/ */
if (cg_all_unified() == 0) { if (cg_all_unified() == 0) {
r = cg_migrate_v1_controllers(u->manager->cgroup_supported, migrate_mask, u->cgroup_path, migrate_callback, u); r = cg_migrate_v1_controllers(u->manager->cgroup_supported, migrate_mask, u->cgroup_path, migrate_callback, u);
if (r < 0) if (r < 0)
log_unit_warning_errno(u, r, "Failed to migrate controller cgroups from %s, ignoring: %m", u->cgroup_path); log_unit_full_errno(
u,
cg_v1_errno_to_log_level(r),
r,
"Failed to migrate controller cgroups from %s, ignoring: %m",
u->cgroup_path);
is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE); is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
r = cg_trim_v1_controllers(u->manager->cgroup_supported, ~target_mask, u->cgroup_path, !is_root_slice); r = cg_trim_v1_controllers(u->manager->cgroup_supported, ~target_mask, u->cgroup_path, !is_root_slice);
if (r < 0) if (r < 0)
log_unit_warning_errno(u, r, "Failed to delete controller cgroups %s, ignoring: %m", u->cgroup_path); log_unit_full_errno(
u,
cg_v1_errno_to_log_level(r),
r,
"Failed to delete controller cgroups %s, ignoring: %m",
u->cgroup_path);
} }
/* Set attributes */ /* Set attributes */
@ -3133,7 +3151,7 @@ int manager_setup_cgroup(Manager *m) {
(void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1"); (void) cg_set_attribute("memory", "/", "memory.use_hierarchy", "1");
/* 8. Figure out which controllers are supported */ /* 8. Figure out which controllers are supported */
r = cg_mask_supported_subtree(m->cgroup_root, &m->cgroup_supported); r = cg_mask_supported(&m->cgroup_supported);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to determine supported controllers: %m"); return log_error_errno(r, "Failed to determine supported controllers: %m");

View File

@ -32,6 +32,7 @@ static int genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint16_t nl
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *genl_cmd_type, *nl_type; const NLType *genl_cmd_type, *nl_type;
const NLTypeSystem *type_system; const NLTypeSystem *type_system;
struct genlmsghdr *genl;
size_t size; size_t size;
int r; int r;
@ -62,11 +63,9 @@ static int genl_message_new(sd_netlink *nl, sd_genl_family_t family, uint16_t nl
m->hdr->nlmsg_type = nlmsg_type; m->hdr->nlmsg_type = nlmsg_type;
type_get_type_system(nl_type, &m->containers[0].type_system); type_get_type_system(nl_type, &m->containers[0].type_system);
genl = NLMSG_DATA(m->hdr);
*(struct genlmsghdr *) NLMSG_DATA(m->hdr) = (struct genlmsghdr) { genl->cmd = cmd;
.cmd = cmd, genl->version = genl_families[family].version;
.version = genl_families[family].version,
};
*ret = TAKE_PTR(m); *ret = TAKE_PTR(m);

View File

@ -144,6 +144,7 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da
size_t message_length; size_t message_length;
struct nlmsghdr *new_hdr; struct nlmsghdr *new_hdr;
struct rtattr *rta; struct rtattr *rta;
unsigned i;
int offset; int offset;
assert(m); assert(m);
@ -171,7 +172,7 @@ static int add_rtattr(sd_netlink_message *m, unsigned short type, const void *da
rtattr_append_attribute_internal(rta, type, data, data_length); rtattr_append_attribute_internal(rta, type, data, data_length);
/* if we are inside containers, extend them */ /* if we are inside containers, extend them */
for (unsigned i = 0; i < m->n_containers; i++) for (i = 0; i < m->n_containers; i++)
GET_CONTAINER(m, i)->rta_len += RTA_SPACE(data_length); GET_CONTAINER(m, i)->rta_len += RTA_SPACE(data_length);
/* update message size */ /* update message size */
@ -642,6 +643,7 @@ int sd_netlink_message_open_array(sd_netlink_message *m, uint16_t type) {
} }
int sd_netlink_message_cancel_array(sd_netlink_message *m) { int sd_netlink_message_cancel_array(sd_netlink_message *m) {
unsigned i;
uint32_t rta_len; uint32_t rta_len;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
@ -650,7 +652,7 @@ int sd_netlink_message_cancel_array(sd_netlink_message *m) {
rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len; rta_len = GET_CONTAINER(m, (m->n_containers - 1))->rta_len;
for (unsigned i = 0; i < m->n_containers; i++) for (i = 0; i < m->n_containers; i++)
GET_CONTAINER(m, i)->rta_len -= rta_len; GET_CONTAINER(m, i)->rta_len -= rta_len;
m->hdr->nlmsg_len -= rta_len; m->hdr->nlmsg_len -= rta_len;
@ -1281,6 +1283,7 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) {
const NLType *nl_type; const NLType *nl_type;
uint16_t type; uint16_t type;
size_t size; size_t size;
unsigned i;
int r; int r;
assert_return(m, -EINVAL); assert_return(m, -EINVAL);
@ -1290,7 +1293,7 @@ int sd_netlink_message_rewind(sd_netlink_message *m, sd_netlink *genl) {
if (!m->sealed) if (!m->sealed)
rtnl_message_seal(m); rtnl_message_seal(m);
for (unsigned i = 1; i <= m->n_containers; i++) for (i = 1; i <= m->n_containers; i++)
m->containers[i].attributes = mfree(m->containers[i].attributes); m->containers[i].attributes = mfree(m->containers[i].attributes);
m->n_containers = 0; m->n_containers = 0;

View File

@ -29,6 +29,7 @@ int socket_open(int family) {
static int broadcast_groups_get(sd_netlink *nl) { static int broadcast_groups_get(sd_netlink *nl) {
_cleanup_free_ uint32_t *groups = NULL; _cleanup_free_ uint32_t *groups = NULL;
socklen_t len = 0, old_len; socklen_t len = 0, old_len;
unsigned i, j;
int r; int r;
assert(nl); assert(nl);
@ -36,11 +37,11 @@ static int broadcast_groups_get(sd_netlink *nl) {
r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len); r = getsockopt(nl->fd, SOL_NETLINK, NETLINK_LIST_MEMBERSHIPS, NULL, &len);
if (r < 0) { if (r < 0) {
if (errno != ENOPROTOOPT) if (errno == ENOPROTOOPT) {
nl->broadcast_group_dont_leave = true;
return 0;
} else
return -errno; return -errno;
nl->broadcast_group_dont_leave = true;
return 0;
} }
if (len == 0) if (len == 0)
@ -63,15 +64,23 @@ static int broadcast_groups_get(sd_netlink *nl) {
if (r < 0) if (r < 0)
return r; return r;
for (unsigned i = 0; i < len; i++) for (i = 0; i < len; i++) {
for (unsigned j = 0; j < sizeof(uint32_t) * 8; j++) for (j = 0; j < sizeof(uint32_t) * 8; j++) {
if (groups[i] & (1U << j)) { uint32_t offset;
unsigned group = i * sizeof(uint32_t) * 8 + j + 1; unsigned group;
r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1)); offset = 1U << j;
if (r < 0)
return r; if (!(groups[i] & offset))
} continue;
group = i * sizeof(uint32_t) * 8 + j + 1;
r = hashmap_put(nl->broadcast_group_refs, UINT_TO_PTR(group), UINT_TO_PTR(1));
if (r < 0)
return r;
}
}
return 0; return 0;
} }
@ -95,7 +104,11 @@ int socket_bind(sd_netlink *nl) {
if (r < 0) if (r < 0)
return -errno; return -errno;
return broadcast_groups_get(nl); r = broadcast_groups_get(nl);
if (r < 0)
return r;
return 0;
} }
static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) { static unsigned broadcast_group_get_ref(sd_netlink *nl, unsigned group) {
@ -117,12 +130,17 @@ static int broadcast_group_set_ref(sd_netlink *nl, unsigned group, unsigned n_re
} }
static int broadcast_group_join(sd_netlink *nl, unsigned group) { static int broadcast_group_join(sd_netlink *nl, unsigned group) {
int r;
assert(nl); assert(nl);
assert(nl->fd >= 0); assert(nl->fd >= 0);
assert(group > 0); assert(group > 0);
/* group is "unsigned", but netlink(7) says the argument for NETLINK_ADD_MEMBERSHIP is "int" */ r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, &group, sizeof(group));
return setsockopt_int(nl->fd, SOL_NETLINK, NETLINK_ADD_MEMBERSHIP, group); if (r < 0)
return -errno;
return 0;
} }
int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) { int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) {
@ -155,6 +173,8 @@ int socket_broadcast_group_ref(sd_netlink *nl, unsigned group) {
} }
static int broadcast_group_leave(sd_netlink *nl, unsigned group) { static int broadcast_group_leave(sd_netlink *nl, unsigned group) {
int r;
assert(nl); assert(nl);
assert(nl->fd >= 0); assert(nl->fd >= 0);
assert(group > 0); assert(group > 0);
@ -162,8 +182,11 @@ static int broadcast_group_leave(sd_netlink *nl, unsigned group) {
if (nl->broadcast_group_dont_leave) if (nl->broadcast_group_dont_leave)
return 0; return 0;
/* group is "unsigned", but netlink(7) says the argument for NETLINK_DROP_MEMBERSHIP is "int" */ r = setsockopt(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, &group, sizeof(group));
return setsockopt_int(nl->fd, SOL_NETLINK, NETLINK_DROP_MEMBERSHIP, group); if (r < 0)
return -errno;
return 0;
} }
int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) { int socket_broadcast_group_unref(sd_netlink *nl, unsigned group) {
@ -217,6 +240,8 @@ int socket_write_message(sd_netlink *nl, sd_netlink_message *m) {
int socket_writev_message(sd_netlink *nl, sd_netlink_message **m, size_t msgcount) { int socket_writev_message(sd_netlink *nl, sd_netlink_message **m, size_t msgcount) {
_cleanup_free_ struct iovec *iovs = NULL; _cleanup_free_ struct iovec *iovs = NULL;
ssize_t k;
size_t i;
assert(nl); assert(nl);
assert(m); assert(m);
@ -226,13 +251,13 @@ int socket_writev_message(sd_netlink *nl, sd_netlink_message **m, size_t msgcoun
if (!iovs) if (!iovs)
return -ENOMEM; return -ENOMEM;
for (size_t i = 0; i < msgcount; i++) { for (i = 0; i < msgcount; i++) {
assert(m[i]->hdr != NULL); assert(m[i]->hdr != NULL);
assert(m[i]->hdr->nlmsg_len > 0); assert(m[i]->hdr->nlmsg_len > 0);
iovs[i] = IOVEC_MAKE(m[i]->hdr, m[i]->hdr->nlmsg_len); iovs[i] = IOVEC_MAKE(m[i]->hdr, m[i]->hdr->nlmsg_len);
} }
ssize_t k = writev(nl->fd, iovs, msgcount); k = writev(nl->fd, iovs, msgcount);
if (k < 0) if (k < 0)
return -errno; return -errno;
@ -300,6 +325,7 @@ int socket_read_message(sd_netlink *rtnl) {
struct iovec iov = {}; struct iovec iov = {};
uint32_t group = 0; uint32_t group = 0;
bool multi_part = false, done = false; bool multi_part = false, done = false;
struct nlmsghdr *new_msg;
size_t len; size_t len;
int r; int r;
unsigned i = 0; unsigned i = 0;
@ -346,7 +372,7 @@ int socket_read_message(sd_netlink *rtnl) {
} }
} }
for (struct nlmsghdr *new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) { for (new_msg = rtnl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
const NLType *nl_type; const NLType *nl_type;

View File

@ -19,6 +19,7 @@
static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t type, uint16_t flags) { static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int family, uint16_t type, uint16_t flags) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
struct nfgenmsg *nfh;
const NLType *nl_type; const NLType *nl_type;
size_t size; size_t size;
int r; int r;
@ -56,11 +57,10 @@ static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int famil
m->hdr->nlmsg_len = size; m->hdr->nlmsg_len = size;
m->hdr->nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | type; m->hdr->nlmsg_type = NFNL_SUBSYS_NFTABLES << 8 | type;
*(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) { nfh = NLMSG_DATA(m->hdr);
.nfgen_family = family, nfh->nfgen_family = family;
.version = NFNETLINK_V0, nfh->version = NFNETLINK_V0;
.res_id = nfnl->serial, nfh->res_id = nfnl->serial;
};
*ret = TAKE_PTR(m); *ret = TAKE_PTR(m);
return 0; return 0;
@ -68,17 +68,17 @@ static int nft_message_new(sd_netlink *nfnl, sd_netlink_message **ret, int famil
static int sd_nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, int v) { static int sd_nfnl_message_batch(sd_netlink *nfnl, sd_netlink_message **ret, int v) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
struct nfgenmsg *nfh;
int r; int r;
r = message_new(nfnl, &m, v); r = message_new(nfnl, &m, v);
if (r < 0) if (r < 0)
return r; return r;
*(struct nfgenmsg*) NLMSG_DATA(m->hdr) = (struct nfgenmsg) { nfh = NLMSG_DATA(m->hdr);
.nfgen_family = AF_UNSPEC, nfh->nfgen_family = AF_UNSPEC;
.version = NFNETLINK_V0, nfh->version = NFNETLINK_V0;
.res_id = NFNL_SUBSYS_NFTABLES, nfh->res_id = NFNL_SUBSYS_NFTABLES;
};
*ret = TAKE_PTR(m); *ret = TAKE_PTR(m);
return r; return r;

View File

@ -4,15 +4,4 @@ TEST_DESCRIPTION="Tmpfiles related tests"
TEST_NO_QEMU=1 TEST_NO_QEMU=1
. $TEST_BASE_DIR/test-functions . $TEST_BASE_DIR/test-functions
test_append_files() {
if [[ "$IS_BUILT_WITH_ASAN" == "yes" ]]; then
if [[ -z "$initdir" ]]; then
echo >&2 "\$initdir is not defined, can't continue"
exit 1
fi
sed -i "s/systemd//g" "$initdir/etc/nsswitch.conf"
fi
}
do_test "$@" 22 do_test "$@" 22