fallbackKill is a slower fallback to the more modern (kernels 5.14+) approach of writing to the cgroup.kill file. This is heavily pulled from runc's same approach (in signalAllProcesses), with the only differences being this is just tailored to the API exposed in this library, and we don't need to c
()
| 442 | // |
| 443 | // https://github.com/opencontainers/runc/blob/8da0a0b5675764feaaaaad466f6567a9983fcd08/libcontainer/init_linux.go#L523-L529 |
| 444 | func (c *Manager) fallbackKill() error { |
| 445 | logger := log.G(context.TODO()).WithFields(log.Fields{"path": c.path}) |
| 446 | |
| 447 | if err := c.Freeze(); err != nil { |
| 448 | logger.WithError(err).Warn("freezing cgroup2.manager") |
| 449 | } |
| 450 | pids, err := c.Procs(true) |
| 451 | if err != nil { |
| 452 | if err := c.Thaw(); err != nil { |
| 453 | logger.WithError(err).Warn("thawing cgroup2.manager") |
| 454 | } |
| 455 | return err |
| 456 | } |
| 457 | var procs []*os.Process |
| 458 | for _, pid := range pids { |
| 459 | p, err := os.FindProcess(int(pid)) |
| 460 | if err != nil { |
| 461 | logger.WithFields(log.Fields{"error": err, "pid": int(pid)}).Warnf("finding process") |
| 462 | continue |
| 463 | } |
| 464 | procs = append(procs, p) |
| 465 | if err := p.Signal(unix.SIGKILL); err != nil { |
| 466 | logger.WithFields(log.Fields{"error": err, "pid": int(pid)}).Warnf("signaling process") |
| 467 | } |
| 468 | } |
| 469 | if err := c.Thaw(); err != nil { |
| 470 | logger.WithError(err).Warn("thawing cgroup2.manager") |
| 471 | } |
| 472 | |
| 473 | subreaper, err := getSubreaper() |
| 474 | if err != nil { |
| 475 | // The error here means that PR_GET_CHILD_SUBREAPER is not |
| 476 | // supported because this code might run on a kernel older |
| 477 | // than 3.4. We don't want to throw an error in that case, |
| 478 | // and we simplify things, considering there is no subreaper |
| 479 | // set. |
| 480 | subreaper = 0 |
| 481 | } |
| 482 | |
| 483 | for _, p := range procs { |
| 484 | // In case a subreaper has been setup, this code must not |
| 485 | // wait for the process. Otherwise, we cannot be sure the |
| 486 | // current process will be reaped by the subreaper, while |
| 487 | // the subreaper might be waiting for this process in order |
| 488 | // to retrieve its exit code. |
| 489 | if subreaper == 0 { |
| 490 | if _, err := p.Wait(); err != nil { |
| 491 | if !errors.Is(err, unix.ECHILD) { |
| 492 | logger.WithFields(log.Fields{"error": err, "pid": p.Pid}).Warn("waiting on process") |
| 493 | } |
| 494 | } |
| 495 | } |
| 496 | } |
| 497 | return nil |
| 498 | } |
| 499 | |
| 500 | func (c *Manager) Delete() error { |
| 501 | // Kernel prevents cgroups with running process from being removed, |
no test coverage detected