⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 snapshot.c

📁 linux 2.6.19 kernel source code before patching
💻 C
📖 第 1 页 / 共 4 页
字号:
	struct highmem_pbe *next;};/* List of highmem PBEs needed for restoring the highmem pages that were * allocated before the suspend and included in the suspend image, but have * also been allocated by the "resume" kernel, so their contents cannot be * written directly to their "original" page frames. */static struct highmem_pbe *highmem_pblist;/** *	count_highmem_image_pages - compute the number of highmem pages in the *	suspend image.  The bits in the memory bitmap @bm that correspond to the *	image pages are assumed to be set. */static unsigned int count_highmem_image_pages(struct memory_bitmap *bm){	unsigned long pfn;	unsigned int cnt = 0;	memory_bm_position_reset(bm);	pfn = memory_bm_next_pfn(bm);	while (pfn != BM_END_OF_MAP) {		if (PageHighMem(pfn_to_page(pfn)))			cnt++;		pfn = memory_bm_next_pfn(bm);	}	return cnt;}/** *	prepare_highmem_image - try to allocate as many highmem pages as *	there are highmem image pages (@nr_highmem_p points to the variable *	containing the number of highmem image pages).  The pages that are *	"safe" (ie. will not be overwritten when the suspend image is *	restored) have the corresponding bits set in @bm (it must be *	unitialized). * *	NOTE: This function should not be called if there are no highmem *	image pages. */static unsigned int safe_highmem_pages;static struct memory_bitmap *safe_highmem_bm;static intprepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p){	unsigned int to_alloc;	if (memory_bm_create(bm, GFP_ATOMIC, PG_SAFE))		return -ENOMEM;	if (get_highmem_buffer(PG_SAFE))		return -ENOMEM;	to_alloc = count_free_highmem_pages();	if (to_alloc > *nr_highmem_p)		to_alloc = *nr_highmem_p;	else		*nr_highmem_p = to_alloc;	safe_highmem_pages = 0;	while (to_alloc-- > 0) {		struct page *page;		page = alloc_page(__GFP_HIGHMEM);		if (!swsusp_page_is_free(page)) {			/* The page is "safe", set its bit the bitmap */			memory_bm_set_bit(bm, page_to_pfn(page));			safe_highmem_pages++;		}		/* Mark the page as allocated */		swsusp_set_page_forbidden(page);		swsusp_set_page_free(page);	}	memory_bm_position_reset(bm);	safe_highmem_bm = bm;	return 0;}/** *	get_highmem_page_buffer - for given highmem image page find the buffer *	that suspend_write_next() should set for its caller to write to. * *	If the page is to be saved to its "original" page frame or a copy of *	the page is to be made in the highmem, @buffer is returned.  Otherwise, *	the copy of the page is to be made in normal memory, so the address of *	the copy is returned. * *	If @buffer is returned, the caller of suspend_write_next() will write *	the page's contents to @buffer, so they will have to be copied to the *	right location on the next call to suspend_write_next() and it is done *	with the help of copy_last_highmem_page().  For this purpose, if *	@buffer is returned, @last_highmem page is set to the page to which *	the data will have to be copied from @buffer. */static struct page *last_highmem_page;static void *get_highmem_page_buffer(struct page *page, struct chain_allocator *ca){	struct highmem_pbe *pbe;	void *kaddr;	if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page)) {		/* We have allocated the "original" page frame and we can		 * use it directly to store the loaded page.		 */		last_highmem_page = page;		return buffer;	}	/* The "original" page frame has not been allocated and we have to	 * use a "safe" page frame to store the loaded page.	 */	pbe = chain_alloc(ca, sizeof(struct highmem_pbe));	if (!pbe) {		swsusp_free();		return NULL;	}	pbe->orig_page = page;	if (safe_highmem_pages > 0) {		struct page *tmp;		/* Copy of the page will be stored in high memory */		kaddr = buffer;		tmp = pfn_to_page(memory_bm_next_pfn(safe_highmem_bm));		safe_highmem_pages--;		last_highmem_page = tmp;		pbe->copy_page = tmp;	} else {		/* Copy of the page will be stored in normal memory */		kaddr = safe_pages_list;		safe_pages_list = safe_pages_list->next;		pbe->copy_page = virt_to_page(kaddr);	}	pbe->next = highmem_pblist;	highmem_pblist = pbe;	return kaddr;}/** *	copy_last_highmem_page - copy the contents of a highmem image from *	@buffer, where the caller of snapshot_write_next() has place them, *	to the right location represented by @last_highmem_page . */static void copy_last_highmem_page(void){	if (last_highmem_page) {		void *dst;		dst = kmap_atomic(last_highmem_page, KM_USER0);		memcpy(dst, buffer, PAGE_SIZE);		kunmap_atomic(dst, KM_USER0);		last_highmem_page = NULL;	}}static inline int last_highmem_page_copied(void){	return !last_highmem_page;}static inline void free_highmem_data(void){	if (safe_highmem_bm)		memory_bm_free(safe_highmem_bm, PG_UNSAFE_CLEAR);	if (buffer)		free_image_page(buffer, PG_UNSAFE_CLEAR);}#elsestatic inline int get_safe_write_buffer(void) { return 0; }static unsigned intcount_highmem_image_pages(struct memory_bitmap *bm) { return 0; }static inline intprepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p){	return 0;}static inline void *get_highmem_page_buffer(struct page *page, struct chain_allocator *ca){	return NULL;}static inline void copy_last_highmem_page(void) {}static inline int last_highmem_page_copied(void) { return 1; }static inline void free_highmem_data(void) {}#endif /* CONFIG_HIGHMEM *//** *	prepare_image - use the memory bitmap @bm to mark the pages that will *	be overwritten in the process of restoring the system memory state *	from the suspend image ("unsafe" pages) and allocate memory for the *	image. * *	The idea is to allocate a new memory bitmap first and then allocate *	as many pages as needed for the image data, but not to assign these *	pages to specific tasks initially.  Instead, we just mark them as *	allocated and create a lists of "safe" pages that will be used *	later.  On systems with high memory a list of "safe" highmem pages is *	also created. */#define PBES_PER_LINKED_PAGE	(LINKED_PAGE_DATA_SIZE / sizeof(struct pbe))static intprepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm){	unsigned int nr_pages, nr_highmem;	struct linked_page *sp_list, *lp;	int error;	/* If there is no highmem, the buffer will not be necessary */	free_image_page(buffer, PG_UNSAFE_CLEAR);	buffer = NULL;	nr_highmem = count_highmem_image_pages(bm);	error = mark_unsafe_pages(bm);	if (error)		goto Free;	error = memory_bm_create(new_bm, GFP_ATOMIC, PG_SAFE);	if (error)		goto Free;	duplicate_memory_bitmap(new_bm, bm);	memory_bm_free(bm, PG_UNSAFE_KEEP);	if (nr_highmem > 0) {		error = prepare_highmem_image(bm, &nr_highmem);		if (error)			goto Free;	}	/* Reserve some safe pages for potential later use.	 *	 * NOTE: This way we make sure there will be enough safe pages for the	 * chain_alloc() in get_buffer().  It is a bit wasteful, but	 * nr_copy_pages cannot be greater than 50% of the memory anyway.	 */	sp_list = NULL;	/* nr_copy_pages cannot be lesser than allocated_unsafe_pages */	nr_pages = nr_copy_pages - nr_highmem - allocated_unsafe_pages;	nr_pages = DIV_ROUND_UP(nr_pages, PBES_PER_LINKED_PAGE);	while (nr_pages > 0) {		lp = get_image_page(GFP_ATOMIC, PG_SAFE);		if (!lp) {			error = -ENOMEM;			goto Free;		}		lp->next = sp_list;		sp_list = lp;		nr_pages--;	}	/* Preallocate memory for the image */	safe_pages_list = NULL;	nr_pages = nr_copy_pages - nr_highmem - allocated_unsafe_pages;	while (nr_pages > 0) {		lp = (struct linked_page *)get_zeroed_page(GFP_ATOMIC);		if (!lp) {			error = -ENOMEM;			goto Free;		}		if (!swsusp_page_is_free(virt_to_page(lp))) {			/* The page is "safe", add it to the list */			lp->next = safe_pages_list;			safe_pages_list = lp;		}		/* Mark the page as allocated */		swsusp_set_page_forbidden(virt_to_page(lp));		swsusp_set_page_free(virt_to_page(lp));		nr_pages--;	}	/* Free the reserved safe pages so that chain_alloc() can use them */	while (sp_list) {		lp = sp_list->next;		free_image_page(sp_list, PG_UNSAFE_CLEAR);		sp_list = lp;	}	return 0; Free:	swsusp_free();	return error;}/** *	get_buffer - compute the address that snapshot_write_next() should *	set for its caller to write to. */static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca){	struct pbe *pbe;	struct page *page = pfn_to_page(memory_bm_next_pfn(bm));	if (PageHighMem(page))		return get_highmem_page_buffer(page, ca);	if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page))		/* We have allocated the "original" page frame and we can		 * use it directly to store the loaded page.		 */		return page_address(page);	/* The "original" page frame has not been allocated and we have to	 * use a "safe" page frame to store the loaded page.	 */	pbe = chain_alloc(ca, sizeof(struct pbe));	if (!pbe) {		swsusp_free();		return NULL;	}	pbe->orig_address = page_address(page);	pbe->address = safe_pages_list;	safe_pages_list = safe_pages_list->next;	pbe->next = restore_pblist;	restore_pblist = pbe;	return pbe->address;}/** *	snapshot_write_next - used for writing the system memory snapshot. * *	On the first call to it @handle should point to a zeroed *	snapshot_handle structure.  The structure gets updated and a pointer *	to it should be passed to this function every next time. * *	The @count parameter should contain the number of bytes the caller *	wants to write to the image.  It must not be zero. * *	On success the function returns a positive number.  Then, the caller *	is allowed to write up to the returned number of bytes to the memory *	location computed by the data_of() macro.  The number returned *	may be smaller than @count, but this only happens if the write would *	cross a page boundary otherwise. * *	The function returns 0 to indicate the "end of file" condition, *	and a negative number is returned on error.  In such cases the *	structure pointed to by @handle is not updated and should not be used *	any more. */int snapshot_write_next(struct snapshot_handle *handle, size_t count){	static struct chain_allocator ca;	int error = 0;	/* Check if we have already loaded the entire image */	if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages)		return 0;	if (handle->offset == 0) {		if (!buffer)			/* This makes the buffer be freed by swsusp_free() */			buffer = get_image_page(GFP_ATOMIC, PG_ANY);		if (!buffer)			return -ENOMEM;		handle->buffer = buffer;	}	handle->sync_read = 1;	if (handle->prev < handle->cur) {		if (handle->prev == 0) {			error = load_header(buffer);			if (error)				return error;			error = memory_bm_create(&copy_bm, GFP_ATOMIC, PG_ANY);			if (error)				return error;		} else if (handle->prev <= nr_meta_pages) {			unpack_orig_pfns(buffer, &copy_bm);			if (handle->prev == nr_meta_pages) {				error = prepare_image(&orig_bm, &copy_bm);				if (error)					return error;				chain_init(&ca, GFP_ATOMIC, PG_SAFE);				memory_bm_position_reset(&orig_bm);				restore_pblist = NULL;				handle->buffer = get_buffer(&orig_bm, &ca);				handle->sync_read = 0;				if (!handle->buffer)					return -ENOMEM;			}		} else {			copy_last_highmem_page();			handle->buffer = get_buffer(&orig_bm, &ca);			if (handle->buffer != buffer)				handle->sync_read = 0;		}		handle->prev = handle->cur;	}	handle->buf_offset = handle->cur_offset;	if (handle->cur_offset + count >= PAGE_SIZE) {		count = PAGE_SIZE - handle->cur_offset;		handle->cur_offset = 0;		handle->cur++;	} else {		handle->cur_offset += count;	}	handle->offset += count;	return count;}/** *	snapshot_write_finalize - must be called after the last call to *	snapshot_write_next() in case the last page in the image happens *	to be a highmem page and its contents should be stored in the *	highmem.  Additionally, it releases the memory that will not be *	used any more. */void snapshot_write_finalize(struct snapshot_handle *handle){	copy_last_highmem_page();	/* Free only if we have loaded the image entirely */	if (handle->prev && handle->cur > nr_meta_pages + nr_copy_pages) {		memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR);		free_highmem_data();	}}int snapshot_image_loaded(struct snapshot_handle *handle){	return !(!nr_copy_pages || !last_highmem_page_copied() ||			handle->cur <= nr_meta_pages + nr_copy_pages);}#ifdef CONFIG_HIGHMEM/* Assumes that @buf is ready and points to a "safe" page */static inline voidswap_two_pages_data(struct page *p1, struct page *p2, void *buf){	void *kaddr1, *kaddr2;	kaddr1 = kmap_atomic(p1, KM_USER0);	kaddr2 = kmap_atomic(p2, KM_USER1);	memcpy(buf, kaddr1, PAGE_SIZE);	memcpy(kaddr1, kaddr2, PAGE_SIZE);	memcpy(kaddr2, buf, PAGE_SIZE);	kunmap_atomic(kaddr1, KM_USER0);	kunmap_atomic(kaddr2, KM_USER1);}/** *	restore_highmem - for each highmem page that was allocated before *	the suspend and included in the suspend image, and also has been *	allocated by the "resume" kernel swap its current (ie. "before *	resume") contents with the previous (ie. "before suspend") one. * *	If the resume eventually fails, we can call this function once *	again and restore the "before resume" highmem state. */int restore_highmem(void){	struct highmem_pbe *pbe = highmem_pblist;	void *buf;	if (!pbe)		return 0;	buf = get_image_page(GFP_ATOMIC, PG_SAFE);	if (!buf)		return -ENOMEM;	while (pbe) {		swap_two_pages_data(pbe->copy_page, pbe->orig_page, buf);		pbe = pbe->next;	}	free_image_page(buf, PG_UNSAFE_CLEAR);	return 0;}#endif /* CONFIG_HIGHMEM */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -