diff options
Diffstat (limited to 'kernel/power/snapshot.c')
-rw-r--r-- | kernel/power/snapshot.c | 141 |
1 files changed, 84 insertions, 57 deletions
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 | /** | 404 | static 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 | |||
411 | struct eaten_page { | ||
412 | struct eaten_page *next; | ||
413 | char padding[PAGE_SIZE - sizeof(void *)]; | ||
414 | }; | ||
415 | |||
416 | static struct eaten_page *eaten_pages = NULL; | ||
417 | |||
418 | static 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 | ||
444 | static inline void *alloc_image_page(gfp_t gfp_mask, int safe_needed) | 415 | static 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 | ||
838 | static int create_image(struct snapshot_handle *handle) | 813 | struct safe_page { |
814 | struct safe_page *next; | ||
815 | char padding[PAGE_SIZE - sizeof(void *)]; | ||
816 | }; | ||
817 | |||
818 | static struct safe_page *safe_pages; | ||
819 | |||
820 | static 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 | ||
866 | static 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 | } |