|
@@ -21,11 +21,31 @@
|
|
#include <linux/mm.h>
|
|
#include <linux/mm.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/sched.h>
|
|
#include <linux/swap.h>
|
|
#include <linux/swap.h>
|
|
|
|
+#include <linux/memcontrol.h>
|
|
|
|
|
|
static DEFINE_SPINLOCK(swap_token_lock);
|
|
static DEFINE_SPINLOCK(swap_token_lock);
|
|
struct mm_struct *swap_token_mm;
|
|
struct mm_struct *swap_token_mm;
|
|
|
|
+struct mem_cgroup *swap_token_memcg;
|
|
static unsigned int global_faults;
|
|
static unsigned int global_faults;
|
|
|
|
|
|
|
|
+#ifdef CONFIG_CGROUP_MEM_RES_CTLR
|
|
|
|
+static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm)
|
|
|
|
+{
|
|
|
|
+ struct mem_cgroup *memcg;
|
|
|
|
+
|
|
|
|
+ memcg = try_get_mem_cgroup_from_mm(mm);
|
|
|
|
+ if (memcg)
|
|
|
|
+ css_put(mem_cgroup_css(memcg));
|
|
|
|
+
|
|
|
|
+ return memcg;
|
|
|
|
+}
|
|
|
|
+#else
|
|
|
|
+static struct mem_cgroup *swap_token_memcg_from_mm(struct mm_struct *mm)
|
|
|
|
+{
|
|
|
|
+ return NULL;
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
void grab_swap_token(struct mm_struct *mm)
|
|
void grab_swap_token(struct mm_struct *mm)
|
|
{
|
|
{
|
|
int current_interval;
|
|
int current_interval;
|
|
@@ -38,40 +58,69 @@ void grab_swap_token(struct mm_struct *mm)
|
|
return;
|
|
return;
|
|
|
|
|
|
/* First come first served */
|
|
/* First come first served */
|
|
- if (swap_token_mm == NULL) {
|
|
|
|
- mm->token_priority = mm->token_priority + 2;
|
|
|
|
- swap_token_mm = mm;
|
|
|
|
|
|
+ if (!swap_token_mm)
|
|
|
|
+ goto replace_token;
|
|
|
|
+
|
|
|
|
+ if (mm == swap_token_mm) {
|
|
|
|
+ mm->token_priority += 2;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
- if (mm != swap_token_mm) {
|
|
|
|
- if (current_interval < mm->last_interval)
|
|
|
|
- mm->token_priority++;
|
|
|
|
- else {
|
|
|
|
- if (likely(mm->token_priority > 0))
|
|
|
|
- mm->token_priority--;
|
|
|
|
- }
|
|
|
|
- /* Check if we deserve the token */
|
|
|
|
- if (mm->token_priority > swap_token_mm->token_priority) {
|
|
|
|
- mm->token_priority += 2;
|
|
|
|
- swap_token_mm = mm;
|
|
|
|
- }
|
|
|
|
- } else {
|
|
|
|
- /* Token holder came in again! */
|
|
|
|
- mm->token_priority += 2;
|
|
|
|
|
|
+ if (current_interval < mm->last_interval)
|
|
|
|
+ mm->token_priority++;
|
|
|
|
+ else {
|
|
|
|
+ if (likely(mm->token_priority > 0))
|
|
|
|
+ mm->token_priority--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ /* Check if we deserve the token */
|
|
|
|
+ if (mm->token_priority > swap_token_mm->token_priority)
|
|
|
|
+ goto replace_token;
|
|
|
|
+
|
|
out:
|
|
out:
|
|
mm->faultstamp = global_faults;
|
|
mm->faultstamp = global_faults;
|
|
mm->last_interval = current_interval;
|
|
mm->last_interval = current_interval;
|
|
spin_unlock(&swap_token_lock);
|
|
spin_unlock(&swap_token_lock);
|
|
|
|
+ return;
|
|
|
|
+
|
|
|
|
+replace_token:
|
|
|
|
+ mm->token_priority += 2;
|
|
|
|
+ swap_token_mm = mm;
|
|
|
|
+ swap_token_memcg = swap_token_memcg_from_mm(mm);
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
/* Called on process exit. */
|
|
/* Called on process exit. */
|
|
void __put_swap_token(struct mm_struct *mm)
|
|
void __put_swap_token(struct mm_struct *mm)
|
|
{
|
|
{
|
|
spin_lock(&swap_token_lock);
|
|
spin_lock(&swap_token_lock);
|
|
- if (likely(mm == swap_token_mm))
|
|
|
|
|
|
+ if (likely(mm == swap_token_mm)) {
|
|
swap_token_mm = NULL;
|
|
swap_token_mm = NULL;
|
|
|
|
+ swap_token_memcg = NULL;
|
|
|
|
+ }
|
|
spin_unlock(&swap_token_lock);
|
|
spin_unlock(&swap_token_lock);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+static bool match_memcg(struct mem_cgroup *a, struct mem_cgroup *b)
|
|
|
|
+{
|
|
|
|
+ if (!a)
|
|
|
|
+ return true;
|
|
|
|
+ if (!b)
|
|
|
|
+ return true;
|
|
|
|
+ if (a == b)
|
|
|
|
+ return true;
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void disable_swap_token(struct mem_cgroup *memcg)
|
|
|
|
+{
|
|
|
|
+ /* memcg reclaim don't disable unrelated mm token. */
|
|
|
|
+ if (match_memcg(memcg, swap_token_memcg)) {
|
|
|
|
+ spin_lock(&swap_token_lock);
|
|
|
|
+ if (match_memcg(memcg, swap_token_memcg)) {
|
|
|
|
+ swap_token_mm = NULL;
|
|
|
|
+ swap_token_memcg = NULL;
|
|
|
|
+ }
|
|
|
|
+ spin_unlock(&swap_token_lock);
|
|
|
|
+ }
|
|
|
|
+}
|