// SPDX-License-Identifier: GPL-2.0-only /* * linux/kernel/power/swap.c * * This file provides functions for reading the suspend image from * and writing it to a swap partition. * * Copyright (C) 1998,2001-2005 Pavel Machek <pavel@ucw.cz> * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl> * Copyright (C) 2010-2012 Bojan Smojver <bojan@rexursive.com>
*/
/* * When reading an {un,}compressed image, we may restore pages in place, * in which case some architectures need these pages cleaning before they * can be executed. We don't know which pages these may be, so clean the lot.
*/ staticbool clean_pages_on_read; staticbool clean_pages_on_decompress;
/* * The swap map is a data structure used for keeping track of each page * written to a swap partition. It consists of many swap_map_page * structures that contain each an array of MAP_PAGE_ENTRIES swap entries. * These structures are stored on the swap and linked together with the * help of the .next_swap member. * * The swap map is created during suspend. The swap map pages are * allocated and populated one at a time, so we only need one memory * page to set up the entire structure. * * During resume we pick up all swap_map_page structures into a list.
*/
/* * Number of free pages that are not high.
*/ staticinlineunsignedlong low_free_pages(void)
{ return nr_free_pages() - nr_free_highpages();
}
/* * Number of pages required to be kept free while writing the image. Always * half of all available low pages before the writing starts.
*/ staticinlineunsignedlong reqd_free_pages(void)
{ return low_free_pages() / 2;
}
/* Figure out where to put the new node */ while (*new) {
ext = rb_entry(*new, struct swsusp_extent, node);
parent = *new; if (swap_offset < ext->start) { /* Try to merge */ if (swap_offset == ext->start - 1) {
ext->start--; return 0;
} new = &((*new)->rb_left);
} elseif (swap_offset > ext->end) { /* Try to merge */ if (swap_offset == ext->end + 1) {
ext->end++; return 0;
} new = &((*new)->rb_right);
} else { /* It already is in the tree */ return -EINVAL;
}
} /* Add the new node and rebalance the tree. */
ext = kzalloc(sizeof(struct swsusp_extent), GFP_KERNEL); if (!ext) return -ENOMEM;
offset = swp_offset(get_swap_page_of_type(swap)); if (offset) { if (swsusp_extents_insert(offset))
swap_free(swp_entry(swap, offset)); else return swapdev_block(swap, offset);
} return 0;
}
/* * free_all_swap_pages - free swap pages allocated for saving image data. * It also frees the extents used to register which swap entries had been * allocated.
*/
staticint hib_wait_io(struct hib_bio_batch *hb)
{ /* * We are relying on the behavior of blk_plug that a thread with * a plug will flush the plug list before sleeping.
*/
wait_event(hb->wait, atomic_read(&hb->count) == 0); return blk_status_to_errno(hb->error);
}
/* * Saving part
*/ staticint mark_swapfiles(struct swap_map_handle *handle, unsignedint flags)
{ int error;
/* * Hold the swsusp_header flag. This is used in software_resume() in * 'kernel/power/hibernate' to check if the image is compressed and query * for the compression algorithm support(if so).
*/ unsignedint swsusp_header_flags;
/** * swsusp_swap_check - check if the resume device is a swap device * and get its index (if so) * * This is called before saving image
*/ staticint swsusp_swap_check(void)
{ int res;
if (swsusp_resume_device)
res = swap_type_of(swsusp_resume_device, swsusp_resume_block); else
res = find_first_swap(&swsusp_resume_device); if (res < 0) return res;
root_swap = res;
hib_resume_bdev_file = bdev_file_open_by_dev(swsusp_resume_device,
BLK_OPEN_WRITE, NULL, NULL); if (IS_ERR(hib_resume_bdev_file)) return PTR_ERR(hib_resume_bdev_file);
return 0;
}
/** * write_page - Write one page to given swap location. * @buf: Address we're writing. * @offset: Offset of the swap page we're writing to. * @hb: bio completion batch
*/
if (!handle->cur) return -EINVAL;
offset = alloc_swapdev_block(root_swap);
error = write_page(buf, offset, hb); if (error) return error;
handle->cur->entries[handle->k++] = offset; if (handle->k >= MAP_PAGE_ENTRIES) {
offset = alloc_swapdev_block(root_swap); if (!offset) return -ENOSPC;
handle->cur->next_swap = offset;
error = write_page(handle->cur, handle->cur_swap, hb); if (error) goto out;
clear_page(handle->cur);
handle->cur_swap = offset;
handle->k = 0;
if (hb && low_free_pages() <= handle->reqd_free_pages) {
error = hib_wait_io(hb); if (error) goto out; /* * Recalculate the number of required free pages, to * make sure we never take more than half.
*/
handle->reqd_free_pages = reqd_free_pages();
}
}
out: return error;
}
staticint swap_writer_finish(struct swap_map_handle *handle, unsignedint flags, int error)
{ if (!error) {
pr_info("S");
error = mark_swapfiles(handle, flags);
pr_cont("|\n");
flush_swap_writer(handle);
}
if (error)
free_all_swap_pages(root_swap);
release_swap_writer(handle);
swsusp_close();
return error;
}
/* * Bytes we need for compressed data in worst case. We assume(limitation) * this is the worst of all the compression algorithms.
*/ #define bytes_worst_compress(x) ((x) + ((x) / 16) + 64 + 3 + 2)
/* We need to remember how much compressed data we need to read. */ #define CMP_HEADER sizeof(size_t)
/* Number of pages/bytes we'll compress at one time. */ #define UNC_PAGES 32 #define UNC_SIZE (UNC_PAGES * PAGE_SIZE)
/* Number of pages we need for compressed data (worst case). */ #define CMP_PAGES DIV_ROUND_UP(bytes_worst_compress(UNC_SIZE) + \
CMP_HEADER, PAGE_SIZE) #define CMP_SIZE (CMP_PAGES * PAGE_SIZE)
/* Maximum number of threads for compression/decompression. */ #define CMP_THREADS 3
/* Minimum/maximum number of pages for read buffering. */ #define CMP_MIN_RD_PAGES 1024 #define CMP_MAX_RD_PAGES 8192
/** * save_image - save the suspend image data
*/
staticint save_image(struct swap_map_handle *handle, struct snapshot_handle *snapshot, unsignedint nr_to_write)
{ unsignedint m; int ret; int nr_pages; int err2; struct hib_bio_batch hb;
ktime_t start;
ktime_t stop;
hib_init_batch(&hb);
pr_info("Saving image data pages (%u pages)...\n",
nr_to_write);
m = nr_to_write / 10; if (!m)
m = 1;
nr_pages = 0;
start = ktime_get(); while (1) {
ret = snapshot_read_next(snapshot); if (ret <= 0) break;
ret = swap_write_page(handle, data_of(*snapshot), &hb); if (ret) break; if (!(nr_pages % m))
pr_info("Image saving progress: %3d%%\n",
nr_pages / m * 10);
nr_pages++;
}
err2 = hib_wait_io(&hb);
hib_finish_batch(&hb);
stop = ktime_get(); if (!ret)
ret = err2; if (!ret)
pr_info("Image saving done\n");
swsusp_show_speed(start, stop, nr_to_write, "Wrote"); return ret;
}
/* * Structure used for CRC32.
*/ struct crc_data { struct task_struct *thr; /* thread */
atomic_t ready; /* ready to start flag */
atomic_t stop; /* ready to stop flag */ unsigned run_threads; /* nr current threads */
wait_queue_head_t go; /* start crc update */
wait_queue_head_t done; /* crc update done */
u32 *crc32; /* points to handle's crc32 */
size_t *unc_len[CMP_THREADS]; /* uncompressed lengths */ unsignedchar *unc[CMP_THREADS]; /* uncompressed data */
};
/* * CRC32 update function that runs in its own thread.
*/ staticint crc32_threadfn(void *data)
{ struct crc_data *d = data; unsigned i;
while (1) {
wait_event(d->go, atomic_read_acquire(&d->ready) ||
kthread_should_stop()); if (kthread_should_stop()) {
d->thr = NULL;
atomic_set_release(&d->stop, 1);
wake_up(&d->done); break;
}
atomic_set(&d->ready, 0);
for (i = 0; i < d->run_threads; i++)
*d->crc32 = crc32_le(*d->crc32,
d->unc[i], *d->unc_len[i]);
atomic_set_release(&d->stop, 1);
wake_up(&d->done);
} return 0;
} /* * Structure used for data compression.
*/ struct cmp_data { struct task_struct *thr; /* thread */ struct crypto_acomp *cc; /* crypto compressor */ struct acomp_req *cr; /* crypto request */
atomic_t ready; /* ready to start flag */
atomic_t stop; /* ready to stop flag */ int ret; /* return code */
wait_queue_head_t go; /* start compression */
wait_queue_head_t done; /* compression done */
size_t unc_len; /* uncompressed length */
size_t cmp_len; /* compressed length */ unsignedchar unc[UNC_SIZE]; /* uncompressed buffer */ unsignedchar cmp[CMP_SIZE]; /* compressed buffer */
};
/* Indicates the image size after compression */ static atomic64_t compressed_size = ATOMIC_INIT(0);
/* * Compression function that runs in its own thread.
*/ staticint compress_threadfn(void *data)
{ struct cmp_data *d = data;
/** * save_compressed_image - Save the suspend image data after compression. * @handle: Swap map handle to use for saving the image. * @snapshot: Image to read data from. * @nr_to_write: Number of pages to save.
*/ staticint save_compressed_image(struct swap_map_handle *handle, struct snapshot_handle *snapshot, unsignedint nr_to_write)
{ unsignedint m; int ret = 0; int nr_pages; int err2; struct hib_bio_batch hb;
ktime_t start;
ktime_t stop;
size_t off; unsigned thr, run_threads, nr_threads; unsignedchar *page = NULL; struct cmp_data *data = NULL; struct crc_data *crc = NULL;
hib_init_batch(&hb);
atomic64_set(&compressed_size, 0);
/* * We'll limit the number of threads for compression to limit memory * footprint.
*/
nr_threads = num_online_cpus() - 1;
nr_threads = clamp_val(nr_threads, 1, CMP_THREADS);
page = (void *)__get_free_page(GFP_NOIO | __GFP_HIGH); if (!page) {
pr_err("Failed to allocate %s page\n", hib_comp_algo);
ret = -ENOMEM; goto out_clean;
}
data = vzalloc(array_size(nr_threads, sizeof(*data))); if (!data) {
pr_err("Failed to allocate %s data\n", hib_comp_algo);
ret = -ENOMEM; goto out_clean;
}
crc = kzalloc(sizeof(*crc), GFP_KERNEL); if (!crc) {
pr_err("Failed to allocate crc\n");
ret = -ENOMEM; goto out_clean;
}
/* * Start the compression threads.
*/ for (thr = 0; thr < nr_threads; thr++) {
init_waitqueue_head(&data[thr].go);
init_waitqueue_head(&data[thr].done);
data[thr].cc = crypto_alloc_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC); if (IS_ERR_OR_NULL(data[thr].cc)) {
pr_err("Could not allocate comp stream %ld\n", PTR_ERR(data[thr].cc));
ret = -EFAULT; goto out_clean;
}
data[thr].cr = acomp_request_alloc(data[thr].cc); if (!data[thr].cr) {
pr_err("Could not allocate comp request\n");
ret = -ENOMEM; goto out_clean;
}
/* * Adjust the number of required free pages after all allocations have * been done. We don't want to run out of pages when writing.
*/
handle->reqd_free_pages = reqd_free_pages();
pr_info("Using %u thread(s) for %s compression\n", nr_threads, hib_comp_algo);
pr_info("Compressing and saving image data (%u pages)...\n",
nr_to_write);
m = nr_to_write / 10; if (!m)
m = 1;
nr_pages = 0;
start = ktime_get(); for (;;) { for (thr = 0; thr < nr_threads; thr++) { for (off = 0; off < UNC_SIZE; off += PAGE_SIZE) {
ret = snapshot_read_next(snapshot); if (ret < 0) goto out_finish;
if (unlikely(!data[thr].cmp_len ||
data[thr].cmp_len >
bytes_worst_compress(data[thr].unc_len))) {
pr_err("Invalid %s compressed length\n", hib_comp_algo);
ret = -1; goto out_finish;
}
*(size_t *)data[thr].cmp = data[thr].cmp_len;
/* * Given we are writing one page at a time to disk, we * copy that much from the buffer, although the last * bit will likely be smaller than full page. This is * OK - we saved the length of the compressed data, so * any garbage at the end will be discarded when we * read it.
*/ for (off = 0;
off < CMP_HEADER + data[thr].cmp_len;
off += PAGE_SIZE) {
memcpy(page, data[thr].cmp + off, PAGE_SIZE);
ret = swap_write_page(handle, page, &hb); if (ret) goto out_finish;
}
}
out_finish:
err2 = hib_wait_io(&hb);
stop = ktime_get(); if (!ret)
ret = err2; if (!ret) {
swsusp_show_speed(start, stop, nr_to_write, "Wrote");
pr_info("Image size after compression: %lld kbytes\n",
(atomic64_read(&compressed_size) / 1024));
pr_info("Image saving done\n");
} else {
pr_err("Image saving failed: %d\n", ret);
}
out_clean:
hib_finish_batch(&hb); if (crc) { if (crc->thr)
kthread_stop(crc->thr);
kfree(crc);
} if (data) { for (thr = 0; thr < nr_threads; thr++) { if (data[thr].thr)
kthread_stop(data[thr].thr);
acomp_request_free(data[thr].cr);
crypto_free_acomp(data[thr].cc);
}
vfree(data);
} if (page) free_page((unsignedlong)page);
return ret;
}
/** * enough_swap - Make sure we have enough swap to save the image. * * Returns TRUE or FALSE after checking the total amount of swap * space available from the resume partition.
*/
/** * swsusp_write - Write entire image and metadata. * @flags: flags to pass to the "boot" kernel in the image header * * It is important _NOT_ to umount filesystems at this point. We want * them synced (in case something goes wrong) but we DO not want to mark * filesystem clean: it is not. (And it does not matter, if we resume * correctly, we'll mark system clean, anyway.)
*/
int swsusp_write(unsignedint flags)
{ struct swap_map_handle handle; struct snapshot_handle snapshot; struct swsusp_info *header; unsignedlong pages; int error;
pages = snapshot_get_image_size();
error = get_swap_writer(&handle); if (error) {
pr_err("Cannot get swap writer\n"); return error;
} if (flags & SF_NOCOMPRESS_MODE) { if (!enough_swap(pages)) {
pr_err("Not enough free swap\n");
error = -ENOSPC; goto out_finish;
}
}
memset(&snapshot, 0, sizeof(struct snapshot_handle));
error = snapshot_read_next(&snapshot); if (error < (int)PAGE_SIZE) { if (error >= 0)
error = -EFAULT;
/** * load_image - load the image using the swap map handle * @handle and the snapshot handle @snapshot * (assume there are @nr_pages pages to load)
*/
staticint load_image(struct swap_map_handle *handle, struct snapshot_handle *snapshot, unsignedint nr_to_read)
{ unsignedint m; int ret = 0;
ktime_t start;
ktime_t stop; struct hib_bio_batch hb; int err2; unsigned nr_pages;
hib_init_batch(&hb);
clean_pages_on_read = true;
pr_info("Loading image data pages (%u pages)...\n", nr_to_read);
m = nr_to_read / 10; if (!m)
m = 1;
nr_pages = 0;
start = ktime_get(); for ( ; ; ) {
ret = snapshot_write_next(snapshot); if (ret <= 0) break;
ret = swap_read_page(handle, data_of(*snapshot), &hb); if (ret) break; if (snapshot->sync_read)
ret = hib_wait_io(&hb); if (ret) break; if (!(nr_pages % m))
pr_info("Image loading progress: %3d%%\n",
nr_pages / m * 10);
nr_pages++;
}
err2 = hib_wait_io(&hb);
hib_finish_batch(&hb);
stop = ktime_get(); if (!ret)
ret = err2; if (!ret) {
pr_info("Image loading done\n");
ret = snapshot_write_finalize(snapshot); if (!ret && !snapshot_image_loaded(snapshot))
ret = -ENODATA;
}
swsusp_show_speed(start, stop, nr_to_read, "Read"); return ret;
}
/** * load_compressed_image - Load compressed image data and decompress it. * @handle: Swap map handle to use for loading data. * @snapshot: Image to copy uncompressed data into. * @nr_to_read: Number of pages to load.
*/ staticint load_compressed_image(struct swap_map_handle *handle, struct snapshot_handle *snapshot, unsignedint nr_to_read)
{ unsignedint m; int ret = 0; int eof = 0; struct hib_bio_batch hb;
ktime_t start;
ktime_t stop; unsigned nr_pages;
size_t off; unsigned i, thr, run_threads, nr_threads; unsigned ring = 0, pg = 0, ring_size = 0,
have = 0, want, need, asked = 0; unsignedlong read_pages = 0; unsignedchar **page = NULL; struct dec_data *data = NULL; struct crc_data *crc = NULL;
hib_init_batch(&hb);
/* * We'll limit the number of threads for decompression to limit memory * footprint.
*/
nr_threads = num_online_cpus() - 1;
nr_threads = clamp_val(nr_threads, 1, CMP_THREADS);
page = vmalloc(array_size(CMP_MAX_RD_PAGES, sizeof(*page))); if (!page) {
pr_err("Failed to allocate %s page\n", hib_comp_algo);
ret = -ENOMEM; goto out_clean;
}
data = vzalloc(array_size(nr_threads, sizeof(*data))); if (!data) {
pr_err("Failed to allocate %s data\n", hib_comp_algo);
ret = -ENOMEM; goto out_clean;
}
crc = kzalloc(sizeof(*crc), GFP_KERNEL); if (!crc) {
pr_err("Failed to allocate crc\n");
ret = -ENOMEM; goto out_clean;
}
clean_pages_on_decompress = true;
/* * Start the decompression threads.
*/ for (thr = 0; thr < nr_threads; thr++) {
init_waitqueue_head(&data[thr].go);
init_waitqueue_head(&data[thr].done);
data[thr].cc = crypto_alloc_acomp(hib_comp_algo, 0, CRYPTO_ALG_ASYNC); if (IS_ERR_OR_NULL(data[thr].cc)) {
pr_err("Could not allocate comp stream %ld\n", PTR_ERR(data[thr].cc));
ret = -EFAULT; goto out_clean;
}
data[thr].cr = acomp_request_alloc(data[thr].cc); if (!data[thr].cr) {
pr_err("Could not allocate comp request\n");
ret = -ENOMEM; goto out_clean;
}
/* * Set the number of pages for read buffering. * This is complete guesswork, because we'll only know the real * picture once prepare_image() is called, which is much later on * during the image load phase. We'll assume the worst case and * say that none of the image pages are from high memory.
*/ if (low_free_pages() > snapshot_get_image_size())
read_pages = (low_free_pages() - snapshot_get_image_size()) / 2;
read_pages = clamp_val(read_pages, CMP_MIN_RD_PAGES, CMP_MAX_RD_PAGES);
for (i = 0; i < read_pages; i++) {
page[i] = (void *)__get_free_page(i < CMP_PAGES ?
GFP_NOIO | __GFP_HIGH :
GFP_NOIO | __GFP_NOWARN |
__GFP_NORETRY);
if (!page[i]) { if (i < CMP_PAGES) {
ring_size = i;
pr_err("Failed to allocate %s pages\n", hib_comp_algo);
ret = -ENOMEM; goto out_clean;
} else { break;
}
}
}
want = ring_size = i;
pr_info("Using %u thread(s) for %s decompression\n", nr_threads, hib_comp_algo);
pr_info("Loading and decompressing image data (%u pages)...\n",
nr_to_read);
m = nr_to_read / 10; if (!m)
m = 1;
nr_pages = 0;
start = ktime_get();
ret = snapshot_write_next(snapshot); if (ret <= 0) goto out_finish;
for(;;) { for (i = 0; !eof && i < want; i++) {
ret = swap_read_page(handle, page[ring], &hb); if (ret) { /* * On real read error, finish. On end of data, * set EOF flag and just exit the read loop.
*/ if (handle->cur &&
handle->cur->entries[handle->k]) { goto out_finish;
} else {
eof = 1; break;
}
} if (++ring >= ring_size)
ring = 0;
}
asked += i;
want -= i;
/* * We are out of data, wait for some more.
*/ if (!have) { if (!asked) break;
ret = hib_wait_io(&hb); if (ret) goto out_finish;
have += asked;
asked = 0; if (eof)
eof = 2;
}
/* * Wait for more data while we are decompressing.
*/ if (have < CMP_PAGES && asked) {
ret = hib_wait_io(&hb); if (ret) goto out_finish;
have += asked;
asked = 0; if (eof)
eof = 2;
}
out_finish: if (crc->run_threads) {
wait_event(crc->done, atomic_read_acquire(&crc->stop));
atomic_set(&crc->stop, 0);
}
stop = ktime_get(); if (!ret) {
pr_info("Image loading done\n");
ret = snapshot_write_finalize(snapshot); if (!ret && !snapshot_image_loaded(snapshot))
ret = -ENODATA; if (!ret) { if (swsusp_header->flags & SF_CRC32_MODE) { if(handle->crc32 != swsusp_header->crc32) {
pr_err("Invalid image CRC32!\n");
ret = -ENODATA;
}
}
}
}
swsusp_show_speed(start, stop, nr_to_read, "Read");
out_clean:
hib_finish_batch(&hb); for (i = 0; i < ring_size; i++)
free_page((unsignedlong)page[i]); if (crc) { if (crc->thr)
kthread_stop(crc->thr);
kfree(crc);
} if (data) { for (thr = 0; thr < nr_threads; thr++) { if (data[thr].thr)
kthread_stop(data[thr].thr);
acomp_request_free(data[thr].cr);
crypto_free_acomp(data[thr].cc);
}
vfree(data);
}
vfree(page);
return ret;
}
/** * swsusp_read - read the hibernation image. * @flags_p: flags passed by the "frozen" kernel in the image header should * be written into this memory location
*/
int swsusp_read(unsignedint *flags_p)
{ int error; struct swap_map_handle handle; struct snapshot_handle snapshot; struct swsusp_info *header;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.