diff options
Diffstat (limited to 'kernel/power/snapshot.c')
-rw-r--r-- | kernel/power/snapshot.c | 145 |
1 files changed, 56 insertions, 89 deletions
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c index be861c26dda7..25ce010e9f8b 100644 --- a/kernel/power/snapshot.c +++ b/kernel/power/snapshot.c | |||
@@ -1604,14 +1604,9 @@ pack_pfns(unsigned long *buf, struct memory_bitmap *bm) | |||
1604 | * snapshot_handle structure. The structure gets updated and a pointer | 1604 | * snapshot_handle structure. The structure gets updated and a pointer |
1605 | * to it should be passed to this function every next time. | 1605 | * to it should be passed to this function every next time. |
1606 | * | 1606 | * |
1607 | * The @count parameter should contain the number of bytes the caller | ||
1608 | * wants to read from the snapshot. It must not be zero. | ||
1609 | * | ||
1610 | * On success the function returns a positive number. Then, the caller | 1607 | * On success the function returns a positive number. Then, the caller |
1611 | * is allowed to read up to the returned number of bytes from the memory | 1608 | * is allowed to read up to the returned number of bytes from the memory |
1612 | * location computed by the data_of() macro. The number returned | 1609 | * location computed by the data_of() macro. |
1613 | * may be smaller than @count, but this only happens if the read would | ||
1614 | * cross a page boundary otherwise. | ||
1615 | * | 1610 | * |
1616 | * The function returns 0 to indicate the end of data stream condition, | 1611 | * The function returns 0 to indicate the end of data stream condition, |
1617 | * and a negative number is returned on error. In such cases the | 1612 | * and a negative number is returned on error. In such cases the |
@@ -1619,7 +1614,7 @@ pack_pfns(unsigned long *buf, struct memory_bitmap *bm) | |||
1619 | * any more. | 1614 | * any more. |
1620 | */ | 1615 | */ |
1621 | 1616 | ||
1622 | int snapshot_read_next(struct snapshot_handle *handle, size_t count) | 1617 | int snapshot_read_next(struct snapshot_handle *handle) |
1623 | { | 1618 | { |
1624 | if (handle->cur > nr_meta_pages + nr_copy_pages) | 1619 | if (handle->cur > nr_meta_pages + nr_copy_pages) |
1625 | return 0; | 1620 | return 0; |
@@ -1630,7 +1625,7 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count) | |||
1630 | if (!buffer) | 1625 | if (!buffer) |
1631 | return -ENOMEM; | 1626 | return -ENOMEM; |
1632 | } | 1627 | } |
1633 | if (!handle->offset) { | 1628 | if (!handle->cur) { |
1634 | int error; | 1629 | int error; |
1635 | 1630 | ||
1636 | error = init_header((struct swsusp_info *)buffer); | 1631 | error = init_header((struct swsusp_info *)buffer); |
@@ -1639,42 +1634,30 @@ int snapshot_read_next(struct snapshot_handle *handle, size_t count) | |||
1639 | handle->buffer = buffer; | 1634 | handle->buffer = buffer; |
1640 | memory_bm_position_reset(&orig_bm); | 1635 | memory_bm_position_reset(&orig_bm); |
1641 | memory_bm_position_reset(©_bm); | 1636 | memory_bm_position_reset(©_bm); |
1642 | } | 1637 | } else if (handle->cur <= nr_meta_pages) { |
1643 | if (handle->prev < handle->cur) { | 1638 | memset(buffer, 0, PAGE_SIZE); |
1644 | if (handle->cur <= nr_meta_pages) { | 1639 | pack_pfns(buffer, &orig_bm); |
1645 | memset(buffer, 0, PAGE_SIZE); | 1640 | } else { |
1646 | pack_pfns(buffer, &orig_bm); | 1641 | struct page *page; |
1647 | } else { | ||
1648 | struct page *page; | ||
1649 | 1642 | ||
1650 | page = pfn_to_page(memory_bm_next_pfn(©_bm)); | 1643 | page = pfn_to_page(memory_bm_next_pfn(©_bm)); |
1651 | if (PageHighMem(page)) { | 1644 | if (PageHighMem(page)) { |
1652 | /* Highmem pages are copied to the buffer, | 1645 | /* Highmem pages are copied to the buffer, |
1653 | * because we can't return with a kmapped | 1646 | * because we can't return with a kmapped |
1654 | * highmem page (we may not be called again). | 1647 | * highmem page (we may not be called again). |
1655 | */ | 1648 | */ |
1656 | void *kaddr; | 1649 | void *kaddr; |
1657 | 1650 | ||
1658 | kaddr = kmap_atomic(page, KM_USER0); | 1651 | kaddr = kmap_atomic(page, KM_USER0); |
1659 | memcpy(buffer, kaddr, PAGE_SIZE); | 1652 | memcpy(buffer, kaddr, PAGE_SIZE); |
1660 | kunmap_atomic(kaddr, KM_USER0); | 1653 | kunmap_atomic(kaddr, KM_USER0); |
1661 | handle->buffer = buffer; | 1654 | handle->buffer = buffer; |
1662 | } else { | 1655 | } else { |
1663 | handle->buffer = page_address(page); | 1656 | handle->buffer = page_address(page); |
1664 | } | ||
1665 | } | 1657 | } |
1666 | handle->prev = handle->cur; | ||
1667 | } | ||
1668 | handle->buf_offset = handle->cur_offset; | ||
1669 | if (handle->cur_offset + count >= PAGE_SIZE) { | ||
1670 | count = PAGE_SIZE - handle->cur_offset; | ||
1671 | handle->cur_offset = 0; | ||
1672 | handle->cur++; | ||
1673 | } else { | ||
1674 | handle->cur_offset += count; | ||
1675 | } | 1658 | } |
1676 | handle->offset += count; | 1659 | handle->cur++; |
1677 | return count; | 1660 | return PAGE_SIZE; |
1678 | } | 1661 | } |
1679 | 1662 | ||
1680 | /** | 1663 | /** |
@@ -2133,14 +2116,9 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) | |||
2133 | * snapshot_handle structure. The structure gets updated and a pointer | 2116 | * snapshot_handle structure. The structure gets updated and a pointer |
2134 | * to it should be passed to this function every next time. | 2117 | * to it should be passed to this function every next time. |
2135 | * | 2118 | * |
2136 | * The @count parameter should contain the number of bytes the caller | ||
2137 | * wants to write to the image. It must not be zero. | ||
2138 | * | ||
2139 | * On success the function returns a positive number. Then, the caller | 2119 | * On success the function returns a positive number. Then, the caller |
2140 | * is allowed to write up to the returned number of bytes to the memory | 2120 | * is allowed to write up to the returned number of bytes to the memory |
2141 | * location computed by the data_of() macro. The number returned | 2121 | * location computed by the data_of() macro. |
2142 | * may be smaller than @count, but this only happens if the write would | ||
2143 | * cross a page boundary otherwise. | ||
2144 | * | 2122 | * |
2145 | * The function returns 0 to indicate the "end of file" condition, | 2123 | * The function returns 0 to indicate the "end of file" condition, |
2146 | * and a negative number is returned on error. In such cases the | 2124 | * and a negative number is returned on error. In such cases the |
@@ -2148,16 +2126,18 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) | |||
2148 | * any more. | 2126 | * any more. |
2149 | */ | 2127 | */ |
2150 | 2128 | ||
2151 | int snapshot_write_next(struct snapshot_handle *handle, size_t count) | 2129 | int snapshot_write_next(struct snapshot_handle *handle) |
2152 | { | 2130 | { |
2153 | static struct chain_allocator ca; | 2131 | static struct chain_allocator ca; |
2154 | int error = 0; | 2132 | int error = 0; |
2155 | 2133 | ||
2156 | /* Check if we have already loaded the entire image */ | 2134 | /* Check if we have already loaded the entire image */ |
2157 | if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) | 2135 | if (handle->cur > 1 && handle->cur > nr_meta_pages + nr_copy_pages) |
2158 | return 0; | 2136 | return 0; |
2159 | 2137 | ||
2160 | if (handle->offset == 0) { | 2138 | handle->sync_read = 1; |
2139 | |||
2140 | if (!handle->cur) { | ||
2161 | if (!buffer) | 2141 | if (!buffer) |
2162 | /* This makes the buffer be freed by swsusp_free() */ | 2142 | /* This makes the buffer be freed by swsusp_free() */ |
2163 | buffer = get_image_page(GFP_ATOMIC, PG_ANY); | 2143 | buffer = get_image_page(GFP_ATOMIC, PG_ANY); |
@@ -2166,56 +2146,43 @@ int snapshot_write_next(struct snapshot_handle *handle, size_t count) | |||
2166 | return -ENOMEM; | 2146 | return -ENOMEM; |
2167 | 2147 | ||
2168 | handle->buffer = buffer; | 2148 | handle->buffer = buffer; |
2169 | } | 2149 | } else if (handle->cur == 1) { |
2170 | handle->sync_read = 1; | 2150 | error = load_header(buffer); |
2171 | if (handle->prev < handle->cur) { | 2151 | if (error) |
2172 | if (handle->prev == 0) { | 2152 | return error; |
2173 | error = load_header(buffer); | ||
2174 | if (error) | ||
2175 | return error; | ||
2176 | 2153 | ||
2177 | error = memory_bm_create(©_bm, GFP_ATOMIC, PG_ANY); | 2154 | error = memory_bm_create(©_bm, GFP_ATOMIC, PG_ANY); |
2178 | if (error) | 2155 | if (error) |
2179 | return error; | 2156 | return error; |
2157 | |||
2158 | } else if (handle->cur <= nr_meta_pages + 1) { | ||
2159 | error = unpack_orig_pfns(buffer, ©_bm); | ||
2160 | if (error) | ||
2161 | return error; | ||
2180 | 2162 | ||
2181 | } else if (handle->prev <= nr_meta_pages) { | 2163 | if (handle->cur == nr_meta_pages + 1) { |
2182 | error = unpack_orig_pfns(buffer, ©_bm); | 2164 | error = prepare_image(&orig_bm, ©_bm); |
2183 | if (error) | 2165 | if (error) |
2184 | return error; | 2166 | return error; |
2185 | 2167 | ||
2186 | if (handle->prev == nr_meta_pages) { | 2168 | chain_init(&ca, GFP_ATOMIC, PG_SAFE); |
2187 | error = prepare_image(&orig_bm, ©_bm); | 2169 | memory_bm_position_reset(&orig_bm); |
2188 | if (error) | 2170 | restore_pblist = NULL; |
2189 | return error; | ||
2190 | |||
2191 | chain_init(&ca, GFP_ATOMIC, PG_SAFE); | ||
2192 | memory_bm_position_reset(&orig_bm); | ||
2193 | restore_pblist = NULL; | ||
2194 | handle->buffer = get_buffer(&orig_bm, &ca); | ||
2195 | handle->sync_read = 0; | ||
2196 | if (IS_ERR(handle->buffer)) | ||
2197 | return PTR_ERR(handle->buffer); | ||
2198 | } | ||
2199 | } else { | ||
2200 | copy_last_highmem_page(); | ||
2201 | handle->buffer = get_buffer(&orig_bm, &ca); | 2171 | handle->buffer = get_buffer(&orig_bm, &ca); |
2172 | handle->sync_read = 0; | ||
2202 | if (IS_ERR(handle->buffer)) | 2173 | if (IS_ERR(handle->buffer)) |
2203 | return PTR_ERR(handle->buffer); | 2174 | return PTR_ERR(handle->buffer); |
2204 | if (handle->buffer != buffer) | ||
2205 | handle->sync_read = 0; | ||
2206 | } | 2175 | } |
2207 | handle->prev = handle->cur; | ||
2208 | } | ||
2209 | handle->buf_offset = handle->cur_offset; | ||
2210 | if (handle->cur_offset + count >= PAGE_SIZE) { | ||
2211 | count = PAGE_SIZE - handle->cur_offset; | ||
2212 | handle->cur_offset = 0; | ||
2213 | handle->cur++; | ||
2214 | } else { | 2176 | } else { |
2215 | handle->cur_offset += count; | 2177 | copy_last_highmem_page(); |
2178 | handle->buffer = get_buffer(&orig_bm, &ca); | ||
2179 | if (IS_ERR(handle->buffer)) | ||
2180 | return PTR_ERR(handle->buffer); | ||
2181 | if (handle->buffer != buffer) | ||
2182 | handle->sync_read = 0; | ||
2216 | } | 2183 | } |
2217 | handle->offset += count; | 2184 | handle->cur++; |
2218 | return count; | 2185 | return PAGE_SIZE; |
2219 | } | 2186 | } |
2220 | 2187 | ||
2221 | /** | 2188 | /** |
@@ -2230,7 +2197,7 @@ void snapshot_write_finalize(struct snapshot_handle *handle) | |||
2230 | { | 2197 | { |
2231 | copy_last_highmem_page(); | 2198 | copy_last_highmem_page(); |
2232 | /* Free only if we have loaded the image entirely */ | 2199 | /* Free only if we have loaded the image entirely */ |
2233 | if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) { | 2200 | if (handle->cur > 1 && handle->cur > nr_meta_pages + nr_copy_pages) { |
2234 | memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR); | 2201 | memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR); |
2235 | free_highmem_data(); | 2202 | free_highmem_data(); |
2236 | } | 2203 | } |