@@ -251,26 +251,38 @@ again:
251251// RemovePath aims to remove cgroup path. It does so recursively,
252252// by removing any subdirectories (sub-cgroups) first.
253253func RemovePath (path string ) error {
254- // Try the fast path first.
254+ // Try the fast path first; don't retry on EBUSY yet .
255255 if err := rmdir (path , false ); err == nil {
256256 return nil
257257 }
258258
259+ // There are many reasons why rmdir can fail, including:
260+ // 1. cgroup have existing sub-cgroups;
261+ // 2. cgroup (still) have some processes (that are about to vanish);
262+ // 3. lack of permission (one example is read-only /sys/fs/cgroup mount,
263+ // in which case rmdir returns EROFS even for for a non-existent path,
264+ // see issue 4518).
265+ //
266+ // Using os.ReadDir here kills two birds with one stone: check if
267+ // the directory exists (handling scenario 3 above), and use
268+ // directory contents to remove sub-cgroups (handling scenario 1).
259269 infos , err := os .ReadDir (path )
260270 if err != nil {
261271 if os .IsNotExist (err ) {
262272 return nil
263273 }
264274 return err
265275 }
276+ // Let's remove sub-cgroups, if any.
266277 for _ , info := range infos {
267278 if info .IsDir () {
268- // We should remove subcgroup first.
269279 if err = RemovePath (filepath .Join (path , info .Name ())); err != nil {
270280 return err
271281 }
272282 }
273283 }
284+ // Finally, try rmdir again, this time with retries on EBUSY,
285+ // which may help with scenario 2 above.
274286 return rmdir (path , true )
275287}
276288
0 commit comments