Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1624049 > unrolled thread
| Started by | Michal Hocko <mhocko@kernel.org> |
|---|---|
| First post | 2017-04-15 14:20 +0200 |
| Last post | 2017-04-24 10:00 +0200 |
| Articles | 13 — 3 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
(none) Michal Hocko <mhocko@kernel.org> - 2017-04-15 14:20 +0200
[PATCH 2/3] mm, compaction: skip over holes in __reset_isolation_suitable Michal Hocko <mhocko@kernel.org> - 2017-04-15 14:20 +0200
Re: your mail Joonsoo Kim <js1304@gmail.com> - 2017-04-17 07:50 +0200
Re: your mail Michal Hocko <mhocko@kernel.org> - 2017-04-17 10:20 +0200
Re: your mail Joonsoo Kim <js1304@gmail.com> - 2017-04-20 03:30 +0200
Re: your mail Michal Hocko <mhocko@kernel.org> - 2017-04-20 09:30 +0200
Re: your mail Michal Hocko <mhocko@kernel.org> - 2017-04-20 10:50 +0200
Re: your mail Vlastimil Babka <vbabka@suse.cz> - 2017-04-20 14:00 +0200
Re: your mail Michal Hocko <mhocko@kernel.org> - 2017-04-20 14:20 +0200
Re: your mail Joonsoo Kim <js1304@gmail.com> - 2017-04-21 06:40 +0200
Re: your mail Michal Hocko <mhocko@kernel.org> - 2017-04-21 09:20 +0200
Re: your mail Joonsoo Kim <js1304@gmail.com> - 2017-04-24 03:50 +0200
Re: your mail Michal Hocko <mhocko@kernel.org> - 2017-04-24 10:00 +0200
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-04-15 14:20 +0200 |
| Subject | (none) |
| Message-ID | <twuQh-6q5-3@gated-at.bofh.it> |
Hi, here I 3 more preparatory patches which I meant to send on Thursday but forgot... After more thinking about pfn walkers I have realized that the current code doesn't check offline holes in zones. From a quick review that doesn't seem to be a problem currently. Pfn walkers can race with memory offlining and with the original hotplug impementation those offline pages can change the zone but I wasn't able to find any serious problem other than small confusion. The new hotplug code, will not have any valid zone, though so those code paths should check PageReserved to rule offline holes. I hope I have addressed all of them in these 3 patches. I would appreciate if Vlastimil and Jonsoo double check after me.
[toc] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-04-15 14:20 +0200 |
| Subject | [PATCH 2/3] mm, compaction: skip over holes in __reset_isolation_suitable |
| Message-ID | <twuQi-6q5-9@gated-at.bofh.it> |
| In reply to | #1624049 |
From: Michal Hocko <mhocko@suse.com> __reset_isolation_suitable walks the whole zone pfn range and it tries to jump over holes by checking the zone for each page. It might still stumble over offline pages, though. Skip those by checking PageReserved. Signed-off-by: Michal Hocko <mhocko@suse.com> --- mm/compaction.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mm/compaction.c b/mm/compaction.c index de64dedefe0e..df4156d8b037 100644 --- a/mm/compaction.c +++ b/mm/compaction.c @@ -239,6 +239,8 @@ static void __reset_isolation_suitable(struct zone *zone) continue; page = pfn_to_page(pfn); + if (PageReserved(page)) + continue; if (zone != page_zone(page)) continue; -- 2.11.0
[toc] | [prev] | [next] | [standalone]
| From | Joonsoo Kim <js1304@gmail.com> |
|---|---|
| Date | 2017-04-17 07:50 +0200 |
| Subject | Re: your mail |
| Message-ID | <tx7HY-5hm-5@gated-at.bofh.it> |
| In reply to | #1624049 |
On Sat, Apr 15, 2017 at 02:17:31PM +0200, Michal Hocko wrote: > Hi, > here I 3 more preparatory patches which I meant to send on Thursday but > forgot... After more thinking about pfn walkers I have realized that > the current code doesn't check offline holes in zones. From a quick > review that doesn't seem to be a problem currently. Pfn walkers can race > with memory offlining and with the original hotplug impementation those > offline pages can change the zone but I wasn't able to find any serious > problem other than small confusion. The new hotplug code, will not have > any valid zone, though so those code paths should check PageReserved > to rule offline holes. I hope I have addressed all of them in these 3 > patches. I would appreciate if Vlastimil and Jonsoo double check after > me. Hello, Michal. s/Jonsoo/Joonsoo. :) I'm not sure that it's a good idea to add PageResereved() check in pfn walkers. First, this makes struct page validity check as two steps, pfn_valid() and then PageResereved(). If we should not use struct page in this case, it's better to pfn_valid() returns false rather than adding a separate check. Anyway, we need to fix more places (all pfn walker?) if we want to check validity by two steps. The other problem I found is that your change will makes some contiguous zones to be considered as non-contiguous. Memory allocated by memblock API is also marked as PageResereved. If we consider this as a hole, we will set such a zone as non-contiguous. And, I guess that it's not enough to check PageResereved() in pageblock_pfn_to_page() in order to skip these pages in compaction. If holes are in the middle of the pageblock, pageblock_pfn_to_page() cannot catch it and compaction will use struct page for this hole. Therefore, I think that making pfn_valid() return false for not onlined memory is a better solution for this problem. I don't know the implementation detail for hotplug and I don't see your recent change but we may defer memmap initialization until the zone is determined. It will make pfn_valid() return false for un-initialized range. Thanks.
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-04-17 10:20 +0200 |
| Subject | Re: your mail |
| Message-ID | <txa37-6NZ-1@gated-at.bofh.it> |
| In reply to | #1624538 |
On Mon 17-04-17 14:47:20, Joonsoo Kim wrote: > On Sat, Apr 15, 2017 at 02:17:31PM +0200, Michal Hocko wrote: > > Hi, > > here I 3 more preparatory patches which I meant to send on Thursday but > > forgot... After more thinking about pfn walkers I have realized that > > the current code doesn't check offline holes in zones. From a quick > > review that doesn't seem to be a problem currently. Pfn walkers can race > > with memory offlining and with the original hotplug impementation those > > offline pages can change the zone but I wasn't able to find any serious > > problem other than small confusion. The new hotplug code, will not have > > any valid zone, though so those code paths should check PageReserved > > to rule offline holes. I hope I have addressed all of them in these 3 > > patches. I would appreciate if Vlastimil and Jonsoo double check after > > me. > > Hello, Michal. > > s/Jonsoo/Joonsoo. :) ups, sorry about that. > I'm not sure that it's a good idea to add PageResereved() check in pfn > walkers. First, this makes struct page validity check as two steps, > pfn_valid() and then PageResereved(). Yes, those are two separate checkes because semantically they are different. Not all pfn walkers do care about the online status. > If we should not use struct page > in this case, it's better to pfn_valid() returns false rather than > adding a separate check. Anyway, we need to fix more places (all pfn > walker?) if we want to check validity by two steps. Which pfn walkers you have in mind? > The other problem I found is that your change will makes some > contiguous zones to be considered as non-contiguous. Memory allocated > by memblock API is also marked as PageResereved. If we consider this as > a hole, we will set such a zone as non-contiguous. Why would that be a problem? We shouldn't touch those pages anyway? > And, I guess that it's not enough to check PageResereved() in > pageblock_pfn_to_page() in order to skip these pages in compaction. If > holes are in the middle of the pageblock, pageblock_pfn_to_page() > cannot catch it and compaction will use struct page for this hole. Yes pageblock_pfn_to_page cannot catch it and it wouldn't with the current implementation anyway. So the implementation won't be any worse than with the current code. On the other hand offline holes will always fill the whole pageblock (assuming those are not spanning multiple memblocks). > Therefore, I think that making pfn_valid() return false for not > onlined memory is a better solution for this problem. I don't know the > implementation detail for hotplug and I don't see your recent change > but we may defer memmap initialization until the zone is determined. > It will make pfn_valid() return false for un-initialized range. I am not really sure. pfn_valid is used in many context and its only purpose is to tell whether pfn_to_page will return a valid struct page AFAIU. I agree that having more checks is more error prone and we can add a helper pfn_to_valid_page or something similar but I believe we can do that on top of the current hotplug rework. This would require a non trivial amount of changes and I believe that a lacking check for the offline holes is not critical - we would (ab)use the lowest zone which is similar to (ab)using ZONE_NORMAL/MOVABLE with the original code. Thanks! -- Michal Hocko SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Joonsoo Kim <js1304@gmail.com> |
|---|---|
| Date | 2017-04-20 03:30 +0200 |
| Subject | Re: your mail |
| Message-ID | <ty94Z-2qb-3@gated-at.bofh.it> |
| In reply to | #1624594 |
On Mon, Apr 17, 2017 at 10:15:15AM +0200, Michal Hocko wrote: > On Mon 17-04-17 14:47:20, Joonsoo Kim wrote: > > On Sat, Apr 15, 2017 at 02:17:31PM +0200, Michal Hocko wrote: > > > Hi, > > > here I 3 more preparatory patches which I meant to send on Thursday but > > > forgot... After more thinking about pfn walkers I have realized that > > > the current code doesn't check offline holes in zones. From a quick > > > review that doesn't seem to be a problem currently. Pfn walkers can race > > > with memory offlining and with the original hotplug impementation those > > > offline pages can change the zone but I wasn't able to find any serious > > > problem other than small confusion. The new hotplug code, will not have > > > any valid zone, though so those code paths should check PageReserved > > > to rule offline holes. I hope I have addressed all of them in these 3 > > > patches. I would appreciate if Vlastimil and Jonsoo double check after > > > me. > > > > Hello, Michal. > > > > s/Jonsoo/Joonsoo. :) > > ups, sorry about that. > > > I'm not sure that it's a good idea to add PageResereved() check in pfn > > walkers. First, this makes struct page validity check as two steps, > > pfn_valid() and then PageResereved(). > > Yes, those are two separate checkes because semantically they are > different. Not all pfn walkers do care about the online status. If offlined page has no valid information, reading information about offlined pages are just wrong. So, all pfn walkers that reads information about the page should do care about it. I guess that many callers for pfn_valid() is in this category. > > > If we should not use struct page > > in this case, it's better to pfn_valid() returns false rather than > > adding a separate check. Anyway, we need to fix more places (all pfn > > walker?) if we want to check validity by two steps. > > Which pfn walkers you have in mind? For example, kpagecount_read() in fs/proc/page.c. I searched it by using pfn_valid(). > > The other problem I found is that your change will makes some > > contiguous zones to be considered as non-contiguous. Memory allocated > > by memblock API is also marked as PageResereved. If we consider this as > > a hole, we will set such a zone as non-contiguous. > > Why would that be a problem? We shouldn't touch those pages anyway? Skipping those pages in compaction are valid so no problem in this case. The problem I mentioned above is that adding PageReserved() check in __pageblock_pfn_to_page() invalidates optimization by set_zone_contiguous(). In compaction, we need to get a valid struct page and it requires a lot of work. There is performance problem report due to this so set_zone_contiguous() optimization is added. It checks if the zone is contiguous or not in boot time. If zone is determined as contiguous, we can easily get a valid struct page in runtime without expensive checks. Your patch try to add PageReserved() to __pageblock_pfn_to_page(). It woule make that zone->contiguous usually returns false since memory used by memblock API is marked as PageReserved() and your patch regard it as a hole. It invalidates set_zone_contiguous() optimization and I worry about it. > > > And, I guess that it's not enough to check PageResereved() in > > pageblock_pfn_to_page() in order to skip these pages in compaction. If > > holes are in the middle of the pageblock, pageblock_pfn_to_page() > > cannot catch it and compaction will use struct page for this hole. > > Yes pageblock_pfn_to_page cannot catch it and it wouldn't with the > current implementation anyway. So the implementation won't be any worse > than with the current code. On the other hand offline holes will always > fill the whole pageblock (assuming those are not spanning multiple > memblocks). > > > Therefore, I think that making pfn_valid() return false for not > > onlined memory is a better solution for this problem. I don't know the > > implementation detail for hotplug and I don't see your recent change > > but we may defer memmap initialization until the zone is determined. > > It will make pfn_valid() return false for un-initialized range. > > I am not really sure. pfn_valid is used in many context and its only > purpose is to tell whether pfn_to_page will return a valid struct page > AFAIU. > > I agree that having more checks is more error prone and we can add a > helper pfn_to_valid_page or something similar but I believe we can do > that on top of the current hotplug rework. This would require a non > trivial amount of changes and I believe that a lacking check for the > offline holes is not critical - we would (ab)use the lowest zone which > is similar to (ab)using ZONE_NORMAL/MOVABLE with the original code. I'm not objecting your hotplug rework. In fact, I don't know the relationship between this work and hotplug rework. I'm agreeing with checking offline holes but I don't like the design and implementation about it. Let me clarify my desire(?) for this issue. 1. If pfn_valid() returns true, struct page has valid information, at least, in flags (zone id, node id, flags, etc...). So, we can use them without checking PageResereved(). 2. pfn_valid() for offlined holes returns false. This can be easily (?) implemented by manipulating SECTION_MAP_MASK in hotplug code. I guess that there is no reason that pfn_valid() returns true for offlined holes. If there is, please let me know. 3. We don't need to check PageReserved() in most of pfn walkers in order to check offline holes. Thanks.
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-04-20 09:30 +0200 |
| Subject | Re: your mail |
| Message-ID | <tyeHn-60B-1@gated-at.bofh.it> |
| In reply to | #1626909 |
On Thu 20-04-17 10:27:55, Joonsoo Kim wrote: > On Mon, Apr 17, 2017 at 10:15:15AM +0200, Michal Hocko wrote: [...] > > Which pfn walkers you have in mind? > > For example, kpagecount_read() in fs/proc/page.c. I searched it by > using pfn_valid(). Yeah, I've checked that one and in fact this is a good example of the case where you do not really care about holes. It just checks the page count which is a valid information under any circumstances. > > > The other problem I found is that your change will makes some > > > contiguous zones to be considered as non-contiguous. Memory allocated > > > by memblock API is also marked as PageResereved. If we consider this as > > > a hole, we will set such a zone as non-contiguous. > > > > Why would that be a problem? We shouldn't touch those pages anyway? > > Skipping those pages in compaction are valid so no problem in this > case. > > The problem I mentioned above is that adding PageReserved() check in > __pageblock_pfn_to_page() invalidates optimization by > set_zone_contiguous(). In compaction, we need to get a valid struct > page and it requires a lot of work. There is performance problem > report due to this so set_zone_contiguous() optimization is added. It > checks if the zone is contiguous or not in boot time. If zone is > determined as contiguous, we can easily get a valid struct page in > runtime without expensive checks. OK, I see. I've had some vague understading and the clarification helps. > Your patch try to add PageReserved() to __pageblock_pfn_to_page(). It > woule make that zone->contiguous usually returns false since memory > used by memblock API is marked as PageReserved() and your patch regard > it as a hole. It invalidates set_zone_contiguous() optimization and I > worry about it. OK, fair enough. I did't consider memblock allocations. I will rethink this patch but there are essentially 3 options - use a different criterion for the offline holes dection. I have just realized we might do it by storing the online information into the mem sections - drop this patch - move the PageReferenced check down the chain into isolate_freepages_block resp. isolate_migratepages_block I would prefer 3 over 2 over 1. I definitely want to make this more robust so 1 is preferable long term but I do not want this to be a roadblock to the rest of the rework. Does that sound acceptable to you? [..] > Let me clarify my desire(?) for this issue. > > 1. If pfn_valid() returns true, struct page has valid information, at > least, in flags (zone id, node id, flags, etc...). So, we can use them > without checking PageResereved(). This is no longer true after my rework. Pages are associated with the zone during _onlining_ rather than when they are physically hotpluged. Basically only the nid is set properly. Strictly speaking this is the case also without my rework because the zone might change during online phase so you cannot assume it is correct even now. It just happens that it more or less works just fine. > 2. pfn_valid() for offlined holes returns false. This can be easily > (?) implemented by manipulating SECTION_MAP_MASK in hotplug code. I > guess that there is no reason that pfn_valid() returns true for > offlined holes. If there is, please let me know. There is some code which really expects that pfn_valid returns true iff there is a struct page and it doesn't care about the online status. E.g. hotplug code itself so no, we cannot change pfn_valid. What we can do though is to add pfn_to_online_page which would do the proper check. I have already sent [1]. As noted above we can (ab)use the remaining bit in SECTION_MAP_MASK to detect offline pages more robustly. > 3. We don't need to check PageReserved() in most of pfn walkers in > order to check offline holes. We still have to distinguish those who care about offline pages from those who do not care about it. Thanks! -- Michal Hocko SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-04-20 10:50 +0200 |
| Subject | Re: your mail |
| Message-ID | <tyfWO-6GX-21@gated-at.bofh.it> |
| In reply to | #1627160 |
On Thu 20-04-17 09:28:20, Michal Hocko wrote:
> On Thu 20-04-17 10:27:55, Joonsoo Kim wrote:
[...]
> > Your patch try to add PageReserved() to __pageblock_pfn_to_page(). It
> > woule make that zone->contiguous usually returns false since memory
> > used by memblock API is marked as PageReserved() and your patch regard
> > it as a hole. It invalidates set_zone_contiguous() optimization and I
> > worry about it.
>
> OK, fair enough. I did't consider memblock allocations. I will rethink
> this patch but there are essentially 3 options
> - use a different criterion for the offline holes dection. I
> have just realized we might do it by storing the online
> information into the mem sections
> - drop this patch
> - move the PageReferenced check down the chain into
> isolate_freepages_block resp. isolate_migratepages_block
>
> I would prefer 3 over 2 over 1. I definitely want to make this more
> robust so 1 is preferable long term but I do not want this to be a
> roadblock to the rest of the rework. Does that sound acceptable to you?
So I've played with all three options just to see how the outcome would
look like and it turned out that going with 1 will be easiest in the
end. What do you think about the following? It should be free of any
false positives. I have only compile tested it yet.
---
From 747794c13c0e82b55b793a31cdbe1a84ee1c6920 Mon Sep 17 00:00:00 2001
From: Michal Hocko <mhocko@suse.com>
Date: Thu, 13 Apr 2017 10:28:45 +0200
Subject: [PATCH] mm: consider zone which is not fully populated to have holes
__pageblock_pfn_to_page has two users currently, set_zone_contiguous
which checks whether the given zone contains holes and
pageblock_pfn_to_page which then carefully returns a first valid
page from the given pfn range for the given zone. This doesn't handle
zones which are not fully populated though. Memory pageblocks can be
offlined or might not have been onlined yet. In such a case the zone
should be considered to have holes otherwise pfn walkers can touch
and play with offline pages.
Current callers of pageblock_pfn_to_page in compaction seem to work
properly right now because they only isolate PageBuddy
(isolate_freepages_block) or PageLRU resp. __PageMovable
(isolate_migratepages_block) which will be always false for these pages.
It would be safer to skip these pages altogether, though.
In order to do this patch adds a new memory section state
(SECTION_IS_ONLINE) which is set in memory_present (during boot
time) or in online_pages_range during the memory hotplug. Similarly
offline_mem_sections clears the bit and it is called when the memory
range is offlined.
pfn_to_online_page helper is then added which check the mem section and
only returns a page if it is onlined already.
Use the new helper in __pageblock_pfn_to_page and skip the whole page
block in such a case.
Signed-off-by: Michal Hocko <mhocko@suse.com>
---
include/linux/memory_hotplug.h | 21 ++++++++++++++++++++
include/linux/mmzone.h | 20 ++++++++++++++++++-
mm/memory_hotplug.c | 3 +++
mm/page_alloc.c | 5 ++++-
mm/sparse.c | 45 +++++++++++++++++++++++++++++++++++++++++-
5 files changed, 91 insertions(+), 3 deletions(-)
diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
index 3c8cf86201c3..fc1c873504eb 100644
--- a/include/linux/memory_hotplug.h
+++ b/include/linux/memory_hotplug.h
@@ -14,6 +14,19 @@ struct memory_block;
struct resource;
#ifdef CONFIG_MEMORY_HOTPLUG
+/*
+ * Return page for the valid pfn only if the page is online. All pfn
+ * walkers which rely on the fully initialized page->flags and others
+ * should use this rather than pfn_valid && pfn_to_page
+ */
+#define pfn_to_online_page(pfn) \
+({ \
+ struct page *___page = NULL; \
+ \
+ if (online_section_nr(pfn_to_section_nr(pfn))) \
+ ___page = pfn_to_page(pfn); \
+ ___page; \
+})
/*
* Types for free bootmem stored in page->lru.next. These have to be in
@@ -203,6 +216,14 @@ extern void set_zone_contiguous(struct zone *zone);
extern void clear_zone_contiguous(struct zone *zone);
#else /* ! CONFIG_MEMORY_HOTPLUG */
+#define pfn_to_online_page(pfn) \
+({ \
+ struct page *___page = NULL; \
+ if (pfn_valid(pfn)) \
+ ___page = pfn_to_page(pfn); \
+ ___page; \
+ })
+
/*
* Stub functions for when hotplug is off
*/
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 0fc121bbf4ff..cad16ac080f5 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -1143,7 +1143,8 @@ extern unsigned long usemap_size(void);
*/
#define SECTION_MARKED_PRESENT (1UL<<0)
#define SECTION_HAS_MEM_MAP (1UL<<1)
-#define SECTION_MAP_LAST_BIT (1UL<<2)
+#define SECTION_IS_ONLINE (1UL<<2)
+#define SECTION_MAP_LAST_BIT (1UL<<3)
#define SECTION_MAP_MASK (~(SECTION_MAP_LAST_BIT-1))
#define SECTION_NID_SHIFT 2
@@ -1174,6 +1175,23 @@ static inline int valid_section_nr(unsigned long nr)
return valid_section(__nr_to_section(nr));
}
+static inline int online_section(struct mem_section *section)
+{
+ return (section && (section->section_mem_map & SECTION_IS_ONLINE));
+}
+
+static inline int online_section_nr(unsigned long nr)
+{
+ return online_section(__nr_to_section(nr));
+}
+
+#ifdef CONFIG_MEMORY_HOTPLUG
+void online_mem_sections(unsigned long start_pfn, unsigned long end_pfn);
+#ifdef CONFIG_MEMORY_HOTREMOVE
+void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn);
+#endif
+#endif
+
static inline struct mem_section *__pfn_to_section(unsigned long pfn)
{
return __nr_to_section(pfn_to_section_nr(pfn));
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index caa58338d121..98f565c279bf 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -929,6 +929,9 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
unsigned long i;
unsigned long onlined_pages = *(unsigned long *)arg;
struct page *page;
+
+ online_mem_sections(start_pfn, start_pfn + nr_pages);
+
if (PageReserved(pfn_to_page(start_pfn)))
for (i = 0; i < nr_pages; i++) {
page = pfn_to_page(start_pfn + i);
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 5d72d29a6ece..fa752de84eef 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -1353,7 +1353,9 @@ struct page *__pageblock_pfn_to_page(unsigned long start_pfn,
if (!pfn_valid(start_pfn) || !pfn_valid(end_pfn))
return NULL;
- start_page = pfn_to_page(start_pfn);
+ start_page = pfn_to_online_page(start_pfn);
+ if (!start_page)
+ return NULL;
if (page_zone(start_page) != zone)
return NULL;
@@ -7686,6 +7688,7 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
break;
if (pfn == end_pfn)
return;
+ offline_mem_sections(pfn, end_pfn);
zone = page_zone(pfn_to_page(pfn));
spin_lock_irqsave(&zone->lock, flags);
pfn = start_pfn;
diff --git a/mm/sparse.c b/mm/sparse.c
index 6903c8fc3085..79017f90d8fc 100644
--- a/mm/sparse.c
+++ b/mm/sparse.c
@@ -185,7 +185,8 @@ void __init memory_present(int nid, unsigned long start, unsigned long end)
ms = __nr_to_section(section);
if (!ms->section_mem_map)
ms->section_mem_map = sparse_encode_early_nid(nid) |
- SECTION_MARKED_PRESENT;
+ SECTION_MARKED_PRESENT |
+ SECTION_IS_ONLINE;
}
}
@@ -590,6 +591,48 @@ void __init sparse_init(void)
}
#ifdef CONFIG_MEMORY_HOTPLUG
+
+/* Mark all memory sections within the pfn range as online */
+void online_mem_sections(unsigned long start_pfn, unsigned long end_pfn)
+{
+ unsigned long pfn;
+
+ for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
+ unsigned long section_nr = pfn_to_section_nr(start_pfn);
+ struct mem_section *ms;
+
+ /* onlining code should never touch invalid ranges */
+ if (WARN_ON(!valid_section_nr(section_nr)))
+ continue;
+
+ ms = __nr_to_section(section_nr);
+ ms->section_mem_map |= SECTION_IS_ONLINE;
+ }
+}
+
+#ifdef CONFIG_MEMORY_HOTREMOVE
+/* Mark all memory sections within the pfn range as online */
+void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn)
+{
+ unsigned long pfn;
+
+ for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
+ unsigned long section_nr = pfn_to_section_nr(start_pfn);
+ struct mem_section *ms;
+
+ /*
+ * TODO this needs some double checking. Offlining code makes
+ * sure to check pfn_valid but those checks might be just bogus
+ */
+ if (WARN_ON(!valid_section_nr(section_nr)))
+ continue;
+
+ ms = __nr_to_section(section_nr);
+ ms->section_mem_map &= ~SECTION_IS_ONLINE;
+ }
+}
+#endif
+
#ifdef CONFIG_SPARSEMEM_VMEMMAP
static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid)
{
--
2.11.0
--
Michal Hocko
SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Vlastimil Babka <vbabka@suse.cz> |
|---|---|
| Date | 2017-04-20 14:00 +0200 |
| Subject | Re: your mail |
| Message-ID | <tyiUF-8tO-7@gated-at.bofh.it> |
| In reply to | #1627213 |
On 04/20/2017 10:49 AM, Michal Hocko wrote:
> On Thu 20-04-17 09:28:20, Michal Hocko wrote:
>> On Thu 20-04-17 10:27:55, Joonsoo Kim wrote:
> [...]
>>> Your patch try to add PageReserved() to __pageblock_pfn_to_page(). It
>>> woule make that zone->contiguous usually returns false since memory
>>> used by memblock API is marked as PageReserved() and your patch regard
>>> it as a hole. It invalidates set_zone_contiguous() optimization and I
>>> worry about it.
>>
>> OK, fair enough. I did't consider memblock allocations. I will rethink
>> this patch but there are essentially 3 options
>> - use a different criterion for the offline holes dection. I
>> have just realized we might do it by storing the online
>> information into the mem sections
>> - drop this patch
>> - move the PageReferenced check down the chain into
>> isolate_freepages_block resp. isolate_migratepages_block
>>
>> I would prefer 3 over 2 over 1. I definitely want to make this more
>> robust so 1 is preferable long term but I do not want this to be a
>> roadblock to the rest of the rework. Does that sound acceptable to you?
>
> So I've played with all three options just to see how the outcome would
> look like and it turned out that going with 1 will be easiest in the
> end. What do you think about the following? It should be free of any
> false positives. I have only compile tested it yet.
That looks fine, can't say immediately if fully correct. I think you'll
need to bump SECTION_NID_SHIFT as well and make sure things still fit?
Otherwise looks like nobody needed a new section bit since 2005, so we
should be fine.
> ---
> From 747794c13c0e82b55b793a31cdbe1a84ee1c6920 Mon Sep 17 00:00:00 2001
> From: Michal Hocko <mhocko@suse.com>
> Date: Thu, 13 Apr 2017 10:28:45 +0200
> Subject: [PATCH] mm: consider zone which is not fully populated to have holes
>
> __pageblock_pfn_to_page has two users currently, set_zone_contiguous
> which checks whether the given zone contains holes and
> pageblock_pfn_to_page which then carefully returns a first valid
> page from the given pfn range for the given zone. This doesn't handle
> zones which are not fully populated though. Memory pageblocks can be
> offlined or might not have been onlined yet. In such a case the zone
> should be considered to have holes otherwise pfn walkers can touch
> and play with offline pages.
>
> Current callers of pageblock_pfn_to_page in compaction seem to work
> properly right now because they only isolate PageBuddy
> (isolate_freepages_block) or PageLRU resp. __PageMovable
> (isolate_migratepages_block) which will be always false for these pages.
> It would be safer to skip these pages altogether, though.
>
> In order to do this patch adds a new memory section state
> (SECTION_IS_ONLINE) which is set in memory_present (during boot
> time) or in online_pages_range during the memory hotplug. Similarly
> offline_mem_sections clears the bit and it is called when the memory
> range is offlined.
>
> pfn_to_online_page helper is then added which check the mem section and
> only returns a page if it is onlined already.
>
> Use the new helper in __pageblock_pfn_to_page and skip the whole page
> block in such a case.
>
> Signed-off-by: Michal Hocko <mhocko@suse.com>
> ---
> include/linux/memory_hotplug.h | 21 ++++++++++++++++++++
> include/linux/mmzone.h | 20 ++++++++++++++++++-
> mm/memory_hotplug.c | 3 +++
> mm/page_alloc.c | 5 ++++-
> mm/sparse.c | 45 +++++++++++++++++++++++++++++++++++++++++-
> 5 files changed, 91 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/memory_hotplug.h b/include/linux/memory_hotplug.h
> index 3c8cf86201c3..fc1c873504eb 100644
> --- a/include/linux/memory_hotplug.h
> +++ b/include/linux/memory_hotplug.h
> @@ -14,6 +14,19 @@ struct memory_block;
> struct resource;
>
> #ifdef CONFIG_MEMORY_HOTPLUG
> +/*
> + * Return page for the valid pfn only if the page is online. All pfn
> + * walkers which rely on the fully initialized page->flags and others
> + * should use this rather than pfn_valid && pfn_to_page
> + */
> +#define pfn_to_online_page(pfn) \
> +({ \
> + struct page *___page = NULL; \
> + \
> + if (online_section_nr(pfn_to_section_nr(pfn))) \
> + ___page = pfn_to_page(pfn); \
> + ___page; \
> +})
>
> /*
> * Types for free bootmem stored in page->lru.next. These have to be in
> @@ -203,6 +216,14 @@ extern void set_zone_contiguous(struct zone *zone);
> extern void clear_zone_contiguous(struct zone *zone);
>
> #else /* ! CONFIG_MEMORY_HOTPLUG */
> +#define pfn_to_online_page(pfn) \
> +({ \
> + struct page *___page = NULL; \
> + if (pfn_valid(pfn)) \
> + ___page = pfn_to_page(pfn); \
> + ___page; \
> + })
> +
> /*
> * Stub functions for when hotplug is off
> */
> diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
> index 0fc121bbf4ff..cad16ac080f5 100644
> --- a/include/linux/mmzone.h
> +++ b/include/linux/mmzone.h
> @@ -1143,7 +1143,8 @@ extern unsigned long usemap_size(void);
> */
> #define SECTION_MARKED_PRESENT (1UL<<0)
> #define SECTION_HAS_MEM_MAP (1UL<<1)
> -#define SECTION_MAP_LAST_BIT (1UL<<2)
> +#define SECTION_IS_ONLINE (1UL<<2)
> +#define SECTION_MAP_LAST_BIT (1UL<<3)
> #define SECTION_MAP_MASK (~(SECTION_MAP_LAST_BIT-1))
> #define SECTION_NID_SHIFT 2
>
> @@ -1174,6 +1175,23 @@ static inline int valid_section_nr(unsigned long nr)
> return valid_section(__nr_to_section(nr));
> }
>
> +static inline int online_section(struct mem_section *section)
> +{
> + return (section && (section->section_mem_map & SECTION_IS_ONLINE));
> +}
> +
> +static inline int online_section_nr(unsigned long nr)
> +{
> + return online_section(__nr_to_section(nr));
> +}
> +
> +#ifdef CONFIG_MEMORY_HOTPLUG
> +void online_mem_sections(unsigned long start_pfn, unsigned long end_pfn);
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn);
> +#endif
> +#endif
> +
> static inline struct mem_section *__pfn_to_section(unsigned long pfn)
> {
> return __nr_to_section(pfn_to_section_nr(pfn));
> diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
> index caa58338d121..98f565c279bf 100644
> --- a/mm/memory_hotplug.c
> +++ b/mm/memory_hotplug.c
> @@ -929,6 +929,9 @@ static int online_pages_range(unsigned long start_pfn, unsigned long nr_pages,
> unsigned long i;
> unsigned long onlined_pages = *(unsigned long *)arg;
> struct page *page;
> +
> + online_mem_sections(start_pfn, start_pfn + nr_pages);
> +
> if (PageReserved(pfn_to_page(start_pfn)))
> for (i = 0; i < nr_pages; i++) {
> page = pfn_to_page(start_pfn + i);
> diff --git a/mm/page_alloc.c b/mm/page_alloc.c
> index 5d72d29a6ece..fa752de84eef 100644
> --- a/mm/page_alloc.c
> +++ b/mm/page_alloc.c
> @@ -1353,7 +1353,9 @@ struct page *__pageblock_pfn_to_page(unsigned long start_pfn,
> if (!pfn_valid(start_pfn) || !pfn_valid(end_pfn))
> return NULL;
>
> - start_page = pfn_to_page(start_pfn);
> + start_page = pfn_to_online_page(start_pfn);
> + if (!start_page)
> + return NULL;
>
> if (page_zone(start_page) != zone)
> return NULL;
> @@ -7686,6 +7688,7 @@ __offline_isolated_pages(unsigned long start_pfn, unsigned long end_pfn)
> break;
> if (pfn == end_pfn)
> return;
> + offline_mem_sections(pfn, end_pfn);
> zone = page_zone(pfn_to_page(pfn));
> spin_lock_irqsave(&zone->lock, flags);
> pfn = start_pfn;
> diff --git a/mm/sparse.c b/mm/sparse.c
> index 6903c8fc3085..79017f90d8fc 100644
> --- a/mm/sparse.c
> +++ b/mm/sparse.c
> @@ -185,7 +185,8 @@ void __init memory_present(int nid, unsigned long start, unsigned long end)
> ms = __nr_to_section(section);
> if (!ms->section_mem_map)
> ms->section_mem_map = sparse_encode_early_nid(nid) |
> - SECTION_MARKED_PRESENT;
> + SECTION_MARKED_PRESENT |
> + SECTION_IS_ONLINE;
> }
> }
>
> @@ -590,6 +591,48 @@ void __init sparse_init(void)
> }
>
> #ifdef CONFIG_MEMORY_HOTPLUG
> +
> +/* Mark all memory sections within the pfn range as online */
> +void online_mem_sections(unsigned long start_pfn, unsigned long end_pfn)
> +{
> + unsigned long pfn;
> +
> + for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
> + unsigned long section_nr = pfn_to_section_nr(start_pfn);
> + struct mem_section *ms;
> +
> + /* onlining code should never touch invalid ranges */
> + if (WARN_ON(!valid_section_nr(section_nr)))
> + continue;
> +
> + ms = __nr_to_section(section_nr);
> + ms->section_mem_map |= SECTION_IS_ONLINE;
> + }
> +}
> +
> +#ifdef CONFIG_MEMORY_HOTREMOVE
> +/* Mark all memory sections within the pfn range as online */
> +void offline_mem_sections(unsigned long start_pfn, unsigned long end_pfn)
> +{
> + unsigned long pfn;
> +
> + for (pfn = start_pfn; pfn < end_pfn; pfn += PAGES_PER_SECTION) {
> + unsigned long section_nr = pfn_to_section_nr(start_pfn);
> + struct mem_section *ms;
> +
> + /*
> + * TODO this needs some double checking. Offlining code makes
> + * sure to check pfn_valid but those checks might be just bogus
> + */
> + if (WARN_ON(!valid_section_nr(section_nr)))
> + continue;
> +
> + ms = __nr_to_section(section_nr);
> + ms->section_mem_map &= ~SECTION_IS_ONLINE;
> + }
> +}
> +#endif
> +
> #ifdef CONFIG_SPARSEMEM_VMEMMAP
> static inline struct page *kmalloc_section_memmap(unsigned long pnum, int nid)
> {
>
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-04-20 14:20 +0200 |
| Subject | Re: your mail |
| Message-ID | <tyje1-o7-5@gated-at.bofh.it> |
| In reply to | #1627396 |
On Thu 20-04-17 13:56:34, Vlastimil Babka wrote:
> On 04/20/2017 10:49 AM, Michal Hocko wrote:
> > On Thu 20-04-17 09:28:20, Michal Hocko wrote:
> >> On Thu 20-04-17 10:27:55, Joonsoo Kim wrote:
> > [...]
> >>> Your patch try to add PageReserved() to __pageblock_pfn_to_page(). It
> >>> woule make that zone->contiguous usually returns false since memory
> >>> used by memblock API is marked as PageReserved() and your patch regard
> >>> it as a hole. It invalidates set_zone_contiguous() optimization and I
> >>> worry about it.
> >>
> >> OK, fair enough. I did't consider memblock allocations. I will rethink
> >> this patch but there are essentially 3 options
> >> - use a different criterion for the offline holes dection. I
> >> have just realized we might do it by storing the online
> >> information into the mem sections
> >> - drop this patch
> >> - move the PageReferenced check down the chain into
> >> isolate_freepages_block resp. isolate_migratepages_block
> >>
> >> I would prefer 3 over 2 over 1. I definitely want to make this more
> >> robust so 1 is preferable long term but I do not want this to be a
> >> roadblock to the rest of the rework. Does that sound acceptable to you?
> >
> > So I've played with all three options just to see how the outcome would
> > look like and it turned out that going with 1 will be easiest in the
> > end. What do you think about the following? It should be free of any
> > false positives. I have only compile tested it yet.
>
> That looks fine, can't say immediately if fully correct. I think you'll
> need to bump SECTION_NID_SHIFT as well and make sure things still fit?
> Otherwise looks like nobody needed a new section bit since 2005, so we
> should be fine.
You are absolutely right. Thanks for spotting this! I have folded this
in
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index 611ff869fa4d..c412e6a3a1e9 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -1166,7 +1166,7 @@ extern unsigned long usemap_size(void);
#define SECTION_IS_ONLINE (1UL<<2)
#define SECTION_MAP_LAST_BIT (1UL<<3)
#define SECTION_MAP_MASK (~(SECTION_MAP_LAST_BIT-1))
-#define SECTION_NID_SHIFT 2
+#define SECTION_NID_SHIFT 3
static inline struct page *__section_mem_map_addr(struct mem_section *section)
{
--
Michal Hocko
SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Joonsoo Kim <js1304@gmail.com> |
|---|---|
| Date | 2017-04-21 06:40 +0200 |
| Subject | Re: your mail |
| Message-ID | <tyywq-1na-9@gated-at.bofh.it> |
| In reply to | #1627160 |
On Thu, Apr 20, 2017 at 09:28:20AM +0200, Michal Hocko wrote: > On Thu 20-04-17 10:27:55, Joonsoo Kim wrote: > > On Mon, Apr 17, 2017 at 10:15:15AM +0200, Michal Hocko wrote: > [...] > > > Which pfn walkers you have in mind? > > > > For example, kpagecount_read() in fs/proc/page.c. I searched it by > > using pfn_valid(). > > Yeah, I've checked that one and in fact this is a good example of the > case where you do not really care about holes. It just checks the page > count which is a valid information under any circumstances. I don't think so. First, it checks the page *map* count. Is it still valid even if PageReserved() is set? What I'd like to ask in this example is that what information is valid if PageReserved() is set. Is there any design document on this? I think that we need to define/document it first. And, I hope that all the information in flags field is valid in all cases if pfn_valid() return true. By the design. This makes all the exsiting pfn walkers happy since we don't need an additional check for PageReserved(). > > > > > The other problem I found is that your change will makes some > > > > contiguous zones to be considered as non-contiguous. Memory allocated > > > > by memblock API is also marked as PageResereved. If we consider this as > > > > a hole, we will set such a zone as non-contiguous. > > > > > > Why would that be a problem? We shouldn't touch those pages anyway? > > > > Skipping those pages in compaction are valid so no problem in this > > case. > > > > The problem I mentioned above is that adding PageReserved() check in > > __pageblock_pfn_to_page() invalidates optimization by > > set_zone_contiguous(). In compaction, we need to get a valid struct > > page and it requires a lot of work. There is performance problem > > report due to this so set_zone_contiguous() optimization is added. It > > checks if the zone is contiguous or not in boot time. If zone is > > determined as contiguous, we can easily get a valid struct page in > > runtime without expensive checks. > > OK, I see. I've had some vague understading and the clarification helps. > > > Your patch try to add PageReserved() to __pageblock_pfn_to_page(). It > > woule make that zone->contiguous usually returns false since memory > > used by memblock API is marked as PageReserved() and your patch regard > > it as a hole. It invalidates set_zone_contiguous() optimization and I > > worry about it. > > OK, fair enough. I did't consider memblock allocations. I will rethink > this patch but there are essentially 3 options > - use a different criterion for the offline holes dection. I > have just realized we might do it by storing the online > information into the mem sections > - drop this patch > - move the PageReferenced check down the chain into > isolate_freepages_block resp. isolate_migratepages_block > > I would prefer 3 over 2 over 1. I definitely want to make this more > robust so 1 is preferable long term but I do not want this to be a > roadblock to the rest of the rework. Does that sound acceptable to you? I like #1 among of above options and I already see your patch for #1. It's much better than your first attempt but I'm still not happy due to the semantic of pfn_valid(). > [..] > > Let me clarify my desire(?) for this issue. > > > > 1. If pfn_valid() returns true, struct page has valid information, at > > least, in flags (zone id, node id, flags, etc...). So, we can use them > > without checking PageResereved(). > > This is no longer true after my rework. Pages are associated with the > zone during _onlining_ rather than when they are physically hotpluged. If your rework make information valid during _onlining_, my suggestion is making pfn_valid() return false until onlining. Caller of pfn_valid() expects that they can get valid information from the struct page. There is no reason to access the struct page if they can't get valid information from it. So, passing pfn_valid() should guarantee that, at least, some kind of information is valid. If pfn_valid() doesn't guarantee it, most of the pfn walker should check PageResereved() to make sure that validity of information from the struct page. > Basically only the nid is set properly. Strictly speaking this is the > case also without my rework because the zone might change during online > phase so you cannot assume it is correct even now. It just happens that > it more or less works just fine. > > > 2. pfn_valid() for offlined holes returns false. This can be easily > > (?) implemented by manipulating SECTION_MAP_MASK in hotplug code. I > > guess that there is no reason that pfn_valid() returns true for > > offlined holes. If there is, please let me know. > > There is some code which really expects that pfn_valid returns true iff > there is a struct page and it doesn't care about the online status. > E.g. hotplug code itself so no, we cannot change pfn_valid. What we can > do though is to add pfn_to_online_page which would do the proper check. > I have already sent [1]. As noted above we can (ab)use the remaining bit > in SECTION_MAP_MASK to detect offline pages more robustly. Some pfn_valid() caller in hotplug code look wrong. They want to check section's validity rather than pfn's validity. Others want to access the struct page so they fit for my assumption (?) for pfn_valid(). Therefore, we can change that pfn_valid() return false until online. > > 3. We don't need to check PageReserved() in most of pfn walkers in > > order to check offline holes. > > We still have to distinguish those who care about offline pages from > those who do not care about it. Hotplug code can distinguish those by another way by using new section mask as you did in a new patch. If someone excluding hotplug code do care about offline pages, it would be just for optimization rather than correteness. I think that it's okay. Thanks.
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-04-21 09:20 +0200 |
| Subject | Re: your mail |
| Message-ID | <tyB1g-2W6-13@gated-at.bofh.it> |
| In reply to | #1627946 |
On Fri 21-04-17 13:38:28, Joonsoo Kim wrote: > On Thu, Apr 20, 2017 at 09:28:20AM +0200, Michal Hocko wrote: > > On Thu 20-04-17 10:27:55, Joonsoo Kim wrote: > > > On Mon, Apr 17, 2017 at 10:15:15AM +0200, Michal Hocko wrote: > > [...] > > > > Which pfn walkers you have in mind? > > > > > > For example, kpagecount_read() in fs/proc/page.c. I searched it by > > > using pfn_valid(). > > > > Yeah, I've checked that one and in fact this is a good example of the > > case where you do not really care about holes. It just checks the page > > count which is a valid information under any circumstances. > > I don't think so. First, it checks the page *map* count. Is it still valid > even if PageReserved() is set? I do not know about any user which would manipulate page map count for referenced pages. The core MM code doesn't. > What I'd like to ask in this example is > that what information is valid if PageReserved() is set. Is there any > design document on this? I think that we need to define/document it first. NO, it is not AFAIK. [...] > > OK, fair enough. I did't consider memblock allocations. I will rethink > > this patch but there are essentially 3 options > > - use a different criterion for the offline holes dection. I > > have just realized we might do it by storing the online > > information into the mem sections > > - drop this patch > > - move the PageReferenced check down the chain into > > isolate_freepages_block resp. isolate_migratepages_block > > > > I would prefer 3 over 2 over 1. I definitely want to make this more > > robust so 1 is preferable long term but I do not want this to be a > > roadblock to the rest of the rework. Does that sound acceptable to you? > > I like #1 among of above options and I already see your patch for #1. > It's much better than your first attempt but I'm still not happy due > to the semantic of pfn_valid(). You are trying to change a semantic of something that has a well defined meaning. I disagree that we should change it. It might sound like a simpler thing to do because pfn walkers will have to be checked but what you are proposing is conflating two different things together. > > [..] > > > Let me clarify my desire(?) for this issue. > > > > > > 1. If pfn_valid() returns true, struct page has valid information, at > > > least, in flags (zone id, node id, flags, etc...). So, we can use them > > > without checking PageResereved(). > > > > This is no longer true after my rework. Pages are associated with the > > zone during _onlining_ rather than when they are physically hotpluged. > > If your rework make information valid during _onlining_, my > suggestion is making pfn_valid() return false until onlining. > > Caller of pfn_valid() expects that they can get valid information from > the struct page. There is no reason to access the struct page if they > can't get valid information from it. So, passing pfn_valid() should > guarantee that, at least, some kind of information is valid. > > If pfn_valid() doesn't guarantee it, most of the pfn walker should > check PageResereved() to make sure that validity of information from > the struct page. This is true only for those walkers which really depend on the full initialization. This is not the case for all of them. I do not see any reason to introduce another _pfn_valid to just check whether there is a struct page... So please do not conflate those two different concepts together. I believe that the most prominent pfn walkers should be covered now and others can be evaluated later. -- Michal Hocko SUSE Labs
[toc] | [prev] | [next] | [standalone]
| From | Joonsoo Kim <js1304@gmail.com> |
|---|---|
| Date | 2017-04-24 03:50 +0200 |
| Subject | Re: your mail |
| Message-ID | <tzBiy-8qY-3@gated-at.bofh.it> |
| In reply to | #1628002 |
On Fri, Apr 21, 2017 at 09:16:16AM +0200, Michal Hocko wrote: > On Fri 21-04-17 13:38:28, Joonsoo Kim wrote: > > On Thu, Apr 20, 2017 at 09:28:20AM +0200, Michal Hocko wrote: > > > On Thu 20-04-17 10:27:55, Joonsoo Kim wrote: > > > > On Mon, Apr 17, 2017 at 10:15:15AM +0200, Michal Hocko wrote: > > > [...] > > > > > Which pfn walkers you have in mind? > > > > > > > > For example, kpagecount_read() in fs/proc/page.c. I searched it by > > > > using pfn_valid(). > > > > > > Yeah, I've checked that one and in fact this is a good example of the > > > case where you do not really care about holes. It just checks the page > > > count which is a valid information under any circumstances. > > > > I don't think so. First, it checks the page *map* count. Is it still valid > > even if PageReserved() is set? > > I do not know about any user which would manipulate page map count for > referenced pages. The core MM code doesn't. That's weird that we can get *map* count without PageReserved() check, but we cannot get zone information. Zone information is more static information than map count. It should be defined/documented in this time that what information in the struct page is valid even if PageReserved() is set. And then, we need to fix all the things based on this design decision. > > > What I'd like to ask in this example is > > that what information is valid if PageReserved() is set. Is there any > > design document on this? I think that we need to define/document it first. > > NO, it is not AFAIK. > > [...] > > > OK, fair enough. I did't consider memblock allocations. I will rethink > > > this patch but there are essentially 3 options > > > - use a different criterion for the offline holes dection. I > > > have just realized we might do it by storing the online > > > information into the mem sections > > > - drop this patch > > > - move the PageReferenced check down the chain into > > > isolate_freepages_block resp. isolate_migratepages_block > > > > > > I would prefer 3 over 2 over 1. I definitely want to make this more > > > robust so 1 is preferable long term but I do not want this to be a > > > roadblock to the rest of the rework. Does that sound acceptable to you? > > > > I like #1 among of above options and I already see your patch for #1. > > It's much better than your first attempt but I'm still not happy due > > to the semantic of pfn_valid(). > > You are trying to change a semantic of something that has a well defined > meaning. I disagree that we should change it. It might sound like a > simpler thing to do because pfn walkers will have to be checked but what > you are proposing is conflating two different things together. I don't think that *I* try to change the semantic of pfn_valid(). It would be original semantic of pfn_valid(). "If pfn_valid() returns true, we can get proper struct page and the zone information," That situation is now being changed by your patch *hotplug rework*. "Even if pfn_valid() returns true, we cannot get the zone information without PageReserved() check, since *zone is determined during onlining* and pfn_valid() return true after adding the memory." > > > > [..] > > > > Let me clarify my desire(?) for this issue. > > > > > > > > 1. If pfn_valid() returns true, struct page has valid information, at > > > > least, in flags (zone id, node id, flags, etc...). So, we can use them > > > > without checking PageResereved(). > > > > > > This is no longer true after my rework. Pages are associated with the > > > zone during _onlining_ rather than when they are physically hotpluged. > > > > If your rework make information valid during _onlining_, my > > suggestion is making pfn_valid() return false until onlining. > > > > Caller of pfn_valid() expects that they can get valid information from > > the struct page. There is no reason to access the struct page if they > > can't get valid information from it. So, passing pfn_valid() should > > guarantee that, at least, some kind of information is valid. > > > > If pfn_valid() doesn't guarantee it, most of the pfn walker should > > check PageResereved() to make sure that validity of information from > > the struct page. > > This is true only for those walkers which really depend on the full > initialization. This is not the case for all of them. I do not see any > reason to introduce another _pfn_valid to just check whether there is a > struct page... It's really confusing concept that only some information is valid for *not* fully initialized struct page. Even, there is no document that what information is valid for this half-initialized struct page. Better design would be that we regard that every information is invalid for half-initialized struct page. In this case, it's natural to make pfn_valid() returns false for this half-initialized struct page. > > So please do not conflate those two different concepts together. I > believe that the most prominent pfn walkers should be covered now and > others can be evaluated later. Even if original pfn_valid()'s semantic is not the one that I mentioned, I think that suggested semantic from me is better. Only hotplug code need to be changed and others doesn't need to be changed. There is no overhead for others. What's the problem about this approach? And, I'm not sure that you covered the most prominent pfn walkers. Please see pagetypeinfo_showblockcount_print() in mm/vmstat.c. As you admitted, additional check approach is really error-prone and this example shows that. Thanks.
[toc] | [prev] | [next] | [standalone]
| From | Michal Hocko <mhocko@kernel.org> |
|---|---|
| Date | 2017-04-24 10:00 +0200 |
| Subject | Re: your mail |
| Message-ID | <tzH4B-4c8-1@gated-at.bofh.it> |
| In reply to | #1629119 |
On Mon 24-04-17 10:44:43, Joonsoo Kim wrote: > On Fri, Apr 21, 2017 at 09:16:16AM +0200, Michal Hocko wrote: > > On Fri 21-04-17 13:38:28, Joonsoo Kim wrote: > > > On Thu, Apr 20, 2017 at 09:28:20AM +0200, Michal Hocko wrote: > > > > On Thu 20-04-17 10:27:55, Joonsoo Kim wrote: > > > > > On Mon, Apr 17, 2017 at 10:15:15AM +0200, Michal Hocko wrote: > > > > [...] > > > > > > Which pfn walkers you have in mind? > > > > > > > > > > For example, kpagecount_read() in fs/proc/page.c. I searched it by > > > > > using pfn_valid(). > > > > > > > > Yeah, I've checked that one and in fact this is a good example of the > > > > case where you do not really care about holes. It just checks the page > > > > count which is a valid information under any circumstances. > > > > > > I don't think so. First, it checks the page *map* count. Is it still valid > > > even if PageReserved() is set? > > > > I do not know about any user which would manipulate page map count for > > referenced pages. The core MM code doesn't. > > That's weird that we can get *map* count without PageReserved() check, > but we cannot get zone information. > Zone information is more static information than map count. As I've already pointed out the rework of the hotplug code is mainly about postponing the zone initialization from the physical hot add to the logical onlining. The zone is really not clear until that moment. > It should be defined/documented in this time that what information in > the struct page is valid even if PageReserved() is set. And then, we > need to fix all the things based on this design decision. Where would you suggest documenting this? We do have Documentation/memory-hotplug.txt but it is not really specific about struct page. [...] > > You are trying to change a semantic of something that has a well defined > > meaning. I disagree that we should change it. It might sound like a > > simpler thing to do because pfn walkers will have to be checked but what > > you are proposing is conflating two different things together. > > I don't think that *I* try to change the semantic of pfn_valid(). > It would be original semantic of pfn_valid(). > > "If pfn_valid() returns true, we can get proper struct page and the > zone information," I do not see any guarantee about the zone information anywhere. In fact this is not true with the original implementation as I've tried to explain already. We do have new pages associated with a zone but that association might change during the online phase. So you cannot really rely on that information until the page is online. There is no real change in that regards after my rework. [...] > > So please do not conflate those two different concepts together. I > > believe that the most prominent pfn walkers should be covered now and > > others can be evaluated later. > > Even if original pfn_valid()'s semantic is not the one that I mentioned, > I think that suggested semantic from me is better. > Only hotplug code need to be changed and others doesn't need to be changed. > There is no overhead for others. What's the problem about this approach? That this would require to check _every_ single pfn_valid user in the kernel. That is beyond my time capacity and not really necessary because the current code already suffers from the same/similar class of problems. > And, I'm not sure that you covered the most prominent pfn walkers. > Please see pagetypeinfo_showblockcount_print() in mm/vmstat.c. I probably haven't (and will send a patch to fix this one - thanks for pointing to it) but the point is they those are broken already and they can be fixed in follow up patches. If you change pfn_valid you might break an existing code in an unexpected ways. -- Michal Hocko SUSE Labs
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web