typedef int (*tg_visitor)(struct task_group *, void *);
 
 /*
- * Iterate the full tree, calling @down when first entering a node and @up when
- * leaving it for the final time.
+ * Iterate task_group tree rooted at *from, calling @down when first entering a
+ * node and @up when leaving it for the final time.
+ *
+ * Caller must hold rcu_lock or sufficient equivalent.
  */
-static int walk_tg_tree(tg_visitor down, tg_visitor up, void *data)
+static int walk_tg_tree_from(struct task_group *from,
+                            tg_visitor down, tg_visitor up, void *data)
 {
        struct task_group *parent, *child;
        int ret;
 
-       rcu_read_lock();
-       parent = &root_task_group;
+       parent = from;
+
 down:
        ret = (*down)(parent, data);
        if (ret)
-               goto out_unlock;
+               goto out;
        list_for_each_entry_rcu(child, &parent->children, siblings) {
                parent = child;
                goto down;
                continue;
        }
        ret = (*up)(parent, data);
-       if (ret)
-               goto out_unlock;
+       if (ret || parent == from)
+               goto out;
 
        child = parent;
        parent = parent->parent;
        if (parent)
                goto up;
-out_unlock:
-       rcu_read_unlock();
-
+out:
        return ret;
 }
 
+/*
+ * Iterate the full tree, calling @down when first entering a node and @up when
+ * leaving it for the final time.
+ *
+ * Caller must hold rcu_lock or sufficient equivalent.
+ */
+
+static inline int walk_tg_tree(tg_visitor down, tg_visitor up, void *data)
+{
+       return walk_tg_tree_from(&root_task_group, down, up, data);
+}
+
 static int tg_nop(struct task_group *tg, void *data)
 {
        return 0;
 
 static int __rt_schedulable(struct task_group *tg, u64 period, u64 runtime)
 {
+       int ret;
+
        struct rt_schedulable_data data = {
                .tg = tg,
                .rt_period = period,
                .rt_runtime = runtime,
        };
 
-       return walk_tg_tree(tg_rt_schedulable, tg_nop, &data);
+       rcu_read_lock();
+       ret = walk_tg_tree(tg_rt_schedulable, tg_nop, &data);
+       rcu_read_unlock();
+
+       return ret;
 }
 
 static int tg_set_rt_bandwidth(struct task_group *tg,
 
 static int __cfs_schedulable(struct task_group *tg, u64 period, u64 quota)
 {
+       int ret;
        struct cfs_schedulable_data data = {
                .tg = tg,
                .period = period,
                do_div(data.quota, NSEC_PER_USEC);
        }
 
-       return walk_tg_tree(tg_cfs_schedulable_down, tg_nop, &data);
+       rcu_read_lock();
+       ret = walk_tg_tree(tg_cfs_schedulable_down, tg_nop, &data);
+       rcu_read_unlock();
+
+       return ret;
 }
 #endif /* CONFIG_CFS_BANDWIDTH */
 #endif /* CONFIG_FAIR_GROUP_SCHED */