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

📄 snapshot.c

📁 linux 2.6.19 kernel source code before patching
💻 C
📖 第 1 页 / 共 4 页
字号:
#else#define page_is_saveable(zone, pfn)	saveable_page(pfn)static inline voidcopy_data_page(unsigned long dst_pfn, unsigned long src_pfn){	do_copy_page(page_address(pfn_to_page(dst_pfn)),			page_address(pfn_to_page(src_pfn)));}#endif /* CONFIG_HIGHMEM */static voidcopy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm){	struct zone *zone;	unsigned long pfn;	for_each_zone(zone) {		unsigned long max_zone_pfn;		mark_free_pages(zone);		max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;		for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)			if (page_is_saveable(zone, pfn))				memory_bm_set_bit(orig_bm, pfn);	}	memory_bm_position_reset(orig_bm);	memory_bm_position_reset(copy_bm);	do {		pfn = memory_bm_next_pfn(orig_bm);		if (likely(pfn != BM_END_OF_MAP))			copy_data_page(memory_bm_next_pfn(copy_bm), pfn);	} while (pfn != BM_END_OF_MAP);}/* Total number of image pages */static unsigned int nr_copy_pages;/* Number of pages needed for saving the original pfns of the image pages */static unsigned int nr_meta_pages;/** *	swsusp_free - free pages allocated for the suspend. * *	Suspend pages are alocated before the atomic copy is made, so we *	need to release them after the resume. */void swsusp_free(void){	struct zone *zone;	unsigned long pfn, max_zone_pfn;	for_each_zone(zone) {		max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;		for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)			if (pfn_valid(pfn)) {				struct page *page = pfn_to_page(pfn);				if (swsusp_page_is_forbidden(page) &&				    swsusp_page_is_free(page)) {					swsusp_unset_page_forbidden(page);					swsusp_unset_page_free(page);					__free_page(page);				}			}	}	nr_copy_pages = 0;	nr_meta_pages = 0;	restore_pblist = NULL;	buffer = NULL;}#ifdef CONFIG_HIGHMEM/**  *	count_pages_for_highmem - compute the number of non-highmem pages  *	that will be necessary for creating copies of highmem pages.  */static unsigned int count_pages_for_highmem(unsigned int nr_highmem){	unsigned int free_highmem = count_free_highmem_pages();	if (free_highmem >= nr_highmem)		nr_highmem = 0;	else		nr_highmem -= free_highmem;	return nr_highmem;}#elsestatic unsigned intcount_pages_for_highmem(unsigned int nr_highmem) { return 0; }#endif /* CONFIG_HIGHMEM *//** *	enough_free_mem - Make sure we have enough free memory for the *	snapshot image. */static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem){	struct zone *zone;	unsigned int free = 0, meta = 0;	for_each_zone(zone) {		meta += snapshot_additional_pages(zone);		if (!is_highmem(zone))			free += zone_page_state(zone, NR_FREE_PAGES);	}	nr_pages += count_pages_for_highmem(nr_highmem);	pr_debug("swsusp: Normal pages needed: %u + %u + %u, available pages: %u\n",		nr_pages, PAGES_FOR_IO, meta, free);	return free > nr_pages + PAGES_FOR_IO + meta;}#ifdef CONFIG_HIGHMEM/** *	get_highmem_buffer - if there are some highmem pages in the suspend *	image, we may need the buffer to copy them and/or load their data. */static inline int get_highmem_buffer(int safe_needed){	buffer = get_image_page(GFP_ATOMIC | __GFP_COLD, safe_needed);	return buffer ? 0 : -ENOMEM;}/** *	alloc_highmem_image_pages - allocate some highmem pages for the image. *	Try to allocate as many pages as needed, but if the number of free *	highmem pages is lesser than that, allocate them all. */static inline unsigned intalloc_highmem_image_pages(struct memory_bitmap *bm, unsigned int nr_highmem){	unsigned int to_alloc = count_free_highmem_pages();	if (to_alloc > nr_highmem)		to_alloc = nr_highmem;	nr_highmem -= to_alloc;	while (to_alloc-- > 0) {		struct page *page;		page = alloc_image_page(__GFP_HIGHMEM);		memory_bm_set_bit(bm, page_to_pfn(page));	}	return nr_highmem;}#elsestatic inline int get_highmem_buffer(int safe_needed) { return 0; }static inline unsigned intalloc_highmem_image_pages(struct memory_bitmap *bm, unsigned int n) { return 0; }#endif /* CONFIG_HIGHMEM *//** *	swsusp_alloc - allocate memory for the suspend image * *	We first try to allocate as many highmem pages as there are *	saveable highmem pages in the system.  If that fails, we allocate *	non-highmem pages for the copies of the remaining highmem ones. * *	In this approach it is likely that the copies of highmem pages will *	also be located in the high memory, because of the way in which *	copy_data_pages() works. */static intswsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm,		unsigned int nr_pages, unsigned int nr_highmem){	int error;	error = memory_bm_create(orig_bm, GFP_ATOMIC | __GFP_COLD, PG_ANY);	if (error)		goto Free;	error = memory_bm_create(copy_bm, GFP_ATOMIC | __GFP_COLD, PG_ANY);	if (error)		goto Free;	if (nr_highmem > 0) {		error = get_highmem_buffer(PG_ANY);		if (error)			goto Free;		nr_pages += alloc_highmem_image_pages(copy_bm, nr_highmem);	}	while (nr_pages-- > 0) {		struct page *page = alloc_image_page(GFP_ATOMIC | __GFP_COLD);		if (!page)			goto Free;		memory_bm_set_bit(copy_bm, page_to_pfn(page));	}	return 0; Free:	swsusp_free();	return -ENOMEM;}/* Memory bitmap used for marking saveable pages (during suspend) or the * suspend image pages (during resume) */static struct memory_bitmap orig_bm;/* Memory bitmap used on suspend for marking allocated pages that will contain * the copies of saveable pages.  During resume it is initially used for * marking the suspend image pages, but then its set bits are duplicated in * @orig_bm and it is released.  Next, on systems with high memory, it may be * used for marking "safe" highmem pages, but it has to be reinitialized for * this purpose. */static struct memory_bitmap copy_bm;asmlinkage int swsusp_save(void){	unsigned int nr_pages, nr_highmem;	printk("swsusp: critical section: \n");	drain_local_pages();	nr_pages = count_data_pages();	nr_highmem = count_highmem_pages();	printk("swsusp: Need to copy %u pages\n", nr_pages + nr_highmem);	if (!enough_free_mem(nr_pages, nr_highmem)) {		printk(KERN_ERR "swsusp: Not enough free memory\n");		return -ENOMEM;	}	if (swsusp_alloc(&orig_bm, &copy_bm, nr_pages, nr_highmem)) {		printk(KERN_ERR "swsusp: Memory allocation failed\n");		return -ENOMEM;	}	/* During allocating of suspend pagedir, new cold pages may appear.	 * Kill them.	 */	drain_local_pages();	copy_data_pages(&copy_bm, &orig_bm);	/*	 * End of critical section. From now on, we can write to memory,	 * but we should not touch disk. This specially means we must _not_	 * touch swap space! Except we must write out our image of course.	 */	nr_pages += nr_highmem;	nr_copy_pages = nr_pages;	nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);	printk("swsusp: critical section: done (%d pages copied)\n", nr_pages);	return 0;}static void init_header(struct swsusp_info *info){	memset(info, 0, sizeof(struct swsusp_info));	info->version_code = LINUX_VERSION_CODE;	info->num_physpages = num_physpages;	memcpy(&info->uts, init_utsname(), sizeof(struct new_utsname));	info->cpus = num_online_cpus();	info->image_pages = nr_copy_pages;	info->pages = nr_copy_pages + nr_meta_pages + 1;	info->size = info->pages;	info->size <<= PAGE_SHIFT;}/** *	pack_pfns - pfns corresponding to the set bits found in the bitmap @bm *	are stored in the array @buf[] (1 page at a time) */static inline voidpack_pfns(unsigned long *buf, struct memory_bitmap *bm){	int j;	for (j = 0; j < PAGE_SIZE / sizeof(long); j++) {		buf[j] = memory_bm_next_pfn(bm);		if (unlikely(buf[j] == BM_END_OF_MAP))			break;	}}/** *	snapshot_read_next - used for reading 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 read from the snapshot.  It must not be zero. * *	On success the function returns a positive number.  Then, the caller *	is allowed to read up to the returned number of bytes from the memory *	location computed by the data_of() macro.  The number returned *	may be smaller than @count, but this only happens if the read would *	cross a page boundary otherwise. * *	The function returns 0 to indicate the end of data stream 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_read_next(struct snapshot_handle *handle, size_t count){	if (handle->cur > nr_meta_pages + nr_copy_pages)		return 0;	if (!buffer) {		/* This makes the buffer be freed by swsusp_free() */		buffer = get_image_page(GFP_ATOMIC, PG_ANY);		if (!buffer)			return -ENOMEM;	}	if (!handle->offset) {		init_header((struct swsusp_info *)buffer);		handle->buffer = buffer;		memory_bm_position_reset(&orig_bm);		memory_bm_position_reset(&copy_bm);	}	if (handle->prev < handle->cur) {		if (handle->cur <= nr_meta_pages) {			memset(buffer, 0, PAGE_SIZE);			pack_pfns(buffer, &orig_bm);		} else {			struct page *page;			page = pfn_to_page(memory_bm_next_pfn(&copy_bm));			if (PageHighMem(page)) {				/* Highmem pages are copied to the buffer,				 * because we can't return with a kmapped				 * highmem page (we may not be called again).				 */				void *kaddr;				kaddr = kmap_atomic(page, KM_USER0);				memcpy(buffer, kaddr, PAGE_SIZE);				kunmap_atomic(kaddr, KM_USER0);				handle->buffer = buffer;			} else {				handle->buffer = page_address(page);			}		}		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;}/** *	mark_unsafe_pages - mark the pages that cannot be used for storing *	the image during resume, because they conflict with the pages that *	had been used before suspend */static int mark_unsafe_pages(struct memory_bitmap *bm){	struct zone *zone;	unsigned long pfn, max_zone_pfn;	/* Clear page flags */	for_each_zone(zone) {		max_zone_pfn = zone->zone_start_pfn + zone->spanned_pages;		for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)			if (pfn_valid(pfn))				swsusp_unset_page_free(pfn_to_page(pfn));	}	/* Mark pages that correspond to the "original" pfns as "unsafe" */	memory_bm_position_reset(bm);	do {		pfn = memory_bm_next_pfn(bm);		if (likely(pfn != BM_END_OF_MAP)) {			if (likely(pfn_valid(pfn)))				swsusp_set_page_free(pfn_to_page(pfn));			else				return -EFAULT;		}	} while (pfn != BM_END_OF_MAP);	allocated_unsafe_pages = 0;	return 0;}static voidduplicate_memory_bitmap(struct memory_bitmap *dst, struct memory_bitmap *src){	unsigned long pfn;	memory_bm_position_reset(src);	pfn = memory_bm_next_pfn(src);	while (pfn != BM_END_OF_MAP) {		memory_bm_set_bit(dst, pfn);		pfn = memory_bm_next_pfn(src);	}}static inline int check_header(struct swsusp_info *info){	char *reason = NULL;	if (info->version_code != LINUX_VERSION_CODE)		reason = "kernel version";	if (info->num_physpages != num_physpages)		reason = "memory size";	if (strcmp(info->uts.sysname,init_utsname()->sysname))		reason = "system type";	if (strcmp(info->uts.release,init_utsname()->release))		reason = "kernel release";	if (strcmp(info->uts.version,init_utsname()->version))		reason = "version";	if (strcmp(info->uts.machine,init_utsname()->machine))		reason = "machine";	if (reason) {		printk(KERN_ERR "swsusp: Resume mismatch: %s\n", reason);		return -EPERM;	}	return 0;}/** *	load header - check the image header and copy data from it */static intload_header(struct swsusp_info *info){	int error;	restore_pblist = NULL;	error = check_header(info);	if (!error) {		nr_copy_pages = info->image_pages;		nr_meta_pages = info->pages - info->image_pages - 1;	}	return error;}/** *	unpack_orig_pfns - for each element of @buf[] (1 page at a time) set *	the corresponding bit in the memory bitmap @bm */static inline voidunpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm){	int j;	for (j = 0; j < PAGE_SIZE / sizeof(long); j++) {		if (unlikely(buf[j] == BM_END_OF_MAP))			break;		memory_bm_set_bit(bm, buf[j]);	}}/* List of "safe" pages that may be used to store data loaded from the suspend * image */static struct linked_page *safe_pages_list;#ifdef CONFIG_HIGHMEM/* struct highmem_pbe is used for creating the list of highmem pages that * should be restored atomically during the resume from disk, because the page * frames they have occupied before the suspend are in use. */struct highmem_pbe {	struct page *copy_page;	/* data is here now */	struct page *orig_page;	/* data was here before the suspend */

⌨️ 快捷键说明

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