Commit 74c0e7cd authored by ZhangPeng's avatar ZhangPeng Committed by Ma Wupeng
Browse files

userswap: fix some type and logical bugs

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



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

As follows, fix some type and logical bugs.
1) The type of index variable is changed from int to unsigned long to
support large memory registration.
2) Fix the bug that USWAP_PAGES_DIRTY does not take effect.
3) Take the mmap_read_lock() when using the VMA in
uswap_adjust_uffd_range().
4) Do some code refactoring and cleancode.

Signed-off-by: default avatarZhangPeng <zhangpeng362@huawei.com>
parent 8c509665
Loading
Loading
Loading
Loading
+5 −6
Original line number Diff line number Diff line
@@ -1314,9 +1314,8 @@ static int userfaultfd_register(struct userfaultfd_ctx *ctx,
	if (ret)
		goto out;
#ifdef CONFIG_USERSWAP
	if (uswap_mode)
		if (!uswap_adjust_uffd_range(&uffdio_register, &vm_flags,
					     mm)) {
	if (uswap_mode && !uswap_adjust_uffd_range(&uffdio_register,
						   &vm_flags, mm)) {
		ret = -EINVAL;
		goto out;
	}
+14 −8
Original line number Diff line number Diff line
@@ -45,13 +45,18 @@ static inline bool uswap_check_copy_mode(struct vm_area_struct *vma, __u64 mode)

static inline bool uswap_validate_mremap_flags(unsigned long flags)
{
	if (!static_branch_unlikely(&userswap_enabled) && flags & MREMAP_USWAP_SET_PTE)
	if (static_branch_unlikely(&userswap_enabled)) {
		if (flags & MREMAP_USWAP_SET_PTE &&
		    flags & ~MREMAP_USWAP_SET_PTE)
			return false;
	if (flags & MREMAP_USWAP_SET_PTE && flags & ~MREMAP_USWAP_SET_PTE)
		if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE |
			      MREMAP_DONTUNMAP | MREMAP_USWAP_SET_PTE))
			return false;
	if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP |
		      MREMAP_USWAP_SET_PTE))
	} else {
		if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE |
			      MREMAP_DONTUNMAP))
			return false;
	}
	return true;
}

@@ -63,7 +68,8 @@ static inline bool uswap_vm_flag_bug_on(unsigned long reason)
	if (reason & ~(VM_UFFD_MISSING | VM_UFFD_WP | VM_USWAP))
		return true;
	if (reason & VM_USWAP)
		return !(reason & VM_UFFD_MISSING) || reason & ~(VM_USWAP|VM_UFFD_MISSING);
		return !(reason & VM_UFFD_MISSING) ||
		       reason & ~(VM_USWAP|VM_UFFD_MISSING);
	return !(reason & VM_UFFD_MISSING) ^ !!(reason & VM_UFFD_WP);
}

+14 −8
Original line number Diff line number Diff line
@@ -82,7 +82,7 @@ static unsigned long pages_can_be_swapped(struct mm_struct *mm,
	struct page **pages = NULL;
	unsigned long addr_end = addr + len;
	unsigned long ret;
	int i, page_num = 0;
	unsigned long i, page_num = 0;
	*ppages = NULL;


@@ -248,7 +248,7 @@ static void uswapout_recover(struct mm_struct *mm,
	struct page *page;
	pmd_t *old_pmd, *new_pmd;
	pte_t pte;
	int i;
	unsigned long i;

	for (i = 0; i < len; i++) {
		page = pages[i];
@@ -288,7 +288,7 @@ static unsigned long do_user_swap(struct mm_struct *mm,
	pmd_t *pmd;
	pte_t old_pte, *ptes;
	bool pages_dirty = false;
	int i = 0, j;
	unsigned long i = 0, j;
	int ret;

	ptes = kmalloc(sizeof(pte_t) * (len / PAGE_SIZE), GFP_KERNEL);
@@ -337,7 +337,7 @@ static unsigned long do_user_swap(struct mm_struct *mm,
	}

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

@@ -361,7 +361,7 @@ unsigned long uswap_mremap(unsigned long old_addr, unsigned long old_len,
	struct mm_struct *mm = current->mm;
	unsigned long len = old_len;
	unsigned long ret = -EINVAL;
	int i;
	unsigned long i;

	if (!len || old_len != new_len || offset_in_page(old_addr) ||
	    (len % PAGE_SIZE))
@@ -485,22 +485,28 @@ bool uswap_adjust_uffd_range(struct uffdio_register *uffdio_register,
{
	struct vm_area_struct *vma;
	unsigned long end;
	bool ret = false;

	if (!static_branch_unlikely(&userswap_enabled))
		return true;
	end = uffdio_register->range.start + uffdio_register->range.len - 1;

	mmap_read_lock(mm);
	vma = find_vma(mm, uffdio_register->range.start);
	if (!vma)
		return false;
		goto out_unlock;
	uffdio_register->range.start = vma->vm_start;
	vma = find_vma(mm, end);
	if (!vma)
		return false;
		goto out_unlock;
	uffdio_register->range.len = vma->vm_end - uffdio_register->range.start;

	*vm_flags |= VM_USWAP;

	return true;
	ret = true;
out_unlock:
	mmap_read_unlock(mm);
	return ret;
}

bool do_uswap_page(swp_entry_t entry, struct vm_fault *vmf,