Commit 005e8dddd497 ("PM: hibernate: don't store zero pages in the image file") added an optimization to skip zero-filled pages in the hibernation image. On restore, zero pages are handled internally by snapshot_write_next() in a loop that processes them without returning to the caller. With the userspace restore interface, writing the last non-zero page to /dev/snapshot is followed by the SNAPSHOT_ATOMIC_RESTORE ioctl. At this point there are no more calls to snapshot_write_next() so any trailing zero pages are not processed, snapshot_image_loaded() fails because handle->cur is smaller than expected, the ioctl returns -EPERM and the image is not restored. The in-kernel restore path is not affected by this because the loop in load_image() in swap.c calls snapshot_write_next() until it returns 0. It is this final call that drains any trailing zero pages. Fixed by calling snapshot_write_next() in snapshot_write_finalize(), giving the kernel the chance to drain any trailing zero pages.
Showing the changes to kernel (1 of 1 file). Show all
Unified · Split
| @@ -2855,6 +2855,17 @@ int snapshot_write_finalize(struct snapshot_handle *handle) · 2854 unmodified lines | |||
| 2855 | { | 2855 | { |
| 2856 | int error; | 2856 | int error; |
| 2857 | 2857 | ||
| 2858 | /* | ||
| 2859 | * Call snapshot_write_next() to drain any trailing zero pages, | ||
| 2860 | * but make sure we're in the data page region first. | ||
| 2861 | * This function can return PAGE_SIZE if the kernel was expecting | ||
| 2862 | * another copy page. Return -ENODATA in that situation. | ||
| 2863 | */ | ||
| 2864 | if (handle->cur > nr_meta_pages + 1) { | ||
| 2865 | error = snapshot_write_next(handle); | ||
| 2866 | if (error) | ||
| 2867 | return error > 0 ? -ENODATA : error; | ||
| 2868 | } | ||
| 2858 | copy_last_highmem_page(); | 2869 | copy_last_highmem_page(); |
| 2859 | error = hibernate_restore_protect_page(handle->buffer); | 2870 | error = hibernate_restore_protect_page(handle->buffer); |
| 2860 | /* Do that only if we have loaded the image entirely */ | 2871 | /* Do that only if we have loaded the image entirely */ |