diff mbox series

[2/6] mm: memory_hotplug: use more folio in do_migrate_range()

Message ID 20240327141034.3712697-3-wangkefeng.wang@huawei.com (mailing list archive)
State New
Headers show
Series mm: remove isolate_lru_page() and isolate_movable_page() | expand

Commit Message

Kefeng Wang March 27, 2024, 2:10 p.m. UTC
With isolate_movable_folio() and folio_isolate_lru(), let's use
more folio in do_migrate_range() to save compound_head() calls.

Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
---
 mm/memory_hotplug.c | 30 +++++++++++++++---------------
 1 file changed, 15 insertions(+), 15 deletions(-)

Comments

Zi Yan March 27, 2024, 2:45 p.m. UTC | #1
On 27 Mar 2024, at 10:10, Kefeng Wang wrote:

> With isolate_movable_folio() and folio_isolate_lru(), let's use
> more folio in do_migrate_range() to save compound_head() calls.
>
> Signed-off-by: Kefeng Wang <wangkefeng.wang@huawei.com>
> ---
>  mm/memory_hotplug.c | 30 +++++++++++++++---------------
>  1 file changed, 15 insertions(+), 15 deletions(-)
>
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index a444e2d7dd2b..bd207772c619 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -1774,14 +1774,14 @@ static int scan_movable_pages(unsigned long start, unsigned long end,
>
>  static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
>  {
> +	struct folio *folio;
>  	unsigned long pfn;
> -	struct page *page, *head;
>  	LIST_HEAD(source);
>  	static DEFINE_RATELIMIT_STATE(migrate_rs, DEFAULT_RATELIMIT_INTERVAL,
>  				      DEFAULT_RATELIMIT_BURST);
>
>  	for (pfn = start_pfn; pfn < end_pfn; pfn++) {
> -		struct folio *folio;
> +		struct page *page, *head;

You could get rid of head too. It is only used to calculate next pfn,
so pfn = folio_to_pfn(folio) + folio_nr_pages(folio) - 1 would work.

And the PageHuge(page) and PageTransHuge(page) can be simplified, since
their pfn calculations are the same. Something like:

if (folio_test_large(folio)) {
	pfn = folio_to_pfn(folio) + folio_nr_pages(folio) - 1;
	if (folio_test_hugetlb(folio)) {
		isolate_hugetlb(folio, &source);
		continue;
	}
}



--
Best Regards,
Yan, Zi
Matthew Wilcox March 27, 2024, 2:54 p.m. UTC | #2
On Wed, Mar 27, 2024 at 10:45:42AM -0400, Zi Yan wrote:
> >  	for (pfn = start_pfn; pfn < end_pfn; pfn++) {
> > -		struct folio *folio;
> > +		struct page *page, *head;
> 
> You could get rid of head too. It is only used to calculate next pfn,
> so pfn = folio_to_pfn(folio) + folio_nr_pages(folio) - 1 would work.
> 
> And the PageHuge(page) and PageTransHuge(page) can be simplified, since
> their pfn calculations are the same. Something like:
> 
> if (folio_test_large(folio)) {
> 	pfn = folio_to_pfn(folio) + folio_nr_pages(folio) - 1;
> 	if (folio_test_hugetlb(folio)) {
> 		isolate_hugetlb(folio, &source);
> 		continue;
> 	}
> }

How much of this is safe without a refcount on the folio?
Zi Yan March 27, 2024, 3:10 p.m. UTC | #3
On 27 Mar 2024, at 10:54, Matthew Wilcox wrote:

> On Wed, Mar 27, 2024 at 10:45:42AM -0400, Zi Yan wrote:
>>>  	for (pfn = start_pfn; pfn < end_pfn; pfn++) {
>>> -		struct folio *folio;
>>> +		struct page *page, *head;
>>
>> You could get rid of head too. It is only used to calculate next pfn,
>> so pfn = folio_to_pfn(folio) + folio_nr_pages(folio) - 1 would work.
>>
>> And the PageHuge(page) and PageTransHuge(page) can be simplified, since
>> their pfn calculations are the same. Something like:
>>
>> if (folio_test_large(folio)) {
>> 	pfn = folio_to_pfn(folio) + folio_nr_pages(folio) - 1;
>> 	if (folio_test_hugetlb(folio)) {
>> 		isolate_hugetlb(folio, &source);
>> 		continue;
>> 	}
>> }
>
> How much of this is safe without a refcount on the folio?

folio_to_pfn() should be fine, isolate_hugetlb() checks the folio
under hugetlb_lock, but folio_nr_pages() might return a bogus number
that makes pfn go beyond end_pfn and ends for loop early. The code
below increases the refcount, so it might be better to move this
part of the code after refcount is increased.

--
Best Regards,
Yan, Zi
Matthew Wilcox March 27, 2024, 3:58 p.m. UTC | #4
On Wed, Mar 27, 2024 at 11:10:48AM -0400, Zi Yan wrote:
> On 27 Mar 2024, at 10:54, Matthew Wilcox wrote:
> > How much of this is safe without a refcount on the folio?
> 
> folio_to_pfn() should be fine, isolate_hugetlb() checks the folio
> under hugetlb_lock, but folio_nr_pages() might return a bogus number
> that makes pfn go beyond end_pfn and ends for loop early. The code
> below increases the refcount, so it might be better to move this
> part of the code after refcount is increased.

I really want to instill a little bit of fear in Kefeng.

This is all really subtle code because it's running without a refcount.
I've mostly stayed away from it because I know that I don't know what
I'm doing.  Kefeng has no idea that he doesn't know what he's doing.

And so we get these patches, and they're sometimes subtly wrong, and it
takes a lot of arguing and revision and thinking and Kefeng is doing
very little of the thinking part!

Kefeng, please stick to working on code that you understand.  Or take
the time to learn code you don't understand before sending patches to
it.  This kind of Leeroy Jenkins approach to development is not good.
Kefeng Wang March 28, 2024, 5:06 a.m. UTC | #5
On 2024/3/27 23:10, Zi Yan wrote:
> On 27 Mar 2024, at 10:54, Matthew Wilcox wrote:
> 
>> On Wed, Mar 27, 2024 at 10:45:42AM -0400, Zi Yan wrote:
>>>>   	for (pfn = start_pfn; pfn < end_pfn; pfn++) {
>>>> -		struct folio *folio;
>>>> +		struct page *page, *head;
>>>
>>> You could get rid of head too. It is only used to calculate next pfn,
>>> so pfn = folio_to_pfn(folio) + folio_nr_pages(folio) - 1 would work.
>>>
>>> And the PageHuge(page) and PageTransHuge(page) can be simplified, since
>>> their pfn calculations are the same. Something like:
>>>
>>> if (folio_test_large(folio)) {
>>> 	pfn = folio_to_pfn(folio) + folio_nr_pages(folio) - 1;
>>> 	if (folio_test_hugetlb(folio)) {
>>> 		isolate_hugetlb(folio, &source);
>>> 		continue;
>>> 	}
>>> }
>>
>> How much of this is safe without a refcount on the folio?
> 
> folio_to_pfn() should be fine, isolate_hugetlb() checks the folio
> under hugetlb_lock, but folio_nr_pages() might return a bogus number
> that makes pfn go beyond end_pfn and ends for loop early. The code
> below increases the refcount, so it might be better to move this
> part of the code after refcount is increased.

The PageHWPoison() is per-page check, for hugetlb, it will directly
try to isolate and ignore the PageHWPoison check, I'm not sure about
moveing PageHWPoison ahead, we need to take the i_mmap_lock_write and
add TTU_RMAP_LOCKED for for hugetlb pages in shared mappings when
try_to_unmap(), but now hugetlb pages won't unmap if there is posion
page, if the get_page_unless_zero() is moved ahead, the logical need be
changed a lot, this minimize changes aim to remove isolate_lru/movable_page,
so could we keep it simple, but as your suggested, we could do more
optimization about do_migrate_range() in the next.

Thanks.


> 
> --
> Best Regards,
> Yan, Zi
Kefeng Wang March 28, 2024, 5:30 a.m. UTC | #6
On 2024/3/27 23:58, Matthew Wilcox wrote:
> On Wed, Mar 27, 2024 at 11:10:48AM -0400, Zi Yan wrote:
>> On 27 Mar 2024, at 10:54, Matthew Wilcox wrote:
>>> How much of this is safe without a refcount on the folio?
>>
>> folio_to_pfn() should be fine, isolate_hugetlb() checks the folio
>> under hugetlb_lock, but folio_nr_pages() might return a bogus number
>> that makes pfn go beyond end_pfn and ends for loop early. The code
>> below increases the refcount, so it might be better to move this
>> part of the code after refcount is increased.
> 
> I really want to instill a little bit of fear in Kefeng.
> 
> This is all really subtle code because it's running without a refcount.
> I've mostly stayed away from it because I know that I don't know what
> I'm doing.  Kefeng has no idea that he doesn't know what he's doing.
> 
> And so we get these patches, and they're sometimes subtly wrong, and it
> takes a lot of arguing and revision and thinking and Kefeng is doing
> very little of the thinking part!
> 
> Kefeng, please stick to working on code that you understand.  Or take
> the time to learn code you don't understand before sending patches to
> it.  This kind of Leeroy Jenkins approach to development is not good.

Oh, I remember your reminder and be in awe of changes and try to think
more about changes, for this one, I only convert page to folio after
refcount increased with get_page_unless_zero(), and as replied to Zi,
PageHWPoison part need more consideration and this one only aims to
remove isolate_lru/movable_page, so don't touch the page before
get_page_unless_zero().

Thanks for your review and help all the time.
diff mbox series

Patch

diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index a444e2d7dd2b..bd207772c619 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1774,14 +1774,14 @@  static int scan_movable_pages(unsigned long start, unsigned long end,
 
 static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 {
+	struct folio *folio;
 	unsigned long pfn;
-	struct page *page, *head;
 	LIST_HEAD(source);
 	static DEFINE_RATELIMIT_STATE(migrate_rs, DEFAULT_RATELIMIT_INTERVAL,
 				      DEFAULT_RATELIMIT_BURST);
 
 	for (pfn = start_pfn; pfn < end_pfn; pfn++) {
-		struct folio *folio;
+		struct page *page, *head;
 		bool isolated;
 
 		if (!pfn_valid(pfn))
@@ -1818,15 +1818,15 @@  static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 		 * We can skip free pages. And we can deal with pages on
 		 * LRU and non-lru movable pages.
 		 */
-		if (PageLRU(page))
-			isolated = isolate_lru_page(page);
+		if (folio_test_lru(folio))
+			isolated = folio_isolate_lru(folio);
 		else
-			isolated = isolate_movable_page(page, ISOLATE_UNEVICTABLE);
+			isolated = isolate_movable_folio(folio, ISOLATE_UNEVICTABLE);
 		if (isolated) {
-			list_add_tail(&page->lru, &source);
-			if (!__PageMovable(page))
-				inc_node_page_state(page, NR_ISOLATED_ANON +
-						    page_is_file_lru(page));
+			list_add_tail(&folio->lru, &source);
+			if (!__folio_test_movable(folio))
+				node_stat_add_folio(folio, NR_ISOLATED_ANON +
+						    folio_is_file_lru(folio));
 
 		} else {
 			if (__ratelimit(&migrate_rs)) {
@@ -1834,7 +1834,7 @@  static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 				dump_page(page, "isolation failed");
 			}
 		}
-		put_page(page);
+		folio_put(folio);
 	}
 	if (!list_empty(&source)) {
 		nodemask_t nmask = node_states[N_MEMORY];
@@ -1846,9 +1846,9 @@  static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 
 		/*
 		 * We have checked that migration range is on a single zone so
-		 * we can use the nid of the first page to all the others.
+		 * we can use the nid of the first folio to all the others.
 		 */
-		mtc.nid = page_to_nid(list_first_entry(&source, struct page, lru));
+		mtc.nid = folio_nid(list_first_entry(&source, struct folio, lru));
 
 		/*
 		 * try to allocate from a different node but reuse this node
@@ -1861,11 +1861,11 @@  static void do_migrate_range(unsigned long start_pfn, unsigned long end_pfn)
 		ret = migrate_pages(&source, alloc_migration_target, NULL,
 			(unsigned long)&mtc, MIGRATE_SYNC, MR_MEMORY_HOTPLUG, NULL);
 		if (ret) {
-			list_for_each_entry(page, &source, lru) {
+			list_for_each_entry(folio, &source, lru) {
 				if (__ratelimit(&migrate_rs)) {
 					pr_warn("migrating pfn %lx failed ret:%d\n",
-						page_to_pfn(page), ret);
-					dump_page(page, "migration failure");
+						folio_pfn(folio), ret);
+					dump_page(&folio->page, "migration failure");
 				}
 			}
 			putback_movable_pages(&source);