cmm.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. /*
  2. * arch/s390/mm/cmm.c
  3. *
  4. * S390 version
  5. * Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
  6. * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com)
  7. *
  8. * Collaborative memory management interface.
  9. */
  10. #include <linux/errno.h>
  11. #include <linux/fs.h>
  12. #include <linux/init.h>
  13. #include <linux/module.h>
  14. #include <linux/sched.h>
  15. #include <linux/sysctl.h>
  16. #include <linux/ctype.h>
  17. #include <asm/pgalloc.h>
  18. #include <asm/uaccess.h>
  19. static char *sender = "VMRMSVM";
  20. module_param(sender, charp, 0400);
  21. MODULE_PARM_DESC(sender,
  22. "Guest name that may send SMSG messages (default VMRMSVM)");
  23. #include "../../../drivers/s390/net/smsgiucv.h"
  24. #define CMM_NR_PAGES ((PAGE_SIZE / sizeof(unsigned long)) - 2)
  25. struct cmm_page_array {
  26. struct cmm_page_array *next;
  27. unsigned long index;
  28. unsigned long pages[CMM_NR_PAGES];
  29. };
  30. static long cmm_pages = 0;
  31. static long cmm_timed_pages = 0;
  32. static volatile long cmm_pages_target = 0;
  33. static volatile long cmm_timed_pages_target = 0;
  34. static long cmm_timeout_pages = 0;
  35. static long cmm_timeout_seconds = 0;
  36. static struct cmm_page_array *cmm_page_list = NULL;
  37. static struct cmm_page_array *cmm_timed_page_list = NULL;
  38. static unsigned long cmm_thread_active = 0;
  39. static struct work_struct cmm_thread_starter;
  40. static wait_queue_head_t cmm_thread_wait;
  41. static struct timer_list cmm_timer;
  42. static void cmm_timer_fn(unsigned long);
  43. static void cmm_set_timer(void);
  44. static long
  45. cmm_alloc_pages(long pages, long *counter, struct cmm_page_array **list)
  46. {
  47. struct cmm_page_array *pa;
  48. unsigned long page;
  49. pa = *list;
  50. while (pages) {
  51. page = __get_free_page(GFP_NOIO);
  52. if (!page)
  53. break;
  54. if (!pa || pa->index >= CMM_NR_PAGES) {
  55. /* Need a new page for the page list. */
  56. pa = (struct cmm_page_array *)
  57. __get_free_page(GFP_NOIO);
  58. if (!pa) {
  59. free_page(page);
  60. break;
  61. }
  62. pa->next = *list;
  63. pa->index = 0;
  64. *list = pa;
  65. }
  66. diag10(page);
  67. pa->pages[pa->index++] = page;
  68. (*counter)++;
  69. pages--;
  70. }
  71. return pages;
  72. }
  73. static void
  74. cmm_free_pages(long pages, long *counter, struct cmm_page_array **list)
  75. {
  76. struct cmm_page_array *pa;
  77. unsigned long page;
  78. pa = *list;
  79. while (pages) {
  80. if (!pa || pa->index <= 0)
  81. break;
  82. page = pa->pages[--pa->index];
  83. if (pa->index == 0) {
  84. pa = pa->next;
  85. free_page((unsigned long) *list);
  86. *list = pa;
  87. }
  88. free_page(page);
  89. (*counter)--;
  90. pages--;
  91. }
  92. }
  93. static int
  94. cmm_thread(void *dummy)
  95. {
  96. int rc;
  97. daemonize("cmmthread");
  98. while (1) {
  99. rc = wait_event_interruptible(cmm_thread_wait,
  100. (cmm_pages != cmm_pages_target ||
  101. cmm_timed_pages != cmm_timed_pages_target));
  102. if (rc == -ERESTARTSYS) {
  103. /* Got kill signal. End thread. */
  104. clear_bit(0, &cmm_thread_active);
  105. cmm_pages_target = cmm_pages;
  106. cmm_timed_pages_target = cmm_timed_pages;
  107. break;
  108. }
  109. if (cmm_pages_target > cmm_pages) {
  110. if (cmm_alloc_pages(1, &cmm_pages, &cmm_page_list))
  111. cmm_pages_target = cmm_pages;
  112. } else if (cmm_pages_target < cmm_pages) {
  113. cmm_free_pages(1, &cmm_pages, &cmm_page_list);
  114. }
  115. if (cmm_timed_pages_target > cmm_timed_pages) {
  116. if (cmm_alloc_pages(1, &cmm_timed_pages,
  117. &cmm_timed_page_list))
  118. cmm_timed_pages_target = cmm_timed_pages;
  119. } else if (cmm_timed_pages_target < cmm_timed_pages) {
  120. cmm_free_pages(1, &cmm_timed_pages,
  121. &cmm_timed_page_list);
  122. }
  123. if (cmm_timed_pages > 0 && !timer_pending(&cmm_timer))
  124. cmm_set_timer();
  125. }
  126. return 0;
  127. }
  128. static void
  129. cmm_start_thread(void)
  130. {
  131. kernel_thread(cmm_thread, NULL, 0);
  132. }
  133. static void
  134. cmm_kick_thread(void)
  135. {
  136. if (!test_and_set_bit(0, &cmm_thread_active))
  137. schedule_work(&cmm_thread_starter);
  138. wake_up(&cmm_thread_wait);
  139. }
  140. static void
  141. cmm_set_timer(void)
  142. {
  143. if (cmm_timed_pages_target <= 0 || cmm_timeout_seconds <= 0) {
  144. if (timer_pending(&cmm_timer))
  145. del_timer(&cmm_timer);
  146. return;
  147. }
  148. if (timer_pending(&cmm_timer)) {
  149. if (mod_timer(&cmm_timer, jiffies + cmm_timeout_seconds*HZ))
  150. return;
  151. }
  152. cmm_timer.function = cmm_timer_fn;
  153. cmm_timer.data = 0;
  154. cmm_timer.expires = jiffies + cmm_timeout_seconds*HZ;
  155. add_timer(&cmm_timer);
  156. }
  157. static void
  158. cmm_timer_fn(unsigned long ignored)
  159. {
  160. long pages;
  161. pages = cmm_timed_pages_target - cmm_timeout_pages;
  162. if (pages < 0)
  163. cmm_timed_pages_target = 0;
  164. else
  165. cmm_timed_pages_target = pages;
  166. cmm_kick_thread();
  167. cmm_set_timer();
  168. }
  169. void
  170. cmm_set_pages(long pages)
  171. {
  172. cmm_pages_target = pages;
  173. cmm_kick_thread();
  174. }
  175. long
  176. cmm_get_pages(void)
  177. {
  178. return cmm_pages;
  179. }
  180. void
  181. cmm_add_timed_pages(long pages)
  182. {
  183. cmm_timed_pages_target += pages;
  184. cmm_kick_thread();
  185. }
  186. long
  187. cmm_get_timed_pages(void)
  188. {
  189. return cmm_timed_pages;
  190. }
  191. void
  192. cmm_set_timeout(long pages, long seconds)
  193. {
  194. cmm_timeout_pages = pages;
  195. cmm_timeout_seconds = seconds;
  196. cmm_set_timer();
  197. }
  198. static inline int
  199. cmm_skip_blanks(char *cp, char **endp)
  200. {
  201. char *str;
  202. for (str = cp; *str == ' ' || *str == '\t'; str++);
  203. *endp = str;
  204. return str != cp;
  205. }
  206. #ifdef CONFIG_CMM_PROC
  207. /* These will someday get removed. */
  208. #define VM_CMM_PAGES 1111
  209. #define VM_CMM_TIMED_PAGES 1112
  210. #define VM_CMM_TIMEOUT 1113
  211. static struct ctl_table cmm_table[];
  212. static int
  213. cmm_pages_handler(ctl_table *ctl, int write, struct file *filp,
  214. void __user *buffer, size_t *lenp, loff_t *ppos)
  215. {
  216. char buf[16], *p;
  217. long pages;
  218. int len;
  219. if (!*lenp || (*ppos && !write)) {
  220. *lenp = 0;
  221. return 0;
  222. }
  223. if (write) {
  224. len = *lenp;
  225. if (copy_from_user(buf, buffer,
  226. len > sizeof(buf) ? sizeof(buf) : len))
  227. return -EFAULT;
  228. buf[sizeof(buf) - 1] = '\0';
  229. cmm_skip_blanks(buf, &p);
  230. pages = simple_strtoul(p, &p, 0);
  231. if (ctl == &cmm_table[0])
  232. cmm_set_pages(pages);
  233. else
  234. cmm_add_timed_pages(pages);
  235. } else {
  236. if (ctl == &cmm_table[0])
  237. pages = cmm_get_pages();
  238. else
  239. pages = cmm_get_timed_pages();
  240. len = sprintf(buf, "%ld\n", pages);
  241. if (len > *lenp)
  242. len = *lenp;
  243. if (copy_to_user(buffer, buf, len))
  244. return -EFAULT;
  245. }
  246. *lenp = len;
  247. *ppos += len;
  248. return 0;
  249. }
  250. static int
  251. cmm_timeout_handler(ctl_table *ctl, int write, struct file *filp,
  252. void __user *buffer, size_t *lenp, loff_t *ppos)
  253. {
  254. char buf[64], *p;
  255. long pages, seconds;
  256. int len;
  257. if (!*lenp || (*ppos && !write)) {
  258. *lenp = 0;
  259. return 0;
  260. }
  261. if (write) {
  262. len = *lenp;
  263. if (copy_from_user(buf, buffer,
  264. len > sizeof(buf) ? sizeof(buf) : len))
  265. return -EFAULT;
  266. buf[sizeof(buf) - 1] = '\0';
  267. cmm_skip_blanks(buf, &p);
  268. pages = simple_strtoul(p, &p, 0);
  269. cmm_skip_blanks(p, &p);
  270. seconds = simple_strtoul(p, &p, 0);
  271. cmm_set_timeout(pages, seconds);
  272. } else {
  273. len = sprintf(buf, "%ld %ld\n",
  274. cmm_timeout_pages, cmm_timeout_seconds);
  275. if (len > *lenp)
  276. len = *lenp;
  277. if (copy_to_user(buffer, buf, len))
  278. return -EFAULT;
  279. }
  280. *lenp = len;
  281. *ppos += len;
  282. return 0;
  283. }
  284. static struct ctl_table cmm_table[] = {
  285. {
  286. .ctl_name = VM_CMM_PAGES,
  287. .procname = "cmm_pages",
  288. .mode = 0644,
  289. .proc_handler = &cmm_pages_handler,
  290. },
  291. {
  292. .ctl_name = VM_CMM_TIMED_PAGES,
  293. .procname = "cmm_timed_pages",
  294. .mode = 0644,
  295. .proc_handler = &cmm_pages_handler,
  296. },
  297. {
  298. .ctl_name = VM_CMM_TIMEOUT,
  299. .procname = "cmm_timeout",
  300. .mode = 0644,
  301. .proc_handler = &cmm_timeout_handler,
  302. },
  303. { .ctl_name = 0 }
  304. };
  305. static struct ctl_table cmm_dir_table[] = {
  306. {
  307. .ctl_name = CTL_VM,
  308. .procname = "vm",
  309. .maxlen = 0,
  310. .mode = 0555,
  311. .child = cmm_table,
  312. },
  313. { .ctl_name = 0 }
  314. };
  315. #endif
  316. #ifdef CONFIG_CMM_IUCV
  317. #define SMSG_PREFIX "CMM"
  318. static void
  319. cmm_smsg_target(char *from, char *msg)
  320. {
  321. long pages, seconds;
  322. if (strlen(sender) > 0 && strcmp(from, sender) != 0)
  323. return;
  324. if (!cmm_skip_blanks(msg + strlen(SMSG_PREFIX), &msg))
  325. return;
  326. if (strncmp(msg, "SHRINK", 6) == 0) {
  327. if (!cmm_skip_blanks(msg + 6, &msg))
  328. return;
  329. pages = simple_strtoul(msg, &msg, 0);
  330. cmm_skip_blanks(msg, &msg);
  331. if (*msg == '\0')
  332. cmm_set_pages(pages);
  333. } else if (strncmp(msg, "RELEASE", 7) == 0) {
  334. if (!cmm_skip_blanks(msg + 7, &msg))
  335. return;
  336. pages = simple_strtoul(msg, &msg, 0);
  337. cmm_skip_blanks(msg, &msg);
  338. if (*msg == '\0')
  339. cmm_add_timed_pages(pages);
  340. } else if (strncmp(msg, "REUSE", 5) == 0) {
  341. if (!cmm_skip_blanks(msg + 5, &msg))
  342. return;
  343. pages = simple_strtoul(msg, &msg, 0);
  344. if (!cmm_skip_blanks(msg, &msg))
  345. return;
  346. seconds = simple_strtoul(msg, &msg, 0);
  347. cmm_skip_blanks(msg, &msg);
  348. if (*msg == '\0')
  349. cmm_set_timeout(pages, seconds);
  350. }
  351. }
  352. #endif
  353. struct ctl_table_header *cmm_sysctl_header;
  354. static int
  355. cmm_init (void)
  356. {
  357. #ifdef CONFIG_CMM_PROC
  358. cmm_sysctl_header = register_sysctl_table(cmm_dir_table, 1);
  359. #endif
  360. #ifdef CONFIG_CMM_IUCV
  361. smsg_register_callback(SMSG_PREFIX, cmm_smsg_target);
  362. #endif
  363. INIT_WORK(&cmm_thread_starter, (void *) cmm_start_thread, NULL);
  364. init_waitqueue_head(&cmm_thread_wait);
  365. init_timer(&cmm_timer);
  366. return 0;
  367. }
  368. static void
  369. cmm_exit(void)
  370. {
  371. cmm_free_pages(cmm_pages, &cmm_pages, &cmm_page_list);
  372. cmm_free_pages(cmm_timed_pages, &cmm_timed_pages, &cmm_timed_page_list);
  373. #ifdef CONFIG_CMM_PROC
  374. unregister_sysctl_table(cmm_sysctl_header);
  375. #endif
  376. #ifdef CONFIG_CMM_IUCV
  377. smsg_unregister_callback(SMSG_PREFIX, cmm_smsg_target);
  378. #endif
  379. }
  380. module_init(cmm_init);
  381. module_exit(cmm_exit);
  382. EXPORT_SYMBOL(cmm_set_pages);
  383. EXPORT_SYMBOL(cmm_get_pages);
  384. EXPORT_SYMBOL(cmm_add_timed_pages);
  385. EXPORT_SYMBOL(cmm_get_timed_pages);
  386. EXPORT_SYMBOL(cmm_set_timeout);
  387. MODULE_LICENSE("GPL");