kernel/power/snapshot.c

Source file repositories/reference/linux-study-clean/kernel/power/snapshot.c

File Facts

System
Linux kernel
Corpus path
kernel/power/snapshot.c
Extension
.c
Size
79690 bytes
Lines
2931
Domain
Core OS
Bucket
Scheduler, Processes, Timers, Sync, And Syscalls
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct linked_page {
	struct linked_page *next;
	char data[LINKED_PAGE_DATA_SIZE];
} __packed;

/*
 * List of "safe" pages (ie. pages that were not used by the image kernel
 * before hibernation) that may be used as temporary storage for image kernel
 * memory contents.
 */
static struct linked_page *safe_pages_list;

/* Pointer to an auxiliary buffer (1 page) */
static void *buffer;

#define PG_ANY		0
#define PG_SAFE		1
#define PG_UNSAFE_CLEAR	1
#define PG_UNSAFE_KEEP	0

static unsigned int allocated_unsafe_pages;

/**
 * get_image_page - Allocate a page for a hibernation image.
 * @gfp_mask: GFP mask for the allocation.
 * @safe_needed: Get pages that were not used before hibernation (restore only)
 *
 * During image restoration, for storing the PBE list and the image data, we can
 * only use memory pages that do not conflict with the pages used before
 * hibernation.  The "unsafe" pages have PageNosaveFree set and we count them
 * using allocated_unsafe_pages.
 *
 * Each allocated image page is marked as PageNosave and PageNosaveFree so that
 * swsusp_free() can release it.
 */
static void *get_image_page(gfp_t gfp_mask, int safe_needed)
{
	void *res;

	res = (void *)get_zeroed_page(gfp_mask);
	if (safe_needed)
		while (res && swsusp_page_is_free(virt_to_page(res))) {
			/* The page is unsafe, mark it for swsusp_free() */
			swsusp_set_page_forbidden(virt_to_page(res));
			allocated_unsafe_pages++;
			res = (void *)get_zeroed_page(gfp_mask);
		}
	if (res) {
		swsusp_set_page_forbidden(virt_to_page(res));
		swsusp_set_page_free(virt_to_page(res));
	}
	return res;
}

static void *__get_safe_page(gfp_t gfp_mask)
{
	if (safe_pages_list) {
		void *ret = safe_pages_list;

		safe_pages_list = safe_pages_list->next;
		memset(ret, 0, PAGE_SIZE);
		return ret;
	}
	return get_image_page(gfp_mask, PG_SAFE);
}

unsigned long get_safe_page(gfp_t gfp_mask)
{
	return (unsigned long)__get_safe_page(gfp_mask);
}

static struct page *alloc_image_page(gfp_t gfp_mask)
{
	struct page *page;

	page = alloc_page(gfp_mask);
	if (page) {
		swsusp_set_page_forbidden(page);
		swsusp_set_page_free(page);
	}
	return page;
}

static void recycle_safe_page(void *page_address)
{
	struct linked_page *lp = page_address;

	lp->next = safe_pages_list;
	safe_pages_list = lp;
}

Annotation

Implementation Notes