Commit 1f2b780e authored by ZhangPeng's avatar ZhangPeng Committed by openeuler-sync-bot
Browse files

userswap: fix kmalloc ENOMEM failed for a large memory

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/I6CAIM



--------------------------------

If the swapped-out memory is large, such as tens of gigabytes, we will
allocate a large management structure, which may be tens of megabytes or
hundreds of megabytes. So if we use kmalloc to allocate management
structures it may fail.
Fix this by changing kmalloc to kvzalloc and kfree to kvfree.

Signed-off-by: default avatarZhangPeng <zhangpeng362@huawei.com>
(cherry picked from commit 6935faf1)
parent e270a13c
Loading
Loading
Loading
Loading
+6 −7
Original line number Diff line number Diff line
@@ -86,7 +86,7 @@ static unsigned long pages_can_be_swapped(struct mm_struct *mm,
	*ppages = NULL;


	pages = kmalloc(sizeof(struct page *) * (len / PAGE_SIZE), GFP_KERNEL);
	pages = kvzalloc(sizeof(struct page *) * (len / PAGE_SIZE), GFP_KERNEL);
	if (!pages)
		return -ENOMEM;

@@ -151,7 +151,7 @@ static unsigned long pages_can_be_swapped(struct mm_struct *mm,
out_err:
	for (i = 0; i < page_num; i++)
		put_page(pages[i]);
	kfree(pages);
	kvfree(pages);
	return ret;
}

@@ -291,10 +291,9 @@ static unsigned long do_user_swap(struct mm_struct *mm,
	unsigned long i = 0, j;
	int ret;

	ptes = kmalloc(sizeof(pte_t) * (len / PAGE_SIZE), GFP_KERNEL);
	ptes = kvzalloc(sizeof(pte_t) * (len / PAGE_SIZE), GFP_KERNEL);
	if (!ptes)
		return -ENOMEM;
	memset(ptes, 0, sizeof(pte_t) * (len / PAGE_SIZE));
	lru_add_drain();
	for (j = 0; j < len; j += PAGE_SIZE) {
		page = pages[i];
@@ -338,12 +337,12 @@ static unsigned long do_user_swap(struct mm_struct *mm,

	if (pages_dirty)
		new_addr_start = new_addr_start | USWAP_PAGES_DIRTY;
	kfree(ptes);
	kvfree(ptes);
	return new_addr_start;

out_recover:
	uswapout_recover(mm, old_addr_start, i, pages, new_addr_start, ptes);
	kfree(ptes);
	kvfree(ptes);
	return ret;
}

@@ -388,7 +387,7 @@ unsigned long uswap_mremap(unsigned long old_addr, unsigned long old_len,
	for (i = 0; i < len / PAGE_SIZE; i++)
		if (pages[i])
			put_page(pages[i]);
	kfree(pages);
	kvfree(pages);
	return ret;
}