Hello, Waiman.

On Thu, Jul 02, 2026 at 05:47:56PM -0400, Waiman Long wrote:
> It is assumed that a given cpuset cannot be both a source and a
> destination cpuset. [...] it will print a warning and fail the attach
> operation in these unexpected cases [...]

This assumption doesn't hold - the WARN_ON_ONCE() and -EINVAL fire on a
legitimate migration. It's the case sashiko flagged, and it does reach
can_attach().

Threaded subtree with partial cpuset delegation:

  P (+cpuset)
  |- R (cpuset)        <- destination
  |  `- C (no cpuset)  -> effective cpuset == R
  `- W (cpuset)

Group leader in R, thread_a in C, thread_b in W; migrate the whole
process into R (echo $PID > R/cgroup.procs). thread_a moves C->R: its
cgroup changes so compare_css_sets() keeps it in the taskset, but its
cpuset css is unchanged (C inherits R's), so task_cs() == cs == R. cpuset
is in ss_mask because thread_b (W->R) changed. can_attach() then tags R
as a source (thread_a) and the destination (thread_b):

  WARNING: kernel/cgroup/cpuset.c:3054 at cpuset_can_attach_check+0xcd/0x130
   cpuset_can_attach+0x131/0x2f0
   cgroup_migrate_execute+0x367/0x450
  cgroup.procs write returns -EINVAL

So a thread already in the destination's effective cpuset does show up in
the iteration when it reaches that cpuset through a different, non-cpuset
child - compare_css_sets() keys on the cgroup, not the cpuset css.

1-9 handle this correctly (the migration succeeds); the patch 10 guard
regresses it. I've taken 1-9 into for-7.3 - please respin 10-11. One
option: when oldcs == cs the pair is a cpuset no-op, so skip it and add
it to neither list.

Thanks.
--
tejun

Reply via email to