在 2026/7/15 06:09, Tejun Heo 写道:
> Hello, Waiman.
> 
>> +    usleep(1000);
>>      if (cg_check_frozen(cgroup, true))
>>              goto cleanup;
> 
> A fixed 1ms sleep only hides the race. On a loaded machine or a slow arch
> (you mention ppc64) the refreeze can take longer than 1ms, and the test
> reads the unfrozen state and fails anyway.
> 
> The freezer test already has a way to wait for this properly.
> cg_prepare_for_wait() sets up an inotify watch on cgroup.events and
> cg_wait_for() blocks until it changes. cg_enter_and_wait_for_frozen() shows
> the pattern: loop cg_wait_for() then cg_check_frozen(). The cgroup always
> ends up frozen, so looping until cg_check_frozen() reports frozen is
> reliable and doesn't depend on timing.
> 
> Can you respin using that instead of usleep()?
> 
> Also, temporaily -> temporarily, in both the changelog and the comment.
> 

Hi Tejun, Waiman,

I ran into a similar issue a while back and can add a data point on
the reproducibility: when running the full cgroup selftest suite, a
few cases -- test_cgfreezer_ptrace and test_cgfreezer_stopped -- fail
intermittently (around 40-70% on VMs), yet each failing case passes
reliably when run on its own. That points at state carried across
tests rather than a per-test bug, which is also why a fixed sleep/retry
is fragile.

On the "unfrozen state" above, I traced where CGRP_FROZEN actually gets
cleared. When the frozen tracee is woken by PTRACE_INTERRUPT,
JOBCTL_TRAP_STOP takes priority over JOBCTL_TRAP_FREEZE in get_signal(),
so the task enters ptrace_stop() instead of going back to
do_freezer_trap(). With debug printk in cgroup_update_frozen_flag() and
cgroup_leave_frozen(), the cg_test_ptrace trace shows:

  0 -> 1  nr_frozen=1  task_count=1   /* initial freeze            */
  1 -> 0  nr_frozen=0  task_count=1   /* dec, task still in cgroup */
  0 -> 1  nr_frozen=0  task_count=0   /* task left cgroup          */

The 1 -> 0 step (nr_frozen 1->0 while task_count is still 1) is
cgroup_dec_frozen_cnt(), called from cgroup_leave_frozen(true) at the
end of ptrace_stop() (signal.c:2479) when the tracee is woken by
PTRACE_DETACH. That clears CGRP_FROZEN until the task loops back into
do_freezer_trap() and re-enters the frozen state -- the transient
unfrozen window the test hits.

As a kernel-side attempt I changed cgroup_enter_frozen() so it no longer
returns early when current->frozen is already true: css_set_lock is
taken before the check and, if CGRP_FREEZE is still set,
cgroup_update_frozen() is called to re-verify the cgroup frozen state
when a frozen task is handed off to ptrace.

Due to other work I've had to pause this investigation for now, so I'm
sharing the above as a data point rather than a finished fix.

Thanks,
Tao

> Thanks.
> 


Reply via email to