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 61 static void cmm_timer_fn(struct timer_list *); 62 static void cmm_set_timer(void); 63 static DEFINE_TIMER(cmm_timer, cmm_timer_fn); 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 mod_timer(&cmm_timer, jiffies + cmm_timeout_seconds * HZ); 195 } 196 197 static void cmm_timer_fn(struct timer_list *unused) 198 { 199 long nr; 200 201 nr = cmm_timed_pages_target - cmm_timeout_pages; 202 if (nr < 0) 203 cmm_timed_pages_target = 0; 204 else 205 cmm_timed_pages_target = nr; 206 cmm_kick_thread(); 207 cmm_set_timer(); 208 } 209 210 static void cmm_set_pages(long nr) 211 { 212 cmm_pages_target = nr; 213 cmm_kick_thread(); 214 } 215 216 static long cmm_get_pages(void) 217 { 218 return cmm_pages; 219 } 220 221 static void cmm_add_timed_pages(long nr) 222 { 223 cmm_timed_pages_target += nr; 224 cmm_kick_thread(); 225 } 226 227 static long cmm_get_timed_pages(void) 228 { 229 return cmm_timed_pages; 230 } 231 232 static void cmm_set_timeout(long nr, long seconds) 233 { 234 cmm_timeout_pages = nr; 235 cmm_timeout_seconds = seconds; 236 cmm_set_timer(); 237 } 238 239 static int cmm_skip_blanks(char *cp, char **endp) 240 { 241 char *str; 242 243 for (str = cp; *str == ' ' || *str == '\t'; str++) 244 ; 245 *endp = str; 246 return str != cp; 247 } 248 249 static int cmm_pages_handler(struct ctl_table *ctl, int write, 250 void __user *buffer, size_t *lenp, loff_t *ppos) 251 { 252 long nr = cmm_get_pages(); 253 struct ctl_table ctl_entry = { 254 .procname = ctl->procname, 255 .data = &nr, 256 .maxlen = sizeof(long), 257 }; 258 int rc; 259 260 rc = proc_doulongvec_minmax(&ctl_entry, write, buffer, lenp, ppos); 261 if (rc < 0 || !write) 262 return rc; 263 264 cmm_set_pages(nr); 265 return 0; 266 } 267 268 static int cmm_timed_pages_handler(struct ctl_table *ctl, int write, 269 void __user *buffer, size_t *lenp, 270 loff_t *ppos) 271 { 272 long nr = cmm_get_timed_pages(); 273 struct ctl_table ctl_entry = { 274 .procname = ctl->procname, 275 .data = &nr, 276 .maxlen = sizeof(long), 277 }; 278 int rc; 279 280 rc = proc_doulongvec_minmax(&ctl_entry, write, buffer, lenp, ppos); 281 if (rc < 0 || !write) 282 return rc; 283 284 cmm_add_timed_pages(nr); 285 return 0; 286 } 287 288 static int cmm_timeout_handler(struct ctl_table *ctl, int write, 289 void __user *buffer, size_t *lenp, loff_t *ppos) 290 { 291 char buf[64], *p; 292 long nr, seconds; 293 unsigned int len; 294 295 if (!*lenp || (*ppos && !write)) { 296 *lenp = 0; 297 return 0; 298 } 299 300 if (write) { 301 len = min(*lenp, sizeof(buf)); 302 if (copy_from_user(buf, buffer, len)) 303 return -EFAULT; 304 buf[len - 1] = '\0'; 305 cmm_skip_blanks(buf, &p); 306 nr = simple_strtoul(p, &p, 0); 307 cmm_skip_blanks(p, &p); 308 seconds = simple_strtoul(p, &p, 0); 309 cmm_set_timeout(nr, seconds); 310 *ppos += *lenp; 311 } else { 312 len = sprintf(buf, "%ld %ld\n", 313 cmm_timeout_pages, cmm_timeout_seconds); 314 if (len > *lenp) 315 len = *lenp; 316 if (copy_to_user(buffer, buf, len)) 317 return -EFAULT; 318 *lenp = len; 319 *ppos += len; 320 } 321 return 0; 322 } 323 324 static struct ctl_table cmm_table[] = { 325 { 326 .procname = "cmm_pages", 327 .mode = 0644, 328 .proc_handler = cmm_pages_handler, 329 }, 330 { 331 .procname = "cmm_timed_pages", 332 .mode = 0644, 333 .proc_handler = cmm_timed_pages_handler, 334 }, 335 { 336 .procname = "cmm_timeout", 337 .mode = 0644, 338 .proc_handler = cmm_timeout_handler, 339 }, 340 { } 341 }; 342 343 static struct ctl_table cmm_dir_table[] = { 344 { 345 .procname = "vm", 346 .maxlen = 0, 347 .mode = 0555, 348 .child = cmm_table, 349 }, 350 { } 351 }; 352 353 #ifdef CONFIG_CMM_IUCV 354 #define SMSG_PREFIX "CMM" 355 static void cmm_smsg_target(const char *from, char *msg) 356 { 357 long nr, seconds; 358 359 if (strlen(sender) > 0 && strcmp(from, sender) != 0) 360 return; 361 if (!cmm_skip_blanks(msg + strlen(SMSG_PREFIX), &msg)) 362 return; 363 if (strncmp(msg, "SHRINK", 6) == 0) { 364 if (!cmm_skip_blanks(msg + 6, &msg)) 365 return; 366 nr = simple_strtoul(msg, &msg, 0); 367 cmm_skip_blanks(msg, &msg); 368 if (*msg == '\0') 369 cmm_set_pages(nr); 370 } else if (strncmp(msg, "RELEASE", 7) == 0) { 371 if (!cmm_skip_blanks(msg + 7, &msg)) 372 return; 373 nr = simple_strtoul(msg, &msg, 0); 374 cmm_skip_blanks(msg, &msg); 375 if (*msg == '\0') 376 cmm_add_timed_pages(nr); 377 } else if (strncmp(msg, "REUSE", 5) == 0) { 378 if (!cmm_skip_blanks(msg + 5, &msg)) 379 return; 380 nr = simple_strtoul(msg, &msg, 0); 381 if (!cmm_skip_blanks(msg, &msg)) 382 return; 383 seconds = simple_strtoul(msg, &msg, 0); 384 cmm_skip_blanks(msg, &msg); 385 if (*msg == '\0') 386 cmm_set_timeout(nr, seconds); 387 } 388 } 389 #endif 390 391 static struct ctl_table_header *cmm_sysctl_header; 392 393 static int cmm_suspend(void) 394 { 395 cmm_suspended = 1; 396 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); 397 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); 398 return 0; 399 } 400 401 static int cmm_resume(void) 402 { 403 cmm_suspended = 0; 404 cmm_kick_thread(); 405 return 0; 406 } 407 408 static int cmm_power_event(struct notifier_block *this, 409 unsigned long event, void *ptr) 410 { 411 switch (event) { 412 case PM_POST_HIBERNATION: 413 return cmm_resume(); 414 case PM_HIBERNATION_PREPARE: 415 return cmm_suspend(); 416 default: 417 return NOTIFY_DONE; 418 } 419 } 420 421 static struct notifier_block cmm_power_notifier = { 422 .notifier_call = cmm_power_event, 423 }; 424 425 static int __init cmm_init(void) 426 { 427 int rc = -ENOMEM; 428 429 cmm_sysctl_header = register_sysctl_table(cmm_dir_table); 430 if (!cmm_sysctl_header) 431 goto out_sysctl; 432 #ifdef CONFIG_CMM_IUCV 433 /* convert sender to uppercase characters */ 434 if (sender) { 435 int len = strlen(sender); 436 while (len--) 437 sender[len] = toupper(sender[len]); 438 } else { 439 sender = cmm_default_sender; 440 } 441 442 rc = smsg_register_callback(SMSG_PREFIX, cmm_smsg_target); 443 if (rc < 0) 444 goto out_smsg; 445 #endif 446 rc = register_oom_notifier(&cmm_oom_nb); 447 if (rc < 0) 448 goto out_oom_notify; 449 rc = register_pm_notifier(&cmm_power_notifier); 450 if (rc) 451 goto out_pm; 452 cmm_thread_ptr = kthread_run(cmm_thread, NULL, "cmmthread"); 453 if (!IS_ERR(cmm_thread_ptr)) 454 return 0; 455 456 rc = PTR_ERR(cmm_thread_ptr); 457 unregister_pm_notifier(&cmm_power_notifier); 458 out_pm: 459 unregister_oom_notifier(&cmm_oom_nb); 460 out_oom_notify: 461 #ifdef CONFIG_CMM_IUCV 462 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); 463 out_smsg: 464 #endif 465 unregister_sysctl_table(cmm_sysctl_header); 466 out_sysctl: 467 del_timer_sync(&cmm_timer); 468 return rc; 469 } 470 module_init(cmm_init); 471 472 static void __exit cmm_exit(void) 473 { 474 unregister_sysctl_table(cmm_sysctl_header); 475 #ifdef CONFIG_CMM_IUCV 476 smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target); 477 #endif 478 unregister_pm_notifier(&cmm_power_notifier); 479 unregister_oom_notifier(&cmm_oom_nb); 480 kthread_stop(cmm_thread_ptr); 481 del_timer_sync(&cmm_timer); 482 cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list); 483 cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list); 484 } 485 module_exit(cmm_exit); 486 487 MODULE_LICENSE("GPL"); 488