aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/power/power.h2
-rw-r--r--kernel/power/snapshot.c141
2 files changed, 85 insertions, 58 deletions
diff --git a/kernel/power/power.h b/kernel/power/power.h
index c81f0ed3eeba..98c41423f3b1 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -55,7 +55,7 @@ struct snapshot_handle {
55 unsigned int page; 55 unsigned int page;
56 unsigned int page_offset; 56 unsigned int page_offset;
57 unsigned int prev; 57 unsigned int prev;
58 struct pbe *pbe; 58 struct pbe *pbe, *last_pbe;
59 void *buffer; 59 void *buffer;
60 unsigned int buf_offset; 60 unsigned int buf_offset;
61}; 61};
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 513eef3391a0..3d9284100b22 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -401,62 +401,29 @@ static inline void create_pbe_list(struct pbe *pblist, unsigned int nr_pages)
401 } 401 }
402} 402}
403 403
404/** 404static unsigned int unsafe_pages;
405 * On resume it is necessary to trace and eventually free the unsafe
406 * pages that have been allocated, because they are needed for I/O
407 * (on x86-64 we likely will "eat" these pages once again while
408 * creating the temporary page translation tables)
409 */
410
411struct eaten_page {
412 struct eaten_page *next;
413 char padding[PAGE_SIZE - sizeof(void *)];
414};
415
416static struct eaten_page *eaten_pages = NULL;
417
418static void release_eaten_pages(void)
419{
420 struct eaten_page *p, *q;
421
422 p = eaten_pages;
423 while (p) {
424 q = p->next;
425 /* We don't want swsusp_free() to free this page again */
426 ClearPageNosave(virt_to_page(p));
427 free_page((unsigned long)p);
428 p = q;
429 }
430 eaten_pages = NULL;
431}
432 405
433/** 406/**
434 * @safe_needed - on resume, for storing the PBE list and the image, 407 * @safe_needed - on resume, for storing the PBE list and the image,
435 * we can only use memory pages that do not conflict with the pages 408 * we can only use memory pages that do not conflict with the pages
436 * which had been used before suspend. 409 * used before suspend.
437 * 410 *
438 * The unsafe pages are marked with the PG_nosave_free flag 411 * The unsafe pages are marked with the PG_nosave_free flag
439 * 412 * and we count them using unsafe_pages
440 * Allocated but unusable (ie eaten) memory pages should be marked
441 * so that swsusp_free() can release them
442 */ 413 */
443 414
444static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed) 415static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed)
445{ 416{
446 void *res; 417 void *res;
447 418
419 res = (void *)get_zeroed_page(gfp_mask);
448 if (safe_needed) 420 if (safe_needed)
449 do { 421 while (res && PageNosaveFree(virt_to_page(res))) {
422 /* The page is unsafe, mark it for swsusp_free() */
423 SetPageNosave(virt_to_page(res));
424 unsafe_pages++;
450 res = (void *)get_zeroed_page(gfp_mask); 425 res = (void *)get_zeroed_page(gfp_mask);
451 if (res && PageNosaveFree(virt_to_page(res))) { 426 }
452 /* This is for swsusp_free() */
453 SetPageNosave(virt_to_page(res));
454 ((struct eaten_page *)res)->next = eaten_pages;
455 eaten_pages = res;
456 }
457 } while (res && PageNosaveFree(virt_to_page(res)));
458 else
459 res = (void *)get_zeroed_page(gfp_mask);
460 if (res) { 427 if (res) {
461 SetPageNosave(virt_to_page(res)); 428 SetPageNosave(virt_to_page(res));
462 SetPageNosaveFree(virt_to_page(res)); 429 SetPageNosaveFree(virt_to_page(res));
@@ -751,6 +718,8 @@ static int mark_unsafe_pages(struct pbe *pblist)
751 return -EFAULT; 718 return -EFAULT;
752 } 719 }
753 720
721 unsafe_pages = 0;
722
754 return 0; 723 return 0;
755} 724}
756 725
@@ -828,42 +797,99 @@ static inline struct pbe *unpack_orig_addresses(unsigned long *buf,
828} 797}
829 798
830/** 799/**
831 * create_image - use metadata contained in the PBE list 800 * prepare_image - use metadata contained in the PBE list
832 * pointed to by pagedir_nosave to mark the pages that will 801 * pointed to by pagedir_nosave to mark the pages that will
833 * be overwritten in the process of restoring the system 802 * be overwritten in the process of restoring the system
834 * memory state from the image and allocate memory for 803 * memory state from the image ("unsafe" pages) and allocate
835 * the image avoiding these pages 804 * memory for the image
805 *
806 * The idea is to allocate the PBE list first and then
807 * allocate as many pages as it's needed for the image data,
808 * but not to assign these pages to the PBEs initially.
809 * Instead, we just mark them as allocated and create a list
810 * of "safe" which will be used later
836 */ 811 */
837 812
838static int create_image(struct snapshot_handle *handle) 813struct safe_page {
814 struct safe_page *next;
815 char padding[PAGE_SIZE - sizeof(void *)];
816};
817
818static struct safe_page *safe_pages;
819
820static int prepare_image(struct snapshot_handle *handle)
839{ 821{
840 int error = 0; 822 int error = 0;
841 struct pbe *p, *pblist; 823 unsigned int nr_pages = nr_copy_pages;
824 struct pbe *p, *pblist = NULL;
842 825
843 p = pagedir_nosave; 826 p = pagedir_nosave;
844 error = mark_unsafe_pages(p); 827 error = mark_unsafe_pages(p);
845 if (!error) { 828 if (!error) {
846 pblist = alloc_pagedir(nr_copy_pages, GFP_ATOMIC, 1); 829 pblist = alloc_pagedir(nr_pages, GFP_ATOMIC, 1);
847 if (pblist) 830 if (pblist)
848 copy_page_backup_list(pblist, p); 831 copy_page_backup_list(pblist, p);
849 free_pagedir(p, 0); 832 free_pagedir(p, 0);
850 if (!pblist) 833 if (!pblist)
851 error = -ENOMEM; 834 error = -ENOMEM;
852 } 835 }
853 if (!error) 836 safe_pages = NULL;
854 error = alloc_data_pages(pblist, GFP_ATOMIC, 1); 837 if (!error && nr_pages > unsafe_pages) {
838 nr_pages -= unsafe_pages;
839 while (nr_pages--) {
840 struct safe_page *ptr;
841
842 ptr = (struct safe_page *)get_zeroed_page(GFP_ATOMIC);
843 if (!ptr) {
844 error = -ENOMEM;
845 break;
846 }
847 if (!PageNosaveFree(virt_to_page(ptr))) {
848 /* The page is "safe", add it to the list */
849 ptr->next = safe_pages;
850 safe_pages = ptr;
851 }
852 /* Mark the page as allocated */
853 SetPageNosave(virt_to_page(ptr));
854 SetPageNosaveFree(virt_to_page(ptr));
855 }
856 }
855 if (!error) { 857 if (!error) {
856 release_eaten_pages();
857 pagedir_nosave = pblist; 858 pagedir_nosave = pblist;
858 } else { 859 } else {
859 pagedir_nosave = NULL;
860 handle->pbe = NULL; 860 handle->pbe = NULL;
861 nr_copy_pages = 0; 861 swsusp_free();
862 nr_meta_pages = 0;
863 } 862 }
864 return error; 863 return error;
865} 864}
866 865
866static void *get_buffer(struct snapshot_handle *handle)
867{
868 struct pbe *pbe = handle->pbe, *last = handle->last_pbe;
869 struct page *page = virt_to_page(pbe->orig_address);
870
871 if (PageNosave(page) && PageNosaveFree(page)) {
872 /*
873 * We have allocated the "original" page frame and we can
874 * use it directly to store the read page
875 */
876 pbe->address = 0;
877 if (last && last->next)
878 last->next = NULL;
879 return (void *)pbe->orig_address;
880 }
881 /*
882 * The "original" page frame has not been allocated and we have to
883 * use a "safe" page frame to store the read page
884 */
885 pbe->address = (unsigned long)safe_pages;
886 safe_pages = safe_pages->next;
887 if (last)
888 last->next = pbe;
889 handle->last_pbe = pbe;
890 return (void *)pbe->address;
891}
892
867/** 893/**
868 * snapshot_write_next - used for writing the system memory snapshot. 894 * snapshot_write_next - used for writing the system memory snapshot.
869 * 895 *
@@ -908,15 +934,16 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count)
908 } else if (handle->prev <= nr_meta_pages) { 934 } else if (handle->prev <= nr_meta_pages) {
909 handle->pbe = unpack_orig_addresses(buffer, handle->pbe); 935 handle->pbe = unpack_orig_addresses(buffer, handle->pbe);
910 if (!handle->pbe) { 936 if (!handle->pbe) {
911 error = create_image(handle); 937 error = prepare_image(handle);
912 if (error) 938 if (error)
913 return error; 939 return error;
914 handle->pbe = pagedir_nosave; 940 handle->pbe = pagedir_nosave;
915 handle->buffer = (void *)handle->pbe->address; 941 handle->last_pbe = NULL;
942 handle->buffer = get_buffer(handle);
916 } 943 }
917 } else { 944 } else {
918 handle->pbe = handle->pbe->next; 945 handle->pbe = handle->pbe->next;
919 handle->buffer = (void *)handle->pbe->address; 946 handle->buffer = get_buffer(handle);
920 } 947 }
921 handle->prev = handle->page; 948 handle->prev = handle->page;
922 } 949 }