|
@@ -627,6 +627,66 @@ out_unlock:
|
|
|
put_online_cpus();
|
|
|
}
|
|
|
|
|
|
+static void kmemcg_deactivate_workfn(struct work_struct *work)
|
|
|
+{
|
|
|
+ struct kmem_cache *s = container_of(work, struct kmem_cache,
|
|
|
+ memcg_params.deact_work);
|
|
|
+
|
|
|
+ get_online_cpus();
|
|
|
+ get_online_mems();
|
|
|
+
|
|
|
+ mutex_lock(&slab_mutex);
|
|
|
+
|
|
|
+ s->memcg_params.deact_fn(s);
|
|
|
+
|
|
|
+ mutex_unlock(&slab_mutex);
|
|
|
+
|
|
|
+ put_online_mems();
|
|
|
+ put_online_cpus();
|
|
|
+
|
|
|
+ /* done, put the ref from slab_deactivate_memcg_cache_rcu_sched() */
|
|
|
+ css_put(&s->memcg_params.memcg->css);
|
|
|
+}
|
|
|
+
|
|
|
+static void kmemcg_deactivate_rcufn(struct rcu_head *head)
|
|
|
+{
|
|
|
+ struct kmem_cache *s = container_of(head, struct kmem_cache,
|
|
|
+ memcg_params.deact_rcu_head);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * We need to grab blocking locks. Bounce to ->deact_work. The
|
|
|
+ * work item shares the space with the RCU head and can't be
|
|
|
+ * initialized eariler.
|
|
|
+ */
|
|
|
+ INIT_WORK(&s->memcg_params.deact_work, kmemcg_deactivate_workfn);
|
|
|
+ schedule_work(&s->memcg_params.deact_work);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * slab_deactivate_memcg_cache_rcu_sched - schedule deactivation after a
|
|
|
+ * sched RCU grace period
|
|
|
+ * @s: target kmem_cache
|
|
|
+ * @deact_fn: deactivation function to call
|
|
|
+ *
|
|
|
+ * Schedule @deact_fn to be invoked with online cpus, mems and slab_mutex
|
|
|
+ * held after a sched RCU grace period. The slab is guaranteed to stay
|
|
|
+ * alive until @deact_fn is finished. This is to be used from
|
|
|
+ * __kmemcg_cache_deactivate().
|
|
|
+ */
|
|
|
+void slab_deactivate_memcg_cache_rcu_sched(struct kmem_cache *s,
|
|
|
+ void (*deact_fn)(struct kmem_cache *))
|
|
|
+{
|
|
|
+ if (WARN_ON_ONCE(is_root_cache(s)) ||
|
|
|
+ WARN_ON_ONCE(s->memcg_params.deact_fn))
|
|
|
+ return;
|
|
|
+
|
|
|
+ /* pin memcg so that @s doesn't get destroyed in the middle */
|
|
|
+ css_get(&s->memcg_params.memcg->css);
|
|
|
+
|
|
|
+ s->memcg_params.deact_fn = deact_fn;
|
|
|
+ call_rcu_sched(&s->memcg_params.deact_rcu_head, kmemcg_deactivate_rcufn);
|
|
|
+}
|
|
|
+
|
|
|
void memcg_deactivate_kmem_caches(struct mem_cgroup *memcg)
|
|
|
{
|
|
|
int idx;
|