Skip to content

Commit 0fa294f

Browse files
committed
cgroup: Replace cgroup_rstat_mutex with a spinlock
Currently, rstat flush path is protected with a mutex which is fine as all the existing users are from interface file show path. However, rstat is being generalized for use by controllers and flushing from atomic contexts will be necessary. This patch replaces cgroup_rstat_mutex with a spinlock and adds a irq-safe flush function - cgroup_rstat_flush_irqsafe(). Explicit yield handling is added to the flush path so that other flush functions can yield to other threads and flushers. Signed-off-by: Tejun Heo <[email protected]>
1 parent 6162cef commit 0fa294f

File tree

2 files changed

+46
-13
lines changed

2 files changed

+46
-13
lines changed

include/linux/cgroup.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -696,6 +696,7 @@ static inline void cgroup_path_from_kernfs_id(const union kernfs_node_id *id,
696696
*/
697697
void cgroup_rstat_updated(struct cgroup *cgrp, int cpu);
698698
void cgroup_rstat_flush(struct cgroup *cgrp);
699+
void cgroup_rstat_flush_irqsafe(struct cgroup *cgrp);
699700
void cgroup_rstat_flush_hold(struct cgroup *cgrp);
700701
void cgroup_rstat_flush_release(void);
701702

kernel/cgroup/rstat.c

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#include <linux/sched/cputime.h>
44

5-
static DEFINE_MUTEX(cgroup_rstat_mutex);
5+
static DEFINE_SPINLOCK(cgroup_rstat_lock);
66
static DEFINE_PER_CPU(raw_spinlock_t, cgroup_rstat_cpu_lock);
77

88
static void cgroup_base_stat_flush(struct cgroup *cgrp, int cpu);
@@ -132,21 +132,31 @@ static struct cgroup *cgroup_rstat_cpu_pop_updated(struct cgroup *pos,
132132
}
133133

134134
/* see cgroup_rstat_flush() */
135-
static void cgroup_rstat_flush_locked(struct cgroup *cgrp)
135+
static void cgroup_rstat_flush_locked(struct cgroup *cgrp, bool may_sleep)
136+
__releases(&cgroup_rstat_lock) __acquires(&cgroup_rstat_lock)
136137
{
137138
int cpu;
138139

139-
lockdep_assert_held(&cgroup_rstat_mutex);
140+
lockdep_assert_held(&cgroup_rstat_lock);
140141

141142
for_each_possible_cpu(cpu) {
142143
raw_spinlock_t *cpu_lock = per_cpu_ptr(&cgroup_rstat_cpu_lock,
143144
cpu);
144145
struct cgroup *pos = NULL;
145146

146-
raw_spin_lock_irq(cpu_lock);
147+
raw_spin_lock(cpu_lock);
147148
while ((pos = cgroup_rstat_cpu_pop_updated(pos, cgrp, cpu)))
148149
cgroup_base_stat_flush(pos, cpu);
149-
raw_spin_unlock_irq(cpu_lock);
150+
raw_spin_unlock(cpu_lock);
151+
152+
/* if @may_sleep, play nice and yield if necessary */
153+
if (may_sleep && (need_resched() ||
154+
spin_needbreak(&cgroup_rstat_lock))) {
155+
spin_unlock_irq(&cgroup_rstat_lock);
156+
if (!cond_resched())
157+
cpu_relax();
158+
spin_lock_irq(&cgroup_rstat_lock);
159+
}
150160
}
151161
}
152162

@@ -160,12 +170,31 @@ static void cgroup_rstat_flush_locked(struct cgroup *cgrp)
160170
*
161171
* This also gets all cgroups in the subtree including @cgrp off the
162172
* ->updated_children lists.
173+
*
174+
* This function may block.
163175
*/
164176
void cgroup_rstat_flush(struct cgroup *cgrp)
165177
{
166-
mutex_lock(&cgroup_rstat_mutex);
167-
cgroup_rstat_flush_locked(cgrp);
168-
mutex_unlock(&cgroup_rstat_mutex);
178+
might_sleep();
179+
180+
spin_lock_irq(&cgroup_rstat_lock);
181+
cgroup_rstat_flush_locked(cgrp, true);
182+
spin_unlock_irq(&cgroup_rstat_lock);
183+
}
184+
185+
/**
186+
* cgroup_rstat_flush_irqsafe - irqsafe version of cgroup_rstat_flush()
187+
* @cgrp: target cgroup
188+
*
189+
* This function can be called from any context.
190+
*/
191+
void cgroup_rstat_flush_irqsafe(struct cgroup *cgrp)
192+
{
193+
unsigned long flags;
194+
195+
spin_lock_irqsave(&cgroup_rstat_lock, flags);
196+
cgroup_rstat_flush_locked(cgrp, false);
197+
spin_unlock_irqrestore(&cgroup_rstat_lock, flags);
169198
}
170199

171200
/**
@@ -174,21 +203,24 @@ void cgroup_rstat_flush(struct cgroup *cgrp)
174203
*
175204
* Flush stats in @cgrp's subtree and prevent further flushes. Must be
176205
* paired with cgroup_rstat_flush_release().
206+
*
207+
* This function may block.
177208
*/
178209
void cgroup_rstat_flush_hold(struct cgroup *cgrp)
179-
__acquires(&cgroup_rstat_mutex)
210+
__acquires(&cgroup_rstat_lock)
180211
{
181-
mutex_lock(&cgroup_rstat_mutex);
182-
cgroup_rstat_flush_locked(cgrp);
212+
might_sleep();
213+
spin_lock_irq(&cgroup_rstat_lock);
214+
cgroup_rstat_flush_locked(cgrp, true);
183215
}
184216

185217
/**
186218
* cgroup_rstat_flush_release - release cgroup_rstat_flush_hold()
187219
*/
188220
void cgroup_rstat_flush_release(void)
189-
__releases(&cgroup_rstat_mutex)
221+
__releases(&cgroup_rstat_lock)
190222
{
191-
mutex_unlock(&cgroup_rstat_mutex);
223+
spin_unlock_irq(&cgroup_rstat_lock);
192224
}
193225

194226
int cgroup_rstat_init(struct cgroup *cgrp)

0 commit comments

Comments
 (0)