Removes a cgroup from a given hierachy. @param hierarchy Path to hierarchy root. @param cgroup Path of the cgroup relative to the hierarchy root. @return Some if the operation succeeds. Error if the operation fails.
| 272 | // @return Some if the operation succeeds. |
| 273 | // Error if the operation fails. |
| 274 | Future<Nothing> remove(const string& hierarchy, const string& cgroup) |
| 275 | { |
| 276 | const string path = path::join(hierarchy, cgroup); |
| 277 | |
| 278 | // We retry on EBUSY as a workaround for kernel bug |
| 279 | // https://lkml.org/lkml/2020/1/15/1349 and others which cause rmdir to fail |
| 280 | // with EBUSY even though the cgroup appears empty. |
| 281 | |
| 282 | Duration delay = Duration::zero(); |
| 283 | |
| 284 | return loop( |
| 285 | [=]() mutable { |
| 286 | auto timeout = process::after(delay); |
| 287 | delay = (delay == Duration::zero()) ? Milliseconds(1) : delay * 2; |
| 288 | return timeout; |
| 289 | }, |
| 290 | [=](const Nothing&) mutable -> Future<ControlFlow<Nothing>> { |
| 291 | if (::rmdir(path.c_str()) == 0) { |
| 292 | return process::Break(); |
| 293 | } else if (errno == EBUSY) { |
| 294 | LOG(WARNING) << "Removal of cgroup " << path |
| 295 | << " failed with EBUSY, will try again"; |
| 296 | |
| 297 | return process::Continue(); |
| 298 | } else { |
| 299 | // If the `cgroup` still exists in the hierarchy, treat this as |
| 300 | // an error; otherwise, treat this as a success since the `cgroup` |
| 301 | // has actually been cleaned up. |
| 302 | // Save the error string as os::exists may clobber errno. |
| 303 | const string error = os::strerror(errno); |
| 304 | if (os::exists(path::join(hierarchy, cgroup))) { |
| 305 | return Failure( |
| 306 | "Failed to remove directory '" + path + "': " + error); |
| 307 | } |
| 308 | |
| 309 | return process::Break(); |
| 310 | } |
| 311 | } |
| 312 | ); |
| 313 | } |
| 314 | |
| 315 | |
| 316 | // Removes a list of cgroups from a given hierachy. |