LINUX.ORG.RU

История изменений

Исправление ttnl, (текущая версия) :

По всей видимости причина в следующем.

Запуск usermode_helper происходит из рабочей очереди. У рабочей очереди стоит флаг PF_NO_SETAFFINITY, поскольку он всегда есть у рабочих очередей.

Далее, после kthread_create, helper его наследует, т.к. при fork()->copy_process() в функции copy_flags() PF_NO_SETAFFINITY не очищается:

static void copy_flags(unsigned long clone_flags, struct task_struct *p)
{
        unsigned long new_flags = p->flags;

        new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
        new_flags |= PF_FORKNOEXEC;
        p->flags = new_flags;
}

Запускается ядерный процесс call_helper(), он делает do_exec. exec этот флаг тоже не трогает, поэтому твой скрипт тоже обладает флагом PF_NO_SETAFFINITY.

Когда ты пытаешься поменять cgroup, то это не получается, поскольку в attach_task_by_pid() стоит проверка:

if (tsk == kthreadd_task || (tsk->flags & PF_NO_SETAFFINITY)) {
                ret = -EINVAL;
                rcu_read_unlock();
                goto out_unlock_cgroup;
        }

-EINVAL берется отсюда.

Исходная версия ttnl, :

По всей видимости причина в следующем.

Запуск usermode_helper происходит из рабочей очереди. У рабочей очереди стоит флаг PF_NO_SETAFFINITY, поскольку он всегда есть у этих очередей.

Далее, после kthread_create, helper наследует этот флаг, т.к. при fork()->copy_process() в функции copy_flags() флаг PF_NO_SETAFFINITY не очищается:

static void copy_flags(unsigned long clone_flags, struct task_struct *p)
{
        unsigned long new_flags = p->flags;

        new_flags &= ~(PF_SUPERPRIV | PF_WQ_WORKER);
        new_flags |= PF_FORKNOEXEC;
        p->flags = new_flags;
}

Запускается ядерный процесс call_helper(), он делает do_exec. exec этот флаг тоже не трогает, поэтому твой скрипт обладает флагом PF_NO_SETAFFINITY.

Когда ты пытаешься поменять cgroup, то это не получается, поскольку в attach_task_by_pid() есть проверка:

if (tsk == kthreadd_task || (tsk->flags & PF_NO_SETAFFINITY)) {
                ret = -EINVAL;
                rcu_read_unlock();
                goto out_unlock_cgroup;
        }

-EINVAL берется отсюда.