1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Collaborative memory management interface. 4 * 5 * Copyright IBM Corp 2003, 2010 6 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>, 7 * 8 */ 9 10 #include <linux/errno.h> 11 #include <linux/fs.h> 12 #include <linux/init.h> 13 #include <linux/module.h> 14 #include <linux/moduleparam.h> 15 #include <linux/gfp.h> 16 #include <linux/sched.h> 17 #include <linux/sysctl.h> 18 #include <linux/ctype.h> 19 #include <linux/swap.h> 20 #include <linux/kthread.h> 21 #include <linux/oom.h> 22 #include <linux/suspend.h> 23 #include <linux/uaccess.h> 24 25 #include <asm/pgalloc.h> 26 #include <asm/diag.h> 27 28 #ifdef CONFIG_CMM_IUCV 29 static char *cmm_default_sender = "VMRMSVM"; 30 #endif 31 static char *sender; 32 module_param(sender, charp, 0400); 33 MODULE_PARM_DESC(sender, 34 "Guest name that may send SMSG messages (default VMRMSVM)"); 35 36 #include "../../../drivers/s390/net/smsgiucv.h" 37 38 #define CMM_NR_PAGES ((PAGE_SIZE / sizeof(unsigned long)) - 2) 39 40 struct cmm_page_array { 41 struct cmm_page_array *next; 42 unsigned long index; 43 unsigned long pages[CMM_NR_PAGES]; 44 }; 45 46 static long cmm_pages; 47 static long cmm_timed_pages; 48 static volatile long cmm_pages_target; 49 static volatile long cmm_timed_pages_target; 50 static long cmm_timeout_pages; 51 static long cmm_timeout_seconds; 52 static int cmm_suspended; 53 54 static struct cmm_page_array *cmm_page_list; 55 static struct cmm_page_array *cmm_timed_page_list; 56 static DEFINE_SPINLOCK(cmm_lock); 57 58 static struct task_struct *cmm_thread_ptr; 59 static DECLARE_WAIT_QUEUE_HEAD(cmm_thread_wait); 60 static DEFINE_TIMER(cmm_timer, NULL); 61 62 static void cmm_timer_fn(unsigned long); 63 static void cmm_set_timer(void); 64 65 static long cmm_alloc_pages(long nr, long *counter, 66 struct cmm_page_array **list) 67 { 68 struct cmm_page_array *pa, *npa; 69 unsigned long addr; 70 71 while (nr) { 72 addr = __get_free_page(GFP_NOIO); 73 if (!addr) 74 break; 75 spin_lock(&cmm_lock); 76 pa = *list; 77 if (!pa || pa->index >= CMM_NR_PAGES) { 78 /* Need a new page for the page list. */ 79 spin_unlock(&cmm_lock); 80 npa = (struct cmm_page_array *) 81 __get_free_page(GFP_NOIO); 82 if (!npa) { 83 free_page(addr); 84 break; 85 } 86 spin_lock(&cmm_lock); 87 pa = *list; 88 if (!pa || pa->index >= CMM_NR_PAGES) { 89 npa->next = pa; 90 npa->index = 0; 91 pa = npa; 92 *list = pa; 93 } else 94 free_page((unsigned long) npa); 95 } 96 diag10_range(addr >> PAGE_SHIFT, 1); 97 pa->pages[pa->index++] = addr; 98 (*counter)++; 99 spin_unlock(&cmm_lock); 100 nr--; 101 } 102 return nr; 103 } 104 105 static long cmm_free_pages(long nr, long *counter, struct cmm_page_array **list) 106 { 107 struct cmm_page_array *pa; 108 unsigned long addr; 109 110 spin_lock(&cmm_lock); 111 pa = *list; 112 while (nr) { 113 if (!pa || pa->index <= 0) 114 break; 115 addr = pa->pages[--pa->index]; 116 if (pa->index == 0) { 117 pa = pa->next; 118 free_page((unsigned long) *list); 119 *list = pa; 120 } 121 free_page(addr); 122 (*counter)--; 123 nr--; 124 } 125 spin_unlock(&cmm_lock); 126 return nr; 127 } 128 129 static int cmm_oom_notify(struct notifier_block *self, 130 unsigned long dummy, void *parm) 131 { 132 unsigned long *freed = parm; 133 long nr = 256; 134 135 nr = cmm_free_pages(nr, &cmm_timed_pages, &cmm_timed_page_list); 136 if (nr > 0) 137 nr = cmm_free_pages(nr, &cmm_pages, &cmm_page_list); 138 cmm_pages_target = cmm_pages; 139 cmm_timed_pages_target = cmm_timed_pages; 140 *freed += 256 - nr; 141 return NOTIFY_OK; 142 } 143 144 static struct notifier_block cmm_oom_nb = { 145 .notifier_call = cmm_oom_notify, 146 }; 147 148 static int cmm_thread(void *dummy) 149 { 150 int rc; 151 152 while (1) { 153 rc = wait_event_interruptible(cmm_thread_wait, 154 (!cmm_suspended && (cmm_pages != cmm_pages_target || 155 cmm_timed_pages != cmm_timed_pages_target)) || 156 kthread_should_stop()); 157 if (kthread_should_stop() || rc == -ERESTARTSYS) { 158 cmm_pages_target = cmm_pages; 159 cmm_timed_pages_target = cmm_timed_pages; 160 break; 161 } 162 if (cmm_pages_target > cmm_pages) { 163 if (cmm_alloc_pages(1, &cmm_pages, &cmm_page_list)) 164 cmm_pages_target = cmm_pages; 165 } else if (cmm_pages_target < cmm_pages) { 166 cmm_free_pages(1, &cmm_pages, &cmm_page_list); 167 } 168 if (cmm_timed_pages_target > cmm_timed_pages) { 169 if (cmm_alloc_pages(1, &cmm_timed_pages, 170 &cmm_timed_page_list)) 171 cmm_timed_pages_target = cmm_timed_pages; 172 } else if (cmm_timed_pages_target < cmm_timed_pages) { 173 cmm_free_pages(1, &cmm_timed_pages, 174 &cmm_timed_page_list); 175 } 176 if (cmm_timed_pages > 0 && !timer_pending(&cmm_timer)) 177 cmm_set_timer(); 178 } 179 return 0; 180 } 181 182 static void cmm_kick_thread(void) 183 { 184 wake_up(&cmm_thread_wait); 185 } 186 187 static void cmm_set_timer(void) 188 { 189 if (cmm_timed_pages_target <= 0 || cmm_timeout_seconds <= 0) { 190 if (timer_pending(&cmm_timer)) 191 del_timer(&cmm_timer); 192 return; 193 } 194 if (timer_pending(&cmm_timer)) { 195 if (mod_timer(&cmm_timer, jiffies + cmm_timeout_seconds*HZ)) 196 return; 197 } 198 cmm_timer.function = cmm_timer_fn; 199 cmm_timer.data = 0; 200 cmm_timer.expires = jiffies + cmm_timeout_seconds*HZ; 201 add_timer(&cmm_timer); 202 } 203 204 static void cmm_timer_fn(unsigned long ignored) 205 { 206 long nr; 207 208 nr = cmm_timed_pages_target - cmm_timeout_pages; 209 if (nr < 0) 210 cmm_timed_pages_target = 0; 211 else 212 cmm_timed_pages_target = nr; 213 cmm_kick_thread(); 214 cmm_set_timer(); 215 } 216 217 static void cmm_set_pages(long nr) 218 { 219 cmm_pages_target = nr; 220 cmm_kick_thread(); 221 } 222 223 static long cmm_get_pages(void) 224 { 225 return cmm_pages; 226 } 227 228 static void cmm_add_timed_pages(long nr) 229 { 230 cmm_timed_pages_target += nr; 231 cmm_kick_thread(); 232 } 233 234 static long cmm_get_timed_pages(void) 235 { 236 return cmm_timed_pages; 237 } 238 239 static void cmm_set_timeout(long nr, long seconds) 240 { 241 cmm_timeout_pages = nr; 242 cmm_timeout_seconds = seconds; 243 cmm_set_timer(); 244 } 245 246 static int cmm_skip_blanks(char *cp, char **endp) 247 { 248 char *str; 249 250 for (str = cp; *str == ' ' || *str == '\t'; str++) 251 ; 252 *endp = str; 253 return str != cp; 254 } 255 256 static struct ctl_table cmm_table[]; 257 258 static int cmm_pages_handler(struct ctl_table *ctl, int write, 259 void __user *buffer, size_t *lenp, loff_t *ppos) 260 { 261 char buf[16], *p; 262 unsigned int len; 263 long nr; 264 265 if (!*lenp || (*ppos && !write)) { 266 *lenp = 0; 267 return 0; 268 } 269 270 if (write) { 271 len = *lenp; 272 if (copy_from_user(buf, buffer, 273 len > sizeof(buf) ? sizeof(buf) : len)) 274 return -EFAULT; 275 buf[sizeof(buf) - 1] = '\0'; 276 cmm_skip_blanks(buf, &p); 277 nr = simple_strtoul(p, &p, 0); 278 if (ctl == &cmm_table[0]) 279 cmm_set_pages(nr); 280 else 281 cmm_add_timed_pages(nr); 282 } else { 283 if (ctl == &cmm_table[0]) 284 nr = cmm_get_pages(); 285 else 286 nr = cmm_get_timed_pages(); 287 len = sprintf(buf, "%ld\n", nr); 288 if (len > *lenp) 289 len = *lenp; 290 if (copy_to_user(buffer, buf, len)) 291 return -EFAULT; 292 } 293 *lenp = len; 294 *ppos += len; 295 return 0; 296 } 297 298 static int cmm_timeout_handler(struct ctl_table *ctl, int write, 299 void __user *buffer, size_t *lenp, loff_t *ppos) 300 { 301 char buf[64], *p; 302 long nr, seconds; 303 unsigned int len; 304 305 if (!*lenp || (*ppos && !write)) { 306 *lenp = 0; 307 return 0; 308 } 309 310 if (write) { 311 len = *lenp; 312 if (copy_from_user(buf, buffer, 313 len > sizeof(buf) ? sizeof(buf) : len)) 314 return -EFAULT; 315 buf[sizeof(buf) - 1] = '\0'; 316 cmm_skip_blanks(buf, &p); 317 nr = simple_strtoul(p, &p, 0); 318 cmm_skip_blanks(p, &p); 319 seconds = simple_strtoul(p, &p, 0); 320 cmm_set_timeout(nr, seconds); 321 } else { 322 len = sprintf(buf, "%ld %ld\n", 323 cmm_timeout_pages, cmm_timeout_seconds); 324 if (len > *lenp) 325 len = *lenp; 326 if (copy_to_user(buffer, buf, len)) 327 return -EFAULT; 328 } 329 *lenp = len; 330 *ppos += len; 331 return 0; 332 } 333 334 static struct ctl_table cmm_table[] = { 335 { 336 .procname = "cmm_pages", 337 .mode = 0644, 338 .proc_handler = cmm_pages_handler, 339 }, 340 { 341 .procname = "cmm_timed_pages", 342 .mode = 0644, 343 .proc_handler = cmm_pages_handler, 344 }, 345 { 346 .procname = "cmm_timeout", 347 .mode = 0644, 348 .proc_handler = cmm_timeout_handler, 349 }, 350 { } 351 }; 352 353 static struct ctl_table cmm_dir_table[] = { 354 { 355 .procname = "vm", 356 .maxlen = 0, 357 .mode = 0555, 358 .child = cmm_table, 359 }, 360 { } 361 }; 362 363 #ifdef CONFIG_CMM_IUCV 364 #define SMSG_PREFIX "CMM" 365 static void cmm_smsg_target(const char *from, char *msg) 366 { 367 long nr, seconds; 368 369 if (strlen(sender) > 0 && strcmp(from, sender) != 0) 370 return; 371 if (!cmm_skip_blanks(msg + strlen(SMSG_PREFIX), &msg)) 372 return; 373 if (strncmp(msg, "SHRINK", 6) == 0) { 374 if (!cmm_skip_blanks(msg + 6, &msg)) 375 return; 376 nr = simple_strtoul(msg, &msg, 0); 377 cmm_skip_blanks(msg, &msg); 378 if (*msg == '\0') 379 cmm_set_pages(nr); 380 } else if (strncmp(msg, "RELEASE", 7) == 0) { 381 if (!cmm_skip_blanks(msg + 7, &msg)) 382 return; 383 nr = simple_strtoul(msg, &msg, 0); 384 cmm_skip_blanks(msg, &msg); 385 if (*msg == '\0') 386 cmm_add_timed_pages(nr); 387 } else if (strncmp(msg, "REUSE", 5) == 0) { 388 if (!cmm_skip_blanks(msg + 5, &msg)) 389 return; 390 nr = simple_strtoul(msg, &msg, 0); 391 if (!cmm_skip_blanks(msg, &msg)) 392 return; 393 seconds = simple_strtoul(msg, &msg, 0); 394 cmm_skip_blanks(msg, &msg); 395 if (*msg == '\0') 396 cmm_set_timeout(nr, seconds); 397 } 398 } 399 #endif 400 401 static struct ctl_table_header *cmm_sysctl_header; 402 403 static int cmm_suspend(void) 404 { 405 cmm_suspended = 1; 406 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); 407 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); 408 return 0; 409 } 410 411 static int cmm_resume(void) 412 { 413 cmm_suspended = 0; 414 cmm_kick_thread(); 415 return 0; 416 } 417 418 static int cmm_power_event(struct notifier_block *this, 419 unsigned long event, void *ptr) 420 { 421 switch (event) { 422 case PM_POST_HIBERNATION: 423 return cmm_resume(); 424 case PM_HIBERNATION_PREPARE: 425 return cmm_suspend(); 426 default: 427 return NOTIFY_DONE; 428 } 429 } 430 431 static struct notifier_block cmm_power_notifier = { 432 .notifier_call = cmm_power_event, 433 }; 434 435 static int __init cmm_init(void) 436 { 437 int rc = -ENOMEM; 438 439 cmm_sysctl_header = register_sysctl_table(cmm_dir_table); 440 if (!cmm_sysctl_header) 441 goto out_sysctl; 442 #ifdef CONFIG_CMM_IUCV 443 /* convert sender to uppercase characters */ 444 if (sender) { 445 int len = strlen(sender); 446 while (len--) 447 sender[len] = toupper(sender[len]); 448 } else { 449 sender = cmm_default_sender; 450 } 451 452 rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); 453 if (rc < 0) 454 goto out_smsg; 455 #endif 456 rc = register_oom_notifier(&cmm_oom_nb); 457 if (rc < 0) 458 goto out_oom_notify; 459 rc = register_pm_notifier(&cmm_power_notifier); 460 if (rc) 461 goto out_pm; 462 cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); 463 if (!IS_ERR(cmm_thread_ptr)) 464 return 0; 465 466 rc = PTR_ERR(cmm_thread_ptr); 467 unregister_pm_notifier(&cmm_power_notifier); 468 out_pm: 469 unregister_oom_notifier(&cmm_oom_nb); 470 out_oom_notify: 471 #ifdef CONFIG_CMM_IUCV 472 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); 473 out_smsg: 474 #endif 475 unregister_sysctl_table(cmm_sysctl_header); 476 out_sysctl: 477 del_timer_sync(&cmm_timer); 478 return rc; 479 } 480 module_init(cmm_init); 481 482 static void __exit cmm_exit(void) 483 { 484 unregister_sysctl_table(cmm_sysctl_header); 485 #ifdef CONFIG_CMM_IUCV 486 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); 487 #endif 488 unregister_pm_notifier(&cmm_power_notifier); 489 unregister_oom_notifier(&cmm_oom_nb); 490 kthread_stop(cmm_thread_ptr); 491 del_timer_sync(&cmm_timer); 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); 494 } 495 module_exit(cmm_exit); 496 497 MODULE_LICENSE("GPL"); 498