9 #include <linux/errno.h>
12 #include <linux/module.h>
14 #include <linux/sched.h>
15 #include <linux/sysctl.h>
16 #include <linux/ctype.h>
19 #include <linux/oom.h>
23 #include <asm/pgalloc.h>
26 #ifdef CONFIG_CMM_IUCV
27 static char *cmm_default_sender =
"VMRMSVM";
32 "Guest name that may send SMSG messages (default VMRMSVM)");
34 #include "../../../drivers/s390/net/smsgiucv.h"
36 #define CMM_NR_PAGES ((PAGE_SIZE / sizeof(unsigned long)) - 2)
44 static long cmm_pages;
45 static long cmm_timed_pages;
46 static volatile long cmm_pages_target;
47 static volatile long cmm_timed_pages_target;
48 static long cmm_timeout_pages;
49 static long cmm_timeout_seconds;
50 static int cmm_suspended;
60 static void cmm_timer_fn(
unsigned long);
61 static void cmm_set_timer(
void);
63 static long cmm_alloc_pages(
long nr,
long *
counter,
77 spin_unlock(&cmm_lock);
97 spin_unlock(&cmm_lock);
103 static long cmm_free_pages(
long nr,
long *counter,
struct cmm_page_array **list)
108 spin_lock(&cmm_lock);
111 if (!pa || pa->
index <= 0)
114 if (pa->
index == 0) {
123 spin_unlock(&cmm_lock);
130 unsigned long *freed =
parm;
133 nr = cmm_free_pages(nr, &cmm_timed_pages, &cmm_timed_page_list);
135 nr = cmm_free_pages(nr, &cmm_pages, &cmm_page_list);
136 cmm_pages_target = cmm_pages;
137 cmm_timed_pages_target = cmm_timed_pages;
143 .notifier_call = cmm_oom_notify,
146 static int cmm_thread(
void *dummy)
152 (!cmm_suspended && (cmm_pages != cmm_pages_target ||
153 cmm_timed_pages != cmm_timed_pages_target)) ||
156 cmm_pages_target = cmm_pages;
157 cmm_timed_pages_target = cmm_timed_pages;
160 if (cmm_pages_target > cmm_pages) {
161 if (cmm_alloc_pages(1, &cmm_pages, &cmm_page_list))
162 cmm_pages_target = cmm_pages;
163 }
else if (cmm_pages_target < cmm_pages) {
164 cmm_free_pages(1, &cmm_pages, &cmm_page_list);
166 if (cmm_timed_pages_target > cmm_timed_pages) {
167 if (cmm_alloc_pages(1, &cmm_timed_pages,
168 &cmm_timed_page_list))
169 cmm_timed_pages_target = cmm_timed_pages;
170 }
else if (cmm_timed_pages_target < cmm_timed_pages) {
171 cmm_free_pages(1, &cmm_timed_pages,
172 &cmm_timed_page_list);
174 if (cmm_timed_pages > 0 && !timer_pending(&cmm_timer))
180 static void cmm_kick_thread(
void)
185 static void cmm_set_timer(
void)
187 if (cmm_timed_pages_target <= 0 || cmm_timeout_seconds <= 0) {
188 if (timer_pending(&cmm_timer))
192 if (timer_pending(&cmm_timer)) {
193 if (
mod_timer(&cmm_timer, jiffies + cmm_timeout_seconds*
HZ))
196 cmm_timer.function = cmm_timer_fn;
198 cmm_timer.expires =
jiffies + cmm_timeout_seconds*
HZ;
202 static void cmm_timer_fn(
unsigned long ignored)
206 nr = cmm_timed_pages_target - cmm_timeout_pages;
208 cmm_timed_pages_target = 0;
210 cmm_timed_pages_target =
nr;
215 static void cmm_set_pages(
long nr)
217 cmm_pages_target =
nr;
221 static long cmm_get_pages(
void)
226 static void cmm_add_timed_pages(
long nr)
228 cmm_timed_pages_target +=
nr;
232 static long cmm_get_timed_pages(
void)
234 return cmm_timed_pages;
237 static void cmm_set_timeout(
long nr,
long seconds)
239 cmm_timeout_pages =
nr;
244 static int cmm_skip_blanks(
char *
cp,
char **endp)
248 for (str = cp; *str ==
' ' || *str ==
'\t'; str++)
257 size_t *lenp, loff_t *ppos)
263 if (!*lenp || (*ppos && !write)) {
271 len >
sizeof(buf) ?
sizeof(buf) : len))
273 buf[
sizeof(
buf) - 1] =
'\0';
274 cmm_skip_blanks(buf, &p);
276 if (ctl == &cmm_table[0])
279 cmm_add_timed_pages(nr);
281 if (ctl == &cmm_table[0])
282 nr = cmm_get_pages();
284 nr = cmm_get_timed_pages();
285 len =
sprintf(buf,
"%ld\n", nr);
296 static int cmm_timeout_handler(
ctl_table *ctl,
int write,
void __user *buffer,
297 size_t *lenp, loff_t *ppos)
303 if (!*lenp || (*ppos && !write)) {
311 len >
sizeof(buf) ?
sizeof(buf) : len))
313 buf[
sizeof(
buf) - 1] =
'\0';
314 cmm_skip_blanks(buf, &p);
316 cmm_skip_blanks(p, &p);
318 cmm_set_timeout(nr, seconds);
320 len =
sprintf(buf,
"%ld %ld\n",
321 cmm_timeout_pages, cmm_timeout_seconds);
334 .procname =
"cmm_pages",
336 .proc_handler = cmm_pages_handler,
339 .procname =
"cmm_timed_pages",
341 .proc_handler = cmm_pages_handler,
344 .procname =
"cmm_timeout",
346 .proc_handler = cmm_timeout_handler,
351 static struct ctl_table cmm_dir_table[] = {
361 #ifdef CONFIG_CMM_IUCV
362 #define SMSG_PREFIX "CMM"
363 static void cmm_smsg_target(
const char *
from,
char *
msg)
371 if (
strncmp(msg,
"SHRINK", 6) == 0) {
372 if (!cmm_skip_blanks(msg + 6, &msg))
375 cmm_skip_blanks(msg, &msg);
378 }
else if (
strncmp(msg,
"RELEASE", 7) == 0) {
379 if (!cmm_skip_blanks(msg + 7, &msg))
382 cmm_skip_blanks(msg, &msg);
384 cmm_add_timed_pages(nr);
385 }
else if (
strncmp(msg,
"REUSE", 5) == 0) {
386 if (!cmm_skip_blanks(msg + 5, &msg))
389 if (!cmm_skip_blanks(msg, &msg))
392 cmm_skip_blanks(msg, &msg);
394 cmm_set_timeout(nr, seconds);
401 static int cmm_suspend(
void)
404 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
405 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
409 static int cmm_resume(
void)
423 return cmm_suspend();
430 .notifier_call = cmm_power_event,
433 static int __init cmm_init(
void)
438 if (!cmm_sysctl_header)
440 #ifdef CONFIG_CMM_IUCV
445 sender[len] =
toupper(sender[len]);
447 sender = cmm_default_sender;
457 rc = register_pm_notifier(&cmm_power_notifier);
461 rc = IS_ERR(cmm_thread_ptr) ? PTR_ERR(cmm_thread_ptr) : 0;
467 unregister_pm_notifier(&cmm_power_notifier);
471 #ifdef CONFIG_CMM_IUCV
482 static void __exit cmm_exit(
void)
485 #ifdef CONFIG_CMM_IUCV
488 unregister_pm_notifier(&cmm_power_notifier);
492 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
493 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);