Commit 4b94c18d authored by Zi Yan's avatar Zi Yan Committed by Andrew Morton
Browse files

mm/huge_memory: add folio_split() to debugfs testing interface

This allows to test folio_split() by specifying an additional in folio
page offset parameter to split_huge_page debugfs interface.

Link: https://lkml.kernel.org/r/20250307174001.242794-7-ziy@nvidia.com


Signed-off-by: default avatarZi Yan <ziy@nvidia.com>
Cc: Baolin Wang <baolin.wang@linux.alibaba.com>
Cc: David Hildenbrand <david@redhat.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: John Hubbard <jhubbard@nvidia.com>
Cc: Kefeng Wang <wangkefeng.wang@huawei.com>
Cc: Kirill A. Shuemov <kirill.shutemov@linux.intel.com>
Cc: Matthew Wilcox <willy@infradead.org>
Cc: Miaohe Lin <linmiaohe@huawei.com>
Cc: Ryan Roberts <ryan.roberts@arm.com>
Cc: Yang Shi <yang@os.amperecomputing.com>
Cc: Yu Zhao <yuzhao@google.com>
Cc: Kairui Song <kasong@tencent.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
parent 1f43d5aa
Loading
Loading
Loading
Loading
+34 −13
Original line number Diff line number Diff line
@@ -4331,7 +4331,8 @@ static inline bool vma_not_suitable_for_thp_split(struct vm_area_struct *vma)
}

static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
				unsigned long vaddr_end, unsigned int new_order)
				unsigned long vaddr_end, unsigned int new_order,
				long in_folio_offset)
{
	int ret = 0;
	struct task_struct *task;
@@ -4415,8 +4416,16 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
		if (!folio_test_anon(folio) && folio->mapping != mapping)
			goto unlock;

		if (in_folio_offset < 0 ||
		    in_folio_offset >= folio_nr_pages(folio)) {
			if (!split_folio_to_order(folio, target_order))
				split++;
		} else {
			struct page *split_at = folio_page(folio,
							   in_folio_offset);
			if (!folio_split(folio, target_order, split_at, NULL))
				split++;
		}

unlock:

@@ -4439,7 +4448,8 @@ static int split_huge_pages_pid(int pid, unsigned long vaddr_start,
}

static int split_huge_pages_in_file(const char *file_path, pgoff_t off_start,
				pgoff_t off_end, unsigned int new_order)
				pgoff_t off_end, unsigned int new_order,
				long in_folio_offset)
{
	struct filename *file;
	struct file *candidate;
@@ -4488,8 +4498,15 @@ static int split_huge_pages_in_file(const char *file_path, pgoff_t off_start,
		if (folio->mapping != mapping)
			goto unlock;

		if (in_folio_offset < 0 || in_folio_offset >= nr_pages) {
			if (!split_folio_to_order(folio, target_order))
				split++;
		} else {
			struct page *split_at = folio_page(folio,
							   in_folio_offset);
			if (!folio_split(folio, target_order, split_at, NULL))
				split++;
		}

unlock:
		folio_unlock(folio);
@@ -4522,6 +4539,7 @@ static ssize_t split_huge_pages_write(struct file *file, const char __user *buf,
	int pid;
	unsigned long vaddr_start, vaddr_end;
	unsigned int new_order = 0;
	long in_folio_offset = -1;

	ret = mutex_lock_interruptible(&split_debug_mutex);
	if (ret)
@@ -4550,30 +4568,33 @@ static ssize_t split_huge_pages_write(struct file *file, const char __user *buf,
			goto out;
		}

		ret = sscanf(tok_buf, "0x%lx,0x%lx,%d", &off_start,
			    &off_end, &new_order);
		if (ret != 2 && ret != 3) {
		ret = sscanf(tok_buf, "0x%lx,0x%lx,%d,%ld", &off_start, &off_end,
				&new_order, &in_folio_offset);
		if (ret != 2 && ret != 3 && ret != 4) {
			ret = -EINVAL;
			goto out;
		}
		ret = split_huge_pages_in_file(file_path, off_start, off_end, new_order);
		ret = split_huge_pages_in_file(file_path, off_start, off_end,
				new_order, in_folio_offset);
		if (!ret)
			ret = input_len;

		goto out;
	}

	ret = sscanf(input_buf, "%d,0x%lx,0x%lx,%d", &pid, &vaddr_start, &vaddr_end, &new_order);
	ret = sscanf(input_buf, "%d,0x%lx,0x%lx,%d,%ld", &pid, &vaddr_start,
			&vaddr_end, &new_order, &in_folio_offset);
	if (ret == 1 && pid == 1) {
		split_huge_pages_all();
		ret = strlen(input_buf);
		goto out;
	} else if (ret != 3 && ret != 4) {
	} else if (ret != 3 && ret != 4 && ret != 5) {
		ret = -EINVAL;
		goto out;
	}

	ret = split_huge_pages_pid(pid, vaddr_start, vaddr_end, new_order);
	ret = split_huge_pages_pid(pid, vaddr_start, vaddr_end, new_order,
			in_folio_offset);
	if (!ret)
		ret = strlen(input_buf);
out: