From: SeongJae Park <sj@kernel.org>
To: Zheng Yejian <zhengyejian@huaweicloud.com>
Cc: SeongJae Park <sj@kernel.org>,
akpm@linux-foundation.org, sieberf@amazon.com,
shakeel.butt@linux.dev, foersleo@amazon.de,
damon@lists.linux.dev, linux-mm@kvack.org,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH] mm/damon/vaddr: Fix issue in damon_va_evenly_split_region()
Date: Fri, 18 Oct 2024 11:33:10 -0700 [thread overview]
Message-ID: <20241018183310.115850-1-sj@kernel.org> (raw)
In-Reply-To: <20241018035304.1050135-1-zhengyejian@huaweicloud.com>
Hi Zheng,
Thank you for sharing this nice finding and fix! I have a few comments below.
On Fri, 18 Oct 2024 11:53:04 +0800 Zheng Yejian <zhengyejian@huaweicloud.com> wrote:
> According to the logic of damon_va_evenly_split_region(), currently at
> least following split cases would not meet the expectation:
>
> Suppose DAMON_MIN_REGION=0x1000,
> Case1: Split [0x0, 0x1100) into 1 pieces, then the result would be
> acutually [0x0, 0x1000), but NOT the expected [0x0, 0x1100) !!!
Nice finding! However, as long as DAMON_MIN_REGION is respected, [0x0, 0x1100]
region could not be created. So, the problematic case cannot happen in real?
Please let me know if I'm missing something.
And, why would someone call the function with nr_pieces 1?
> Case2: Split [0x0, 0x3000) into 2 pieces, then the result would be
> acutually 3 regions:
> [0x0, 0x1000), [0x1000, 0x2000), [0x2000, 0x3000)
> but NOT the expected 2 regions:
> [0x0, 0x1000), [0x1000, 0x3000) !!!
Nice finding!
>
> The root cause is that when calculating size of each split piece in
> damon_va_evenly_split_region():
>
> `sz_piece = ALIGN_DOWN(sz_orig / nr_pieces, DAMON_MIN_REGION);`
>
> both the dividing and the ALIGN_DOWN may cause loss of precision,
> then each time split one piece of size 'sz_piece' from origin 'start' to
> 'end' would cause:
> 1. For the above Case1, the 'end' value of the split 1 piece is
> aligned but not updated!!!
> 2. For the above Case2, more pieces are split out than expected!!!
>
> To fix it, in this patch:
> - As for the expect to split 1 piece, just return 0;
As mentioned above, I think this is not needed, since the problematic case is
unreal.
> - Count for each piece split and make sure no more than 'nr_pieces';
> - Add above two cases into damon_test_split_evenly().
Thank you for adding tests!
>
> BTW, currently when running kunit test, DAMON_MIN_REGION is redefined
> as 1, then above ALIGN_DOWN cases may not be test, since every int
> value is ALIGN-ed to 1.
>
> After this patch, damon-operations test passed:
>
> # ./tools/testing/kunit/kunit.py run damon-operations
> [...]
> ============== damon-operations (6 subtests) ===============
> [PASSED] damon_test_three_regions_in_vmas
> [PASSED] damon_test_apply_three_regions1
> [PASSED] damon_test_apply_three_regions2
> [PASSED] damon_test_apply_three_regions3
> [PASSED] damon_test_apply_three_regions4
> [PASSED] damon_test_split_evenly
> ================ [PASSED] damon-operations =================
>
> Fixes: 3f49584b262c ("mm/damon: implement primitives for the virtual memory address spaces")
> Signed-off-by: Zheng Yejian <zhengyejian@huaweicloud.com>
> ---
> mm/damon/tests/vaddr-kunit.h | 2 ++
> mm/damon/vaddr.c | 13 +++++++++----
> 2 files changed, 11 insertions(+), 4 deletions(-)
>
> diff --git a/mm/damon/tests/vaddr-kunit.h b/mm/damon/tests/vaddr-kunit.h
> index a339d117150f..b9a03e4e29e5 100644
> --- a/mm/damon/tests/vaddr-kunit.h
> +++ b/mm/damon/tests/vaddr-kunit.h
> @@ -300,6 +300,8 @@ static void damon_test_split_evenly(struct kunit *test)
> damon_test_split_evenly_fail(test, 0, 100, 0);
> damon_test_split_evenly_succ(test, 0, 100, 10);
> damon_test_split_evenly_succ(test, 5, 59, 5);
> + damon_test_split_evenly_succ(test, 4, 6, 1);
If my above assumption (the first problem is unreal) is not wrong, maybe this
test is not needed?
> + damon_test_split_evenly_succ(test, 0, 3, 2);
Nice.
> damon_test_split_evenly_fail(test, 5, 6, 2);
> }
>
> diff --git a/mm/damon/vaddr.c b/mm/damon/vaddr.c
> index 08cfd22b5249..1f3cebd20829 100644
> --- a/mm/damon/vaddr.c
> +++ b/mm/damon/vaddr.c
> @@ -67,10 +67,14 @@ static int damon_va_evenly_split_region(struct damon_target *t,
> unsigned long sz_orig, sz_piece, orig_end;
> struct damon_region *n = NULL, *next;
> unsigned long start;
> + int i;
Purpose of this variable is counting the number of splitted regions, and
comparing it against 'nr_pieces', right? Because nr_pieces is 'unsigned int',
let's make this 'unsigned int' type, too.
>
> if (!r || !nr_pieces)
> return -EINVAL;
>
> + if (nr_pieces == 1)
> + return 0;
> +
As mentioned above, I don't think this is not needed.
> orig_end = r->ar.end;
> sz_orig = damon_sz_region(r);
> sz_piece = ALIGN_DOWN(sz_orig / nr_pieces, DAMON_MIN_REGION);
> @@ -79,9 +83,11 @@ static int damon_va_evenly_split_region(struct damon_target *t,
> return -EINVAL;
>
> r->ar.end = r->ar.start + sz_piece;
> + /* origin region will be updated as the first one after splitting */
I don't think this comment is easy to understand. Let's just remove it.
> + i = 1;
> + n = r;
Why we need this? for 'nr_pieces == 1' case? If so, I don't think we need to
take care about the case for the above mentioned reason. Please let me know if
I'm missing something.
> next = damon_next_region(r);
> - for (start = r->ar.end; start + sz_piece <= orig_end;
> - start += sz_piece) {
> + for (start = r->ar.end; i < nr_pieces; start += sz_piece, i++) {
> n = damon_new_region(start, start + sz_piece);
> if (!n)
> return -ENOMEM;
> @@ -89,8 +95,7 @@ static int damon_va_evenly_split_region(struct damon_target *t,
> r = n;
> }
> /* complement last region for possible rounding error */
> - if (n)
> - n->ar.end = orig_end;
> + n->ar.end = orig_end;
Maybe this change is related with the above 'n = r' line? But, I don't think
we need that, as commented there.
>
> return 0;
> }
> --
> 2.25.1
Thanks,
SJ
next prev parent reply other threads:[~2024-10-18 18:33 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-18 3:53 [PATCH] mm/damon/vaddr: Fix issue in damon_va_evenly_split_region() Zheng Yejian
2024-10-18 18:33 ` SeongJae Park [this message]
2024-10-21 3:56 ` Zheng Yejian
2024-10-21 16:33 ` SeongJae Park
2024-10-22 8:39 ` [PATCH v2 0/2] " Zheng Yejian
2024-10-22 8:39 ` [PATCH v2 1/2] " Zheng Yejian
2024-10-22 17:54 ` SeongJae Park
2024-10-22 18:00 ` SeongJae Park
2024-10-22 8:39 ` [PATCH v2 2/2] mm/damon/vaddr: Add 'nr_piece == 1' check " Zheng Yejian
2024-10-22 17:57 ` SeongJae Park
2024-10-22 18:05 ` [PATCH v2 0/2] mm/damon/vaddr: Fix issue " SeongJae Park
2024-10-23 1:27 ` Zheng Yejian
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20241018183310.115850-1-sj@kernel.org \
--to=sj@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=damon@lists.linux.dev \
--cc=foersleo@amazon.de \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=shakeel.butt@linux.dev \
--cc=sieberf@amazon.com \
--cc=zhengyejian@huaweicloud.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.