tuxonice_storage.c 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * kernel/power/tuxonice_storage.c
  3. *
  4. * Copyright (C) 2005-2014 Nigel Cunningham (nigel at tuxonice net)
  5. *
  6. * This file is released under the GPLv2.
  7. *
  8. * Routines for talking to a userspace program that manages storage.
  9. *
  10. * The kernel side:
  11. * - starts the userspace program;
  12. * - sends messages telling it when to open and close the connection;
  13. * - tells it when to quit;
  14. *
  15. * The user space side:
  16. * - passes messages regarding status;
  17. *
  18. */
  19. #include <linux/module.h>
  20. #include <linux/suspend.h>
  21. #include <linux/freezer.h>
  22. #include "tuxonice_sysfs.h"
  23. #include "tuxonice_modules.h"
  24. #include "tuxonice_netlink.h"
  25. #include "tuxonice_storage.h"
  26. #include "tuxonice_ui.h"
  27. static struct user_helper_data usm_helper_data;
  28. static struct toi_module_ops usm_ops;
  29. static int message_received, usm_prepare_count;
  30. static int storage_manager_last_action, storage_manager_action;
  31. static int usm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh)
  32. {
  33. int type;
  34. int *data;
  35. type = nlh->nlmsg_type;
  36. /* A control message: ignore them */
  37. if (type < NETLINK_MSG_BASE)
  38. return 0;
  39. /* Unknown message: reply with EINVAL */
  40. if (type >= USM_MSG_MAX)
  41. return -EINVAL;
  42. /* All operations require privileges, even GET */
  43. if (!capable(CAP_NET_ADMIN))
  44. return -EPERM;
  45. /* Only allow one task to receive NOFREEZE privileges */
  46. if (type == NETLINK_MSG_NOFREEZE_ME && usm_helper_data.pid != -1)
  47. return -EBUSY;
  48. data = (int *)NLMSG_DATA(nlh);
  49. switch (type) {
  50. case USM_MSG_SUCCESS:
  51. case USM_MSG_FAILED:
  52. message_received = type;
  53. complete(&usm_helper_data.wait_for_process);
  54. break;
  55. default:
  56. pr_warn("Storage manager doesn't recognise " "message %d.\n", type);
  57. }
  58. return 1;
  59. }
  60. #ifdef CONFIG_NET
  61. static int activations;
  62. int toi_activate_storage(int force)
  63. {
  64. int tries = 1;
  65. if (usm_helper_data.pid == -1 || !usm_ops.enabled)
  66. return 0;
  67. message_received = 0;
  68. activations++;
  69. if (activations > 1 && !force)
  70. return 0;
  71. while ((!message_received || message_received == USM_MSG_FAILED) && tries < 2) {
  72. toi_prepare_status(DONT_CLEAR_BAR, "Activate storage attempt " "%d.\n", tries);
  73. init_completion(&usm_helper_data.wait_for_process);
  74. toi_send_netlink_message(&usm_helper_data, USM_MSG_CONNECT, NULL, 0);
  75. /* Wait 2 seconds for the userspace process to make contact */
  76. wait_for_completion_timeout(&usm_helper_data.wait_for_process, 2 * HZ);
  77. tries++;
  78. }
  79. return 0;
  80. }
  81. int toi_deactivate_storage(int force)
  82. {
  83. if (usm_helper_data.pid == -1 || !usm_ops.enabled)
  84. return 0;
  85. message_received = 0;
  86. activations--;
  87. if (activations && !force)
  88. return 0;
  89. init_completion(&usm_helper_data.wait_for_process);
  90. toi_send_netlink_message(&usm_helper_data, USM_MSG_DISCONNECT, NULL, 0);
  91. wait_for_completion_timeout(&usm_helper_data.wait_for_process, 2 * HZ);
  92. if (!message_received || message_received == USM_MSG_FAILED) {
  93. pr_warn("Returning failure disconnecting storage.\n");
  94. return 1;
  95. }
  96. return 0;
  97. }
  98. #endif
  99. static void storage_manager_simulate(void)
  100. {
  101. pr_warn("--- Storage manager simulate ---\n");
  102. toi_prepare_usm();
  103. schedule();
  104. pr_warn("--- Activate storage 1 ---\n");
  105. toi_activate_storage(1);
  106. schedule();
  107. pr_warn("--- Deactivate storage 1 ---\n");
  108. toi_deactivate_storage(1);
  109. schedule();
  110. pr_warn("--- Cleanup usm ---\n");
  111. toi_cleanup_usm();
  112. schedule();
  113. pr_warn("--- Storage manager simulate ends ---\n");
  114. }
  115. static int usm_storage_needed(void)
  116. {
  117. return sizeof(int) + strlen(usm_helper_data.program) + 1;
  118. }
  119. static int usm_save_config_info(char *buf)
  120. {
  121. int len = strlen(usm_helper_data.program);
  122. memcpy(buf, usm_helper_data.program, len + 1);
  123. return sizeof(int) + len + 1;
  124. }
  125. static void usm_load_config_info(char *buf, int size)
  126. {
  127. /* Don't load the saved path if one has already been set */
  128. if (usm_helper_data.program[0])
  129. return;
  130. memcpy(usm_helper_data.program, buf + sizeof(int), *((int *)buf));
  131. }
  132. static int usm_memory_needed(void)
  133. {
  134. /* ball park figure of 32 pages */
  135. return 32 * PAGE_SIZE;
  136. }
  137. /* toi_prepare_usm
  138. */
  139. int toi_prepare_usm(void)
  140. {
  141. usm_prepare_count++;
  142. if (usm_prepare_count > 1 || !usm_ops.enabled)
  143. return 0;
  144. usm_helper_data.pid = -1;
  145. if (!*usm_helper_data.program)
  146. return 0;
  147. toi_netlink_setup(&usm_helper_data);
  148. if (usm_helper_data.pid == -1)
  149. pr_warn("TuxOnIce Storage Manager wanted, but couldn't" " start it.\n");
  150. toi_activate_storage(0);
  151. return usm_helper_data.pid != -1;
  152. }
  153. void toi_cleanup_usm(void)
  154. {
  155. usm_prepare_count--;
  156. if (usm_helper_data.pid > -1 && !usm_prepare_count) {
  157. toi_deactivate_storage(0);
  158. toi_netlink_close(&usm_helper_data);
  159. }
  160. }
  161. static void storage_manager_activate(void)
  162. {
  163. if (storage_manager_action == storage_manager_last_action)
  164. return;
  165. if (storage_manager_action)
  166. toi_prepare_usm();
  167. else
  168. toi_cleanup_usm();
  169. storage_manager_last_action = storage_manager_action;
  170. }
  171. /*
  172. * User interface specific /sys/power/tuxonice entries.
  173. */
  174. static struct toi_sysfs_data sysfs_params[] = {
  175. SYSFS_NONE("simulate_atomic_copy", storage_manager_simulate),
  176. SYSFS_INT("enabled", SYSFS_RW, &usm_ops.enabled, 0, 1, 0, NULL),
  177. SYSFS_STRING("program", SYSFS_RW, usm_helper_data.program, 254, 0,
  178. NULL),
  179. SYSFS_INT("activate_storage", SYSFS_RW, &storage_manager_action, 0, 1,
  180. 0, storage_manager_activate)
  181. };
  182. static struct toi_module_ops usm_ops = {
  183. .type = MISC_MODULE,
  184. .name = "usm",
  185. .directory = "storage_manager",
  186. .module = THIS_MODULE,
  187. .storage_needed = usm_storage_needed,
  188. .save_config_info = usm_save_config_info,
  189. .load_config_info = usm_load_config_info,
  190. .memory_needed = usm_memory_needed,
  191. .sysfs_data = sysfs_params,
  192. .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct toi_sysfs_data),
  193. };
  194. /* toi_usm_sysfs_init
  195. * Description: Boot time initialisation for user interface.
  196. */
  197. int toi_usm_init(void)
  198. {
  199. usm_helper_data.nl = NULL;
  200. usm_helper_data.program[0] = '\0';
  201. usm_helper_data.pid = -1;
  202. usm_helper_data.skb_size = 0;
  203. usm_helper_data.pool_limit = 6;
  204. usm_helper_data.netlink_id = NETLINK_TOI_USM;
  205. usm_helper_data.name = "userspace storage manager";
  206. usm_helper_data.rcv_msg = usm_user_rcv_msg;
  207. usm_helper_data.interface_version = 2;
  208. usm_helper_data.must_init = 0;
  209. init_completion(&usm_helper_data.wait_for_process);
  210. return toi_register_module(&usm_ops);
  211. }
  212. void toi_usm_exit(void)
  213. {
  214. toi_netlink_close_complete(&usm_helper_data);
  215. toi_unregister_module(&usm_ops);
  216. }