diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/mmap.c | 76 |
1 files changed, 74 insertions, 2 deletions
@@ -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 | */ |
3113 | static int __meminit init_user_reserve(void) | 3115 | static 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 | */ |
3134 | static int __meminit init_admin_reserve(void) | 3136 | static 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 | } |
3143 | module_init(init_admin_reserve) | 3145 | module_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 | */ | ||
3165 | static 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 | |||
3204 | static struct notifier_block reserve_mem_nb = { | ||
3205 | .notifier_call = reserve_mem_notifier, | ||
3206 | }; | ||
3207 | |||
3208 | static 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 | } | ||
3215 | module_init(init_reserve_notifier) | ||