@@ -2686,7 +2686,7 @@ int unit_set_cgroup_path(Unit *u, const char *path) {
26862686 if (crt && streq_ptr (crt -> cgroup_path , path ))
26872687 return 0 ;
26882688
2689- unit_release_cgroup (u );
2689+ unit_release_cgroup (u , /* drop_cgroup_runtime = */ true );
26902690
26912691 crt = unit_setup_cgroup_runtime (u );
26922692 if (!crt )
@@ -3484,7 +3484,7 @@ int unit_realize_cgroup(Unit *u) {
34843484 return unit_realize_cgroup_now (u , manager_state (u -> manager ));
34853485}
34863486
3487- void unit_release_cgroup (Unit * u ) {
3487+ void unit_release_cgroup (Unit * u , bool drop_cgroup_runtime ) {
34883488 assert (u );
34893489
34903490 /* Forgets all cgroup details for this cgroup — but does *not* destroy the cgroup. This is hence OK to call
@@ -3515,7 +3515,8 @@ void unit_release_cgroup(Unit *u) {
35153515 crt -> cgroup_memory_inotify_wd = -1 ;
35163516 }
35173517
3518- * (CGroupRuntime * * ) ((uint8_t * ) u + UNIT_VTABLE (u )-> cgroup_runtime_offset ) = cgroup_runtime_free (crt );
3518+ if (drop_cgroup_runtime )
3519+ * (CGroupRuntime * * ) ((uint8_t * ) u + UNIT_VTABLE (u )-> cgroup_runtime_offset ) = cgroup_runtime_free (crt );
35193520}
35203521
35213522int unit_cgroup_is_empty (Unit * u ) {
@@ -3535,31 +3536,33 @@ int unit_cgroup_is_empty(Unit *u) {
35353536 return r ;
35363537}
35373538
3538- bool unit_maybe_release_cgroup (Unit * u ) {
3539+ static bool unit_maybe_release_cgroup (Unit * u ) {
35393540 int r ;
35403541
3541- assert (u );
3542+ /* Releases the cgroup only if it is recursively empty.
3543+ * Returns true if the cgroup was released, false otherwise. */
35423544
3543- CGroupRuntime * crt = unit_get_cgroup_runtime (u );
3544- if (!crt || !crt -> cgroup_path )
3545- return true;
3545+ assert (u );
35463546
35473547 /* Don't release the cgroup if there are still processes under it. If we get notified later when all
35483548 * the processes exit (e.g. the processes were in D-state and exited after the unit was marked as
35493549 * failed) we need the cgroup paths to continue to be tracked by the manager so they can be looked up
35503550 * and cleaned up later. */
35513551 r = unit_cgroup_is_empty (u );
35523552 if (r > 0 ) {
3553- unit_release_cgroup (u );
3553+ /* Do not free CGroupRuntime when called from unit_prune_cgroup. Various accounting data
3554+ * we should keep, especially CPU usage and *_peak ones which would be shown even after
3555+ * the unit stops. */
3556+ unit_release_cgroup (u , /* drop_cgroup_runtime = */ false);
35543557 return true;
35553558 }
35563559
35573560 return false;
35583561}
35593562
35603563void unit_prune_cgroup (Unit * u ) {
3561- int r ;
35623564 bool is_root_slice ;
3565+ int r ;
35633566
35643567 assert (u );
35653568
@@ -3597,9 +3600,8 @@ void unit_prune_cgroup(Unit *u) {
35973600 if (!unit_maybe_release_cgroup (u )) /* Returns true if the cgroup was released */
35983601 return ;
35993602
3600- crt = unit_get_cgroup_runtime (u ); /* The above might have destroyed the runtime object, let's see if it's still there */
3601- if (!crt )
3602- return ;
3603+ assert (crt == unit_get_cgroup_runtime (u ));
3604+ assert (!crt -> cgroup_path );
36033605
36043606 crt -> cgroup_realized = false;
36053607 crt -> cgroup_realized_mask = 0 ;
0 commit comments