Patch "cgroup,freezer: hold cpu_hotplug_lock before freezer_mutex" has been added to the 6.2-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    cgroup,freezer: hold cpu_hotplug_lock before freezer_mutex

to the 6.2-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     cgroup-freezer-hold-cpu_hotplug_lock-before-freezer_.patch
and it can be found in the queue-6.2 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 1515f4e0b26b2dd32db668cd1e4e3d19e2ee2800
Author: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
Date:   Wed Apr 5 22:15:32 2023 +0900

    cgroup,freezer: hold cpu_hotplug_lock before freezer_mutex
    
    [ Upstream commit 57dcd64c7e036299ef526b400a8d12b8a2352f26 ]
    
    syzbot is reporting circular locking dependency between cpu_hotplug_lock
    and freezer_mutex, for commit f5d39b020809 ("freezer,sched: Rewrite core
    freezer logic") replaced atomic_inc() in freezer_apply_state() with
    static_branch_inc() which holds cpu_hotplug_lock.
    
    cpu_hotplug_lock => cgroup_threadgroup_rwsem => freezer_mutex
    
      cgroup_file_write() {
        cgroup_procs_write() {
          __cgroup_procs_write() {
            cgroup_procs_write_start() {
              cgroup_attach_lock() {
                cpus_read_lock() {
                  percpu_down_read(&cpu_hotplug_lock);
                }
                percpu_down_write(&cgroup_threadgroup_rwsem);
              }
            }
            cgroup_attach_task() {
              cgroup_migrate() {
                cgroup_migrate_execute() {
                  freezer_attach() {
                    mutex_lock(&freezer_mutex);
                    (...snipped...)
                  }
                }
              }
            }
            (...snipped...)
          }
        }
      }
    
    freezer_mutex => cpu_hotplug_lock
    
      cgroup_file_write() {
        freezer_write() {
          freezer_change_state() {
            mutex_lock(&freezer_mutex);
            freezer_apply_state() {
              static_branch_inc(&freezer_active) {
                static_key_slow_inc() {
                  cpus_read_lock();
                  static_key_slow_inc_cpuslocked();
                  cpus_read_unlock();
                }
              }
            }
            mutex_unlock(&freezer_mutex);
          }
        }
      }
    
    Swap locking order by moving cpus_read_lock() in freezer_apply_state()
    to before mutex_lock(&freezer_mutex) in freezer_change_state().
    
    Reported-by: syzbot <syzbot+c39682e86c9d84152f93@xxxxxxxxxxxxxxxxxxxxxxxxx>
    Link: https://syzkaller.appspot.com/bug?extid=c39682e86c9d84152f93
    Suggested-by: Hillf Danton <hdanton@xxxxxxxx>
    Fixes: f5d39b020809 ("freezer,sched: Rewrite core freezer logic")
    Signed-off-by: Tetsuo Handa <penguin-kernel@xxxxxxxxxxxxxxxxxxx>
    Acked-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
    Reviewed-by: Mukesh Ojha <quic_mojha@xxxxxxxxxxx>
    Signed-off-by: Tejun Heo <tj@xxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/kernel/cgroup/legacy_freezer.c b/kernel/cgroup/legacy_freezer.c
index 1b6b21851e9d4..936473203a6b5 100644
--- a/kernel/cgroup/legacy_freezer.c
+++ b/kernel/cgroup/legacy_freezer.c
@@ -22,6 +22,7 @@
 #include <linux/freezer.h>
 #include <linux/seq_file.h>
 #include <linux/mutex.h>
+#include <linux/cpu.h>
 
 /*
  * A cgroup is freezing if any FREEZING flags are set.  FREEZING_SELF is
@@ -350,7 +351,7 @@ static void freezer_apply_state(struct freezer *freezer, bool freeze,
 
 	if (freeze) {
 		if (!(freezer->state & CGROUP_FREEZING))
-			static_branch_inc(&freezer_active);
+			static_branch_inc_cpuslocked(&freezer_active);
 		freezer->state |= state;
 		freeze_cgroup(freezer);
 	} else {
@@ -361,7 +362,7 @@ static void freezer_apply_state(struct freezer *freezer, bool freeze,
 		if (!(freezer->state & CGROUP_FREEZING)) {
 			freezer->state &= ~CGROUP_FROZEN;
 			if (was_freezing)
-				static_branch_dec(&freezer_active);
+				static_branch_dec_cpuslocked(&freezer_active);
 			unfreeze_cgroup(freezer);
 		}
 	}
@@ -379,6 +380,7 @@ static void freezer_change_state(struct freezer *freezer, bool freeze)
 {
 	struct cgroup_subsys_state *pos;
 
+	cpus_read_lock();
 	/*
 	 * Update all its descendants in pre-order traversal.  Each
 	 * descendant will try to inherit its parent's FREEZING state as
@@ -407,6 +409,7 @@ static void freezer_change_state(struct freezer *freezer, bool freeze)
 	}
 	rcu_read_unlock();
 	mutex_unlock(&freezer_mutex);
+	cpus_read_unlock();
 }
 
 static ssize_t freezer_write(struct kernfs_open_file *of,



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux