forked from mirrors/linux
		
	zsmalloc: factor page chain functionality out
For page migration, we need to create page chain of zspage dynamically so this patch factors it out from alloc_zspage. Link: http://lkml.kernel.org/r/1464736881-24886-8-git-send-email-minchan@kernel.org Signed-off-by: Minchan Kim <minchan@kernel.org> Reviewed-by: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Cc: Vlastimil Babka <vbabka@suse.cz> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									4f42047bbd
								
							
						
					
					
						commit
						bdb0af7ca8
					
				
					 1 changed files with 35 additions and 24 deletions
				
			
		|  | @ -960,7 +960,8 @@ static void init_zspage(struct size_class *class, struct page *first_page) | ||||||
| 	unsigned long off = 0; | 	unsigned long off = 0; | ||||||
| 	struct page *page = first_page; | 	struct page *page = first_page; | ||||||
| 
 | 
 | ||||||
| 	VM_BUG_ON_PAGE(!is_first_page(first_page), first_page); | 	first_page->freelist = NULL; | ||||||
|  | 	set_zspage_inuse(first_page, 0); | ||||||
| 
 | 
 | ||||||
| 	while (page) { | 	while (page) { | ||||||
| 		struct page *next_page; | 		struct page *next_page; | ||||||
|  | @ -996,15 +997,16 @@ static void init_zspage(struct size_class *class, struct page *first_page) | ||||||
| 		page = next_page; | 		page = next_page; | ||||||
| 		off %= PAGE_SIZE; | 		off %= PAGE_SIZE; | ||||||
| 	} | 	} | ||||||
|  | 
 | ||||||
|  | 	set_freeobj(first_page, (unsigned long)location_to_obj(first_page, 0)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /*
 | static void create_page_chain(struct page *pages[], int nr_pages) | ||||||
|  * Allocate a zspage for the given size class |  | ||||||
|  */ |  | ||||||
| static struct page *alloc_zspage(struct size_class *class, gfp_t flags) |  | ||||||
| { | { | ||||||
| 	int i, error; | 	int i; | ||||||
| 	struct page *first_page = NULL, *uninitialized_var(prev_page); | 	struct page *page; | ||||||
|  | 	struct page *prev_page = NULL; | ||||||
|  | 	struct page *first_page = NULL; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Allocate individual pages and link them together as: | 	 * Allocate individual pages and link them together as: | ||||||
|  | @ -1017,20 +1019,14 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) | ||||||
| 	 * (i.e. no other sub-page has this flag set) and PG_private_2 to | 	 * (i.e. no other sub-page has this flag set) and PG_private_2 to | ||||||
| 	 * identify the last page. | 	 * identify the last page. | ||||||
| 	 */ | 	 */ | ||||||
| 	error = -ENOMEM; | 	for (i = 0; i < nr_pages; i++) { | ||||||
| 	for (i = 0; i < class->pages_per_zspage; i++) { | 		page = pages[i]; | ||||||
| 		struct page *page; |  | ||||||
| 
 |  | ||||||
| 		page = alloc_page(flags); |  | ||||||
| 		if (!page) |  | ||||||
| 			goto cleanup; |  | ||||||
| 
 | 
 | ||||||
| 		INIT_LIST_HEAD(&page->lru); | 		INIT_LIST_HEAD(&page->lru); | ||||||
| 		if (i == 0) {	/* first page */ | 		if (i == 0) { | ||||||
| 			SetPagePrivate(page); | 			SetPagePrivate(page); | ||||||
| 			set_page_private(page, 0); | 			set_page_private(page, 0); | ||||||
| 			first_page = page; | 			first_page = page; | ||||||
| 			set_zspage_inuse(first_page, 0); |  | ||||||
| 		} | 		} | ||||||
| 		if (i == 1) | 		if (i == 1) | ||||||
| 			set_page_private(first_page, (unsigned long)page); | 			set_page_private(first_page, (unsigned long)page); | ||||||
|  | @ -1038,22 +1034,37 @@ static struct page *alloc_zspage(struct size_class *class, gfp_t flags) | ||||||
| 			set_page_private(page, (unsigned long)first_page); | 			set_page_private(page, (unsigned long)first_page); | ||||||
| 		if (i >= 2) | 		if (i >= 2) | ||||||
| 			list_add(&page->lru, &prev_page->lru); | 			list_add(&page->lru, &prev_page->lru); | ||||||
| 		if (i == class->pages_per_zspage - 1)	/* last page */ | 		if (i == nr_pages - 1) | ||||||
| 			SetPagePrivate2(page); | 			SetPagePrivate2(page); | ||||||
| 		prev_page = page; | 		prev_page = page; | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	init_zspage(class, first_page); | /*
 | ||||||
|  |  * Allocate a zspage for the given size class | ||||||
|  |  */ | ||||||
|  | static struct page *alloc_zspage(struct size_class *class, gfp_t flags) | ||||||
|  | { | ||||||
|  | 	int i; | ||||||
|  | 	struct page *first_page = NULL; | ||||||
|  | 	struct page *pages[ZS_MAX_PAGES_PER_ZSPAGE]; | ||||||
| 
 | 
 | ||||||
| 	set_freeobj(first_page,	(unsigned long)location_to_obj(first_page, 0)); | 	for (i = 0; i < class->pages_per_zspage; i++) { | ||||||
| 	error = 0; /* Success */ | 		struct page *page; | ||||||
| 
 | 
 | ||||||
| cleanup: | 		page = alloc_page(flags); | ||||||
| 	if (unlikely(error) && first_page) { | 		if (!page) { | ||||||
| 		free_zspage(first_page); | 			while (--i >= 0) | ||||||
| 		first_page = NULL; | 				__free_page(pages[i]); | ||||||
|  | 			return NULL; | ||||||
|  | 		} | ||||||
|  | 		pages[i] = page; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	create_page_chain(pages, class->pages_per_zspage); | ||||||
|  | 	first_page = pages[0]; | ||||||
|  | 	init_zspage(class, first_page); | ||||||
|  | 
 | ||||||
| 	return first_page; | 	return first_page; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Minchan Kim
						Minchan Kim