diff options
Diffstat (limited to 'mm/ksm.c')
-rw-r--r-- | mm/ksm.c | 89 |
1 files changed, 85 insertions, 4 deletions
@@ -37,6 +37,7 @@ #include <linux/freezer.h> #include <linux/oom.h> #include <linux/numa.h> +#include <linux/show_mem_notifier.h> #include <asm/tlbflush.h> #include "internal.h" @@ -223,6 +224,9 @@ static unsigned int ksm_thread_pages_to_scan = 100; /* Milliseconds ksmd should sleep between batches */ static unsigned int ksm_thread_sleep_millisecs = 20; +/* Boolean to indicate whether to use deferred timer or not */ +static bool use_deferred_timer; + #ifdef CONFIG_NUMA /* Zeroed when merging across nodes is not allowed */ static unsigned int ksm_merge_across_nodes = 1; @@ -236,7 +240,7 @@ static int ksm_nr_node_ids = 1; #define KSM_RUN_MERGE 1 #define KSM_RUN_UNMERGE 2 #define KSM_RUN_OFFLINE 4 -static unsigned long ksm_run = KSM_RUN_STOP; +static unsigned long ksm_run = KSM_RUN_MERGE; static void wait_while_offlining(void); static DECLARE_WAIT_QUEUE_HEAD(ksm_thread_wait); @@ -247,6 +251,20 @@ static DEFINE_SPINLOCK(ksm_mmlist_lock); sizeof(struct __struct), __alignof__(struct __struct),\ (__flags), NULL) +static int ksm_show_mem_notifier(struct notifier_block *nb, + unsigned long action, + void *data) +{ + pr_info("ksm_pages_sharing: %lu\n", ksm_pages_sharing); + pr_info("ksm_pages_shared: %lu\n", ksm_pages_shared); + + return 0; +} + +static struct notifier_block ksm_show_mem_notifier_block = { + .notifier_call = ksm_show_mem_notifier, +}; + static int __init ksm_slab_init(void) { rmap_item_cache = KSM_KMEM_CACHE(rmap_item, 0); @@ -541,8 +559,8 @@ static struct page *get_ksm_page(struct stable_node *stable_node, bool lock_it) void *expected_mapping; unsigned long kpfn; - expected_mapping = (void *)stable_node + - (PAGE_MAPPING_ANON | PAGE_MAPPING_KSM); + expected_mapping = (void *)((unsigned long)stable_node | + PAGE_MAPPING_KSM); again: kpfn = READ_ONCE(stable_node->kpfn); page = pfn_to_page(kpfn); @@ -1725,6 +1743,41 @@ static void ksm_do_scan(unsigned int scan_npages) } } +static void process_timeout(unsigned long __data) +{ + wake_up_process((struct task_struct *)__data); +} + +static signed long __sched deferred_schedule_timeout(signed long timeout) +{ + struct timer_list timer; + unsigned long expire; + + __set_current_state(TASK_INTERRUPTIBLE); + if (timeout < 0) { + pr_err("schedule_timeout: wrong timeout value %lx\n", + timeout); + __set_current_state(TASK_RUNNING); + goto out; + } + + expire = timeout + jiffies; + + setup_deferrable_timer_on_stack(&timer, process_timeout, + (unsigned long)current); + mod_timer(&timer, expire); + schedule(); + del_singleshot_timer_sync(&timer); + + /* Remove the timer from the object tracker */ + destroy_timer_on_stack(&timer); + + timeout = expire - jiffies; + +out: + return timeout < 0 ? 0 : timeout; +} + static int ksmd_should_run(void) { return (ksm_run & KSM_RUN_MERGE) && !list_empty(&ksm_mm_head.mm_list); @@ -1745,7 +1798,11 @@ static int ksm_scan_thread(void *nothing) try_to_freeze(); if (ksmd_should_run()) { - schedule_timeout_interruptible( + if (use_deferred_timer) + deferred_schedule_timeout( + msecs_to_jiffies(ksm_thread_sleep_millisecs)); + else + schedule_timeout_interruptible( msecs_to_jiffies(ksm_thread_sleep_millisecs)); } else { wait_event_freezable(ksm_thread_wait, @@ -1928,6 +1985,7 @@ int rmap_walk_ksm(struct page *page, struct rmap_walk_control *rwc) stable_node = page_stable_node(page); if (!stable_node) return ret; + again: hlist_for_each_entry(rmap_item, &stable_node->hlist, hlist) { struct anon_vma *anon_vma = rmap_item->anon_vma; @@ -2197,6 +2255,26 @@ static ssize_t run_store(struct kobject *kobj, struct kobj_attribute *attr, } KSM_ATTR(run); +static ssize_t deferred_timer_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return snprintf(buf, 8, "%d\n", use_deferred_timer); +} + +static ssize_t deferred_timer_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + unsigned long enable; + int err; + + err = kstrtoul(buf, 10, &enable); + use_deferred_timer = enable; + + return count; +} +KSM_ATTR(deferred_timer); + #ifdef CONFIG_NUMA static ssize_t merge_across_nodes_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -2309,6 +2387,7 @@ static struct attribute *ksm_attrs[] = { &pages_unshared_attr.attr, &pages_volatile_attr.attr, &full_scans_attr.attr, + &deferred_timer_attr.attr, #ifdef CONFIG_NUMA &merge_across_nodes_attr.attr, #endif @@ -2353,6 +2432,8 @@ static int __init ksm_init(void) /* There is no significance to this priority 100 */ hotplug_memory_notifier(ksm_memory_callback, 100); #endif + + show_mem_notifier_register(&ksm_show_mem_notifier_block); return 0; out_free: |