Created
August 10, 2023 18:36
-
-
Save avagin/2e465e7c362c515ec84d72a201a28de4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c | |
index feeb8a07012c..b4b15a4f53e3 100644 | |
--- a/fs/proc/task_mmu.c | |
+++ b/fs/proc/task_mmu.c | |
@@ -1766,7 +1766,7 @@ static int pagemap_release(struct inode *inode, struct file *file) | |
struct pagemap_scan_private { | |
struct pm_scan_arg arg; | |
unsigned long masks_of_interest, cur_vma_category; | |
- struct page_region *vec_buf, cur_buf; | |
+ struct page_region *vec_buf; | |
unsigned long vec_buf_len, vec_buf_index, found_pages, walk_end_addr; | |
struct page_region __user *vec_out; | |
}; | |
@@ -1958,7 +1958,7 @@ static bool pagemap_scan_push_range(unsigned long categories, | |
struct pagemap_scan_private *p, | |
unsigned long addr, unsigned long end) | |
{ | |
- struct page_region *cur_buf = &p->cur_buf; | |
+ struct page_region *cur_buf = &p->vec_buf[p->vec_buf_index]; | |
/* | |
* When there is no output buffer provided at all, the sentinel values | |
@@ -1971,10 +1971,11 @@ static bool pagemap_scan_push_range(unsigned long categories, | |
} | |
if (cur_buf->end) { | |
- if (p->vec_buf_index >= p->vec_buf_len) | |
+ if (p->vec_buf_index >= p->vec_buf_len - 1) | |
return false; | |
- p->vec_buf[p->vec_buf_index++] = *cur_buf; | |
+ p->vec_buf_index++; | |
+ cur_buf = &p->vec_buf[p->vec_buf_index]; | |
} | |
cur_buf->start = addr; | |
@@ -1988,12 +1989,15 @@ static void pagemap_scan_backout_range(struct pagemap_scan_private *p, | |
unsigned long addr, unsigned long end, | |
unsigned long walk_end_addr) | |
{ | |
- struct page_region *cur_buf = &p->cur_buf; | |
+ struct page_region *cur_buf = &p->vec_buf[p->vec_buf_index]; | |
if (cur_buf->start != addr) | |
cur_buf->end = addr; | |
- else | |
+ else { | |
cur_buf->start = cur_buf->end = 0; | |
+ if (p->vec_buf_index > 0) | |
+ p->vec_buf_index--; | |
+ } | |
p->walk_end_addr = walk_end_addr; | |
p->found_pages -= (end - addr) / PAGE_SIZE; | |
@@ -2006,9 +2010,6 @@ static int pagemap_scan_output(unsigned long categories, | |
unsigned long n_pages, total_pages; | |
int ret = 0; | |
- if (!p->vec_buf) | |
- return 0; | |
- | |
categories &= p->arg.return_mask; | |
n_pages = (*end - addr) / PAGE_SIZE; | |
@@ -2326,13 +2327,13 @@ static int pagemap_scan_writeback_args(struct pm_scan_arg *arg, | |
static int pagemap_scan_init_bounce_buffer(struct pagemap_scan_private *p) | |
{ | |
if (!p->arg.vec_len) { | |
+ static struct page_region nop = {.start = ULLONG_MAX, .end = ULLONG_MAX}; | |
/* | |
* An arbitrary non-page-aligned sentinel value for | |
* pagemap_scan_push_range(). | |
*/ | |
- p->cur_buf.start = p->cur_buf.end = ULLONG_MAX; | |
if (p->arg.vec) | |
- p->vec_buf = ZERO_SIZE_PTR; | |
+ p->vec_buf = &nop; | |
return 0; | |
} | |
@@ -2344,12 +2345,13 @@ static int pagemap_scan_init_bounce_buffer(struct pagemap_scan_private *p) | |
* walk_page_range() calls. | |
*/ | |
p->vec_buf_len = min_t(size_t, PAGEMAP_WALK_SIZE >> PAGE_SHIFT, | |
- p->arg.vec_len - 1); | |
+ p->arg.vec_len); | |
p->vec_buf = kmalloc_array(p->vec_buf_len, sizeof(*p->vec_buf), | |
GFP_KERNEL); | |
if (!p->vec_buf) | |
return -ENOMEM; | |
+ p->vec_buf[0].end = 0; | |
p->vec_out = (struct page_region __user *)p->arg.vec; | |
return 0; | |
@@ -2360,6 +2362,12 @@ static int pagemap_scan_flush_buffer(struct pagemap_scan_private *p) | |
const struct page_region *buf = p->vec_buf; | |
int n = (int)p->vec_buf_index; | |
+ if (p->arg.vec_len == 0) | |
+ return 0; | |
+ | |
+ if (buf[n].end && buf[n].end != buf[n].start) | |
+ n++; | |
+ | |
if (!n) | |
return 0; | |
@@ -2370,7 +2378,8 @@ static int pagemap_scan_flush_buffer(struct pagemap_scan_private *p) | |
p->vec_out += n; | |
p->vec_buf_index = 0; | |
- p->vec_buf_len = min_t(size_t, p->vec_buf_len, p->arg.vec_len - 1); | |
+ p->vec_buf_len = min_t(size_t, p->vec_buf_len, p->arg.vec_len); | |
+ p->vec_buf[0].end = 0; | |
return n; | |
} | |
@@ -2425,18 +2434,11 @@ static long do_pagemap_scan(struct mm_struct *mm, unsigned long uarg) | |
if (!ret) | |
p.walk_end_addr = p.arg.end; | |
- if (ret != -ENOSPC || p.arg.vec_len - 1 == 0 || | |
+ if (ret != -ENOSPC || p.arg.vec_len == 0 || | |
p.found_pages == p.arg.max_pages) | |
break; | |
} | |
- if (p.cur_buf.start != p.cur_buf.end) { | |
- if (copy_to_user(p.vec_out, &p.cur_buf, sizeof(p.cur_buf))) | |
- ret = -EFAULT; | |
- else | |
- ++n_ranges_out; | |
- } | |
- | |
/* ENOSPC signifies early stop (buffer full) from the walk. */ | |
if (!ret || ret == -ENOSPC) | |
ret = n_ranges_out; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment