tuxonice_swap.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. /*
  2. * kernel/power/tuxonice_swap.c
  3. *
  4. * Copyright (C) 2004-2014 Nigel Cunningham (nigel at tuxonice net)
  5. *
  6. * Distributed under GPLv2.
  7. *
  8. * This file encapsulates functions for usage of swap space as a
  9. * backing store.
  10. */
  11. #include <linux/suspend.h>
  12. #include <linux/blkdev.h>
  13. #include <linux/swapops.h>
  14. #include <linux/swap.h>
  15. #include <linux/syscalls.h>
  16. #include <linux/fs_uuid.h>
  17. #include "tuxonice.h"
  18. #include "tuxonice_sysfs.h"
  19. #include "tuxonice_modules.h"
  20. #include "tuxonice_io.h"
  21. #include "tuxonice_ui.h"
  22. #include "tuxonice_extent.h"
  23. #include "tuxonice_bio.h"
  24. #include "tuxonice_alloc.h"
  25. #include "tuxonice_builtin.h"
  26. static struct toi_module_ops toi_swapops;
  27. /* For swapfile automatically swapon/off'd. */
  28. static char swapfilename[255] = "";
  29. static int toi_swapon_status;
  30. /* Swap Pages */
  31. static unsigned long swap_allocated;
  32. static struct sysinfo swapinfo;
  33. static int is_ram_backed(struct swap_info_struct *si)
  34. {
  35. if (!strncmp(si->bdev->bd_disk->disk_name, "ram", 3) ||
  36. !strncmp(si->bdev->bd_disk->disk_name, "zram", 4))
  37. return 1;
  38. return 0;
  39. }
  40. /**
  41. * enable_swapfile: Swapon the user specified swapfile prior to hibernating.
  42. *
  43. * Activate the given swapfile if it wasn't already enabled. Remember whether
  44. * we really did swapon it for swapoffing later.
  45. */
  46. static void enable_swapfile(void)
  47. {
  48. int activateswapresult = -EINVAL;
  49. hib_log("swapfilename = '%s'\n", swapfilename);
  50. if (swapfilename[0]) {
  51. /* Attempt to swap on with maximum priority */
  52. activateswapresult = sys_swapon(swapfilename, 0xFFFF);
  53. if (activateswapresult && activateswapresult != -EBUSY)
  54. pr_err("TuxOnIce: /sys/power/tuxonice/swap/swapfile (%s) could not be turned on (error %d)",
  55. swapfilename, activateswapresult);
  56. if (!activateswapresult)
  57. toi_swapon_status = 1;
  58. }
  59. }
  60. /**
  61. * disable_swapfile: Swapoff any file swaponed at the start of the cycle.
  62. *
  63. * If we did successfully swapon a file at the start of the cycle, swapoff
  64. * it now (finishing up).
  65. */
  66. static void disable_swapfile(void)
  67. {
  68. if (!toi_swapon_status)
  69. return;
  70. hib_log("swapfilename = '%s'\n", swapfilename);
  71. sys_swapoff(swapfilename);
  72. toi_swapon_status = 0;
  73. }
  74. static int add_blocks_to_extent_chain(struct toi_bdev_info *chain,
  75. unsigned long start, unsigned long end)
  76. {
  77. if (test_action_state(TOI_TEST_BIO))
  78. toi_message(TOI_IO, TOI_VERBOSE, 0, "Adding extent %lu-%lu to chain %p.", start << chain->bmap_shift,
  79. end << chain->bmap_shift, chain);
  80. return toi_add_to_extent_chain(&chain->blocks, start, end);
  81. }
  82. static int get_main_pool_phys_params(struct toi_bdev_info *chain)
  83. {
  84. struct hibernate_extent *extentpointer = NULL;
  85. unsigned long address, extent_min = 0, extent_max = 0;
  86. int empty = 1;
  87. toi_message(TOI_IO, TOI_VERBOSE, 0, "get main pool phys params for chain %d.", chain->allocator_index);
  88. if (!chain->allocations.first)
  89. return 0;
  90. if (chain->blocks.first)
  91. toi_put_extent_chain(&chain->blocks);
  92. toi_extent_for_each(&chain->allocations, extentpointer, address) {
  93. swp_entry_t swap_address = (swp_entry_t) { address };
  94. struct block_device *bdev;
  95. sector_t new_sector = map_swap_entry(swap_address, &bdev);
  96. if (empty) {
  97. empty = 0;
  98. extent_min = extent_max = new_sector;
  99. continue;
  100. }
  101. if (new_sector == extent_max + 1) {
  102. extent_max++;
  103. continue;
  104. }
  105. if (add_blocks_to_extent_chain(chain, extent_min, extent_max)) {
  106. pr_err("Out of memory while making block " "chains.\n");
  107. return -ENOMEM;
  108. }
  109. extent_min = new_sector;
  110. extent_max = new_sector;
  111. }
  112. if (!empty && add_blocks_to_extent_chain(chain, extent_min, extent_max)) {
  113. pr_err("Out of memory while making block chains.\n");
  114. return -ENOMEM;
  115. }
  116. return 0;
  117. }
  118. /*
  119. * Like si_swapinfo, except that we don't include ram backed swap (compcache!)
  120. * and don't need to use the spinlocks (userspace is stopped when this
  121. * function is called).
  122. */
  123. void si_swapinfo_no_compcache(void)
  124. {
  125. unsigned int i;
  126. si_swapinfo(&swapinfo);
  127. swapinfo.freeswap = 0;
  128. swapinfo.totalswap = 0;
  129. for (i = 0; i < MAX_SWAPFILES; i++) {
  130. struct swap_info_struct *si = get_swap_info_struct(i);
  131. if (si && (si->flags & SWP_WRITEOK) && !is_ram_backed(si)) {
  132. swapinfo.totalswap += si->inuse_pages;
  133. swapinfo.freeswap += si->pages - si->inuse_pages;
  134. }
  135. }
  136. }
  137. /*
  138. * We can't just remember the value from allocation time, because other
  139. * processes might have allocated swap in the mean time.
  140. */
  141. static unsigned long toi_swap_storage_available(void)
  142. {
  143. toi_message(TOI_IO, TOI_VERBOSE, 0, "In toi_swap_storage_available.");
  144. si_swapinfo_no_compcache();
  145. return swapinfo.freeswap + swap_allocated;
  146. }
  147. static int toi_swap_initialise(int starting_cycle)
  148. {
  149. if (!starting_cycle)
  150. return 0;
  151. enable_swapfile();
  152. return 0;
  153. }
  154. static void toi_swap_cleanup(int ending_cycle)
  155. {
  156. if (!ending_cycle)
  157. return;
  158. disable_swapfile();
  159. }
  160. static void toi_swap_free_storage(struct toi_bdev_info *chain)
  161. {
  162. /* Free swap entries */
  163. struct hibernate_extent *extentpointer;
  164. unsigned long extentvalue;
  165. toi_message(TOI_IO, TOI_VERBOSE, 0, "Freeing storage for chain %p.", chain);
  166. swap_allocated -= chain->allocations.size;
  167. toi_extent_for_each(&chain->allocations, extentpointer, extentvalue)
  168. swap_free((swp_entry_t) {
  169. extentvalue});
  170. toi_put_extent_chain(&chain->allocations);
  171. }
  172. static void free_swap_range(unsigned long min, unsigned long max)
  173. {
  174. int j;
  175. for (j = min; j <= max; j++)
  176. swap_free((swp_entry_t) {
  177. j}
  178. );
  179. swap_allocated -= (max - min + 1);
  180. }
  181. /*
  182. * Allocation of a single swap type. Swap priorities are handled at the higher
  183. * level.
  184. */
  185. static int toi_swap_allocate_storage(struct toi_bdev_info *chain, unsigned long request)
  186. {
  187. unsigned long gotten = 0;
  188. toi_message(TOI_IO, TOI_VERBOSE, 0, " Swap allocate storage: Asked to allocate %lu pages from device %d.",
  189. request, chain->allocator_index);
  190. while (gotten < request) {
  191. swp_entry_t start, end;
  192. if (0) {
  193. /* Broken at the moment for SSDs */
  194. get_swap_range_of_type(chain->allocator_index, &start, &end,
  195. request - gotten + 1);
  196. } else {
  197. start = end = get_swap_page_of_type(chain->allocator_index);
  198. }
  199. if (start.val) {
  200. int added = end.val - start.val + 1;
  201. if (toi_add_to_extent_chain(&chain->allocations, start.val, end.val)) {
  202. pr_warn("Failed to allocate extent for %lu-%lu.\n", start.val, end.val);
  203. free_swap_range(start.val, end.val);
  204. break;
  205. }
  206. gotten += added;
  207. swap_allocated += added;
  208. } else
  209. break;
  210. }
  211. toi_message(TOI_IO, TOI_VERBOSE, 0, " Allocated %lu pages.", gotten);
  212. return gotten;
  213. }
  214. static int toi_swap_register_storage(void)
  215. {
  216. int i, result = 0;
  217. toi_message(TOI_IO, TOI_VERBOSE, 0, "toi_swap_register_storage.");
  218. for (i = 0; i < MAX_SWAPFILES; i++) {
  219. struct swap_info_struct *si = get_swap_info_struct(i);
  220. struct toi_bdev_info *devinfo;
  221. unsigned char *p;
  222. unsigned char buf[256];
  223. struct fs_info *fs_info;
  224. if (!si || !(si->flags & SWP_WRITEOK) || is_ram_backed(si))
  225. continue;
  226. devinfo = toi_kzalloc(39, sizeof(struct toi_bdev_info), GFP_ATOMIC);
  227. if (!devinfo) {
  228. pr_warn("Failed to allocate devinfo struct for swap " "device %d.\n", i);
  229. return -ENOMEM;
  230. }
  231. devinfo->bdev = si->bdev;
  232. devinfo->allocator = &toi_swapops;
  233. devinfo->allocator_index = i;
  234. fs_info = fs_info_from_block_dev(si->bdev);
  235. if (fs_info && !IS_ERR(fs_info)) {
  236. memcpy(devinfo->uuid, &fs_info->uuid, 16);
  237. free_fs_info(fs_info);
  238. } else
  239. result = (int)PTR_ERR(fs_info);
  240. if (!fs_info)
  241. pr_warn("fs_info from block dev returned %d.\n", result);
  242. devinfo->dev_t = si->bdev->bd_dev;
  243. devinfo->prio = si->prio;
  244. devinfo->bmap_shift = 3;
  245. devinfo->blocks_per_page = 1;
  246. p = d_path(&si->swap_file->f_path, buf, sizeof(buf));
  247. sprintf(devinfo->name, "swap on %s", p);
  248. toi_message(TOI_IO, TOI_VERBOSE, 0, "Registering swap storage: Device %d (%lx), prio %d.", i,
  249. (unsigned long)devinfo->dev_t, devinfo->prio);
  250. toi_bio_ops.register_storage(devinfo);
  251. }
  252. return 0;
  253. }
  254. /*
  255. * workspace_size
  256. *
  257. * Description:
  258. * Returns the number of bytes of RAM needed for this
  259. * code to do its work. (Used when calculating whether
  260. * we have enough memory to be able to hibernate & resume).
  261. *
  262. */
  263. static int toi_swap_memory_needed(void)
  264. {
  265. return 1;
  266. }
  267. /*
  268. * Print debug info
  269. *
  270. * Description:
  271. */
  272. static int toi_swap_print_debug_stats(char *buffer, int size)
  273. {
  274. int len = 0;
  275. len = scnprintf(buffer, size, "- Swap Allocator enabled.\n");
  276. if (swapfilename[0])
  277. len += scnprintf(buffer + len, size - len,
  278. " Attempting to automatically swapon: %s.\n", swapfilename);
  279. si_swapinfo_no_compcache();
  280. len += scnprintf(buffer + len, size - len,
  281. " Swap available for image: %lu pages.\n",
  282. swapinfo.freeswap + swap_allocated);
  283. return len;
  284. }
  285. static int header_locations_read_sysfs(const char *page, int count)
  286. {
  287. int i, printedpartitionsmessage = 0, len = 0, haveswap = 0;
  288. struct inode *swapf = NULL;
  289. int zone;
  290. char *path_page = (char *)toi_get_free_page(10, GFP_KERNEL);
  291. char *path, *output = (char *)page;
  292. int path_len;
  293. if (!page)
  294. return 0;
  295. for (i = 0; i < MAX_SWAPFILES; i++) {
  296. struct swap_info_struct *si = get_swap_info_struct(i);
  297. if (!si || !(si->flags & SWP_WRITEOK))
  298. continue;
  299. if (S_ISBLK(si->swap_file->f_mapping->host->i_mode)) {
  300. haveswap = 1;
  301. if (!printedpartitionsmessage) {
  302. len += sprintf(output + len,
  303. "For swap partitions, simply use the format: resume=swap:/dev/hda1.\n");
  304. printedpartitionsmessage = 1;
  305. }
  306. } else {
  307. path_len = 0;
  308. path = d_path(&si->swap_file->f_path, path_page, PAGE_SIZE);
  309. path_len = snprintf(path_page, PAGE_SIZE, "%s", path);
  310. haveswap = 1;
  311. swapf = si->swap_file->f_mapping->host;
  312. zone = bmap(swapf, 0);
  313. if (!zone) {
  314. len += sprintf(output + len,
  315. "Swapfile %s has been corrupted. Reuse mkswap on it and try again.\n",
  316. path_page);
  317. } else {
  318. char name_buffer[BDEVNAME_SIZE];
  319. len += sprintf(output + len,
  320. "For swapfile `%s`, use resume=swap:/dev/%s:0x%x.\n",
  321. path_page,
  322. bdevname(si->bdev, name_buffer),
  323. zone << (swapf->i_blkbits - 9));
  324. }
  325. }
  326. }
  327. if (!haveswap)
  328. len = sprintf(output, "You need to turn on swap partitions before examining this file.\n");
  329. toi_free_page(10, (unsigned long)path_page);
  330. return len;
  331. }
  332. static struct toi_sysfs_data sysfs_params[] = {
  333. SYSFS_STRING("swapfilename", SYSFS_RW, swapfilename, 255, 0, NULL),
  334. SYSFS_CUSTOM("headerlocations", SYSFS_READONLY,
  335. header_locations_read_sysfs, NULL, 0, NULL),
  336. SYSFS_INT("enabled", SYSFS_RW, &toi_swapops.enabled, 0, 1, 0,
  337. attempt_to_parse_resume_device2),
  338. };
  339. static struct toi_bio_allocator_ops toi_bio_swapops = {
  340. .register_storage = toi_swap_register_storage,
  341. .storage_available = toi_swap_storage_available,
  342. .allocate_storage = toi_swap_allocate_storage,
  343. .bmap = get_main_pool_phys_params,
  344. .free_storage = toi_swap_free_storage,
  345. };
  346. static struct toi_module_ops toi_swapops = {
  347. .type = BIO_ALLOCATOR_MODULE,
  348. .name = "swap storage",
  349. .directory = "swap",
  350. .module = THIS_MODULE,
  351. .memory_needed = toi_swap_memory_needed,
  352. .print_debug_info = toi_swap_print_debug_stats,
  353. .initialise = toi_swap_initialise,
  354. .cleanup = toi_swap_cleanup,
  355. .bio_allocator_ops = &toi_bio_swapops,
  356. .sysfs_data = sysfs_params,
  357. .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct toi_sysfs_data),
  358. };
  359. /* ---- Registration ---- */
  360. static __init int toi_swap_load(void)
  361. {
  362. return toi_register_module(&toi_swapops);
  363. }
  364. #ifdef MODULE
  365. static __exit void toi_swap_unload(void)
  366. {
  367. toi_unregister_module(&toi_swapops);
  368. }
  369. module_init(toi_swap_load);
  370. module_exit(toi_swap_unload);
  371. MODULE_LICENSE("GPL");
  372. MODULE_AUTHOR("Nigel Cunningham");
  373. MODULE_DESCRIPTION("TuxOnIce SwapAllocator");
  374. #else
  375. late_initcall(toi_swap_load);
  376. #endif