diff options
-rw-r--r-- | include/linux/swap.h | 8 | ||||
-rw-r--r-- | kernel/power/hibernate.c | 1 | ||||
-rw-r--r-- | kernel/power/snapshot.c | 1 | ||||
-rw-r--r-- | kernel/power/swap.c | 6 | ||||
-rw-r--r-- | mm/swapfile.c | 94 |
5 files changed, 84 insertions, 26 deletions
diff --git a/include/linux/swap.h b/include/linux/swap.h index ff4acea9bbdb..91c9d3fc8513 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h | |||
@@ -316,7 +316,6 @@ extern long nr_swap_pages; | |||
316 | extern long total_swap_pages; | 316 | extern long total_swap_pages; |
317 | extern void si_swapinfo(struct sysinfo *); | 317 | extern void si_swapinfo(struct sysinfo *); |
318 | extern swp_entry_t get_swap_page(void); | 318 | extern swp_entry_t get_swap_page(void); |
319 | extern swp_entry_t get_swap_page_of_type(int); | ||
320 | extern int valid_swaphandles(swp_entry_t, unsigned long *); | 319 | extern int valid_swaphandles(swp_entry_t, unsigned long *); |
321 | extern int add_swap_count_continuation(swp_entry_t, gfp_t); | 320 | extern int add_swap_count_continuation(swp_entry_t, gfp_t); |
322 | extern void swap_shmem_alloc(swp_entry_t); | 321 | extern void swap_shmem_alloc(swp_entry_t); |
@@ -333,6 +332,13 @@ extern int reuse_swap_page(struct page *); | |||
333 | extern int try_to_free_swap(struct page *); | 332 | extern int try_to_free_swap(struct page *); |
334 | struct backing_dev_info; | 333 | struct backing_dev_info; |
335 | 334 | ||
335 | #ifdef CONFIG_HIBERNATION | ||
336 | void hibernation_freeze_swap(void); | ||
337 | void hibernation_thaw_swap(void); | ||
338 | swp_entry_t get_swap_for_hibernation(int type); | ||
339 | void swap_free_for_hibernation(swp_entry_t val); | ||
340 | #endif | ||
341 | |||
336 | /* linux/mm/thrash.c */ | 342 | /* linux/mm/thrash.c */ |
337 | extern struct mm_struct *swap_token_mm; | 343 | extern struct mm_struct *swap_token_mm; |
338 | extern void grab_swap_token(struct mm_struct *); | 344 | extern void grab_swap_token(struct mm_struct *); |
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c index 8dc31e02ae12..c77963938bca 100644 --- a/kernel/power/hibernate.c +++ b/kernel/power/hibernate.c | |||
@@ -338,6 +338,7 @@ int hibernation_snapshot(int platform_mode) | |||
338 | goto Close; | 338 | goto Close; |
339 | 339 | ||
340 | suspend_console(); | 340 | suspend_console(); |
341 | hibernation_freeze_swap(); | ||
341 | saved_mask = clear_gfp_allowed_mask(GFP_IOFS); | 342 | saved_mask = clear_gfp_allowed_mask(GFP_IOFS); |
342 | error = dpm_suspend_start(PMSG_FREEZE); | 343 | error = dpm_suspend_start(PMSG_FREEZE); |
343 | if (error) | 344 | if (error) |
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index f6cd6faf84fd..5e7edfb05e66 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -1086,6 +1086,7 @@ void swsusp_free(void) | |||
1086 | buffer = NULL; | 1086 | buffer = NULL; |
1087 | alloc_normal = 0; | 1087 | alloc_normal = 0; |
1088 | alloc_highmem = 0; | 1088 | alloc_highmem = 0; |
1089 | hibernation_thaw_swap(); | ||
1089 | } | 1090 | } |
1090 | 1091 | ||
1091 | /* Helper functions used for the shrinking of memory. */ | 1092 | /* Helper functions used for the shrinking of memory. */ |
diff --git a/kernel/power/swap.c b/kernel/power/swap.c index e6a5bdf61a37..5d0059eed3e4 100644 --- a/kernel/power/swap.c +++ b/kernel/power/swap.c | |||
@@ -136,10 +136,10 @@ sector_t alloc_swapdev_block(int swap) | |||
136 | { | 136 | { |
137 | unsigned long offset; | 137 | unsigned long offset; |
138 | 138 | ||
139 | offset = swp_offset(get_swap_page_of_type(swap)); | 139 | offset = swp_offset(get_swap_for_hibernation(swap)); |
140 | if (offset) { | 140 | if (offset) { |
141 | if (swsusp_extents_insert(offset)) | 141 | if (swsusp_extents_insert(offset)) |
142 | swap_free(swp_entry(swap, offset)); | 142 | swap_free_for_hibernation(swp_entry(swap, offset)); |
143 | else | 143 | else |
144 | return swapdev_block(swap, offset); | 144 | return swapdev_block(swap, offset); |
145 | } | 145 | } |
@@ -163,7 +163,7 @@ void free_all_swap_pages(int swap) | |||
163 | ext = container_of(node, struct swsusp_extent, node); | 163 | ext = container_of(node, struct swsusp_extent, node); |
164 | rb_erase(node, &swsusp_extents); | 164 | rb_erase(node, &swsusp_extents); |
165 | for (offset = ext->start; offset <= ext->end; offset++) | 165 | for (offset = ext->start; offset <= ext->end; offset++) |
166 | swap_free(swp_entry(swap, offset)); | 166 | swap_free_for_hibernation(swp_entry(swap, offset)); |
167 | 167 | ||
168 | kfree(ext); | 168 | kfree(ext); |
169 | } | 169 | } |
diff --git a/mm/swapfile.c b/mm/swapfile.c index f08d165871b3..1f3f9c59a73a 100644 --- a/mm/swapfile.c +++ b/mm/swapfile.c | |||
@@ -47,6 +47,8 @@ long nr_swap_pages; | |||
47 | long total_swap_pages; | 47 | long total_swap_pages; |
48 | static int least_priority; | 48 | static int least_priority; |
49 | 49 | ||
50 | static bool swap_for_hibernation; | ||
51 | |||
50 | static const char Bad_file[] = "Bad swap file entry "; | 52 | static const char Bad_file[] = "Bad swap file entry "; |
51 | static const char Unused_file[] = "Unused swap file entry "; | 53 | static const char Unused_file[] = "Unused swap file entry "; |
52 | static const char Bad_offset[] = "Bad swap offset entry "; | 54 | static const char Bad_offset[] = "Bad swap offset entry "; |
@@ -451,6 +453,8 @@ swp_entry_t get_swap_page(void) | |||
451 | spin_lock(&swap_lock); | 453 | spin_lock(&swap_lock); |
452 | if (nr_swap_pages <= 0) | 454 | if (nr_swap_pages <= 0) |
453 | goto noswap; | 455 | goto noswap; |
456 | if (swap_for_hibernation) | ||
457 | goto noswap; | ||
454 | nr_swap_pages--; | 458 | nr_swap_pages--; |
455 | 459 | ||
456 | for (type = swap_list.next; type >= 0 && wrapped < 2; type = next) { | 460 | for (type = swap_list.next; type >= 0 && wrapped < 2; type = next) { |
@@ -483,28 +487,6 @@ noswap: | |||
483 | return (swp_entry_t) {0}; | 487 | return (swp_entry_t) {0}; |
484 | } | 488 | } |
485 | 489 | ||
486 | /* The only caller of this function is now susupend routine */ | ||
487 | swp_entry_t get_swap_page_of_type(int type) | ||
488 | { | ||
489 | struct swap_info_struct *si; | ||
490 | pgoff_t offset; | ||
491 | |||
492 | spin_lock(&swap_lock); | ||
493 | si = swap_info[type]; | ||
494 | if (si && (si->flags & SWP_WRITEOK)) { | ||
495 | nr_swap_pages--; | ||
496 | /* This is called for allocating swap entry, not cache */ | ||
497 | offset = scan_swap_map(si, 1); | ||
498 | if (offset) { | ||
499 | spin_unlock(&swap_lock); | ||
500 | return swp_entry(type, offset); | ||
501 | } | ||
502 | nr_swap_pages++; | ||
503 | } | ||
504 | spin_unlock(&swap_lock); | ||
505 | return (swp_entry_t) {0}; | ||
506 | } | ||
507 | |||
508 | static struct swap_info_struct *swap_info_get(swp_entry_t entry) | 490 | static struct swap_info_struct *swap_info_get(swp_entry_t entry) |
509 | { | 491 | { |
510 | struct swap_info_struct *p; | 492 | struct swap_info_struct *p; |
@@ -764,6 +746,74 @@ int mem_cgroup_count_swap_user(swp_entry_t ent, struct page **pagep) | |||
764 | #endif | 746 | #endif |
765 | 747 | ||
766 | #ifdef CONFIG_HIBERNATION | 748 | #ifdef CONFIG_HIBERNATION |
749 | |||
750 | static pgoff_t hibernation_offset[MAX_SWAPFILES]; | ||
751 | /* | ||
752 | * Once hibernation starts to use swap, we freeze swap_map[]. Otherwise, | ||
753 | * saved swap_map[] image to the disk will be an incomplete because it's | ||
754 | * changing without synchronization with hibernation snap shot. | ||
755 | * At resume, we just make swap_for_hibernation=false. We can forget | ||
756 | * used maps easily. | ||
757 | */ | ||
758 | void hibernation_freeze_swap(void) | ||
759 | { | ||
760 | int i; | ||
761 | |||
762 | spin_lock(&swap_lock); | ||
763 | |||
764 | printk(KERN_INFO "PM: Freeze Swap\n"); | ||
765 | swap_for_hibernation = true; | ||
766 | for (i = 0; i < MAX_SWAPFILES; i++) | ||
767 | hibernation_offset[i] = 1; | ||
768 | spin_unlock(&swap_lock); | ||
769 | } | ||
770 | |||
771 | void hibernation_thaw_swap(void) | ||
772 | { | ||
773 | spin_lock(&swap_lock); | ||
774 | if (swap_for_hibernation) { | ||
775 | printk(KERN_INFO "PM: Thaw Swap\n"); | ||
776 | swap_for_hibernation = false; | ||
777 | } | ||
778 | spin_unlock(&swap_lock); | ||
779 | } | ||
780 | |||
781 | /* | ||
782 | * Because updateing swap_map[] can make not-saved-status-change, | ||
783 | * we use our own easy allocator. | ||
784 | * Please see kernel/power/swap.c, Used swaps are recorded into | ||
785 | * RB-tree. | ||
786 | */ | ||
787 | swp_entry_t get_swap_for_hibernation(int type) | ||
788 | { | ||
789 | pgoff_t off; | ||
790 | swp_entry_t val = {0}; | ||
791 | struct swap_info_struct *si; | ||
792 | |||
793 | spin_lock(&swap_lock); | ||
794 | |||
795 | si = swap_info[type]; | ||
796 | if (!si || !(si->flags & SWP_WRITEOK)) | ||
797 | goto done; | ||
798 | |||
799 | for (off = hibernation_offset[type]; off < si->max; ++off) { | ||
800 | if (!si->swap_map[off]) | ||
801 | break; | ||
802 | } | ||
803 | if (off < si->max) { | ||
804 | val = swp_entry(type, off); | ||
805 | hibernation_offset[type] = off + 1; | ||
806 | } | ||
807 | done: | ||
808 | spin_unlock(&swap_lock); | ||
809 | return val; | ||
810 | } | ||
811 | |||
812 | void swap_free_for_hibernation(swp_entry_t ent) | ||
813 | { | ||
814 | /* Nothing to do */ | ||
815 | } | ||
816 | |||
767 | /* | 817 | /* |
768 | * Find the swap type that corresponds to given device (if any). | 818 | * Find the swap type that corresponds to given device (if any). |
769 | * | 819 | * |