aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
context:
space:
mode:
authorAndrew Shewmaker <agshew@gmail.com>2013-04-29 18:08:12 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-04-29 18:54:37 -0400
commit1640879afe0065caf276e98fff059c4dc01c97ae (patch)
tree2ba94e09a5cd2c49dbeed2d30bc5bdbbddc04ec8 /mm
parent4eeab4f5580d11bffedc697684b91b0bca0d5009 (diff)
mm: reinititalise user and admin reserves if memory is added or removed
Alter the admin and user reserves of the previous patches in this series when memory is added or removed. If memory is added and the reserves have been eliminated or increased above the default max, then we'll trust the admin. If memory is removed and there isn't enough free memory, then we need to reset the reserves. Otherwise keep the reserve set by the admin. The reserve reset code is the same as the reserve initialization code. I tested hot addition and removal by triggering it via sysfs. The reserves shrunk when they were set high and memory was removed. They were reset higher when memory was added again. [akpm@linux-foundation.org: use register_hotmemory_notifier()] [akpm@linux-foundation.org: init_user_reserve() and init_admin_reserve can no longer be __meminit] [fengguang.wu@intel.com: make init_reserve_notifier() static] [akpm@linux-foundation.org: coding-style fixes] Signed-off-by: Andrew Shewmaker <agshew@gmail.com> Signed-off-by: Fengguang Wu <fengguang.wu@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/mmap.c76
1 files changed, 74 insertions, 2 deletions
diff --git a/mm/mmap.c b/mm/mmap.c
index 5485f18e6631..43c4955535aa 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -33,6 +33,8 @@
33#include <linux/uprobes.h> 33#include <linux/uprobes.h>
34#include <linux/rbtree_augmented.h> 34#include <linux/rbtree_augmented.h>
35#include <linux/sched/sysctl.h> 35#include <linux/sched/sysctl.h>
36#include <linux/notifier.h>
37#include <linux/memory.h>
36 38
37#include <asm/uaccess.h> 39#include <asm/uaccess.h>
38#include <asm/cacheflush.h> 40#include <asm/cacheflush.h>
@@ -3110,7 +3112,7 @@ void __init mmap_init(void)
3110 * The default value is min(3% of free memory, 128MB) 3112 * The default value is min(3% of free memory, 128MB)
3111 * 128MB is enough to recover with sshd/login, bash, and top/kill. 3113 * 128MB is enough to recover with sshd/login, bash, and top/kill.
3112 */ 3114 */
3113static int __meminit init_user_reserve(void) 3115static int init_user_reserve(void)
3114{ 3116{
3115 unsigned long free_kbytes; 3117 unsigned long free_kbytes;
3116 3118
@@ -3131,7 +3133,7 @@ module_init(init_user_reserve)
3131 * with sshd, bash, and top in OVERCOMMIT_GUESS. Smaller systems will 3133 * with sshd, bash, and top in OVERCOMMIT_GUESS. Smaller systems will
3132 * only reserve 3% of free pages by default. 3134 * only reserve 3% of free pages by default.
3133 */ 3135 */
3134static int __meminit init_admin_reserve(void) 3136static int init_admin_reserve(void)
3135{ 3137{
3136 unsigned long free_kbytes; 3138 unsigned long free_kbytes;
3137 3139
@@ -3141,3 +3143,73 @@ static int __meminit init_admin_reserve(void)
3141 return 0; 3143 return 0;
3142} 3144}
3143module_init(init_admin_reserve) 3145module_init(init_admin_reserve)
3146
3147/*
3148 * Reinititalise user and admin reserves if memory is added or removed.
3149 *
3150 * The default user reserve max is 128MB, and the default max for the
3151 * admin reserve is 8MB. These are usually, but not always, enough to
3152 * enable recovery from a memory hogging process using login/sshd, a shell,
3153 * and tools like top. It may make sense to increase or even disable the
3154 * reserve depending on the existence of swap or variations in the recovery
3155 * tools. So, the admin may have changed them.
3156 *
3157 * If memory is added and the reserves have been eliminated or increased above
3158 * the default max, then we'll trust the admin.
3159 *
3160 * If memory is removed and there isn't enough free memory, then we
3161 * need to reset the reserves.
3162 *
3163 * Otherwise keep the reserve set by the admin.
3164 */
3165static int reserve_mem_notifier(struct notifier_block *nb,
3166 unsigned long action, void *data)
3167{
3168 unsigned long tmp, free_kbytes;
3169
3170 switch (action) {
3171 case MEM_ONLINE:
3172 /* Default max is 128MB. Leave alone if modified by operator. */
3173 tmp = sysctl_user_reserve_kbytes;
3174 if (0 < tmp && tmp < (1UL << 17))
3175 init_user_reserve();
3176
3177 /* Default max is 8MB. Leave alone if modified by operator. */
3178 tmp = sysctl_admin_reserve_kbytes;
3179 if (0 < tmp && tmp < (1UL << 13))
3180 init_admin_reserve();
3181
3182 break;
3183 case MEM_OFFLINE:
3184 free_kbytes = global_page_state(NR_FREE_PAGES) << (PAGE_SHIFT - 10);
3185
3186 if (sysctl_user_reserve_kbytes > free_kbytes) {
3187 init_user_reserve();
3188 pr_info("vm.user_reserve_kbytes reset to %lu\n",
3189 sysctl_user_reserve_kbytes);
3190 }
3191
3192 if (sysctl_admin_reserve_kbytes > free_kbytes) {
3193 init_admin_reserve();
3194 pr_info("vm.admin_reserve_kbytes reset to %lu\n",
3195 sysctl_admin_reserve_kbytes);
3196 }
3197 break;
3198 default:
3199 break;
3200 }
3201 return NOTIFY_OK;
3202}
3203
3204static struct notifier_block reserve_mem_nb = {
3205 .notifier_call = reserve_mem_notifier,
3206};
3207
3208static int __meminit init_reserve_notifier(void)
3209{
3210 if (register_hotmemory_notifier(&reserve_mem_nb))
3211 printk("Failed registering memory add/remove notifier for admin reserve");
3212
3213 return 0;
3214}
3215module_init(init_reserve_notifier)