Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1340578 > unrolled thread
| Started by | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| First post | 2016-02-23 13:20 +0100 |
| Last post | 2016-02-24 17:50 +0100 |
| Articles | 18 — 9 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.
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) "Kirill A. Shutemov" <kirill@shutemov.name> - 2016-02-23 13:20 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Linus Torvalds <torvalds@linux-foundation.org> - 2016-02-23 18:50 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Gerald Schaefer <gerald.schaefer@de.ibm.com> - 2016-02-23 19:20 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Will Deacon <will.deacon@arm.com> - 2016-02-23 19:50 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Steve Capper <steve.capper@linaro.org> - 2016-02-25 16:50 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) "Kirill A. Shutemov" <kirill@shutemov.name> - 2016-02-25 17:10 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Steve Capper <steve.capper@linaro.org> - 2016-02-25 17:10 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Will Deacon <will.deacon@arm.com> - 2016-02-23 21:30 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Christian Borntraeger <borntraeger@de.ibm.com> - 2016-02-24 11:20 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Will Deacon <will.deacon@arm.com> - 2016-02-24 11:50 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Christian Borntraeger <borntraeger@de.ibm.com> - 2016-02-24 12:00 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Will Deacon <will.deacon@arm.com> - 2016-02-24 12:10 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> - 2016-02-24 18:30 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Martin Schwidefsky <schwidefsky@de.ibm.com> - 2016-02-24 09:30 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Martin Schwidefsky <schwidefsky@de.ibm.com> - 2016-02-24 09:40 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Sebastian Ott <sebott@linux.vnet.ibm.com> - 2016-02-24 13:20 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) "Kirill A. Shutemov" <kirill@shutemov.name> - 2016-02-24 10:20 +0100
Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) Gerald Schaefer <gerald.schaefer@de.ibm.com> - 2016-02-24 17:50 +0100
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2016-02-23 13:20 +0100 |
| Subject | Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) |
| Message-ID | <r5k6C-5fs-17@gated-at.bofh.it> |
On Fri, Feb 12, 2016 at 06:16:40PM +0100, Gerald Schaefer wrote:
> On Fri, 12 Feb 2016 16:57:27 +0100
> Christian Borntraeger <borntraeger@de.ibm.com> wrote:
>
> > > I'm also confused by pmd_none() is equal to !pmd_present() on s390. Hm?
> >
> > Don't know, Gerald or Martin?
>
> The implementation frequently changes depending on how many new bits Martin
> needs to squeeze out :-)
> We don't have a _PAGE_PRESENT bit for pmds, so pmd_present() just checks if the
> entry is not empty. pmd_none() of course does the opposite, it checks if it is
> empty.
I still worry about pmd_present(). It looks wrong to me. I wounder if
patch below makes a difference.
The theory is that the splitting bit effetely masked bogus pmd_present():
we had pmd_trans_splitting() in all code path and that prevented mm from
touching the pmd. Once pmd_trans_splitting() has gone, mm proceed with the
pmd where it shouldn't and here's a boom.
I'm not sure that the patch is correct wrt yound/old pmds and I have no
way to test it...
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index 64ead8091248..2eeb17ab68ac 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -490,7 +490,7 @@ static inline int pud_bad(pud_t pud)
static inline int pmd_present(pmd_t pmd)
{
- return pmd_val(pmd) != _SEGMENT_ENTRY_INVALID;
+ return !(pmd_val(pmd) & _SEGMENT_ENTRY_INVALID);
}
static inline int pmd_none(pmd_t pmd)
--
Kirill A. Shutemov
[toc] | [next] | [standalone]
| From | Linus Torvalds <torvalds@linux-foundation.org> |
|---|---|
| Date | 2016-02-23 18:50 +0100 |
| Message-ID | <r5pfX-fN-3@gated-at.bofh.it> |
| In reply to | #1340578 |
On Tue, Feb 23, 2016 at 2:32 AM, Kirill A. Shutemov
<kirill@shutemov.name> wrote:
>
> I still worry about pmd_present(). It looks wrong to me. I wounder if
> patch below makes a difference.
Let's hope that's it, but in the meantime I do want to start the
discussion about what to do if it isn't. We're at rc5, and 4.5 is just
a few weeks away, and so far this issue hasn't gone anywhere.
So the *good* scenario is that your pmd_present() patch fixes it, and
we can all take a relieved breath.
But if not, what then? It looks like we have two options:
(a) do a (hopefully minimal) revert.
I say "hopefully minimal", but I suspect the revert is going to
have to undo pretty much all of the core THP changes. I'd hate to see
that, because I really liked the cleanups.
(b) mark THP as "depends on !S390" in the 4.5 release
The (b) option is obviously much simpler, but it's a regression. I
really don't like it, even if it generally shouldn't be the kind of
regression that is actually user-noticeable (apart from performance).
I also hate the fact that while the problem only seems to happen on
s390, we don't even understand it, so maybe it's a more generic issue
that for some reason just ends up being *much* more noticeable on one
odd architecture that happens to be a bit different.
I'm inclined to think of (b) as just a "give us more time to figure it
out" thing, but I'm also worried that it will then make people not
pursue this issue.
How big is a revert patch that makes THP work on s390 again? Can we do
a revert that keeps the infrastructure intact and makes it easy to
revisit the THP cleanups later? Or is the revert inevitably going to
be all the core patches in that series?
Linus
[toc] | [prev] | [next] | [standalone]
| From | Gerald Schaefer <gerald.schaefer@de.ibm.com> |
|---|---|
| Date | 2016-02-23 19:20 +0100 |
| Subject | Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) |
| Message-ID | <r5pJ1-G1-25@gated-at.bofh.it> |
| In reply to | #1340578 |
On Tue, 23 Feb 2016 13:32:21 +0300
"Kirill A. Shutemov" <kirill@shutemov.name> wrote:
> On Fri, Feb 12, 2016 at 06:16:40PM +0100, Gerald Schaefer wrote:
> > On Fri, 12 Feb 2016 16:57:27 +0100
> > Christian Borntraeger <borntraeger@de.ibm.com> wrote:
> >
> > > > I'm also confused by pmd_none() is equal to !pmd_present() on s390. Hm?
> > >
> > > Don't know, Gerald or Martin?
> >
> > The implementation frequently changes depending on how many new bits Martin
> > needs to squeeze out :-)
> > We don't have a _PAGE_PRESENT bit for pmds, so pmd_present() just checks if the
> > entry is not empty. pmd_none() of course does the opposite, it checks if it is
> > empty.
>
> I still worry about pmd_present(). It looks wrong to me. I wounder if
> patch below makes a difference.
>
> The theory is that the splitting bit effetely masked bogus pmd_present():
> we had pmd_trans_splitting() in all code path and that prevented mm from
> touching the pmd. Once pmd_trans_splitting() has gone, mm proceed with the
> pmd where it shouldn't and here's a boom.
Well, I don't think pmd_present() == true is bogus for a trans_huge pmd under
splitting, after all there is a page behind the the pmd. Also, if it was
bogus, and it would need to be false, why should it be marked !pmd_present()
only at the pmdp_invalidate() step before the pmd_populate()? It clearly
is pmd_present() before that, on all architectures, and if there was any
problem/race with that, setting it to !pmd_present() at this stage would
only (marginally) reduce the race window.
BTW, PowerPC and Sparc seem to do the same thing in pmdp_invalidate(),
i.e. they do not set pmd_present() == false, only mark it so that it would
not generate a new TLB entry, just like on s390. After all, the function
is called pmdp_invalidate(), and I think the comment in mm/huge_memory.c
before that call is just a little ambiguous in its wording. When it says
"mark the pmd notpresent" it probably means "mark it so that it will not
generate a new TLB entry", which is also what the comment is really about:
prevent huge and small entries in the TLB for the same page at the same
time.
FWIW, and since the ARM arch-list is already on cc, I think there is
an issue with pmdp_invalidate() on ARM, since it also seems to clear
the trans_huge (and formerly trans_splitting) bit, which actually makes
the pmd !pmd_present(), but it violates the other requirement from the
comment:
"the pmd_trans_huge and pmd_trans_splitting must remain set at all times
on the pmd until the split is complete for this pmd"
>
> I'm not sure that the patch is correct wrt yound/old pmds and I have no
> way to test it...
>
> diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
> index 64ead8091248..2eeb17ab68ac 100644
> --- a/arch/s390/include/asm/pgtable.h
> +++ b/arch/s390/include/asm/pgtable.h
> @@ -490,7 +490,7 @@ static inline int pud_bad(pud_t pud)
>
> static inline int pmd_present(pmd_t pmd)
> {
> - return pmd_val(pmd) != _SEGMENT_ENTRY_INVALID;
> + return !(pmd_val(pmd) & _SEGMENT_ENTRY_INVALID);
> }
>
> static inline int pmd_none(pmd_t pmd)
No, that would not work well with young rw and ro pmds. We do now
have an extra free bit in the pmd on s390, after the removal of the
splitting bit, so we could try to implement pmd_present() with that
sw bit, but that would also require several not-so-trivial changes
to the other code in arch/s390/include/asm/pgtable.h.
I'll check with Martin, maybe it is actually trivial, then we can
do a quick test it to rule that one out.
[toc] | [prev] | [next] | [standalone]
| From | Will Deacon <will.deacon@arm.com> |
|---|---|
| Date | 2016-02-23 19:50 +0100 |
| Message-ID | <r5qc2-SW-31@gated-at.bofh.it> |
| In reply to | #1340925 |
[adding Steve, since he worked on THP for 32-bit ARM] On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote: > On Tue, 23 Feb 2016 13:32:21 +0300 > "Kirill A. Shutemov" <kirill@shutemov.name> wrote: > > The theory is that the splitting bit effetely masked bogus pmd_present(): > > we had pmd_trans_splitting() in all code path and that prevented mm from > > touching the pmd. Once pmd_trans_splitting() has gone, mm proceed with the > > pmd where it shouldn't and here's a boom. > > Well, I don't think pmd_present() == true is bogus for a trans_huge pmd under > splitting, after all there is a page behind the the pmd. Also, if it was > bogus, and it would need to be false, why should it be marked !pmd_present() > only at the pmdp_invalidate() step before the pmd_populate()? It clearly > is pmd_present() before that, on all architectures, and if there was any > problem/race with that, setting it to !pmd_present() at this stage would > only (marginally) reduce the race window. > > BTW, PowerPC and Sparc seem to do the same thing in pmdp_invalidate(), > i.e. they do not set pmd_present() == false, only mark it so that it would > not generate a new TLB entry, just like on s390. After all, the function > is called pmdp_invalidate(), and I think the comment in mm/huge_memory.c > before that call is just a little ambiguous in its wording. When it says > "mark the pmd notpresent" it probably means "mark it so that it will not > generate a new TLB entry", which is also what the comment is really about: > prevent huge and small entries in the TLB for the same page at the same > time. > > FWIW, and since the ARM arch-list is already on cc, I think there is > an issue with pmdp_invalidate() on ARM, since it also seems to clear > the trans_huge (and formerly trans_splitting) bit, which actually makes > the pmd !pmd_present(), but it violates the other requirement from the > comment: > "the pmd_trans_huge and pmd_trans_splitting must remain set at all times > on the pmd until the split is complete for this pmd" I've only been testing this for arm64 (where I'm yet to see a problem), but we use the generic pmdp_invalidate implementation from mm/pgtable-generic.c there. On arm64, pmd_trans_huge will return true after pmd_mknotpresent. On arm, it does look to be buggy, since it nukes the entire entry... Steve? Will
[toc] | [prev] | [next] | [standalone]
| From | Steve Capper <steve.capper@linaro.org> |
|---|---|
| Date | 2016-02-25 16:50 +0100 |
| Message-ID | <r66kW-5Wh-11@gated-at.bofh.it> |
| In reply to | #1340944 |
On 23 February 2016 at 18:47, Will Deacon <will.deacon@arm.com> wrote: > [adding Steve, since he worked on THP for 32-bit ARM] Apologies for my late reply... > > On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote: >> On Tue, 23 Feb 2016 13:32:21 +0300 >> "Kirill A. Shutemov" <kirill@shutemov.name> wrote: >> > The theory is that the splitting bit effetely masked bogus pmd_present(): >> > we had pmd_trans_splitting() in all code path and that prevented mm from >> > touching the pmd. Once pmd_trans_splitting() has gone, mm proceed with the >> > pmd where it shouldn't and here's a boom. >> >> Well, I don't think pmd_present() == true is bogus for a trans_huge pmd under >> splitting, after all there is a page behind the the pmd. Also, if it was >> bogus, and it would need to be false, why should it be marked !pmd_present() >> only at the pmdp_invalidate() step before the pmd_populate()? It clearly >> is pmd_present() before that, on all architectures, and if there was any >> problem/race with that, setting it to !pmd_present() at this stage would >> only (marginally) reduce the race window. >> >> BTW, PowerPC and Sparc seem to do the same thing in pmdp_invalidate(), >> i.e. they do not set pmd_present() == false, only mark it so that it would >> not generate a new TLB entry, just like on s390. After all, the function >> is called pmdp_invalidate(), and I think the comment in mm/huge_memory.c >> before that call is just a little ambiguous in its wording. When it says >> "mark the pmd notpresent" it probably means "mark it so that it will not >> generate a new TLB entry", which is also what the comment is really about: >> prevent huge and small entries in the TLB for the same page at the same >> time. >> >> FWIW, and since the ARM arch-list is already on cc, I think there is >> an issue with pmdp_invalidate() on ARM, since it also seems to clear >> the trans_huge (and formerly trans_splitting) bit, which actually makes >> the pmd !pmd_present(), but it violates the other requirement from the >> comment: >> "the pmd_trans_huge and pmd_trans_splitting must remain set at all times >> on the pmd until the split is complete for this pmd" > > I've only been testing this for arm64 (where I'm yet to see a problem), > but we use the generic pmdp_invalidate implementation from > mm/pgtable-generic.c there. On arm64, pmd_trans_huge will return true > after pmd_mknotpresent. On arm, it does look to be buggy, since it nukes > the entire entry... Steve? pmd_mknotpresent on arm looks inconsistent with the other architectures and can be changed. Having had a look at the usage, I can't see it causing an immediate problem (that needs to be addressed by an emergency patch). We don't have a notion of splitting pmds (so there is no splitting information to lose), and the only usage I could see of pmd_mknotpresent was: pmdp_invalidate(vma, haddr, pmd); pmd_populate(mm, pmd, pgtable); In mm/huge_memory.c, around line 3588. So we invalidate the entry (which puts down a faulting entry from pmd_mknotpresent and invalidates tlb), then immediately put down a table entry with pmd_populate. I have run a 32-bit ARM test kernel and exacerbated THP splits (that's what took me time), and I didn't notice any problems with 4.5-rc5. Cheers, -- Steve > > Will > > -- > To unsubscribe, send a message with 'unsubscribe linux-mm' in > the body to majordomo@kvack.org. For more info on Linux MM, > see: http://www.linux-mm.org/ . > Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
[toc] | [prev] | [next] | [standalone]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2016-02-25 17:10 +0100 |
| Message-ID | <r66Eh-6kS-3@gated-at.bofh.it> |
| In reply to | #1343279 |
On Thu, Feb 25, 2016 at 03:49:33PM +0000, Steve Capper wrote: > On 23 February 2016 at 18:47, Will Deacon <will.deacon@arm.com> wrote: > > [adding Steve, since he worked on THP for 32-bit ARM] > > Apologies for my late reply... > > > > > On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote: > >> On Tue, 23 Feb 2016 13:32:21 +0300 > >> "Kirill A. Shutemov" <kirill@shutemov.name> wrote: > >> > The theory is that the splitting bit effetely masked bogus pmd_present(): > >> > we had pmd_trans_splitting() in all code path and that prevented mm from > >> > touching the pmd. Once pmd_trans_splitting() has gone, mm proceed with the > >> > pmd where it shouldn't and here's a boom. > >> > >> Well, I don't think pmd_present() == true is bogus for a trans_huge pmd under > >> splitting, after all there is a page behind the the pmd. Also, if it was > >> bogus, and it would need to be false, why should it be marked !pmd_present() > >> only at the pmdp_invalidate() step before the pmd_populate()? It clearly > >> is pmd_present() before that, on all architectures, and if there was any > >> problem/race with that, setting it to !pmd_present() at this stage would > >> only (marginally) reduce the race window. > >> > >> BTW, PowerPC and Sparc seem to do the same thing in pmdp_invalidate(), > >> i.e. they do not set pmd_present() == false, only mark it so that it would > >> not generate a new TLB entry, just like on s390. After all, the function > >> is called pmdp_invalidate(), and I think the comment in mm/huge_memory.c > >> before that call is just a little ambiguous in its wording. When it says > >> "mark the pmd notpresent" it probably means "mark it so that it will not > >> generate a new TLB entry", which is also what the comment is really about: > >> prevent huge and small entries in the TLB for the same page at the same > >> time. > >> > >> FWIW, and since the ARM arch-list is already on cc, I think there is > >> an issue with pmdp_invalidate() on ARM, since it also seems to clear > >> the trans_huge (and formerly trans_splitting) bit, which actually makes > >> the pmd !pmd_present(), but it violates the other requirement from the > >> comment: > >> "the pmd_trans_huge and pmd_trans_splitting must remain set at all times > >> on the pmd until the split is complete for this pmd" > > > > I've only been testing this for arm64 (where I'm yet to see a problem), > > but we use the generic pmdp_invalidate implementation from > > mm/pgtable-generic.c there. On arm64, pmd_trans_huge will return true > > after pmd_mknotpresent. On arm, it does look to be buggy, since it nukes > > the entire entry... Steve? > > pmd_mknotpresent on arm looks inconsistent with the other > architectures and can be changed. > > Having had a look at the usage, I can't see it causing an immediate > problem (that needs to be addressed by an emergency patch). > We don't have a notion of splitting pmds (so there is no splitting > information to lose), and the only usage I could see of > pmd_mknotpresent was: > > pmdp_invalidate(vma, haddr, pmd); > pmd_populate(mm, pmd, pgtable); > > In mm/huge_memory.c, around line 3588. > > So we invalidate the entry (which puts down a faulting entry from > pmd_mknotpresent and invalidates tlb), then immediately put down a > table entry with pmd_populate. > > I have run a 32-bit ARM test kernel and exacerbated THP splits (that's > what took me time), and I didn't notice any problems with 4.5-rc5. If I read code correctly, your pmd_mknotpresent() makes the pmd pmd_none(), right? If yes, it's a problem. It introduces race I've described here: https://marc.info/?l=linux-mm&m=144723658100512&w=4 Basically, if zap_pmd_range() would see pmd_none() between pmdp_mknotpresent() and pmd_populate(), we're screwed. The race window is small, but it's there. -- Kirill A. Shutemov
[toc] | [prev] | [next] | [standalone]
| From | Steve Capper <steve.capper@linaro.org> |
|---|---|
| Date | 2016-02-25 17:10 +0100 |
| Message-ID | <r66Ei-6kS-9@gated-at.bofh.it> |
| In reply to | #1343287 |
On 25 February 2016 at 16:01, Kirill A. Shutemov <kirill@shutemov.name> wrote: > On Thu, Feb 25, 2016 at 03:49:33PM +0000, Steve Capper wrote: >> On 23 February 2016 at 18:47, Will Deacon <will.deacon@arm.com> wrote: >> > [adding Steve, since he worked on THP for 32-bit ARM] >> >> Apologies for my late reply... >> >> > >> > On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote: >> >> On Tue, 23 Feb 2016 13:32:21 +0300 >> >> "Kirill A. Shutemov" <kirill@shutemov.name> wrote: >> >> > The theory is that the splitting bit effetely masked bogus pmd_present(): >> >> > we had pmd_trans_splitting() in all code path and that prevented mm from >> >> > touching the pmd. Once pmd_trans_splitting() has gone, mm proceed with the >> >> > pmd where it shouldn't and here's a boom. >> >> >> >> Well, I don't think pmd_present() == true is bogus for a trans_huge pmd under >> >> splitting, after all there is a page behind the the pmd. Also, if it was >> >> bogus, and it would need to be false, why should it be marked !pmd_present() >> >> only at the pmdp_invalidate() step before the pmd_populate()? It clearly >> >> is pmd_present() before that, on all architectures, and if there was any >> >> problem/race with that, setting it to !pmd_present() at this stage would >> >> only (marginally) reduce the race window. >> >> >> >> BTW, PowerPC and Sparc seem to do the same thing in pmdp_invalidate(), >> >> i.e. they do not set pmd_present() == false, only mark it so that it would >> >> not generate a new TLB entry, just like on s390. After all, the function >> >> is called pmdp_invalidate(), and I think the comment in mm/huge_memory.c >> >> before that call is just a little ambiguous in its wording. When it says >> >> "mark the pmd notpresent" it probably means "mark it so that it will not >> >> generate a new TLB entry", which is also what the comment is really about: >> >> prevent huge and small entries in the TLB for the same page at the same >> >> time. >> >> >> >> FWIW, and since the ARM arch-list is already on cc, I think there is >> >> an issue with pmdp_invalidate() on ARM, since it also seems to clear >> >> the trans_huge (and formerly trans_splitting) bit, which actually makes >> >> the pmd !pmd_present(), but it violates the other requirement from the >> >> comment: >> >> "the pmd_trans_huge and pmd_trans_splitting must remain set at all times >> >> on the pmd until the split is complete for this pmd" >> > >> > I've only been testing this for arm64 (where I'm yet to see a problem), >> > but we use the generic pmdp_invalidate implementation from >> > mm/pgtable-generic.c there. On arm64, pmd_trans_huge will return true >> > after pmd_mknotpresent. On arm, it does look to be buggy, since it nukes >> > the entire entry... Steve? >> >> pmd_mknotpresent on arm looks inconsistent with the other >> architectures and can be changed. >> >> Having had a look at the usage, I can't see it causing an immediate >> problem (that needs to be addressed by an emergency patch). >> We don't have a notion of splitting pmds (so there is no splitting >> information to lose), and the only usage I could see of >> pmd_mknotpresent was: >> >> pmdp_invalidate(vma, haddr, pmd); >> pmd_populate(mm, pmd, pgtable); >> >> In mm/huge_memory.c, around line 3588. >> >> So we invalidate the entry (which puts down a faulting entry from >> pmd_mknotpresent and invalidates tlb), then immediately put down a >> table entry with pmd_populate. >> >> I have run a 32-bit ARM test kernel and exacerbated THP splits (that's >> what took me time), and I didn't notice any problems with 4.5-rc5. > > If I read code correctly, your pmd_mknotpresent() makes the pmd > pmd_none(), right? If yes, it's a problem. > > It introduces race I've described here: > > https://marc.info/?l=linux-mm&m=144723658100512&w=4 > > Basically, if zap_pmd_range() would see pmd_none() between > pmdp_mknotpresent() and pmd_populate(), we're screwed. > > The race window is small, but it's there. Ahhhh, okay, thank you Kirill. I agree, I'll get a patch out. Cheers, -- Steve
[toc] | [prev] | [next] | [standalone]
| From | Will Deacon <will.deacon@arm.com> |
|---|---|
| Date | 2016-02-23 21:30 +0100 |
| Message-ID | <r5rKO-24m-33@gated-at.bofh.it> |
| In reply to | #1340925 |
On Tue, Feb 23, 2016 at 10:33:45PM +0300, Kirill A. Shutemov wrote: > On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote: > > I'll check with Martin, maybe it is actually trivial, then we can > > do a quick test it to rule that one out. > > Oh. I found a bug in __split_huge_pmd_locked(). Although, not sure if it's > _the_ bug. > > pmdp_invalidate() is called for the wrong address :-/ > I guess that can be destructive on the architecture, right? FWIW, arm64 ignores the address parameter for set_pmd_at, so this would only result in the TLBI nuking the wrong entries, which is going to be tricky to observe in practice given that we install a table entry immediately afterwards that maps the same pages. If s390 does more here (I see some magic asm using the address), that could be the answer... Will
[toc] | [prev] | [next] | [standalone]
| From | Christian Borntraeger <borntraeger@de.ibm.com> |
|---|---|
| Date | 2016-02-24 11:20 +0100 |
| Message-ID | <r5EI2-313-19@gated-at.bofh.it> |
| In reply to | #1341001 |
On 02/23/2016 09:22 PM, Will Deacon wrote:
> On Tue, Feb 23, 2016 at 10:33:45PM +0300, Kirill A. Shutemov wrote:
>> On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote:
>>> I'll check with Martin, maybe it is actually trivial, then we can
>>> do a quick test it to rule that one out.
>>
>> Oh. I found a bug in __split_huge_pmd_locked(). Although, not sure if it's
>> _the_ bug.
>>
>> pmdp_invalidate() is called for the wrong address :-/
>> I guess that can be destructive on the architecture, right?
>
> FWIW, arm64 ignores the address parameter for set_pmd_at, so this would
> only result in the TLBI nuking the wrong entries, which is going to be
> tricky to observe in practice given that we install a table entry
> immediately afterwards that maps the same pages. If s390 does more here
> (I see some magic asm using the address), that could be the answer...
This patch does not change the address for set_pmd_at, it does that for the
pmdp_invalidate here (by keeping haddr at the start of the pmd)
---> pmdp_invalidate(vma, haddr, pmd);
pmd_populate(mm, pmd, pgtable);
Without that fix we would clearly have stale tlb entries, no?
[toc] | [prev] | [next] | [standalone]
| From | Will Deacon <will.deacon@arm.com> |
|---|---|
| Date | 2016-02-24 11:50 +0100 |
| Message-ID | <r5Fb4-3dH-27@gated-at.bofh.it> |
| In reply to | #1341740 |
On Wed, Feb 24, 2016 at 11:16:34AM +0100, Christian Borntraeger wrote:
> On 02/23/2016 09:22 PM, Will Deacon wrote:
> > On Tue, Feb 23, 2016 at 10:33:45PM +0300, Kirill A. Shutemov wrote:
> >> On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote:
> >>> I'll check with Martin, maybe it is actually trivial, then we can
> >>> do a quick test it to rule that one out.
> >>
> >> Oh. I found a bug in __split_huge_pmd_locked(). Although, not sure if it's
> >> _the_ bug.
> >>
> >> pmdp_invalidate() is called for the wrong address :-/
> >> I guess that can be destructive on the architecture, right?
> >
> > FWIW, arm64 ignores the address parameter for set_pmd_at, so this would
> > only result in the TLBI nuking the wrong entries, which is going to be
> > tricky to observe in practice given that we install a table entry
> > immediately afterwards that maps the same pages. If s390 does more here
> > (I see some magic asm using the address), that could be the answer...
>
> This patch does not change the address for set_pmd_at, it does that for the
> pmdp_invalidate here (by keeping haddr at the start of the pmd)
>
> ---> pmdp_invalidate(vma, haddr, pmd);
> pmd_populate(mm, pmd, pgtable);
On arm64, pmdp_invalidate looks like:
void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
pmd_t *pmdp)
{
pmd_t entry = *pmdp;
set_pmd_at(vma->vm_mm, address, pmdp, pmd_mknotpresent(entry));
flush_pmd_tlb_range(vma, address, address + hpage_pmd_size);
}
so that's the set_pmd_at call I was referring to.
On s390, that address ends up in __pmdp_idte[_local], but I don't know
what .insn rrf,0xb98e0000,%2,%3,0,{0,1} do ;)
> Without that fix we would clearly have stale tlb entries, no?
Yes, but AFAIU the sequence on arm64 is:
1. trans huge mapping (block mapping in arm64 speak)
2. faulting entry (pmd_mknotpresent)
3. tlb invalidation
4. table entry mapping the same pages as (1).
so if the microarchitecture we're on can tolerate a mixture of block
mappings and page mappings mapping the same VA to the same PA, then the
lack of TLB maintenance would go unnoticed. There are certainly systems
where that could cause an issue, but I believe the one I've been testing
on would be ok.
Will
[toc] | [prev] | [next] | [standalone]
| From | Christian Borntraeger <borntraeger@de.ibm.com> |
|---|---|
| Date | 2016-02-24 12:00 +0100 |
| Message-ID | <r5FkK-3hc-15@gated-at.bofh.it> |
| In reply to | #1341812 |
On 02/24/2016 11:41 AM, Will Deacon wrote:
> On Wed, Feb 24, 2016 at 11:16:34AM +0100, Christian Borntraeger wrote:
>> On 02/23/2016 09:22 PM, Will Deacon wrote:
>>> On Tue, Feb 23, 2016 at 10:33:45PM +0300, Kirill A. Shutemov wrote:
>>>> On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote:
>>>>> I'll check with Martin, maybe it is actually trivial, then we can
>>>>> do a quick test it to rule that one out.
>>>>
>>>> Oh. I found a bug in __split_huge_pmd_locked(). Although, not sure if it's
>>>> _the_ bug.
>>>>
>>>> pmdp_invalidate() is called for the wrong address :-/
>>>> I guess that can be destructive on the architecture, right?
>>>
>>> FWIW, arm64 ignores the address parameter for set_pmd_at, so this would
>>> only result in the TLBI nuking the wrong entries, which is going to be
>>> tricky to observe in practice given that we install a table entry
>>> immediately afterwards that maps the same pages. If s390 does more here
>>> (I see some magic asm using the address), that could be the answer...
>>
>> This patch does not change the address for set_pmd_at, it does that for the
>> pmdp_invalidate here (by keeping haddr at the start of the pmd)
>>
>> ---> pmdp_invalidate(vma, haddr, pmd);
>> pmd_populate(mm, pmd, pgtable);
>
> On arm64, pmdp_invalidate looks like:
>
> void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
> pmd_t *pmdp)
> {
> pmd_t entry = *pmdp;
> set_pmd_at(vma->vm_mm, address, pmdp, pmd_mknotpresent(entry));
> flush_pmd_tlb_range(vma, address, address + hpage_pmd_size);
> }
>
> so that's the set_pmd_at call I was referring to.
>
> On s390, that address ends up in __pmdp_idte[_local], but I don't know
> what .insn rrf,0xb98e0000,%2,%3,0,{0,1} do ;)
It does invalidation of the pmd entry and tlb clearing for this entry.
>
>> Without that fix we would clearly have stale tlb entries, no?
>
> Yes, but AFAIU the sequence on arm64 is:
>
> 1. trans huge mapping (block mapping in arm64 speak)
> 2. faulting entry (pmd_mknotpresent)
> 3. tlb invalidation
> 4. table entry mapping the same pages as (1).
>
> so if the microarchitecture we're on can tolerate a mixture of block
> mappings and page mappings mapping the same VA to the same PA, then the
> lack of TLB maintenance would go unnoticed. There are certainly systems
> where that could cause an issue, but I believe the one I've been testing
> on would be ok.
So in essence you say it does not matter that you flush the wrong range in
flush_pmd_tlb_range as long as it will be flushed later on when the pages
really go away. Yes, then it really might be ok for arm64.
[toc] | [prev] | [next] | [standalone]
| From | Will Deacon <will.deacon@arm.com> |
|---|---|
| Date | 2016-02-24 12:10 +0100 |
| Message-ID | <r5Fur-3EV-47@gated-at.bofh.it> |
| In reply to | #1341834 |
On Wed, Feb 24, 2016 at 11:51:47AM +0100, Christian Borntraeger wrote: > On 02/24/2016 11:41 AM, Will Deacon wrote: > > On Wed, Feb 24, 2016 at 11:16:34AM +0100, Christian Borntraeger wrote: > >> Without that fix we would clearly have stale tlb entries, no? > > > > Yes, but AFAIU the sequence on arm64 is: > > > > 1. trans huge mapping (block mapping in arm64 speak) > > 2. faulting entry (pmd_mknotpresent) > > 3. tlb invalidation > > 4. table entry mapping the same pages as (1). > > > > so if the microarchitecture we're on can tolerate a mixture of block > > mappings and page mappings mapping the same VA to the same PA, then the > > lack of TLB maintenance would go unnoticed. There are certainly systems > > where that could cause an issue, but I believe the one I've been testing > > on would be ok. > > So in essence you say it does not matter that you flush the wrong range in > flush_pmd_tlb_range as long as it will be flushed later on when the pages > really go away. Yes, then it really might be ok for arm64. Indeed, although that's a property of the microarchitecture I'm using rather than an architectural guarantee so the code should certainly be fixed! Will
[toc] | [prev] | [next] | [standalone]
| From | "Aneesh Kumar K.V" <aneesh.kumar@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-02-24 18:30 +0100 |
| Subject | Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) |
| Message-ID | <r5Lq9-7M2-3@gated-at.bofh.it> |
| In reply to | #1341834 |
Christian Borntraeger <borntraeger@de.ibm.com> writes:
> On 02/24/2016 11:41 AM, Will Deacon wrote:
>> On Wed, Feb 24, 2016 at 11:16:34AM +0100, Christian Borntraeger wrote:
>>> On 02/23/2016 09:22 PM, Will Deacon wrote:
>>>> On Tue, Feb 23, 2016 at 10:33:45PM +0300, Kirill A. Shutemov wrote:
>>>>> On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote:
>>>>>> I'll check with Martin, maybe it is actually trivial, then we can
>>>>>> do a quick test it to rule that one out.
>>>>>
>>>>> Oh. I found a bug in __split_huge_pmd_locked(). Although, not sure if it's
>>>>> _the_ bug.
>>>>>
>>>>> pmdp_invalidate() is called for the wrong address :-/
>>>>> I guess that can be destructive on the architecture, right?
>>>>
>>>> FWIW, arm64 ignores the address parameter for set_pmd_at, so this would
>>>> only result in the TLBI nuking the wrong entries, which is going to be
>>>> tricky to observe in practice given that we install a table entry
>>>> immediately afterwards that maps the same pages. If s390 does more here
>>>> (I see some magic asm using the address), that could be the answer...
>>>
>>> This patch does not change the address for set_pmd_at, it does that for the
>>> pmdp_invalidate here (by keeping haddr at the start of the pmd)
>>>
>>> ---> pmdp_invalidate(vma, haddr, pmd);
>>> pmd_populate(mm, pmd, pgtable);
>>
>> On arm64, pmdp_invalidate looks like:
>>
>> void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
>> pmd_t *pmdp)
>> {
>> pmd_t entry = *pmdp;
>> set_pmd_at(vma->vm_mm, address, pmdp, pmd_mknotpresent(entry));
>> flush_pmd_tlb_range(vma, address, address + hpage_pmd_size);
>> }
>>
>> so that's the set_pmd_at call I was referring to.
>>
>> On s390, that address ends up in __pmdp_idte[_local], but I don't know
>> what .insn rrf,0xb98e0000,%2,%3,0,{0,1} do ;)
>
> It does invalidation of the pmd entry and tlb clearing for this entry.
>
>>
>>> Without that fix we would clearly have stale tlb entries, no?
>>
>> Yes, but AFAIU the sequence on arm64 is:
>>
>> 1. trans huge mapping (block mapping in arm64 speak)
>> 2. faulting entry (pmd_mknotpresent)
>> 3. tlb invalidation
>> 4. table entry mapping the same pages as (1).
>>
>> so if the microarchitecture we're on can tolerate a mixture of block
>> mappings and page mappings mapping the same VA to the same PA, then the
>> lack of TLB maintenance would go unnoticed. There are certainly systems
>> where that could cause an issue, but I believe the one I've been testing
>> on would be ok.
>
> So in essence you say it does not matter that you flush the wrong range in
> flush_pmd_tlb_range as long as it will be flushed later on when the pages
> really go away. Yes, then it really might be ok for arm64.
This is more or less same for ppc64 too. With ppc64 the actual flush
happened in pmdp_huge_split_prepare() and pmdp_invalidate() is mostly a
no-op w.r.t thp split in our case.
-aneesh
[toc] | [prev] | [next] | [standalone]
| From | Martin Schwidefsky <schwidefsky@de.ibm.com> |
|---|---|
| Date | 2016-02-24 09:30 +0100 |
| Subject | Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) |
| Message-ID | <r5CZA-1JL-13@gated-at.bofh.it> |
| In reply to | #1340925 |
On Tue, 23 Feb 2016 19:19:07 +0100 Gerald Schaefer <gerald.schaefer@de.ibm.com> wrote: > On Tue, 23 Feb 2016 13:32:21 +0300 > "Kirill A. Shutemov" <kirill@shutemov.name> wrote: > > > On Fri, Feb 12, 2016 at 06:16:40PM +0100, Gerald Schaefer wrote: > > > On Fri, 12 Feb 2016 16:57:27 +0100 > > > Christian Borntraeger <borntraeger@de.ibm.com> wrote: > > > > > > > > I'm also confused by pmd_none() is equal to !pmd_present() on s390. Hm? > > > > > > > > Don't know, Gerald or Martin? > > > > > > The implementation frequently changes depending on how many new bits Martin > > > needs to squeeze out :-) > > > We don't have a _PAGE_PRESENT bit for pmds, so pmd_present() just checks if the > > > entry is not empty. pmd_none() of course does the opposite, it checks if it is > > > empty. > > > > I still worry about pmd_present(). It looks wrong to me. I wounder if > > patch below makes a difference. > > > > The theory is that the splitting bit effetely masked bogus pmd_present(): > > we had pmd_trans_splitting() in all code path and that prevented mm from > > touching the pmd. Once pmd_trans_splitting() has gone, mm proceed with the > > pmd where it shouldn't and here's a boom. > > Well, I don't think pmd_present() == true is bogus for a trans_huge pmd under > splitting, after all there is a page behind the the pmd. Also, if it was > bogus, and it would need to be false, why should it be marked !pmd_present() > only at the pmdp_invalidate() step before the pmd_populate()? It clearly > is pmd_present() before that, on all architectures, and if there was any > problem/race with that, setting it to !pmd_present() at this stage would > only (marginally) reduce the race window. > > BTW, PowerPC and Sparc seem to do the same thing in pmdp_invalidate(), > i.e. they do not set pmd_present() == false, only mark it so that it would > not generate a new TLB entry, just like on s390. After all, the function > is called pmdp_invalidate(), and I think the comment in mm/huge_memory.c > before that call is just a little ambiguous in its wording. When it says > "mark the pmd notpresent" it probably means "mark it so that it will not > generate a new TLB entry", which is also what the comment is really about: > prevent huge and small entries in the TLB for the same page at the same > time. If I am not mistaken this is true for x86 as well. The generic implementation for pmdp_invalidate sets a new pmd that has been modified with pmd_mknotpresent. For x86 this function removes the _PAGE_PRESENT and _PAGE_PROTNONE bits from the entry. The _PAGE_PSE bit stays set and that makes pmd_present return true. -- blue skies, Martin. "Reality continues to ruin my life." - Calvin.
[toc] | [prev] | [next] | [standalone]
| From | Martin Schwidefsky <schwidefsky@de.ibm.com> |
|---|---|
| Date | 2016-02-24 09:40 +0100 |
| Subject | Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) |
| Message-ID | <r5D9f-1Oq-3@gated-at.bofh.it> |
| In reply to | #1340925 |
On Tue, 23 Feb 2016 22:33:45 +0300
"Kirill A. Shutemov" <kirill@shutemov.name> wrote:
> On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote:
> > I'll check with Martin, maybe it is actually trivial, then we can
> > do a quick test it to rule that one out.
>
> Oh. I found a bug in __split_huge_pmd_locked(). Although, not sure if it's
> _the_ bug.
>
> pmdp_invalidate() is called for the wrong address :-/
> I guess that can be destructive on the architecture, right?
>
> Could you check this?
>
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 1c317b85ea7d..4246bc70e55a 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -2865,7 +2865,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
> pgtable = pgtable_trans_huge_withdraw(mm, pmd);
> pmd_populate(mm, &_pmd, pgtable);
>
> - for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
> + for (i = 0; i < HPAGE_PMD_NR; i++) {
> pte_t entry, *pte;
> /*
> * Note that NUMA hinting access restrictions are not
> @@ -2886,9 +2886,9 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
> }
> if (dirty)
> SetPageDirty(page + i);
> - pte = pte_offset_map(&_pmd, haddr);
> + pte = pte_offset_map(&_pmd, haddr + i * PAGE_SIZE);
> BUG_ON(!pte_none(*pte));
> - set_pte_at(mm, haddr, pte, entry);
> + set_pte_at(mm, haddr + i * PAGE_SIZE, pte, entry);
> atomic_inc(&page[i]._mapcount);
> pte_unmap(pte);
> }
> @@ -2938,7 +2938,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
> pmd_populate(mm, pmd, pgtable);
>
> if (freeze) {
> - for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
> + for (i = 0; i < HPAGE_PMD_NR; i++) {
> page_remove_rmap(page + i, false);
> put_page(page + i);
> }
Test is running and it looks good so far. For the final assessment I defer
to Gerald and Sebastian.
--
blue skies,
Martin.
"Reality continues to ruin my life." - Calvin.
[toc] | [prev] | [next] | [standalone]
| From | Sebastian Ott <sebott@linux.vnet.ibm.com> |
|---|---|
| Date | 2016-02-24 13:20 +0100 |
| Message-ID | <r5GAa-4oo-17@gated-at.bofh.it> |
| In reply to | #1341641 |
On Wed, 24 Feb 2016, Martin Schwidefsky wrote:
> On Tue, 23 Feb 2016 22:33:45 +0300
> "Kirill A. Shutemov" <kirill@shutemov.name> wrote:
>
> > On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote:
> > > I'll check with Martin, maybe it is actually trivial, then we can
> > > do a quick test it to rule that one out.
> >
> > Oh. I found a bug in __split_huge_pmd_locked(). Although, not sure if it's
> > _the_ bug.
> >
> > pmdp_invalidate() is called for the wrong address :-/
> > I guess that can be destructive on the architecture, right?
> >
> > Could you check this?
> >
> > diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> > index 1c317b85ea7d..4246bc70e55a 100644
> > --- a/mm/huge_memory.c
> > +++ b/mm/huge_memory.c
> > @@ -2865,7 +2865,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
> > pgtable = pgtable_trans_huge_withdraw(mm, pmd);
> > pmd_populate(mm, &_pmd, pgtable);
> >
> > - for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
> > + for (i = 0; i < HPAGE_PMD_NR; i++) {
> > pte_t entry, *pte;
> > /*
> > * Note that NUMA hinting access restrictions are not
> > @@ -2886,9 +2886,9 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
> > }
> > if (dirty)
> > SetPageDirty(page + i);
> > - pte = pte_offset_map(&_pmd, haddr);
> > + pte = pte_offset_map(&_pmd, haddr + i * PAGE_SIZE);
> > BUG_ON(!pte_none(*pte));
> > - set_pte_at(mm, haddr, pte, entry);
> > + set_pte_at(mm, haddr + i * PAGE_SIZE, pte, entry);
> > atomic_inc(&page[i]._mapcount);
> > pte_unmap(pte);
> > }
> > @@ -2938,7 +2938,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
> > pmd_populate(mm, pmd, pgtable);
> >
> > if (freeze) {
> > - for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
> > + for (i = 0; i < HPAGE_PMD_NR; i++) {
> > page_remove_rmap(page + i, false);
> > put_page(page + i);
> > }
>
> Test is running and it looks good so far. For the final assessment I defer
> to Gerald and Sebastian.
>
Yes, that one worked. My testsystem is doing make -j10 && make clean
in a loop since 4 hours now. Thanks!
Sebastian
[toc] | [prev] | [next] | [standalone]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2016-02-24 10:20 +0100 |
| Message-ID | <r5rKO-24m-35@gated-at.bofh.it> |
| In reply to | #1340925 |
On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote:
> I'll check with Martin, maybe it is actually trivial, then we can
> do a quick test it to rule that one out.
Oh. I found a bug in __split_huge_pmd_locked(). Although, not sure if it's
_the_ bug.
pmdp_invalidate() is called for the wrong address :-/
I guess that can be destructive on the architecture, right?
Could you check this?
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 1c317b85ea7d..4246bc70e55a 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -2865,7 +2865,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
pgtable = pgtable_trans_huge_withdraw(mm, pmd);
pmd_populate(mm, &_pmd, pgtable);
- for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
+ for (i = 0; i < HPAGE_PMD_NR; i++) {
pte_t entry, *pte;
/*
* Note that NUMA hinting access restrictions are not
@@ -2886,9 +2886,9 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
}
if (dirty)
SetPageDirty(page + i);
- pte = pte_offset_map(&_pmd, haddr);
+ pte = pte_offset_map(&_pmd, haddr + i * PAGE_SIZE);
BUG_ON(!pte_none(*pte));
- set_pte_at(mm, haddr, pte, entry);
+ set_pte_at(mm, haddr + i * PAGE_SIZE, pte, entry);
atomic_inc(&page[i]._mapcount);
pte_unmap(pte);
}
@@ -2938,7 +2938,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
pmd_populate(mm, pmd, pgtable);
if (freeze) {
- for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
+ for (i = 0; i < HPAGE_PMD_NR; i++) {
page_remove_rmap(page + i, false);
put_page(page + i);
}
--
Kirill A. Shutemov
[toc] | [prev] | [next] | [standalone]
| From | Gerald Schaefer <gerald.schaefer@de.ibm.com> |
|---|---|
| Date | 2016-02-24 17:50 +0100 |
| Subject | Re: [BUG] random kernel crashes after THP rework on s390 (maybe also on PowerPC and ARM) |
| Message-ID | <r5KNt-7fP-25@gated-at.bofh.it> |
| In reply to | #1341693 |
On Tue, 23 Feb 2016 22:33:45 +0300
"Kirill A. Shutemov" <kirill@shutemov.name> wrote:
> On Tue, Feb 23, 2016 at 07:19:07PM +0100, Gerald Schaefer wrote:
> > I'll check with Martin, maybe it is actually trivial, then we can
> > do a quick test it to rule that one out.
>
> Oh. I found a bug in __split_huge_pmd_locked(). Although, not sure if it's
> _the_ bug.
>
> pmdp_invalidate() is called for the wrong address :-/
> I guess that can be destructive on the architecture, right?
Thanks, that's it! We can no longer reproduce the crashes and calling
pmdp_invalidate() with a wrong address also perfectly explains the
memory corruption that I found in several dumps: 0x020 was ORed into
pte entries, which didn't make sense, and caused the list corruption
for example. 0x020 it is the invalid bit for pmd entries on s390 and
thus can be explained by this bug when a pte table lies before a pmd
table in memory.
>
> Could you check this?
>
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 1c317b85ea7d..4246bc70e55a 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -2865,7 +2865,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
> pgtable = pgtable_trans_huge_withdraw(mm, pmd);
> pmd_populate(mm, &_pmd, pgtable);
>
> - for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
> + for (i = 0; i < HPAGE_PMD_NR; i++) {
> pte_t entry, *pte;
> /*
> * Note that NUMA hinting access restrictions are not
> @@ -2886,9 +2886,9 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
> }
> if (dirty)
> SetPageDirty(page + i);
> - pte = pte_offset_map(&_pmd, haddr);
> + pte = pte_offset_map(&_pmd, haddr + i * PAGE_SIZE);
> BUG_ON(!pte_none(*pte));
> - set_pte_at(mm, haddr, pte, entry);
> + set_pte_at(mm, haddr + i * PAGE_SIZE, pte, entry);
> atomic_inc(&page[i]._mapcount);
> pte_unmap(pte);
> }
> @@ -2938,7 +2938,7 @@ static void __split_huge_pmd_locked(struct vm_area_struct *vma, pmd_t *pmd,
> pmd_populate(mm, pmd, pgtable);
>
> if (freeze) {
> - for (i = 0; i < HPAGE_PMD_NR; i++, haddr += PAGE_SIZE) {
> + for (i = 0; i < HPAGE_PMD_NR; i++) {
> page_remove_rmap(page + i, false);
> put_page(page + i);
> }
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web