Skip to content

Commit fc7f0ec

Browse files
committed
reaper: don't reap unpopulated cgroups that still have child cgroups
Fixes a race condition that led to an endless loop.
1 parent 0e1ec6c commit fc7f0ec

6 files changed

Lines changed: 44 additions & 1 deletion

File tree

debian/changelog

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ cm4all-spawn (0.26) unstable; urgency=low
22

33
* reaper: schedule EPOLLPRI on cgroup.events
44
* reaper: reduce number of system calls while scanning cgroup tree
5+
* reaper: don't reap unpopulated cgroups that still have child cgroups
56
* lua: new libraries:
67
- "control_client
78
- "socket"

src/reaper/TreeWatch.cxx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,12 @@ TreeWatch::HandleDeletedDirectory(Directory &parent,
261261

262262
HandleDeletedDirectory(child);
263263

264-
if (!child.persist)
264+
if (!child.persist) {
265265
parent.children.erase(i);
266+
267+
if (parent.children.empty())
268+
OnDirectoryEmpty(parent.GetRelativePath());
269+
}
266270
}
267271

268272
inline void

src/reaper/TreeWatch.hxx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,14 @@ public:
7676
: FileDescriptor::Undefined();
7777
}
7878

79+
[[gnu::pure]]
80+
bool IsDirectoryEmpty(std::string_view relative_path) const noexcept {
81+
const auto *directory = FindDirectory(relative_path);
82+
return directory != nullptr
83+
? directory->children.empty()
84+
: true;
85+
}
86+
7987
private:
8088
/**
8189
* Look up a #Directory object. Returns nullptr if the
@@ -110,5 +118,6 @@ protected:
110118

111119
virtual void OnDirectoryCreated(std::string_view relative_path,
112120
FileDescriptor directory_fd) noexcept = 0;
121+
virtual void OnDirectoryEmpty(std::string_view relative_path) noexcept = 0;
113122
virtual void OnDirectoryDeleted(std::string_view relative_path) noexcept = 0;
114123
};

src/reaper/UnifiedWatch.cxx

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,13 @@ UnifiedCgroupWatch::ReAddCgroup(std::string_view relative_path) noexcept
114114
void
115115
UnifiedCgroupWatch::OnGroupEmpty(Group &group) noexcept
116116
{
117+
if (!IsDirectoryEmpty(group.GetRelativePath()))
118+
/* there are still child cgroups, but they are
119+
unpopulated; they may be populated soon, so don't
120+
reap this cgroup yet; later, OnDirectoryEmpty() may
121+
do that */
122+
return;
123+
117124
callback(("/" + group.GetRelativePath()).c_str());
118125

119126
auto i = groups.find(group.GetRelativePath());
@@ -224,6 +231,23 @@ UnifiedCgroupWatch::OnDirectoryCreated(const std::string_view relative_path,
224231
}
225232
}
226233

234+
void
235+
UnifiedCgroupWatch::OnDirectoryEmpty(std::string_view relative_path) noexcept
236+
{
237+
auto i = groups.find(relative_path);
238+
if (i == groups.end())
239+
return;
240+
241+
auto &group = i->second;
242+
if (group.IsPopulated())
243+
/* the last child cgroup was deleted, but this one is
244+
still populated, so don't reap it */
245+
return;
246+
247+
callback(("/" + group.GetRelativePath()).c_str());
248+
groups.erase(i);
249+
}
250+
227251
void
228252
UnifiedCgroupWatch::OnDirectoryDeleted(const std::string_view relative_path) noexcept
229253
{

src/reaper/UnifiedWatch.hxx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,5 +56,6 @@ protected:
5656
bool ShouldSkipName(std::string_view name) const noexcept override;
5757
void OnDirectoryCreated(std::string_view relative_path,
5858
FileDescriptor directory_fd) noexcept override;
59+
void OnDirectoryEmpty(std::string_view relative_path) noexcept override;
5960
void OnDirectoryDeleted(std::string_view relative_path) noexcept override;
6061
};

test/RunTreeWatch.cxx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class MyTreeWatch final : public TreeWatch {
2828
fmt::print("+ {}\n", relative_path);
2929
}
3030

31+
void OnDirectoryEmpty(std::string_view relative_path) noexcept override {
32+
fmt::print("e {}\n", relative_path);
33+
}
34+
3135
void OnDirectoryDeleted(std::string_view relative_path) noexcept override {
3236
fmt::print("- {}\n", relative_path);
3337
}

0 commit comments

Comments
 (0)