/* * Invoked by the selfballoon worker thread, uses current number of pages * in frontswap (frontswap_curr_pages()), previous status, and control * values (hysteresis and inertia) to determine if frontswap should be * shrunk and what the new frontswap size should be. Note that * frontswap_shrink is essentially a partial swapoff that immediately * transfers pages from the "swap device" (frontswap) back into kernel * RAM; despite the name, frontswap "shrinking" is very different from * the "shrinker" interface used by the kernel MM subsystem to reclaim * memory. */ static void frontswap_selfshrink(void) { static unsigned long cur_frontswap_pages; static unsigned long last_frontswap_pages; static unsigned long tgt_frontswap_pages; last_frontswap_pages = cur_frontswap_pages; cur_frontswap_pages = frontswap_curr_pages(); if (!cur_frontswap_pages || (cur_frontswap_pages > last_frontswap_pages)) { frontswap_inertia_counter = frontswap_inertia; return; } if (frontswap_inertia_counter && --frontswap_inertia_counter) return; if (cur_frontswap_pages <= frontswap_hysteresis) tgt_frontswap_pages = 0; else tgt_frontswap_pages = cur_frontswap_pages - (cur_frontswap_pages / frontswap_hysteresis); frontswap_shrink(tgt_frontswap_pages); }
/* * Use current balloon size, the goal (vm_committed_as), and hysteresis * parameters to set a new target balloon size */ static void selfballoon_process(struct work_struct *work) { int cur_pages, goal_pages, tgt_pages; bool reset_timer = false; if (kvm_selfballooning_enabled) { cur_pages = vbal->num_pages; tgt_pages = cur_pages; /* default is no change */ goal_pages = totalram_pages + cur_pages - percpu_counter_read_positive(&vm_committed_as); #ifdef CONFIG_FRONTSWAP /* allow space for frontswap pages to be repatriated */ if (frontswap_selfshrinking && frontswap_enabled) goal_pages += frontswap_curr_pages(); #endif if (cur_pages > goal_pages) tgt_pages = cur_pages - ((cur_pages - goal_pages) / selfballoon_downhysteresis); else if (cur_pages < goal_pages) tgt_pages = cur_pages + ((goal_pages - cur_pages) / selfballoon_uphysteresis); /* else if cur_pages == goal_pages, no change */ selfballoon_target(vbal, (unsigned int)(tgt_pages)); reset_timer = true; } #ifdef CONFIG_FRONTSWAP if (frontswap_selfshrinking && frontswap_enabled) { frontswap_selfshrink(); reset_timer = true; } #endif if (reset_timer) schedule_delayed_work(&selfballoon_worker, selfballoon_interval * HZ); }
static ssize_t curr_pages_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) { return sprintf(buf, "%lu\n", frontswap_curr_pages()); }