* [PATCH v3 0/5] simple sort swap function improvements
From: Andrey Abramov @ 2019-04-02 20:41 UTC (permalink / raw)
To: vgupta, benh, paulus, Michael Ellerman, tglx, mingo, bp, hpa, x86,
mark, jlbec, richard, dedekind1, adrian.hunter, gregkh,
naveen.n.rao, jpoimboe, Dave Chinner, darrick.wong,
ard.biesheuvel, George Spelvin, linux-snps-arc,
Linux Kernel Mailing List, linuxppc-dev, ocfs2-devel, linux-mtd,
sfr
Cc: mhocko, gustavo, peterz, amir73il, Rasmus Villemoes, kamalesh,
piaojun, yamada.masahiro, jiang.biao2, jslaby, yuehaibing, rppt,
ge.changwei, keescook, jannh, ashish.samant, npiggin, jiangyiwen,
Andy Shevchenko, lchen, malat, Morton Andrew
This is the logical continuation of the "lib/sort & lib/list_sort:
faster and smaller" series by George Spelvin (added to linux-next
recently).
Since Spectre mitigations have made indirect function calls more
expensive, and the previous patch series implements the default
simple byte copies without them, an "optimized" custom swap
function is now a waste of time as well as code.
Patches 1 to 4 replace trivial swap functions with the built-in
(which is now much faster) and are grouped by subsystem.
Being pure code deletion patches, they are sure to bring joy to
Linus's heart.
Having reviewed all call sites, only three non-trivial swap
functions remain: arch/x86/kernel/unwind_orc.c,
kernel/jump_label.c and lib/extable.c.
Patch #5 removes size argument from the swap function because:
1) It wasn't used.
2) Custom swap function knows what kind of objects it swaps,
so it already knows their sizes.
v1->v2: Only commit messages have changed to better explain
the purpose of commits. (Thanks to George Spelvin and Greg KH)
v2->v3: Patch #5 now completely removes the size argument
Andrey Abramov (5):
arch/arc: unwind.c: replace swap function with built-in one
powerpc: module_[32|64].c: replace swap function with built-in one
ocfs2: dir,refcounttree,xattr: replace swap functions with built-in
one
ubifs: find.c: replace swap function with built-in one
Lib: sort.h: remove the size argument from the swap function
arch/arc/kernel/unwind.c | 20 ++------------------
arch/powerpc/kernel/module_32.c | 17 +----------------
arch/powerpc/kernel/module_64.c | 17 +----------------
arch/x86/kernel/unwind_orc.c | 2 +-
fs/ocfs2/dir.c | 13 +------------
fs/ocfs2/refcounttree.c | 13 +++----------
fs/ocfs2/xattr.c | 15 +++------------
fs/ubifs/find.c | 9 +--------
include/linux/sort.h | 2 +-
kernel/jump_label.c | 2 +-
lib/extable.c | 2 +-
lib/sort.c | 7 +++----
12 files changed, 19 insertions(+), 100 deletions(-)
--
2.21.0
^ permalink raw reply
* Re: [RFC PATCH v2 3/3] kasan: add interceptors for all string functions
From: Christophe Leroy @ 2019-04-02 20:36 UTC (permalink / raw)
To: Andrey Ryabinin, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, Nicholas Piggin, Aneesh Kumar K.V,
Alexander Potapenko, Dmitry Vyukov, Daniel Axtens
Cc: linux-mm, linuxppc-dev, linux-kernel, kasan-dev
In-Reply-To: <ae9262e5-0917-b7c9-52c7-fe21db2ecacb@virtuozzo.com>
Le 02/04/2019 à 18:14, Andrey Ryabinin a écrit :
>
>
> On 4/2/19 12:43 PM, Christophe Leroy wrote:
>> Hi Dmitry, Andrey and others,
>>
>> Do you have any comments to this series ?
>>
>
> I don't see justification for adding all these non-instrumented functions. We need only some subset of these functions
> and only on powerpc so far. Arches that don't use str*() that early simply doesn't need not-instrumented __str*() variant.
>
> Also I don't think that auto-replace str* to __str* for all not instrumented files is a good idea, as this will reduce KASAN coverage.
> E.g. we don't instrument slub.c but there is no reason to use non-instrumented __str*() functions there.
Ok, I didn't see it that way.
In fact I was seeing the opposite and was considering it as an
opportunity to increase KASAN coverage. E.g.: at the time being things
like the above (from arch/xtensa/include/asm/string.h) are not covered
at all I believe:
#define __HAVE_ARCH_STRCPY
static inline char *strcpy(char *__dest, const char *__src)
{
register char *__xdest = __dest;
unsigned long __dummy;
__asm__ __volatile__("1:\n\t"
"l8ui %2, %1, 0\n\t"
"s8i %2, %0, 0\n\t"
"addi %1, %1, 1\n\t"
"addi %0, %0, 1\n\t"
"bnez %2, 1b\n\t"
: "=r" (__dest), "=r" (__src), "=&r" (__dummy)
: "0" (__dest), "1" (__src)
: "memory");
return __xdest;
}
In my series, I have deactivated optimised string functions when KASAN
is selected like arm64 do. See https://patchwork.ozlabs.org/patch/1055780/
But not every arch does that, meaning that some string functions remains
not instrumented at all.
Also, I was seeing it as a way to reduce impact on performance with
KASAN. Because instrumenting each byte access of the non-optimised
string functions is a performance genocide.
>
> And finally, this series make bug reporting slightly worse. E.g. let's look at strcpy():
>
> +char *strcpy(char *dest, const char *src)
> +{
> + size_t len = __strlen(src) + 1;
> +
> + check_memory_region((unsigned long)src, len, false, _RET_IP_);
> + check_memory_region((unsigned long)dest, len, true, _RET_IP_);
> +
> + return __strcpy(dest, src);
> +}
>
> If src is not-null terminated string we might not see proper out-of-bounds report from KASAN only a crash in __strlen().
> Which might make harder to identify where 'src' comes from, where it was allocated and what's the size of allocated area.
>
>
>> I'd like to know if this approach is ok or if it is better to keep doing as in https://patchwork.ozlabs.org/patch/1055788/
>>
> I think the patch from link is a better solution to the problem.
>
Ok, I'll stick with it then. Thanks for your feedback
Christophe
^ permalink raw reply
* Re: [PATCH] ASoC: fsl_esai: Support synchronous mode
From: Nicolin Chen @ 2019-04-02 20:01 UTC (permalink / raw)
To: S.j. Wang
Cc: alsa-devel@alsa-project.org, timur@kernel.org,
Xiubo.Lee@gmail.com, festevam@gmail.com, broonie@kernel.org,
linuxppc-dev@lists.ozlabs.org
In-Reply-To: <VE1PR04MB64799B3261D1F9F63E441769E3560@VE1PR04MB6479.eurprd04.prod.outlook.com>
> > On Mon, Apr 01, 2019 at 11:39:10AM +0000, S.j. Wang wrote:
> > > In ESAI synchronous mode, the clock is generated by Tx, So we should
> > > always set registers of Tx which relate with the bit clock and frame
> > > clock generation (TCCR, TCR, ECR), even there is only Rx is working.
> > >
> > > Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com>
> > > ---
> > > sound/soc/fsl/fsl_esai.c | 28 +++++++++++++++++++++++++++-
> > > 1 file changed, 27 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index
> > > 3623aa9a6f2e..d9fcddd55c02 100644
> > > --- a/sound/soc/fsl/fsl_esai.c
> > > +++ b/sound/soc/fsl/fsl_esai.c
> > > @@ -230,6 +230,21 @@ static int fsl_esai_set_dai_sysclk(struct
> > snd_soc_dai *dai, int clk_id,
> > > return -EINVAL;
> > > }
> > >
> > > + if (esai_priv->synchronous && !tx) {
> > > + switch (clk_id) {
> > > + case ESAI_HCKR_FSYS:
> > > + fsl_esai_set_dai_sysclk(dai, ESAI_HCKT_FSYS,
> > > + freq, dir);
> > > + break;
> > > + case ESAI_HCKR_EXTAL:
> > > + fsl_esai_set_dai_sysclk(dai, ESAI_HCKT_EXTAL,
> > > + freq, dir);
> >
> > Not sure why you call set_dai_sysclk inside set_dai_sysclk again. It feels very
> > confusing to do so, especially without a comments.
>
> For sync mode, only RX is enabled, the register of tx should be set, so call the
> Set_dai_sysclk again.
Yea, I understood that. But why not just replace RX with TX on the
register-writing level? Do we need to set both TCCR and RCCR? Your
change in hw_params() only sets TCCR inside fsl_esai_set_bclk(), so
we probably only need to change TCCR for recordings running in sync
mode, right?
From the commit message, it feels like that only the clock-related
fields in the TX registers need to be set. Things like calculation
and setting the direction of HCKx pin don't need to run again.
> > > @@ -537,10 +552,21 @@ static int fsl_esai_hw_params(struct
> > > snd_pcm_substream *substream,
> > >
> > > bclk = params_rate(params) * slot_width * esai_priv->slots;
> > >
> > > - ret = fsl_esai_set_bclk(dai, tx, bclk);
> > > + ret = fsl_esai_set_bclk(dai, esai_priv->synchronous ? true : tx,
> > > +bclk);
> > > if (ret)
> > > return ret;
> > >
> > > + if (esai_priv->synchronous && !tx) {
> > > + /* Use Normal mode to support monaural audio */
> > > + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
> > > + ESAI_xCR_xMOD_MASK,
> > params_channels(params) > 1 ?
> > > + ESAI_xCR_xMOD_NETWORK : 0);
> > > +
> > > + mask = ESAI_xCR_xSWS_MASK | ESAI_xCR_PADC;
> > > + val = ESAI_xCR_xSWS(slot_width, width) | ESAI_xCR_PADC;
> > > + regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
> > mask, val);
> > > + }
> >
> > Does synchronous mode require to set both TCR and RCR? or just TCR?
> Both TCR and RCR. RCR will be set in normal flow.
OK. Settings both xCRs makes sense. Would you please try this:
===============
@@ -537,14 +552,20 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
bclk = params_rate(params) * slot_width * esai_priv->slots;
- ret = fsl_esai_set_bclk(dai, tx, bclk);
+ /* Synchronous mode uses TX clock generator */
+ ret = fsl_esai_set_bclk(dai, esai_priv->synchronous || tx, bclk);
if (ret)
return ret;
+ mask = ESAI_xCR_xMOD_MASK | ESAI_xCR_xSWS_MASK;
+ val = ESAI_xCR_xSWS(slot_width, width);
/* Use Normal mode to support monaural audio */
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx),
- ESAI_xCR_xMOD_MASK, params_channels(params) > 1 ?
- ESAI_xCR_xMOD_NETWORK : 0);
+ val |= params_channels(params) > 1 ? ESAI_xCR_xMOD_NETWORK : 0;
+
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
+ /* Recording in synchronous mode needs to set TCR also */
+ if (!tx && esai_priv->synchronous)
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR, mask, val);
regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx),
ESAI_xFCR_xFR_MASK, ESAI_xFCR_xFR);
@@ -556,10 +577,10 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
- mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0);
- val = ESAI_xCR_xSWS(slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
-
- regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
+ /* Only TCR has padding bit and needs to be set for synchronous mode */
+ if (tx || esai_priv->synchronous)
+ regmap_update_bits(esai_priv->regmap, REG_ESAI_TCR,
+ ESAI_xCR_PADC, ESAI_xCR_PADC);
/* Remove ESAI personal reset by configuring ESAI_PCRC and ESAI_PRRC */
regmap_update_bits(esai_priv->regmap, REG_ESAI_PRRC,
===============
It merges those plain settings so we won't need to change both
sides if there's a modification of xCR settings in the future.
^ permalink raw reply
* Re: [PATCH 2/5] powerpc: module_[32|64].c: replace swap function with built-in one
From: Andrey Abramov @ 2019-04-02 19:11 UTC (permalink / raw)
To: Michael Ellerman
Cc: linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org
In-Reply-To: <87zhpaox14.fsf@concordia.ellerman.id.au>
01.04.2019, 13:11, "Michael Ellerman" <mpe@ellerman.id.au>:
> This looks OK. It's a bit of a pity to replace the 8-byte-at-a-time copy
> with a byte-at-a-time copy, but I suspect it's insignificant compared to
> the overhead of calling the comparison and swap functions.
>
> And we could always add a generic 8-byte-at-a-time swap function if it's
> a bottleneck.
I am sorry, I forgot to quickly comment on your letter.
Now (after George Spelvin's patches) the generic swap is able
to use u64 or u32 if the alignment and size are divisible
by 4 or 8, so we lose nothing here.
^ permalink raw reply
* Re: [RFC PATCH] powerpc/mm: Reduce memory usage for mm_context_t for radix
From: Christophe Leroy @ 2019-04-02 18:37 UTC (permalink / raw)
To: Aneesh Kumar K.V, npiggin, benh, paulus, mpe; +Cc: linuxppc-dev
In-Reply-To: <88b8b995-87d3-e264-e0d6-a99c3e8e098b@c-s.fr>
Le 02/04/2019 à 20:31, Christophe Leroy a écrit :
>
>
> Le 02/04/2019 à 16:34, Aneesh Kumar K.V a écrit :
>> Currently, our mm_context_t on book3s64 include all hash specific
>> context details like slice mask, subpage protection details. We
>> can skip allocating those on radix. This will help us to save
>> 8K per mm_context with radix translation.
>>
>> With the patch applied we have
>>
>> sizeof(mm_context_t) = 136
>> sizeof(struct hash_mm_context) = 8288
>>
>> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
>> ---
>> NOTE:
>>
>> If we want to do this, I am still trying to figure out how best we can
>> do this
>> without all the #ifdef and other overhead for 8xx book3e
>>
>>
>> arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 +-
>> arch/powerpc/include/asm/book3s/64/mmu.h | 48 +++++++++++--------
>> arch/powerpc/include/asm/book3s/64/slice.h | 6 +--
>> arch/powerpc/kernel/paca.c | 9 ++--
>> arch/powerpc/kernel/setup-common.c | 7 ++-
>> arch/powerpc/mm/hash_utils_64.c | 10 ++--
>> arch/powerpc/mm/mmu_context_book3s64.c | 16 ++++++-
>> arch/powerpc/mm/slb.c | 2 +-
>> arch/powerpc/mm/slice.c | 48 +++++++++----------
>> arch/powerpc/mm/subpage-prot.c | 8 ++--
>> 10 files changed, 91 insertions(+), 65 deletions(-)
>>
[...]
>> @@ -253,7 +253,7 @@ static void slice_convert(struct mm_struct *mm,
>> */
>> spin_lock_irqsave(&slice_convert_lock, flags);
>> - lpsizes = mm->context.low_slices_psize;
>> + lpsizes = mm->context.hash_context->low_slices_psize;
>
> A help to get ->low_slices_psize would help,
> something like:
>
> In nohash/32/mmu-8xx:
>
> unsigned char *slice_low_slices_psize(context_t *ctx)
> {
> return mm->context.low_slices_psize;
Of course here I meant:
unsigned char *slice_low_slices_psize(mm_context_t *ctx)
{
return ctx->low_slices_psize;
}
> }
>
> And in book3s/64/mmu.h:
>
> unsigned char *slice_low_slices_psize(context_t *ctx)
> {
> return mm->context.hash_context->low_slices_psize;
and
unsigned char *slice_low_slices_psize(mm_context_t *ctx)
{
return ctx->hash_context->low_slices_psize;
}
Christophe
^ permalink raw reply
* Re: [RFC PATCH] powerpc/mm: Reduce memory usage for mm_context_t for radix
From: Christophe Leroy @ 2019-04-02 18:34 UTC (permalink / raw)
To: Aneesh Kumar K.V, npiggin, benh, paulus, mpe; +Cc: linuxppc-dev
In-Reply-To: <200e5a1a-9475-8d43-666c-1845f9d95d1b@linux.ibm.com>
Le 02/04/2019 à 17:42, Aneesh Kumar K.V a écrit :
> On 4/2/19 9:06 PM, Christophe Leroy wrote:
>>
>>
>> Le 02/04/2019 à 16:34, Aneesh Kumar K.V a écrit :
>>> Currently, our mm_context_t on book3s64 include all hash specific
>>> context details like slice mask, subpage protection details. We
>>> can skip allocating those on radix. This will help us to save
>>> 8K per mm_context with radix translation.
>>>
>>> With the patch applied we have
>>>
>>> sizeof(mm_context_t) = 136
>>> sizeof(struct hash_mm_context) = 8288
>>>
>>> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
>>> ---
>>> NOTE:
>>>
>>> If we want to do this, I am still trying to figure out how best we
>>> can do this
>>> without all the #ifdef and other overhead for 8xx book3e
>>
>> Did you have a look at my series
>> https://patchwork.ozlabs.org/project/linuxppc-dev/list/?series=98170 ?
>>
>> It tries to reduce as much as feasible the #ifdefs and stuff.
>>
>>
>
> Not yet. But a cursory look tell me introducing hash_mm_context
> complicates this further unless I introduce something similar for nohash
> 32? Are you ok with that?
Have a look at my review in the other mail, I think we can limit the
changes and avoid introducing the hash_mm_context for 8xx.
Otherwise, we should call it something else, for instance
extended_mm_context, but that looks unnecessary from my point of view.
Christophe
^ permalink raw reply
* Re: [RFC PATCH] powerpc/mm: Reduce memory usage for mm_context_t for radix
From: Christophe Leroy @ 2019-04-02 18:31 UTC (permalink / raw)
To: Aneesh Kumar K.V, npiggin, benh, paulus, mpe; +Cc: linuxppc-dev
In-Reply-To: <20190402143424.7075-1-aneesh.kumar@linux.ibm.com>
Le 02/04/2019 à 16:34, Aneesh Kumar K.V a écrit :
> Currently, our mm_context_t on book3s64 include all hash specific
> context details like slice mask, subpage protection details. We
> can skip allocating those on radix. This will help us to save
> 8K per mm_context with radix translation.
>
> With the patch applied we have
>
> sizeof(mm_context_t) = 136
> sizeof(struct hash_mm_context) = 8288
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
> ---
> NOTE:
>
> If we want to do this, I am still trying to figure out how best we can do this
> without all the #ifdef and other overhead for 8xx book3e
>
>
> arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 +-
> arch/powerpc/include/asm/book3s/64/mmu.h | 48 +++++++++++--------
> arch/powerpc/include/asm/book3s/64/slice.h | 6 +--
> arch/powerpc/kernel/paca.c | 9 ++--
> arch/powerpc/kernel/setup-common.c | 7 ++-
> arch/powerpc/mm/hash_utils_64.c | 10 ++--
> arch/powerpc/mm/mmu_context_book3s64.c | 16 ++++++-
> arch/powerpc/mm/slb.c | 2 +-
> arch/powerpc/mm/slice.c | 48 +++++++++----------
> arch/powerpc/mm/subpage-prot.c | 8 ++--
> 10 files changed, 91 insertions(+), 65 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
> index a28a28079edb..d801be977623 100644
> --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h
> +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
> @@ -657,7 +657,7 @@ extern void slb_set_size(u16 size);
>
> /* 4 bits per slice and we have one slice per 1TB */
> #define SLICE_ARRAY_SIZE (H_PGTABLE_RANGE >> 41)
> -#define TASK_SLICE_ARRAY_SZ(x) ((x)->context.slb_addr_limit >> 41)
> +#define TASK_SLICE_ARRAY_SZ(x) ((x)->context.hash_context->slb_addr_limit >> 41)
>
> #ifndef __ASSEMBLY__
>
> diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
> index a809bdd77322..07e76e304a3b 100644
> --- a/arch/powerpc/include/asm/book3s/64/mmu.h
> +++ b/arch/powerpc/include/asm/book3s/64/mmu.h
> @@ -114,6 +114,33 @@ struct slice_mask {
> DECLARE_BITMAP(high_slices, SLICE_NUM_HIGH);
> };
>
> +struct hash_mm_context {
> +
> + u16 user_psize; /* page size index */
Could we keep that in mm_context_t ?
> +
> +#ifdef CONFIG_PPC_MM_SLICES
CONFIG_PPC_MM_SLICES is always selected on book3s64 so this #ifdef is
useless.
> + /* SLB page size encodings*/
> + unsigned char low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE];
> + unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
> + unsigned long slb_addr_limit;
Could we keep slb_addr_limit in mm_context_t too ?
> +#ifdef CONFIG_PPC_64K_PAGES
> + struct slice_mask mask_64k;
> +#endif
> + struct slice_mask mask_4k;
> +#ifdef CONFIG_HUGETLB_PAGE
> + struct slice_mask mask_16m;
> + struct slice_mask mask_16g;
> +#endif
> +#else
> + u16 sllp; /* SLB page size encoding */
This can get away as CONFIG_PPC_MM_SLICES is always set.
> +#endif
> +
> +#ifdef CONFIG_PPC_SUBPAGE_PROT
> + struct subpage_prot_table spt;
> +#endif /* CONFIG_PPC_SUBPAGE_PROT */
> +
> +};
> +
> typedef struct {
> union {
> /*
> @@ -127,7 +154,6 @@ typedef struct {
> mm_context_id_t id;
> mm_context_id_t extended_id[TASK_SIZE_USER64/TASK_CONTEXT_SIZE];
> };
> - u16 user_psize; /* page size index */
>
> /* Number of bits in the mm_cpumask */
> atomic_t active_cpus;
> @@ -137,27 +163,9 @@ typedef struct {
>
> /* NPU NMMU context */
> struct npu_context *npu_context;
> + struct hash_mm_context *hash_context;
>
> -#ifdef CONFIG_PPC_MM_SLICES
> - /* SLB page size encodings*/
> - unsigned char low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE];
> - unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
> - unsigned long slb_addr_limit;
> -# ifdef CONFIG_PPC_64K_PAGES
> - struct slice_mask mask_64k;
> -# endif
> - struct slice_mask mask_4k;
> -# ifdef CONFIG_HUGETLB_PAGE
> - struct slice_mask mask_16m;
> - struct slice_mask mask_16g;
> -# endif
> -#else
> - u16 sllp; /* SLB page size encoding */
> -#endif
> unsigned long vdso_base;
> -#ifdef CONFIG_PPC_SUBPAGE_PROT
> - struct subpage_prot_table spt;
> -#endif /* CONFIG_PPC_SUBPAGE_PROT */
> /*
> * pagetable fragment support
> */
> diff --git a/arch/powerpc/include/asm/book3s/64/slice.h b/arch/powerpc/include/asm/book3s/64/slice.h
> index db0dedab65ee..3ca1bebe258e 100644
> --- a/arch/powerpc/include/asm/book3s/64/slice.h
> +++ b/arch/powerpc/include/asm/book3s/64/slice.h
> @@ -15,11 +15,11 @@
>
> #else /* CONFIG_PPC_MM_SLICES */
That never happens since book3s/64 always selects CONFIG_PPC_MM_SLICES
>
> -#define get_slice_psize(mm, addr) ((mm)->context.user_psize)
> +#define get_slice_psize(mm, addr) ((mm)->context.hash_context->user_psize)
> #define slice_set_user_psize(mm, psize) \
> do { \
> - (mm)->context.user_psize = (psize); \
> - (mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
> + (mm)->context.hash_context->user_psize = (psize); \
> + (mm)->context.hash_context->sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
> } while (0)
>
> #endif /* CONFIG_PPC_MM_SLICES */
> diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
> index e7382abee868..9f1e5d08fa74 100644
> --- a/arch/powerpc/kernel/paca.c
> +++ b/arch/powerpc/kernel/paca.c
> @@ -267,12 +267,13 @@ void copy_mm_to_paca(struct mm_struct *mm)
>
> get_paca()->mm_ctx_id = context->id;
> #ifdef CONFIG_PPC_MM_SLICES
> - VM_BUG_ON(!mm->context.slb_addr_limit);
> - get_paca()->mm_ctx_slb_addr_limit = mm->context.slb_addr_limit;
> + VM_BUG_ON(!mm->context.hash_context->slb_addr_limit);
> + get_paca()->mm_ctx_slb_addr_limit = mm->context.hash_context->slb_addr_limit;
> memcpy(&get_paca()->mm_ctx_low_slices_psize,
> - &context->low_slices_psize, sizeof(context->low_slices_psize));
> + &context->hash_context->low_slices_psize,
> + sizeof(context->hash_context->low_slices_psize));
I guess we should set helpers to get pointers to low_slices_psize and
high_slices_psize. That would help doing the change only for book3s/64.
> memcpy(&get_paca()->mm_ctx_high_slices_psize,
> - &context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm));
> + &context->hash_context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm));
> #else /* CONFIG_PPC_MM_SLICES */
> get_paca()->mm_ctx_user_psize = context->user_psize;
> get_paca()->mm_ctx_sllp = context->sllp;
> diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
> index 2e5dfb6e0823..40290d3d95b0 100644
> --- a/arch/powerpc/kernel/setup-common.c
> +++ b/arch/powerpc/kernel/setup-common.c
> @@ -862,6 +862,7 @@ static void smp_setup_pacas(void)
> }
> #endif
>
> +struct hash_mm_context init_hash_mm_context;
Should it be for CONFIG_PPC64 only ?
> /*
> * Called into from start_kernel this initializes memblock, which is used
> * to manage page allocation until mem_init is called.
> @@ -949,8 +950,10 @@ void __init setup_arch(char **cmdline_p)
>
> #ifdef CONFIG_PPC_MM_SLICES
> #ifdef CONFIG_PPC64
> - if (!radix_enabled())
> - init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> + if (!radix_enabled()) {
> + init_mm.context.hash_context = &init_hash_mm_context;
> + init_mm.context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> + }
> #elif defined(CONFIG_PPC_8xx)
> init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW;
> #else
> diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
> index 0a4f939a8161..df035c3ebb4b 100644
> --- a/arch/powerpc/mm/hash_utils_64.c
> +++ b/arch/powerpc/mm/hash_utils_64.c
> @@ -1147,7 +1147,7 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
> */
> static int subpage_protection(struct mm_struct *mm, unsigned long ea)
> {
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> u32 spp = 0;
> u32 **sbpm, *sbpp;
>
> @@ -1470,7 +1470,7 @@ static bool should_hash_preload(struct mm_struct *mm, unsigned long ea)
> int psize = get_slice_psize(mm, ea);
>
> /* We only prefault standard pages for now */
> - if (unlikely(psize != mm->context.user_psize))
> + if (unlikely(psize != mm->context.hash_context->user_psize))
> return false;
>
> /*
> @@ -1549,7 +1549,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
>
> /* Hash it in */
> #ifdef CONFIG_PPC_64K_PAGES
> - if (mm->context.user_psize == MMU_PAGE_64K)
> + if (mm->context.hash_context->user_psize == MMU_PAGE_64K)
> rc = __hash_page_64K(ea, access, vsid, ptep, trap,
> update_flags, ssize);
> else
> @@ -1562,8 +1562,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
> */
> if (rc == -1)
> hash_failure_debug(ea, access, vsid, trap, ssize,
> - mm->context.user_psize,
> - mm->context.user_psize,
> + mm->context.hash_context->user_psize,
> + mm->context.hash_context->user_psize,
> pte_val(*ptep));
> out_exit:
> local_irq_restore(flags);
> diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c
> index f720c5cc0b5e..6eef5a36b2e9 100644
> --- a/arch/powerpc/mm/mmu_context_book3s64.c
> +++ b/arch/powerpc/mm/mmu_context_book3s64.c
> @@ -63,6 +63,12 @@ static int hash__init_new_context(struct mm_struct *mm)
> if (index < 0)
> return index;
>
> + mm->context.hash_context = kmalloc(sizeof(struct hash_mm_context), GFP_KERNEL);
> + if (!mm->context.hash_context) {
> + ida_free(&mmu_context_ida, index);
> + return -ENOMEM;
> + }
> +
> /*
> * The old code would re-promote on fork, we don't do that when using
> * slices as it could cause problem promoting slices that have been
> @@ -77,8 +83,14 @@ static int hash__init_new_context(struct mm_struct *mm)
> * We should not be calling init_new_context() on init_mm. Hence a
> * check against 0 is OK.
> */
> - if (mm->context.id == 0)
> + if (mm->context.id == 0) {
> + memset(mm->context.hash_context, 0, sizeof(struct hash_mm_context));
can use kzalloc() instead ?
> slice_init_new_context_exec(mm);
> + } else {
> + /* This is fork. Copy hash_context details from current->mm */
> + memcpy(mm->context.hash_context, current->mm->context.hash_context, sizeof(struct hash_mm_context));
> +
> + }
>
> subpage_prot_init_new_context(mm);
>
> @@ -118,6 +130,7 @@ static int radix__init_new_context(struct mm_struct *mm)
> asm volatile("ptesync;isync" : : : "memory");
>
> mm->context.npu_context = NULL;
> + mm->context.hash_context = NULL;
>
> return index;
> }
> @@ -162,6 +175,7 @@ static void destroy_contexts(mm_context_t *ctx)
> if (context_id)
> ida_free(&mmu_context_ida, context_id);
> }
> + kfree(ctx->hash_context);
> }
>
> static void pmd_frag_destroy(void *pmd_frag)
> diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
> index 5986df48359b..2b128939e2e7 100644
> --- a/arch/powerpc/mm/slb.c
> +++ b/arch/powerpc/mm/slb.c
> @@ -739,7 +739,7 @@ static long slb_allocate_user(struct mm_struct *mm, unsigned long ea)
> * consider this as bad access if we take a SLB miss
> * on an address above addr limit.
> */
> - if (ea >= mm->context.slb_addr_limit)
> + if (ea >= mm->context.hash_context->slb_addr_limit)
> return -EFAULT;
>
> context = get_user_context(&mm->context, ea);
> diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
> index aec91dbcdc0b..84b200429464 100644
> --- a/arch/powerpc/mm/slice.c
> +++ b/arch/powerpc/mm/slice.c
> @@ -101,7 +101,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
> {
> struct vm_area_struct *vma;
>
> - if ((mm->context.slb_addr_limit - len) < addr)
> + if ((mm->context.hash_context->slb_addr_limit - len) < addr)
> return 0;
> vma = find_vma(mm, addr);
> return (!vma || (addr + len) <= vm_start_gap(vma));
> @@ -155,15 +155,15 @@ static struct slice_mask *slice_mask_for_size(struct mm_struct *mm, int psize)
> {
> #ifdef CONFIG_PPC_64K_PAGES
> if (psize == MMU_PAGE_64K)
> - return &mm->context.mask_64k;
> + return &mm->context.hash_context->mask_64k;
You should take the two patches below, that would help:
https://patchwork.ozlabs.org/patch/1059056/
https://patchwork.ozlabs.org/patch/1059058/
> #endif
> if (psize == MMU_PAGE_4K)
> - return &mm->context.mask_4k;
> + return &mm->context.hash_context->mask_4k;
> #ifdef CONFIG_HUGETLB_PAGE
> if (psize == MMU_PAGE_16M)
> - return &mm->context.mask_16m;
> + return &mm->context.hash_context->mask_16m;
> if (psize == MMU_PAGE_16G)
> - return &mm->context.mask_16g;
> + return &mm->context.hash_context->mask_16g;
> #endif
> BUG();
> }
> @@ -253,7 +253,7 @@ static void slice_convert(struct mm_struct *mm,
> */
> spin_lock_irqsave(&slice_convert_lock, flags);
>
> - lpsizes = mm->context.low_slices_psize;
> + lpsizes = mm->context.hash_context->low_slices_psize;
A help to get ->low_slices_psize would help,
something like:
In nohash/32/mmu-8xx:
unsigned char *slice_low_slices_psize(context_t *ctx)
{
return mm->context.low_slices_psize;
}
And in book3s/64/mmu.h:
unsigned char *slice_low_slices_psize(context_t *ctx)
{
return mm->context.hash_context->low_slices_psize;
}
And the same for high_slices_psize
Christophe
> for (i = 0; i < SLICE_NUM_LOW; i++) {
> if (!(mask->low_slices & (1u << i)))
> continue;
> @@ -272,8 +272,8 @@ static void slice_convert(struct mm_struct *mm,
> (((unsigned long)psize) << (mask_index * 4));
> }
>
> - hpsizes = mm->context.high_slices_psize;
> - for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.slb_addr_limit); i++) {
> + hpsizes = mm->context.hash_context->high_slices_psize;
> + for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.hash_context->slb_addr_limit); i++) {
> if (!test_bit(i, mask->high_slices))
> continue;
>
> @@ -292,8 +292,8 @@ static void slice_convert(struct mm_struct *mm,
> }
>
> slice_dbg(" lsps=%lx, hsps=%lx\n",
> - (unsigned long)mm->context.low_slices_psize,
> - (unsigned long)mm->context.high_slices_psize);
> + (unsigned long)mm->context.hash_context->low_slices_psize,
> + (unsigned long)mm->context.hash_context->high_slices_psize);
>
> spin_unlock_irqrestore(&slice_convert_lock, flags);
>
> @@ -393,7 +393,7 @@ static unsigned long slice_find_area_topdown(struct mm_struct *mm,
> * DEFAULT_MAP_WINDOW we should apply this.
> */
> if (high_limit > DEFAULT_MAP_WINDOW)
> - addr += mm->context.slb_addr_limit - DEFAULT_MAP_WINDOW;
> + addr += mm->context.hash_context->slb_addr_limit - DEFAULT_MAP_WINDOW;
>
> while (addr > min_addr) {
> info.high_limit = addr;
> @@ -505,20 +505,20 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
> return -ENOMEM;
> }
>
> - if (high_limit > mm->context.slb_addr_limit) {
> + if (high_limit > mm->context.hash_context->slb_addr_limit) {
> /*
> * Increasing the slb_addr_limit does not require
> * slice mask cache to be recalculated because it should
> * be already initialised beyond the old address limit.
> */
> - mm->context.slb_addr_limit = high_limit;
> + mm->context.hash_context->slb_addr_limit = high_limit;
>
> on_each_cpu(slice_flush_segments, mm, 1);
> }
>
> /* Sanity checks */
> BUG_ON(mm->task_size == 0);
> - BUG_ON(mm->context.slb_addr_limit == 0);
> + BUG_ON(mm->context.hash_context->slb_addr_limit == 0);
> VM_BUG_ON(radix_enabled());
>
> slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize);
> @@ -696,7 +696,7 @@ unsigned long arch_get_unmapped_area(struct file *filp,
> unsigned long flags)
> {
> return slice_get_unmapped_area(addr, len, flags,
> - current->mm->context.user_psize, 0);
> + current->mm->context.hash_context->user_psize, 0);
> }
>
> unsigned long arch_get_unmapped_area_topdown(struct file *filp,
> @@ -706,7 +706,7 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp,
> const unsigned long flags)
> {
> return slice_get_unmapped_area(addr0, len, flags,
> - current->mm->context.user_psize, 1);
> + current->mm->context.hash_context->user_psize, 1);
> }
>
> unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
> @@ -717,10 +717,10 @@ unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
> VM_BUG_ON(radix_enabled());
>
> if (slice_addr_is_low(addr)) {
> - psizes = mm->context.low_slices_psize;
> + psizes = mm->context.hash_context->low_slices_psize;
> index = GET_LOW_SLICE_INDEX(addr);
> } else {
> - psizes = mm->context.high_slices_psize;
> + psizes = mm->context.hash_context->high_slices_psize;
> index = GET_HIGH_SLICE_INDEX(addr);
> }
> mask_index = index & 0x1;
> @@ -742,20 +742,20 @@ void slice_init_new_context_exec(struct mm_struct *mm)
> * duplicated.
> */
> #ifdef CONFIG_PPC64
> - mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> + mm->context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> #else
> mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW;
> #endif
>
> - mm->context.user_psize = psize;
> + mm->context.hash_context->user_psize = psize;
>
> /*
> * Set all slice psizes to the default.
> */
> - lpsizes = mm->context.low_slices_psize;
> + lpsizes = mm->context.hash_context->low_slices_psize;
> memset(lpsizes, (psize << 4) | psize, SLICE_NUM_LOW >> 1);
>
> - hpsizes = mm->context.high_slices_psize;
> + hpsizes = mm->context.hash_context->high_slices_psize;
> memset(hpsizes, (psize << 4) | psize, SLICE_NUM_HIGH >> 1);
>
> /*
> @@ -777,7 +777,7 @@ void slice_setup_new_exec(void)
> if (!is_32bit_task())
> return;
>
> - mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW;
> + mm->context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW;
> }
> #endif
>
> @@ -816,7 +816,7 @@ int slice_is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
> unsigned long len)
> {
> const struct slice_mask *maskp;
> - unsigned int psize = mm->context.user_psize;
> + unsigned int psize = mm->context.hash_context->user_psize;
>
> VM_BUG_ON(radix_enabled());
>
> diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c
> index 5e4178790dee..3a13cbcb6f97 100644
> --- a/arch/powerpc/mm/subpage-prot.c
> +++ b/arch/powerpc/mm/subpage-prot.c
> @@ -25,7 +25,7 @@
> */
> void subpage_prot_free(struct mm_struct *mm)
> {
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> unsigned long i, j, addr;
> u32 **p;
>
> @@ -52,7 +52,7 @@ void subpage_prot_free(struct mm_struct *mm)
>
> void subpage_prot_init_new_context(struct mm_struct *mm)
> {
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
>
> memset(spt, 0, sizeof(*spt));
> }
> @@ -93,7 +93,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
> static void subpage_prot_clear(unsigned long addr, unsigned long len)
> {
> struct mm_struct *mm = current->mm;
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> u32 **spm, *spp;
> unsigned long i;
> size_t nw;
> @@ -189,7 +189,7 @@ SYSCALL_DEFINE3(subpage_prot, unsigned long, addr,
> unsigned long, len, u32 __user *, map)
> {
> struct mm_struct *mm = current->mm;
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> u32 **spm, *spp;
> unsigned long i;
> size_t nw;
>
^ permalink raw reply
* [PATCH 4/4] powerpc: Add support to initialize ima policy rules
From: Claudio Carvalho @ 2019-04-02 18:15 UTC (permalink / raw)
To: linuxppc-dev, linux-efi, linux-integrity, linux-kernel
Cc: Ard Biesheuvel, Nayna Jain, Claudio Carvalho, Matthew Garret,
Paul Mackerras, Jeremy Kerr
In-Reply-To: <20190402181505.25037-1-cclaudio@linux.ibm.com>
From: Nayna Jain <nayna@linux.ibm.com>
PowerNV secure boot relies on the kernel IMA security subsystem to
perform the OS kernel image signature verification. Since each secure
boot mode has different IMA policy requirements, dynamic definition of
the policy rules based on the runtime secure boot mode of the system is
required. On systems that support secure boot, but have it disabled,
only measurement policy rules of the kernel image and modules are
defined.
This patch defines the arch-specific implementation to retrieve the
secure boot mode of the system and accordingly configures the IMA policy
rules.
This patch will provide arch-specific IMA policies if PPC_SECURE_BOOT
config is enabled.
Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
---
arch/powerpc/Kconfig | 12 ++++++++
arch/powerpc/kernel/Makefile | 1 +
arch/powerpc/kernel/ima_arch.c | 54 ++++++++++++++++++++++++++++++++++
include/linux/ima.h | 3 +-
4 files changed, 69 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/kernel/ima_arch.c
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index 2d0be82c3061..e0ba9a9114b3 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -901,6 +901,18 @@ config PPC_MEM_KEYS
If unsure, say y.
+config PPC_SECURE_BOOT
+ prompt "Enable PowerPC Secure Boot"
+ bool
+ default n
+ depends on IMA
+ depends on IMA_ARCH_POLICY
+ help
+ Linux on POWER with firmware secure boot enabled needs to define
+ security policies to extend secure boot to the OS.
+ This config allows user to enable OS Secure Boot on PowerPC systems
+ that have firmware secure boot support.
+
endmenu
config ISA_DMA_API
diff --git a/arch/powerpc/kernel/Makefile b/arch/powerpc/kernel/Makefile
index cddadccf551d..0f08ed7dfd1b 100644
--- a/arch/powerpc/kernel/Makefile
+++ b/arch/powerpc/kernel/Makefile
@@ -119,6 +119,7 @@ ifdef CONFIG_IMA
obj-y += ima_kexec.o
endif
endif
+obj-$(CONFIG_IMA) += ima_arch.o
obj-$(CONFIG_AUDIT) += audit.o
obj64-$(CONFIG_AUDIT) += compat_audit.o
diff --git a/arch/powerpc/kernel/ima_arch.c b/arch/powerpc/kernel/ima_arch.c
new file mode 100644
index 000000000000..871b321656fb
--- /dev/null
+++ b/arch/powerpc/kernel/ima_arch.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Nayna Jain <nayna@linux.ibm.com>
+ *
+ * ima_arch.c
+ * - initialize ima policies for PowerPC Secure Boot
+ */
+
+#include <linux/ima.h>
+#include <asm/secboot.h>
+
+bool arch_ima_get_secureboot(void)
+{
+ bool sb_mode;
+
+ sb_mode = get_powerpc_sb_mode();
+ if (sb_mode)
+ return true;
+ else
+ return false;
+}
+
+/*
+ * File signature verification is not needed, include only measurements
+ */
+static const char *const default_arch_rules[] = {
+ "measure func=KEXEC_KERNEL_CHECK",
+ "measure func=MODULE_CHECK",
+ NULL
+};
+
+/* Both file signature verification and measurements are needed */
+static const char *const sb_arch_rules[] = {
+ "measure func=KEXEC_KERNEL_CHECK",
+ "measure func=MODULE_CHECK",
+ "appraise func=KEXEC_KERNEL_CHECK appraise_type=imasig",
+#if !IS_ENABLED(CONFIG_MODULE_SIG)
+ "appraise func=MODULE_CHECK appraise_type=imasig",
+#endif
+ NULL
+};
+
+/*
+ * On PowerPC, file measurements are to be added to the IMA measurement list
+ * irrespective of the secure boot state of the system. Signature verification
+ * is conditionally enabled based on the secure boot state.
+ */
+const char *const *arch_get_ima_policy(void)
+{
+ if (IS_ENABLED(CONFIG_IMA_ARCH_POLICY) && arch_ima_get_secureboot())
+ return sb_arch_rules;
+ return default_arch_rules;
+}
diff --git a/include/linux/ima.h b/include/linux/ima.h
index dc12fbcf484c..32f46d69ebd7 100644
--- a/include/linux/ima.h
+++ b/include/linux/ima.h
@@ -31,7 +31,8 @@ extern void ima_post_path_mknod(struct dentry *dentry);
extern void ima_add_kexec_buffer(struct kimage *image);
#endif
-#if defined(CONFIG_X86) && defined(CONFIG_EFI)
+#if defined(CONFIG_X86) && defined(CONFIG_EFI) \
+ || defined(CONFIG_PPC_SECURE_BOOT)
extern bool arch_ima_get_secureboot(void);
extern const char * const *arch_get_ima_policy(void);
#else
--
2.20.1
^ permalink raw reply related
* [PATCH 3/4] powerpc/powernv: Detect the secure boot mode of the system
From: Claudio Carvalho @ 2019-04-02 18:15 UTC (permalink / raw)
To: linuxppc-dev, linux-efi, linux-integrity, linux-kernel
Cc: Ard Biesheuvel, Nayna Jain, Claudio Carvalho, Matthew Garret,
Paul Mackerras, Jeremy Kerr
In-Reply-To: <20190402181505.25037-1-cclaudio@linux.ibm.com>
From: Nayna Jain <nayna@linux.ibm.com>
PowerNV secure boot defines different IMA policies based on the secure
boot state of the system.
This patch defines a function to detect the secure boot state of the
system.
Signed-off-by: Nayna Jain <nayna@linux.ibm.com>
---
arch/powerpc/include/asm/secboot.h | 21 +++++++++
arch/powerpc/platforms/powernv/Makefile | 2 +-
arch/powerpc/platforms/powernv/secboot.c | 54 ++++++++++++++++++++++++
3 files changed, 76 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/include/asm/secboot.h
create mode 100644 arch/powerpc/platforms/powernv/secboot.c
diff --git a/arch/powerpc/include/asm/secboot.h b/arch/powerpc/include/asm/secboot.h
new file mode 100644
index 000000000000..1904fb4a3352
--- /dev/null
+++ b/arch/powerpc/include/asm/secboot.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PowerPC secure boot definitions
+ *
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Nayna Jain <nayna@linux.ibm.com>
+ *
+ */
+#ifndef POWERPC_SECBOOT_H
+#define POWERPC_SECBOOT_H
+
+#if defined(CONFIG_OPAL_SECVAR)
+extern bool get_powerpc_sb_mode(void);
+#else
+static inline bool get_powerpc_sb_mode(void)
+{
+ return false;
+}
+#endif
+
+#endif
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 1511d836fd19..a36e22f8ecf8 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -16,4 +16,4 @@ obj-$(CONFIG_PERF_EVENTS) += opal-imc.o
obj-$(CONFIG_PPC_MEMTRACE) += memtrace.o
obj-$(CONFIG_PPC_VAS) += vas.o vas-window.o vas-debug.o
obj-$(CONFIG_OCXL_BASE) += ocxl.o
-obj-$(CONFIG_OPAL_SECVAR) += opal-secvar.o
+obj-$(CONFIG_OPAL_SECVAR) += opal-secvar.o secboot.o
diff --git a/arch/powerpc/platforms/powernv/secboot.c b/arch/powerpc/platforms/powernv/secboot.c
new file mode 100644
index 000000000000..afb1552636c5
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/secboot.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Nayna Jain <nayna@linux.ibm.com>
+ *
+ * secboot.c
+ * - util functions to get powerpc secboot state
+ *
+ */
+#include <linux/efi.h>
+#include <asm/secboot.h>
+
+bool get_powerpc_sb_mode(void)
+{
+ efi_char16_t efi_SecureBoot_name[] = L"SecureBoot";
+ efi_char16_t efi_SetupMode_name[] = L"SetupMode";
+ efi_guid_t efi_variable_guid = EFI_GLOBAL_VARIABLE_GUID;
+ efi_status_t status;
+ u8 secboot, setupmode;
+ unsigned long size = sizeof(secboot);
+
+ status = efi.get_variable(efi_SecureBoot_name, &efi_variable_guid,
+ NULL, &size, &secboot);
+
+ /*
+ * For now assume all failures reading the SecureBoot variable implies
+ * secure boot is not enabled. Later differentiate failure types.
+ */
+ if (status != EFI_SUCCESS) {
+ secboot = 0;
+ setupmode = 0;
+ goto out;
+ }
+
+ size = sizeof(setupmode);
+ status = efi.get_variable(efi_SetupMode_name, &efi_variable_guid,
+ NULL, &size, &setupmode);
+
+ /*
+ * Failure to read the SetupMode variable does not prevent
+ * secure boot mode
+ */
+ if (status != EFI_SUCCESS)
+ setupmode = 0;
+
+out:
+ if ((secboot == 0) || (setupmode == 1)) {
+ pr_info("ima: secureboot mode disabled\n");
+ return false;
+ }
+
+ pr_info("ima: secureboot mode enabled\n");
+ return true;
+}
--
2.20.1
^ permalink raw reply related
* [PATCH 2/4] powerpc/powernv: Add support for OPAL secure variables
From: Claudio Carvalho @ 2019-04-02 18:15 UTC (permalink / raw)
To: linuxppc-dev, linux-efi, linux-integrity, linux-kernel
Cc: Ard Biesheuvel, Nayna Jain, Claudio Carvalho, Matthew Garret,
Paul Mackerras, Jeremy Kerr
In-Reply-To: <20190402181505.25037-1-cclaudio@linux.ibm.com>
The X.509 certificates trusted by the platform and other information
required to secure boot the host OS kernel are wrapped in secure
variables, which are controlled by OPAL.
The OPAL secure variables can be handled through the following OPAL
calls.
OPAL_SECVAR_GET:
Returns the data for a given secure variable name and vendor GUID.
OPAL_SECVAR_GET_NEXT:
For a given secure variable, it returns the name and vendor GUID
of the next variable.
OPAL_SECVAR_ENQUEUE:
Enqueue the supplied secure variable update so that it can be processed
by OPAL in the next boot. Variable updates cannot be be processed right
away because the variable storage is write locked at runtime.
OPAL_SECVAR_INFO:
Returns size information about the variable.
This patch adds support for OPAL secure variables by setting up the EFI
runtime variable services to make OPAL calls.
This patch also introduces CONFIG_OPAL_SECVAR for enabling the OPAL
secure variables support in the kernel. Since CONFIG_OPAL_SECVAR selects
CONFIG_EFI, it also allow us to manage the OPAL secure variables from
userspace via efivarfs.
Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com>
---
This patch depends on new OPAL calls that are being added to skiboot.
The patch set that implements the new calls has been posted to
https://patchwork.ozlabs.org/project/skiboot/list/?series=99805
---
arch/powerpc/include/asm/opal-api.h | 6 +-
arch/powerpc/include/asm/opal.h | 10 ++
arch/powerpc/platforms/Kconfig | 3 +
arch/powerpc/platforms/powernv/Kconfig | 9 +
arch/powerpc/platforms/powernv/Makefile | 1 +
arch/powerpc/platforms/powernv/opal-call.c | 4 +
arch/powerpc/platforms/powernv/opal-secvar.c | 179 +++++++++++++++++++
7 files changed, 211 insertions(+), 1 deletion(-)
create mode 100644 arch/powerpc/platforms/powernv/opal-secvar.c
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 870fb7b239ea..d3066f29cb7a 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -210,7 +210,11 @@
#define OPAL_PCI_GET_PBCQ_TUNNEL_BAR 164
#define OPAL_PCI_SET_PBCQ_TUNNEL_BAR 165
#define OPAL_NX_COPROC_INIT 167
-#define OPAL_LAST 167
+#define OPAL_SECVAR_GET 170
+#define OPAL_SECVAR_GET_NEXT 171
+#define OPAL_SECVAR_ENQUEUE 172
+#define OPAL_SECVAR_INFO 173
+#define OPAL_LAST 173
#define QUIESCE_HOLD 1 /* Spin all calls at entry */
#define QUIESCE_REJECT 2 /* Fail all calls with OPAL_BUSY */
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index a55b01c90bb1..fdfd8dd7b326 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -385,6 +385,16 @@ void opal_powercap_init(void);
void opal_psr_init(void);
void opal_sensor_groups_init(void);
+extern int opal_secvar_get(uint64_t name, uint64_t vendor, uint64_t attr,
+ uint64_t data_size, uint64_t data);
+extern int opal_secvar_get_next(uint64_t name_size, uint64_t name,
+ uint64_t vendor);
+extern int opal_secvar_enqueue(uint64_t name, uint64_t vendor, uint64_t attr,
+ uint64_t data_size, uint64_t data);
+extern int opal_secvar_info(uint64_t attr, uint64_t storage_space,
+ uint64_t remaining_space,
+ uint64_t max_variable_size);
+
#endif /* __ASSEMBLY__ */
#endif /* _ASM_POWERPC_OPAL_H */
diff --git a/arch/powerpc/platforms/Kconfig b/arch/powerpc/platforms/Kconfig
index f3fb79fccc72..8e30510bc0c1 100644
--- a/arch/powerpc/platforms/Kconfig
+++ b/arch/powerpc/platforms/Kconfig
@@ -326,4 +326,7 @@ config XILINX_PCI
bool "Xilinx PCI host bridge support"
depends on PCI && XILINX_VIRTEX
+config EFI
+ bool
+
endmenu
diff --git a/arch/powerpc/platforms/powernv/Kconfig b/arch/powerpc/platforms/powernv/Kconfig
index 850eee860cf2..879f8e766098 100644
--- a/arch/powerpc/platforms/powernv/Kconfig
+++ b/arch/powerpc/platforms/powernv/Kconfig
@@ -47,3 +47,12 @@ config PPC_VAS
VAS adapters are found in POWER9 based systems.
If unsure, say N.
+
+config OPAL_SECVAR
+ bool "OPAL Secure Variables"
+ depends on PPC_POWERNV && !CPU_BIG_ENDIAN
+ select UCS2_STRING
+ select EFI
+ help
+ This enables the kernel to access OPAL secure variables via EFI
+ runtime variable services.
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index da2e99efbd04..1511d836fd19 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_PERF_EVENTS) += opal-imc.o
obj-$(CONFIG_PPC_MEMTRACE) += memtrace.o
obj-$(CONFIG_PPC_VAS) += vas.o vas-window.o vas-debug.o
obj-$(CONFIG_OCXL_BASE) += ocxl.o
+obj-$(CONFIG_OPAL_SECVAR) += opal-secvar.o
diff --git a/arch/powerpc/platforms/powernv/opal-call.c b/arch/powerpc/platforms/powernv/opal-call.c
index daad8c45c8e7..8c791c4c187b 100644
--- a/arch/powerpc/platforms/powernv/opal-call.c
+++ b/arch/powerpc/platforms/powernv/opal-call.c
@@ -282,3 +282,7 @@ OPAL_CALL(opal_pci_set_pbcq_tunnel_bar, OPAL_PCI_SET_PBCQ_TUNNEL_BAR);
OPAL_CALL(opal_sensor_read_u64, OPAL_SENSOR_READ_U64);
OPAL_CALL(opal_sensor_group_enable, OPAL_SENSOR_GROUP_ENABLE);
OPAL_CALL(opal_nx_coproc_init, OPAL_NX_COPROC_INIT);
+OPAL_CALL(opal_secvar_get, OPAL_SECVAR_GET);
+OPAL_CALL(opal_secvar_get_next, OPAL_SECVAR_GET_NEXT);
+OPAL_CALL(opal_secvar_enqueue, OPAL_SECVAR_ENQUEUE);
+OPAL_CALL(opal_secvar_info, OPAL_SECVAR_INFO)
diff --git a/arch/powerpc/platforms/powernv/opal-secvar.c b/arch/powerpc/platforms/powernv/opal-secvar.c
new file mode 100644
index 000000000000..e333828bd0bc
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-secvar.c
@@ -0,0 +1,179 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PowerNV code for secure variables
+ *
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Claudio Carvalho <cclaudio@linux.ibm.com>
+ *
+ */
+#define pr_fmt(fmt) "secvar: "fmt
+
+#include <linux/efi.h>
+#include <asm/machdep.h>
+#include <asm/opal.h>
+
+static bool opal_secvar_supported;
+
+static efi_status_t opal_to_efi_status_log(int rc, const char *func_name)
+{
+ efi_status_t status;
+
+ switch (rc) {
+ case OPAL_EMPTY:
+ status = EFI_NOT_FOUND;
+ break;
+ case OPAL_HARDWARE:
+ status = EFI_DEVICE_ERROR;
+ break;
+ case OPAL_NO_MEM:
+ pr_err("%s: No space in the volatile storage\n", func_name);
+ status = EFI_OUT_OF_RESOURCES;
+ break;
+ case OPAL_PARAMETER:
+ status = EFI_INVALID_PARAMETER;
+ break;
+ case OPAL_PARTIAL:
+ status = EFI_BUFFER_TOO_SMALL;
+ break;
+ case OPAL_PERMISSION:
+ status = EFI_WRITE_PROTECTED;
+ break;
+ case OPAL_RESOURCE:
+ pr_err("%s: No space in the non-volatile storage\n", func_name);
+ status = EFI_OUT_OF_RESOURCES;
+ break;
+ case OPAL_SUCCESS:
+ status = EFI_SUCCESS;
+ break;
+ default:
+ pr_err("%s: Unknown OPAL error %d\n", func_name, rc);
+ status = EFI_DEVICE_ERROR;
+ break;
+ }
+
+ return status;
+}
+
+#define opal_to_efi_status(rc) opal_to_efi_status_log(rc, __func__)
+
+static efi_status_t
+opal_get_variable(efi_char16_t *name, efi_guid_t *vendor, u32 *attr,
+ unsigned long *data_size, void *data)
+{
+ int rc;
+
+ if (!opal_secvar_supported)
+ return EFI_UNSUPPORTED;
+
+ *data_size = cpu_to_be64(*data_size);
+
+ rc = opal_secvar_get(__pa(name), __pa(vendor), __pa(attr),
+ __pa(data_size), __pa(data));
+ /*
+ * The @attr is an optional output parameter. It is returned in
+ * big-endian.
+ */
+ if (attr)
+ *attr = be32_to_cpup(attr);
+ *data_size = be64_to_cpu(*data_size);
+
+ return opal_to_efi_status(rc);
+}
+
+static efi_status_t
+opal_get_next_variable(unsigned long *name_size, efi_char16_t *name,
+ efi_guid_t *vendor)
+{
+ int rc;
+
+ if (!opal_secvar_supported)
+ return EFI_UNSUPPORTED;
+
+ *name_size = cpu_to_be64(*name_size);
+
+ rc = opal_secvar_get_next(__pa(name_size), __pa(name),
+ __pa(vendor));
+
+ *name_size = be64_to_cpu(*name_size);
+
+ return opal_to_efi_status(rc);
+}
+
+static efi_status_t
+opal_set_variable(efi_char16_t *name, efi_guid_t *vendor, u32 attr,
+ unsigned long data_size, void *data)
+{
+ int rc;
+
+ if (!opal_secvar_supported)
+ return EFI_UNSUPPORTED;
+ /*
+ * The secure variable update must be enqueued in order to be processed
+ * in the next boot by firmware. The secure variable storage is write
+ * locked at runtime.
+ */
+ rc = opal_secvar_enqueue(__pa(name), __pa(vendor), attr,
+ data_size, __pa(data));
+ return opal_to_efi_status(rc);
+}
+
+static efi_status_t
+opal_query_variable_info(u32 attr, u64 *storage_space, u64 *remaining_space,
+ u64 *max_variable_size)
+{
+ int rc;
+
+ if (!opal_secvar_supported)
+ return EFI_UNSUPPORTED;
+
+ *storage_space = cpu_to_be64p(storage_space);
+ *remaining_space = cpu_to_be64p(remaining_space);
+ *max_variable_size = cpu_to_be64p(max_variable_size);
+
+ rc = opal_secvar_info(attr, __pa(storage_space), __pa(remaining_space),
+ __pa(max_variable_size));
+
+ *storage_space = be64_to_cpup(storage_space);
+ *remaining_space = be64_to_cpup(remaining_space);
+ *max_variable_size = be64_to_cpup(max_variable_size);
+
+ return opal_to_efi_status(rc);
+}
+
+static void pnv_efi_runtime_setup(void)
+{
+ /*
+ * The opal wrappers below treat the @name, @vendor, and @data
+ * parameters as little endian blobs.
+ * @name is a ucs2 string
+ * @vendor is the vendor GUID. It is converted to LE in the kernel
+ * @data variable data, which layout may be different for each variable
+ */
+ efi.get_variable = opal_get_variable;
+ efi.get_next_variable = opal_get_next_variable;
+ efi.set_variable = opal_set_variable;
+ efi.query_variable_info = opal_query_variable_info;
+
+ if (!opal_check_token(OPAL_SECVAR_GET) ||
+ !opal_check_token(OPAL_SECVAR_GET_NEXT) ||
+ !opal_check_token(OPAL_SECVAR_ENQUEUE) ||
+ !opal_check_token(OPAL_SECVAR_INFO)) {
+ pr_err("OPAL doesn't support secure variables\n");
+ opal_secvar_supported = false;
+ } else {
+ opal_secvar_supported = true;
+ }
+}
+
+static int __init pnv_efi_init(void)
+{
+ set_bit(EFI_RUNTIME_SERVICES, &efi.flags);
+ set_bit(EFI_BOOT, &efi.flags);
+
+ if (IS_ENABLED(CONFIG_64BIT))
+ set_bit(EFI_64BIT, &efi.flags);
+
+ pnv_efi_runtime_setup();
+ return 0;
+}
+machine_arch_initcall(powernv, pnv_efi_init);
--
2.20.1
^ permalink raw reply related
* [PATCH 1/4] powerpc/include: Override unneeded early ioremap functions
From: Claudio Carvalho @ 2019-04-02 18:15 UTC (permalink / raw)
To: linuxppc-dev, linux-efi, linux-integrity, linux-kernel
Cc: Ard Biesheuvel, Nayna Jain, Claudio Carvalho, Matthew Garret,
Paul Mackerras, Jeremy Kerr
In-Reply-To: <20190402181505.25037-1-cclaudio@linux.ibm.com>
When CONFIG_EFI is enabled, the EFI driver includes the generic
early_ioremap header, which assumes that architectures may want to
provide their own early ioremap functions.
This patch overrides the ioremap functions in powerpc because they are
not required for secure boot on powerpc systems.
Signed-off-by: Claudio Carvalho <cclaudio@linux.ibm.com>
---
arch/powerpc/include/asm/early_ioremap.h | 41 ++++++++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 arch/powerpc/include/asm/early_ioremap.h
diff --git a/arch/powerpc/include/asm/early_ioremap.h b/arch/powerpc/include/asm/early_ioremap.h
new file mode 100644
index 000000000000..a86a06e9f3b9
--- /dev/null
+++ b/arch/powerpc/include/asm/early_ioremap.h
@@ -0,0 +1,41 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Early ioremap definitions
+ *
+ * Copyright (C) 2019 IBM Corporation
+ * Author: Claudio Carvalho <cclaudio@linux.ibm.com>
+ *
+ */
+#ifndef _ASM_POWERPC_EARLY_IOREMAP_H
+#define _ASM_POWERPC_EARLY_IOREMAP_H
+
+static inline void __iomem *early_ioremap(resource_size_t phys_addr,
+ unsigned long size)
+{
+ return NULL;
+}
+
+static inline void *early_memremap(resource_size_t phys_addr,
+ unsigned long size)
+{
+ return NULL;
+}
+
+static inline void *early_memremap_ro(resource_size_t phys_addr,
+ unsigned long size)
+{
+ return NULL;
+}
+
+static inline void *early_memremap_prot(resource_size_t phys_addr,
+ unsigned long size,
+ unsigned long prot_val)
+{
+ return NULL;
+}
+
+static inline void early_iounmap(void __iomem *addr, unsigned long size) { }
+static inline void early_memunmap(void *addr, unsigned long size) { }
+static inline void early_ioremap_shutdown(void) { }
+
+#endif
--
2.20.1
^ permalink raw reply related
* [PATCH 0/4] Enabling secure boot on PowerNV systems
From: Claudio Carvalho @ 2019-04-02 18:15 UTC (permalink / raw)
To: linuxppc-dev, linux-efi, linux-integrity, linux-kernel
Cc: Ard Biesheuvel, Nayna Jain, Claudio Carvalho, Matthew Garret,
Paul Mackerras, Jeremy Kerr
This patch set is part of a series that implements secure boot on
PowerNV systems.
In order to verify the OS kernel on PowerNV, secure boot requires X.509
certificates trusted by the platform, the secure boot modes, and several
other pieces of information. These are stored in secure variables
controlled by OPAL, also known as OPAL secure variables.
This patch set adds the following features:
1. Enable efivarfs by selecting CONFIG_EFI in the CONFIG_OPAL_SECVAR
introduced in this patch set. With CONFIG_EFIVAR_FS, userspace tools can
be used to manage the secure variables.
2. Add support for OPAL secure variables by overwriting the EFI hooks
(get_variable, get_next_variable, set_variable and query_variable_info)
with OPAL call wrappers. There is probably a better way to add this
support, for example, we are investigating if we could register the
efivar_operations rather than overwriting the EFI hooks. In this patch
set, CONFIG_OPAL_SECVAR selects CONFIG_EFI. If, instead, we registered
efivar_operations, CONFIG_EFIVAR_FS would need to depend on
CONFIG_EFI|| CONFIG_OPAL_SECVAR. Comments or suggestions on the
preferred technique would be greatly appreciated.
3. Define IMA arch-specific policies based on the secure boot state and
mode of the system. On secure boot enabled powernv systems, the host OS
kernel signature will be verified by IMA appraisal.
Claudio Carvalho (2):
powerpc/include: Override unneeded early ioremap functions
powerpc/powernv: Add support for OPAL secure variables
Nayna Jain (2):
powerpc/powernv: Detect the secure boot mode of the system
powerpc: Add support to initialize ima policy rules
arch/powerpc/Kconfig | 12 ++
arch/powerpc/include/asm/early_ioremap.h | 41 +++++
arch/powerpc/include/asm/opal-api.h | 6 +-
arch/powerpc/include/asm/opal.h | 10 ++
arch/powerpc/include/asm/secboot.h | 21 +++
arch/powerpc/kernel/Makefile | 1 +
arch/powerpc/kernel/ima_arch.c | 54 ++++++
arch/powerpc/platforms/Kconfig | 3 +
arch/powerpc/platforms/powernv/Kconfig | 9 +
arch/powerpc/platforms/powernv/Makefile | 1 +
arch/powerpc/platforms/powernv/opal-call.c | 4 +
arch/powerpc/platforms/powernv/opal-secvar.c | 179 +++++++++++++++++++
arch/powerpc/platforms/powernv/secboot.c | 54 ++++++
include/linux/ima.h | 3 +-
14 files changed, 396 insertions(+), 2 deletions(-)
create mode 100644 arch/powerpc/include/asm/early_ioremap.h
create mode 100644 arch/powerpc/include/asm/secboot.h
create mode 100644 arch/powerpc/kernel/ima_arch.c
create mode 100644 arch/powerpc/platforms/powernv/opal-secvar.c
create mode 100644 arch/powerpc/platforms/powernv/secboot.c
--
2.20.1
^ permalink raw reply
* Re: [RFC PATCH v2 3/3] kasan: add interceptors for all string functions
From: Andrey Ryabinin @ 2019-04-02 16:14 UTC (permalink / raw)
To: Christophe Leroy, Benjamin Herrenschmidt, Paul Mackerras,
Michael Ellerman, Nicholas Piggin, Aneesh Kumar K.V,
Alexander Potapenko, Dmitry Vyukov, Daniel Axtens
Cc: linux-mm, linuxppc-dev, linux-kernel, kasan-dev
In-Reply-To: <3211b0f8-7b52-01b7-8208-65d746969248@c-s.fr>
On 4/2/19 12:43 PM, Christophe Leroy wrote:
> Hi Dmitry, Andrey and others,
>
> Do you have any comments to this series ?
>
I don't see justification for adding all these non-instrumented functions. We need only some subset of these functions
and only on powerpc so far. Arches that don't use str*() that early simply doesn't need not-instrumented __str*() variant.
Also I don't think that auto-replace str* to __str* for all not instrumented files is a good idea, as this will reduce KASAN coverage.
E.g. we don't instrument slub.c but there is no reason to use non-instrumented __str*() functions there.
And finally, this series make bug reporting slightly worse. E.g. let's look at strcpy():
+char *strcpy(char *dest, const char *src)
+{
+ size_t len = __strlen(src) + 1;
+
+ check_memory_region((unsigned long)src, len, false, _RET_IP_);
+ check_memory_region((unsigned long)dest, len, true, _RET_IP_);
+
+ return __strcpy(dest, src);
+}
If src is not-null terminated string we might not see proper out-of-bounds report from KASAN only a crash in __strlen().
Which might make harder to identify where 'src' comes from, where it was allocated and what's the size of allocated area.
> I'd like to know if this approach is ok or if it is better to keep doing as in https://patchwork.ozlabs.org/patch/1055788/
>
I think the patch from link is a better solution to the problem.
^ permalink raw reply
* Re: [PATCH stable v4.14 00/32] powerpc spectre backports for 4.14
From: Greg KH @ 2019-04-02 15:49 UTC (permalink / raw)
To: Diana Madalina Craciun
Cc: msuchanek@suse.de, stable@vger.kernel.org,
linuxppc-dev@ozlabs.org
In-Reply-To: <VI1PR0401MB246396C22088623F2971A0DCFF560@VI1PR0401MB2463.eurprd04.prod.outlook.com>
On Tue, Apr 02, 2019 at 03:21:09PM +0000, Diana Madalina Craciun wrote:
> On 3/31/2019 12:53 PM, Michael Ellerman wrote:
> > Greg KH <gregkh@linuxfoundation.org> writes:
> >> On Fri, Mar 29, 2019 at 03:51:16PM +0100, Greg KH wrote:
> >>> On Fri, Mar 29, 2019 at 10:25:48PM +1100, Michael Ellerman wrote:
> >>>> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi Greg, Please queue
> >>>> up these powerpc patches for 4.14 if you have no objections.
> >>> Some of these also need to go to 4.19, right? Want me to add them
> >>> there, or are you going to provide a backported series?
> > Yes some of them do, but I wasn't sure if they'd go cleanly.
> >> Nevermind, I've queued up the missing ones to 4.19.y, and one missing
> >> one to 5.0.y. If I've missed anything, please let me know.
> > Thanks. I'll check everything's working as expected.
>
> I have validated on NXP PowerPC and worked as expected on both kernel
> 4.14 and kernel 4.19.
Great, thanks for testing!
greg k-h
^ permalink raw reply
* Re: [RFC PATCH] powerpc/mm: Reduce memory usage for mm_context_t for radix
From: Aneesh Kumar K.V @ 2019-04-02 15:42 UTC (permalink / raw)
To: Christophe Leroy, npiggin, benh, paulus, mpe; +Cc: linuxppc-dev
In-Reply-To: <80f34a0e-2bbe-8751-6571-3f844103fc37@c-s.fr>
On 4/2/19 9:06 PM, Christophe Leroy wrote:
>
>
> Le 02/04/2019 à 16:34, Aneesh Kumar K.V a écrit :
>> Currently, our mm_context_t on book3s64 include all hash specific
>> context details like slice mask, subpage protection details. We
>> can skip allocating those on radix. This will help us to save
>> 8K per mm_context with radix translation.
>>
>> With the patch applied we have
>>
>> sizeof(mm_context_t) = 136
>> sizeof(struct hash_mm_context) = 8288
>>
>> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
>> ---
>> NOTE:
>>
>> If we want to do this, I am still trying to figure out how best we can
>> do this
>> without all the #ifdef and other overhead for 8xx book3e
>
> Did you have a look at my series
> https://patchwork.ozlabs.org/project/linuxppc-dev/list/?series=98170 ?
>
> It tries to reduce as much as feasible the #ifdefs and stuff.
>
>
Not yet. But a cursory look tell me introducing hash_mm_context
complicates this further unless I introduce something similar for nohash
32? Are you ok with that?
-aneesh
^ permalink raw reply
* Re: [RFC PATCH] powerpc/mm: Reduce memory usage for mm_context_t for radix
From: Christophe Leroy @ 2019-04-02 15:36 UTC (permalink / raw)
To: Aneesh Kumar K.V, npiggin, benh, paulus, mpe; +Cc: linuxppc-dev
In-Reply-To: <20190402143424.7075-1-aneesh.kumar@linux.ibm.com>
Le 02/04/2019 à 16:34, Aneesh Kumar K.V a écrit :
> Currently, our mm_context_t on book3s64 include all hash specific
> context details like slice mask, subpage protection details. We
> can skip allocating those on radix. This will help us to save
> 8K per mm_context with radix translation.
>
> With the patch applied we have
>
> sizeof(mm_context_t) = 136
> sizeof(struct hash_mm_context) = 8288
>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
> ---
> NOTE:
>
> If we want to do this, I am still trying to figure out how best we can do this
> without all the #ifdef and other overhead for 8xx book3e
Did you have a look at my series
https://patchwork.ozlabs.org/project/linuxppc-dev/list/?series=98170 ?
It tries to reduce as much as feasible the #ifdefs and stuff.
Christophe
>
>
> arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 +-
> arch/powerpc/include/asm/book3s/64/mmu.h | 48 +++++++++++--------
> arch/powerpc/include/asm/book3s/64/slice.h | 6 +--
> arch/powerpc/kernel/paca.c | 9 ++--
> arch/powerpc/kernel/setup-common.c | 7 ++-
> arch/powerpc/mm/hash_utils_64.c | 10 ++--
> arch/powerpc/mm/mmu_context_book3s64.c | 16 ++++++-
> arch/powerpc/mm/slb.c | 2 +-
> arch/powerpc/mm/slice.c | 48 +++++++++----------
> arch/powerpc/mm/subpage-prot.c | 8 ++--
> 10 files changed, 91 insertions(+), 65 deletions(-)
>
> diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
> index a28a28079edb..d801be977623 100644
> --- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h
> +++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
> @@ -657,7 +657,7 @@ extern void slb_set_size(u16 size);
>
> /* 4 bits per slice and we have one slice per 1TB */
> #define SLICE_ARRAY_SIZE (H_PGTABLE_RANGE >> 41)
> -#define TASK_SLICE_ARRAY_SZ(x) ((x)->context.slb_addr_limit >> 41)
> +#define TASK_SLICE_ARRAY_SZ(x) ((x)->context.hash_context->slb_addr_limit >> 41)
>
> #ifndef __ASSEMBLY__
>
> diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
> index a809bdd77322..07e76e304a3b 100644
> --- a/arch/powerpc/include/asm/book3s/64/mmu.h
> +++ b/arch/powerpc/include/asm/book3s/64/mmu.h
> @@ -114,6 +114,33 @@ struct slice_mask {
> DECLARE_BITMAP(high_slices, SLICE_NUM_HIGH);
> };
>
> +struct hash_mm_context {
> +
> + u16 user_psize; /* page size index */
> +
> +#ifdef CONFIG_PPC_MM_SLICES
> + /* SLB page size encodings*/
> + unsigned char low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE];
> + unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
> + unsigned long slb_addr_limit;
> +#ifdef CONFIG_PPC_64K_PAGES
> + struct slice_mask mask_64k;
> +#endif
> + struct slice_mask mask_4k;
> +#ifdef CONFIG_HUGETLB_PAGE
> + struct slice_mask mask_16m;
> + struct slice_mask mask_16g;
> +#endif
> +#else
> + u16 sllp; /* SLB page size encoding */
> +#endif
> +
> +#ifdef CONFIG_PPC_SUBPAGE_PROT
> + struct subpage_prot_table spt;
> +#endif /* CONFIG_PPC_SUBPAGE_PROT */
> +
> +};
> +
> typedef struct {
> union {
> /*
> @@ -127,7 +154,6 @@ typedef struct {
> mm_context_id_t id;
> mm_context_id_t extended_id[TASK_SIZE_USER64/TASK_CONTEXT_SIZE];
> };
> - u16 user_psize; /* page size index */
>
> /* Number of bits in the mm_cpumask */
> atomic_t active_cpus;
> @@ -137,27 +163,9 @@ typedef struct {
>
> /* NPU NMMU context */
> struct npu_context *npu_context;
> + struct hash_mm_context *hash_context;
>
> -#ifdef CONFIG_PPC_MM_SLICES
> - /* SLB page size encodings*/
> - unsigned char low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE];
> - unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
> - unsigned long slb_addr_limit;
> -# ifdef CONFIG_PPC_64K_PAGES
> - struct slice_mask mask_64k;
> -# endif
> - struct slice_mask mask_4k;
> -# ifdef CONFIG_HUGETLB_PAGE
> - struct slice_mask mask_16m;
> - struct slice_mask mask_16g;
> -# endif
> -#else
> - u16 sllp; /* SLB page size encoding */
> -#endif
> unsigned long vdso_base;
> -#ifdef CONFIG_PPC_SUBPAGE_PROT
> - struct subpage_prot_table spt;
> -#endif /* CONFIG_PPC_SUBPAGE_PROT */
> /*
> * pagetable fragment support
> */
> diff --git a/arch/powerpc/include/asm/book3s/64/slice.h b/arch/powerpc/include/asm/book3s/64/slice.h
> index db0dedab65ee..3ca1bebe258e 100644
> --- a/arch/powerpc/include/asm/book3s/64/slice.h
> +++ b/arch/powerpc/include/asm/book3s/64/slice.h
> @@ -15,11 +15,11 @@
>
> #else /* CONFIG_PPC_MM_SLICES */
>
> -#define get_slice_psize(mm, addr) ((mm)->context.user_psize)
> +#define get_slice_psize(mm, addr) ((mm)->context.hash_context->user_psize)
> #define slice_set_user_psize(mm, psize) \
> do { \
> - (mm)->context.user_psize = (psize); \
> - (mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
> + (mm)->context.hash_context->user_psize = (psize); \
> + (mm)->context.hash_context->sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
> } while (0)
>
> #endif /* CONFIG_PPC_MM_SLICES */
> diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
> index e7382abee868..9f1e5d08fa74 100644
> --- a/arch/powerpc/kernel/paca.c
> +++ b/arch/powerpc/kernel/paca.c
> @@ -267,12 +267,13 @@ void copy_mm_to_paca(struct mm_struct *mm)
>
> get_paca()->mm_ctx_id = context->id;
> #ifdef CONFIG_PPC_MM_SLICES
> - VM_BUG_ON(!mm->context.slb_addr_limit);
> - get_paca()->mm_ctx_slb_addr_limit = mm->context.slb_addr_limit;
> + VM_BUG_ON(!mm->context.hash_context->slb_addr_limit);
> + get_paca()->mm_ctx_slb_addr_limit = mm->context.hash_context->slb_addr_limit;
> memcpy(&get_paca()->mm_ctx_low_slices_psize,
> - &context->low_slices_psize, sizeof(context->low_slices_psize));
> + &context->hash_context->low_slices_psize,
> + sizeof(context->hash_context->low_slices_psize));
> memcpy(&get_paca()->mm_ctx_high_slices_psize,
> - &context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm));
> + &context->hash_context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm));
> #else /* CONFIG_PPC_MM_SLICES */
> get_paca()->mm_ctx_user_psize = context->user_psize;
> get_paca()->mm_ctx_sllp = context->sllp;
> diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
> index 2e5dfb6e0823..40290d3d95b0 100644
> --- a/arch/powerpc/kernel/setup-common.c
> +++ b/arch/powerpc/kernel/setup-common.c
> @@ -862,6 +862,7 @@ static void smp_setup_pacas(void)
> }
> #endif
>
> +struct hash_mm_context init_hash_mm_context;
> /*
> * Called into from start_kernel this initializes memblock, which is used
> * to manage page allocation until mem_init is called.
> @@ -949,8 +950,10 @@ void __init setup_arch(char **cmdline_p)
>
> #ifdef CONFIG_PPC_MM_SLICES
> #ifdef CONFIG_PPC64
> - if (!radix_enabled())
> - init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> + if (!radix_enabled()) {
> + init_mm.context.hash_context = &init_hash_mm_context;
> + init_mm.context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> + }
> #elif defined(CONFIG_PPC_8xx)
> init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW;
> #else
> diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
> index 0a4f939a8161..df035c3ebb4b 100644
> --- a/arch/powerpc/mm/hash_utils_64.c
> +++ b/arch/powerpc/mm/hash_utils_64.c
> @@ -1147,7 +1147,7 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
> */
> static int subpage_protection(struct mm_struct *mm, unsigned long ea)
> {
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> u32 spp = 0;
> u32 **sbpm, *sbpp;
>
> @@ -1470,7 +1470,7 @@ static bool should_hash_preload(struct mm_struct *mm, unsigned long ea)
> int psize = get_slice_psize(mm, ea);
>
> /* We only prefault standard pages for now */
> - if (unlikely(psize != mm->context.user_psize))
> + if (unlikely(psize != mm->context.hash_context->user_psize))
> return false;
>
> /*
> @@ -1549,7 +1549,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
>
> /* Hash it in */
> #ifdef CONFIG_PPC_64K_PAGES
> - if (mm->context.user_psize == MMU_PAGE_64K)
> + if (mm->context.hash_context->user_psize == MMU_PAGE_64K)
> rc = __hash_page_64K(ea, access, vsid, ptep, trap,
> update_flags, ssize);
> else
> @@ -1562,8 +1562,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
> */
> if (rc == -1)
> hash_failure_debug(ea, access, vsid, trap, ssize,
> - mm->context.user_psize,
> - mm->context.user_psize,
> + mm->context.hash_context->user_psize,
> + mm->context.hash_context->user_psize,
> pte_val(*ptep));
> out_exit:
> local_irq_restore(flags);
> diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c
> index f720c5cc0b5e..6eef5a36b2e9 100644
> --- a/arch/powerpc/mm/mmu_context_book3s64.c
> +++ b/arch/powerpc/mm/mmu_context_book3s64.c
> @@ -63,6 +63,12 @@ static int hash__init_new_context(struct mm_struct *mm)
> if (index < 0)
> return index;
>
> + mm->context.hash_context = kmalloc(sizeof(struct hash_mm_context), GFP_KERNEL);
> + if (!mm->context.hash_context) {
> + ida_free(&mmu_context_ida, index);
> + return -ENOMEM;
> + }
> +
> /*
> * The old code would re-promote on fork, we don't do that when using
> * slices as it could cause problem promoting slices that have been
> @@ -77,8 +83,14 @@ static int hash__init_new_context(struct mm_struct *mm)
> * We should not be calling init_new_context() on init_mm. Hence a
> * check against 0 is OK.
> */
> - if (mm->context.id == 0)
> + if (mm->context.id == 0) {
> + memset(mm->context.hash_context, 0, sizeof(struct hash_mm_context));
> slice_init_new_context_exec(mm);
> + } else {
> + /* This is fork. Copy hash_context details from current->mm */
> + memcpy(mm->context.hash_context, current->mm->context.hash_context, sizeof(struct hash_mm_context));
> +
> + }
>
> subpage_prot_init_new_context(mm);
>
> @@ -118,6 +130,7 @@ static int radix__init_new_context(struct mm_struct *mm)
> asm volatile("ptesync;isync" : : : "memory");
>
> mm->context.npu_context = NULL;
> + mm->context.hash_context = NULL;
>
> return index;
> }
> @@ -162,6 +175,7 @@ static void destroy_contexts(mm_context_t *ctx)
> if (context_id)
> ida_free(&mmu_context_ida, context_id);
> }
> + kfree(ctx->hash_context);
> }
>
> static void pmd_frag_destroy(void *pmd_frag)
> diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
> index 5986df48359b..2b128939e2e7 100644
> --- a/arch/powerpc/mm/slb.c
> +++ b/arch/powerpc/mm/slb.c
> @@ -739,7 +739,7 @@ static long slb_allocate_user(struct mm_struct *mm, unsigned long ea)
> * consider this as bad access if we take a SLB miss
> * on an address above addr limit.
> */
> - if (ea >= mm->context.slb_addr_limit)
> + if (ea >= mm->context.hash_context->slb_addr_limit)
> return -EFAULT;
>
> context = get_user_context(&mm->context, ea);
> diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
> index aec91dbcdc0b..84b200429464 100644
> --- a/arch/powerpc/mm/slice.c
> +++ b/arch/powerpc/mm/slice.c
> @@ -101,7 +101,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
> {
> struct vm_area_struct *vma;
>
> - if ((mm->context.slb_addr_limit - len) < addr)
> + if ((mm->context.hash_context->slb_addr_limit - len) < addr)
> return 0;
> vma = find_vma(mm, addr);
> return (!vma || (addr + len) <= vm_start_gap(vma));
> @@ -155,15 +155,15 @@ static struct slice_mask *slice_mask_for_size(struct mm_struct *mm, int psize)
> {
> #ifdef CONFIG_PPC_64K_PAGES
> if (psize == MMU_PAGE_64K)
> - return &mm->context.mask_64k;
> + return &mm->context.hash_context->mask_64k;
> #endif
> if (psize == MMU_PAGE_4K)
> - return &mm->context.mask_4k;
> + return &mm->context.hash_context->mask_4k;
> #ifdef CONFIG_HUGETLB_PAGE
> if (psize == MMU_PAGE_16M)
> - return &mm->context.mask_16m;
> + return &mm->context.hash_context->mask_16m;
> if (psize == MMU_PAGE_16G)
> - return &mm->context.mask_16g;
> + return &mm->context.hash_context->mask_16g;
> #endif
> BUG();
> }
> @@ -253,7 +253,7 @@ static void slice_convert(struct mm_struct *mm,
> */
> spin_lock_irqsave(&slice_convert_lock, flags);
>
> - lpsizes = mm->context.low_slices_psize;
> + lpsizes = mm->context.hash_context->low_slices_psize;
> for (i = 0; i < SLICE_NUM_LOW; i++) {
> if (!(mask->low_slices & (1u << i)))
> continue;
> @@ -272,8 +272,8 @@ static void slice_convert(struct mm_struct *mm,
> (((unsigned long)psize) << (mask_index * 4));
> }
>
> - hpsizes = mm->context.high_slices_psize;
> - for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.slb_addr_limit); i++) {
> + hpsizes = mm->context.hash_context->high_slices_psize;
> + for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.hash_context->slb_addr_limit); i++) {
> if (!test_bit(i, mask->high_slices))
> continue;
>
> @@ -292,8 +292,8 @@ static void slice_convert(struct mm_struct *mm,
> }
>
> slice_dbg(" lsps=%lx, hsps=%lx\n",
> - (unsigned long)mm->context.low_slices_psize,
> - (unsigned long)mm->context.high_slices_psize);
> + (unsigned long)mm->context.hash_context->low_slices_psize,
> + (unsigned long)mm->context.hash_context->high_slices_psize);
>
> spin_unlock_irqrestore(&slice_convert_lock, flags);
>
> @@ -393,7 +393,7 @@ static unsigned long slice_find_area_topdown(struct mm_struct *mm,
> * DEFAULT_MAP_WINDOW we should apply this.
> */
> if (high_limit > DEFAULT_MAP_WINDOW)
> - addr += mm->context.slb_addr_limit - DEFAULT_MAP_WINDOW;
> + addr += mm->context.hash_context->slb_addr_limit - DEFAULT_MAP_WINDOW;
>
> while (addr > min_addr) {
> info.high_limit = addr;
> @@ -505,20 +505,20 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
> return -ENOMEM;
> }
>
> - if (high_limit > mm->context.slb_addr_limit) {
> + if (high_limit > mm->context.hash_context->slb_addr_limit) {
> /*
> * Increasing the slb_addr_limit does not require
> * slice mask cache to be recalculated because it should
> * be already initialised beyond the old address limit.
> */
> - mm->context.slb_addr_limit = high_limit;
> + mm->context.hash_context->slb_addr_limit = high_limit;
>
> on_each_cpu(slice_flush_segments, mm, 1);
> }
>
> /* Sanity checks */
> BUG_ON(mm->task_size == 0);
> - BUG_ON(mm->context.slb_addr_limit == 0);
> + BUG_ON(mm->context.hash_context->slb_addr_limit == 0);
> VM_BUG_ON(radix_enabled());
>
> slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize);
> @@ -696,7 +696,7 @@ unsigned long arch_get_unmapped_area(struct file *filp,
> unsigned long flags)
> {
> return slice_get_unmapped_area(addr, len, flags,
> - current->mm->context.user_psize, 0);
> + current->mm->context.hash_context->user_psize, 0);
> }
>
> unsigned long arch_get_unmapped_area_topdown(struct file *filp,
> @@ -706,7 +706,7 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp,
> const unsigned long flags)
> {
> return slice_get_unmapped_area(addr0, len, flags,
> - current->mm->context.user_psize, 1);
> + current->mm->context.hash_context->user_psize, 1);
> }
>
> unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
> @@ -717,10 +717,10 @@ unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
> VM_BUG_ON(radix_enabled());
>
> if (slice_addr_is_low(addr)) {
> - psizes = mm->context.low_slices_psize;
> + psizes = mm->context.hash_context->low_slices_psize;
> index = GET_LOW_SLICE_INDEX(addr);
> } else {
> - psizes = mm->context.high_slices_psize;
> + psizes = mm->context.hash_context->high_slices_psize;
> index = GET_HIGH_SLICE_INDEX(addr);
> }
> mask_index = index & 0x1;
> @@ -742,20 +742,20 @@ void slice_init_new_context_exec(struct mm_struct *mm)
> * duplicated.
> */
> #ifdef CONFIG_PPC64
> - mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> + mm->context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
> #else
> mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW;
> #endif
>
> - mm->context.user_psize = psize;
> + mm->context.hash_context->user_psize = psize;
>
> /*
> * Set all slice psizes to the default.
> */
> - lpsizes = mm->context.low_slices_psize;
> + lpsizes = mm->context.hash_context->low_slices_psize;
> memset(lpsizes, (psize << 4) | psize, SLICE_NUM_LOW >> 1);
>
> - hpsizes = mm->context.high_slices_psize;
> + hpsizes = mm->context.hash_context->high_slices_psize;
> memset(hpsizes, (psize << 4) | psize, SLICE_NUM_HIGH >> 1);
>
> /*
> @@ -777,7 +777,7 @@ void slice_setup_new_exec(void)
> if (!is_32bit_task())
> return;
>
> - mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW;
> + mm->context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW;
> }
> #endif
>
> @@ -816,7 +816,7 @@ int slice_is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
> unsigned long len)
> {
> const struct slice_mask *maskp;
> - unsigned int psize = mm->context.user_psize;
> + unsigned int psize = mm->context.hash_context->user_psize;
>
> VM_BUG_ON(radix_enabled());
>
> diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c
> index 5e4178790dee..3a13cbcb6f97 100644
> --- a/arch/powerpc/mm/subpage-prot.c
> +++ b/arch/powerpc/mm/subpage-prot.c
> @@ -25,7 +25,7 @@
> */
> void subpage_prot_free(struct mm_struct *mm)
> {
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> unsigned long i, j, addr;
> u32 **p;
>
> @@ -52,7 +52,7 @@ void subpage_prot_free(struct mm_struct *mm)
>
> void subpage_prot_init_new_context(struct mm_struct *mm)
> {
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
>
> memset(spt, 0, sizeof(*spt));
> }
> @@ -93,7 +93,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
> static void subpage_prot_clear(unsigned long addr, unsigned long len)
> {
> struct mm_struct *mm = current->mm;
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> u32 **spm, *spp;
> unsigned long i;
> size_t nw;
> @@ -189,7 +189,7 @@ SYSCALL_DEFINE3(subpage_prot, unsigned long, addr,
> unsigned long, len, u32 __user *, map)
> {
> struct mm_struct *mm = current->mm;
> - struct subpage_prot_table *spt = &mm->context.spt;
> + struct subpage_prot_table *spt = &mm->context.hash_context->spt;
> u32 **spm, *spp;
> unsigned long i;
> size_t nw;
>
^ permalink raw reply
* Re: [PATCH v2] mm: Fix modifying of page protection by insert_pfn_pmd()
From: Jan Kara @ 2019-04-02 15:24 UTC (permalink / raw)
To: Aneesh Kumar K.V
Cc: Jan Kara, linux-nvdimm, stable, linux-mm, Chandan Rajendra,
dan.j.williams, linuxppc-dev, akpm
In-Reply-To: <20190402115125.18803-1-aneesh.kumar@linux.ibm.com>
On Tue 02-04-19 17:21:25, Aneesh Kumar K.V wrote:
> With some architectures like ppc64, set_pmd_at() cannot cope with
> a situation where there is already some (different) valid entry present.
>
> Use pmdp_set_access_flags() instead to modify the pfn which is built to
> deal with modifying existing PMD entries.
>
> This is similar to
> commit cae85cb8add3 ("mm/memory.c: fix modifying of page protection by insert_pfn()")
>
> We also do similar update w.r.t insert_pfn_pud eventhough ppc64 don't support
> pud pfn entries now.
>
> Without this patch we also see the below message in kernel log
> "BUG: non-zero pgtables_bytes on freeing mm:"
>
> CC: stable@vger.kernel.org
> Reported-by: Chandan Rajendra <chandan@linux.ibm.com>
> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Looks good to me. You can add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> Changes from v1:
> * Fix the pgtable leak
>
> mm/huge_memory.c | 36 ++++++++++++++++++++++++++++++++++++
> 1 file changed, 36 insertions(+)
>
> diff --git a/mm/huge_memory.c b/mm/huge_memory.c
> index 404acdcd0455..165ea46bf149 100644
> --- a/mm/huge_memory.c
> +++ b/mm/huge_memory.c
> @@ -755,6 +755,21 @@ static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
> spinlock_t *ptl;
>
> ptl = pmd_lock(mm, pmd);
> + if (!pmd_none(*pmd)) {
> + if (write) {
> + if (pmd_pfn(*pmd) != pfn_t_to_pfn(pfn)) {
> + WARN_ON_ONCE(!is_huge_zero_pmd(*pmd));
> + goto out_unlock;
> + }
> + entry = pmd_mkyoung(*pmd);
> + entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
> + if (pmdp_set_access_flags(vma, addr, pmd, entry, 1))
> + update_mmu_cache_pmd(vma, addr, pmd);
> + }
> +
> + goto out_unlock;
> + }
> +
> entry = pmd_mkhuge(pfn_t_pmd(pfn, prot));
> if (pfn_t_devmap(pfn))
> entry = pmd_mkdevmap(entry);
> @@ -766,11 +781,16 @@ static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
> if (pgtable) {
> pgtable_trans_huge_deposit(mm, pmd, pgtable);
> mm_inc_nr_ptes(mm);
> + pgtable = NULL;
> }
>
> set_pmd_at(mm, addr, pmd, entry);
> update_mmu_cache_pmd(vma, addr, pmd);
> +
> +out_unlock:
> spin_unlock(ptl);
> + if (pgtable)
> + pte_free(mm, pgtable);
> }
>
> vm_fault_t vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
> @@ -821,6 +841,20 @@ static void insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
> spinlock_t *ptl;
>
> ptl = pud_lock(mm, pud);
> + if (!pud_none(*pud)) {
> + if (write) {
> + if (pud_pfn(*pud) != pfn_t_to_pfn(pfn)) {
> + WARN_ON_ONCE(!is_huge_zero_pud(*pud));
> + goto out_unlock;
> + }
> + entry = pud_mkyoung(*pud);
> + entry = maybe_pud_mkwrite(pud_mkdirty(entry), vma);
> + if (pudp_set_access_flags(vma, addr, pud, entry, 1))
> + update_mmu_cache_pud(vma, addr, pud);
> + }
> + goto out_unlock;
> + }
> +
> entry = pud_mkhuge(pfn_t_pud(pfn, prot));
> if (pfn_t_devmap(pfn))
> entry = pud_mkdevmap(entry);
> @@ -830,6 +864,8 @@ static void insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
> }
> set_pud_at(mm, addr, pud, entry);
> update_mmu_cache_pud(vma, addr, pud);
> +
> +out_unlock:
> spin_unlock(ptl);
> }
>
> --
> 2.20.1
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
^ permalink raw reply
* Re: [PATCH stable v4.14 00/32] powerpc spectre backports for 4.14
From: Diana Madalina Craciun @ 2019-04-02 15:21 UTC (permalink / raw)
To: Michael Ellerman, Greg KH
Cc: linuxppc-dev@ozlabs.org, msuchanek@suse.de,
stable@vger.kernel.org
In-Reply-To: <87v9zzl68u.fsf@concordia.ellerman.id.au>
On 3/31/2019 12:53 PM, Michael Ellerman wrote:
> Greg KH <gregkh@linuxfoundation.org> writes:
>> On Fri, Mar 29, 2019 at 03:51:16PM +0100, Greg KH wrote:
>>> On Fri, Mar 29, 2019 at 10:25:48PM +1100, Michael Ellerman wrote:
>>>> -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Hi Greg, Please queue
>>>> up these powerpc patches for 4.14 if you have no objections.
>>> Some of these also need to go to 4.19, right? Want me to add them
>>> there, or are you going to provide a backported series?
> Yes some of them do, but I wasn't sure if they'd go cleanly.
>> Nevermind, I've queued up the missing ones to 4.19.y, and one missing
>> one to 5.0.y. If I've missed anything, please let me know.
> Thanks. I'll check everything's working as expected.
I have validated on NXP PowerPC and worked as expected on both kernel
4.14 and kernel 4.19.
Thanks,
Diana
^ permalink raw reply
* Re: [RFC PATCH v2 3/3] kasan: add interceptors for all string functions
From: Christophe Leroy @ 2019-04-02 14:57 UTC (permalink / raw)
To: Dmitry Vyukov
Cc: LKML, Nicholas Piggin, Linux-MM, Paul Mackerras, Aneesh Kumar K.V,
Andrey Ryabinin, Alexander Potapenko, kasan-dev, linuxppc-dev,
Daniel Axtens
In-Reply-To: <CACT4Y+YYMJX-PKZhOkjDFnhaC1wcC0h_DzhhgxEwtffNNUh_Nw@mail.gmail.com>
Le 02/04/2019 à 14:58, Dmitry Vyukov a écrit :
> On Tue, Apr 2, 2019 at 11:43 AM Christophe Leroy
> <christophe.leroy@c-s.fr> wrote:
>>
>> Hi Dmitry, Andrey and others,
>>
>> Do you have any comments to this series ?
>>
>> I'd like to know if this approach is ok or if it is better to keep doing
>> as in https://patchwork.ozlabs.org/patch/1055788/
>
> Hi Christophe,
>
> Forking every kernel function does not look like a scalable approach
> to me. There is not much special about str* functions. There is
> something a bit special about memset/memcpy as compiler emits them for
> struct set/copy.
> Could powerpc do the same as x86 and map some shadow early enough
> (before "prom")? Then we would not need anything of this? Sorry if we
> already discussed this, I am losing context quickly.
Hi Dmitry,
I'm afraid we can't map shadow ram that early. This code gets run by
third party BIOS SW which manages the MMU and provides a 1:1 mapping, so
there is no way we can map shadow memory.
If you feel providing interceptors for the string functions is not a
good idea, I'm ok with it, I'll keep the necessary string functions in
prom_init.c
I was proposing the interceptor's approach because behind the specific
need for handling early prom_init code, I thought it was also a way to
limit KASAN performance impact on string functions, and it was also a
way to handle all the optimised string functions provided by architectures.
In my series I have a patch that disables powerpc's optimised string
functions (https://patchwork.ozlabs.org/patch/1055780/). The
interceptor's approach was a way to avoid that. As far as I can see, at
the time being the other arches don't disable their optimised string
functions, meaning the KASAN checks are skipped.
Thanks
Christophe
>
>
>
>
>> Thanks
>> Christophe
>>
>> Le 28/03/2019 à 16:00, Christophe Leroy a écrit :
>>> In the same spirit as commit 393f203f5fd5 ("x86_64: kasan: add
>>> interceptors for memset/memmove/memcpy functions"), this patch
>>> adds interceptors for string manipulation functions so that we
>>> can compile lib/string.o without kasan support hence allow the
>>> string functions to also be used from places where kasan has
>>> to be disabled.
>>>
>>> Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
>>> ---
>>> v2: Fixed a few checkpatch stuff and added missing EXPORT_SYMBOL() and missing #undefs
>>>
>>> include/linux/string.h | 79 ++++++++++
>>> lib/Makefile | 2 +
>>> lib/string.c | 8 +
>>> mm/kasan/string.c | 394 +++++++++++++++++++++++++++++++++++++++++++++++++
>>> 4 files changed, 483 insertions(+)
>>>
>>> diff --git a/include/linux/string.h b/include/linux/string.h
>>> index 7927b875f80c..3d2aff2ed402 100644
>>> --- a/include/linux/string.h
>>> +++ b/include/linux/string.h
>>> @@ -19,54 +19,117 @@ extern void *memdup_user_nul(const void __user *, size_t);
>>> */
>>> #include <asm/string.h>
>>>
>>> +#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
>>> +/*
>>> + * For files that are not instrumented (e.g. mm/slub.c) we
>>> + * should use not instrumented version of mem* functions.
>>> + */
>>> +#define memset16 __memset16
>>> +#define memset32 __memset32
>>> +#define memset64 __memset64
>>> +#define memzero_explicit __memzero_explicit
>>> +#define strcpy __strcpy
>>> +#define strncpy __strncpy
>>> +#define strlcpy __strlcpy
>>> +#define strscpy __strscpy
>>> +#define strcat __strcat
>>> +#define strncat __strncat
>>> +#define strlcat __strlcat
>>> +#define strcmp __strcmp
>>> +#define strncmp __strncmp
>>> +#define strcasecmp __strcasecmp
>>> +#define strncasecmp __strncasecmp
>>> +#define strchr __strchr
>>> +#define strchrnul __strchrnul
>>> +#define strrchr __strrchr
>>> +#define strnchr __strnchr
>>> +#define skip_spaces __skip_spaces
>>> +#define strim __strim
>>> +#define strstr __strstr
>>> +#define strnstr __strnstr
>>> +#define strlen __strlen
>>> +#define strnlen __strnlen
>>> +#define strpbrk __strpbrk
>>> +#define strsep __strsep
>>> +#define strspn __strspn
>>> +#define strcspn __strcspn
>>> +#define memscan __memscan
>>> +#define memcmp __memcmp
>>> +#define memchr __memchr
>>> +#define memchr_inv __memchr_inv
>>> +#define strreplace __strreplace
>>> +
>>> +#ifndef __NO_FORTIFY
>>> +#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */
>>> +#endif
>>> +
>>> +#endif
>>> +
>>> #ifndef __HAVE_ARCH_STRCPY
>>> extern char * strcpy(char *,const char *);
>>> +char *__strcpy(char *, const char *);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRNCPY
>>> extern char * strncpy(char *,const char *, __kernel_size_t);
>>> +char *__strncpy(char *, const char *, __kernel_size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRLCPY
>>> size_t strlcpy(char *, const char *, size_t);
>>> +size_t __strlcpy(char *, const char *, size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRSCPY
>>> ssize_t strscpy(char *, const char *, size_t);
>>> +ssize_t __strscpy(char *, const char *, size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRCAT
>>> extern char * strcat(char *, const char *);
>>> +char *__strcat(char *, const char *);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRNCAT
>>> extern char * strncat(char *, const char *, __kernel_size_t);
>>> +char *__strncat(char *, const char *, __kernel_size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRLCAT
>>> extern size_t strlcat(char *, const char *, __kernel_size_t);
>>> +size_t __strlcat(char *, const char *, __kernel_size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRCMP
>>> extern int strcmp(const char *,const char *);
>>> +int __strcmp(const char *, const char *);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRNCMP
>>> extern int strncmp(const char *,const char *,__kernel_size_t);
>>> +int __strncmp(const char *, const char *, __kernel_size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRCASECMP
>>> extern int strcasecmp(const char *s1, const char *s2);
>>> +int __strcasecmp(const char *s1, const char *s2);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRNCASECMP
>>> extern int strncasecmp(const char *s1, const char *s2, size_t n);
>>> +int __strncasecmp(const char *s1, const char *s2, size_t n);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRCHR
>>> extern char * strchr(const char *,int);
>>> +char *__strchr(const char *, int);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRCHRNUL
>>> extern char * strchrnul(const char *,int);
>>> +char *__strchrnul(const char *, int);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRNCHR
>>> extern char * strnchr(const char *, size_t, int);
>>> +char *__strnchr(const char *, size_t, int);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRRCHR
>>> extern char * strrchr(const char *,int);
>>> +char *__strrchr(const char *, int);
>>> #endif
>>> extern char * __must_check skip_spaces(const char *);
>>> +char * __must_check __skip_spaces(const char *);
>>>
>>> extern char *strim(char *);
>>> +char *__strim(char *);
>>>
>>> static inline __must_check char *strstrip(char *str)
>>> {
>>> @@ -75,27 +138,35 @@ static inline __must_check char *strstrip(char *str)
>>>
>>> #ifndef __HAVE_ARCH_STRSTR
>>> extern char * strstr(const char *, const char *);
>>> +char *__strstr(const char *, const char *);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRNSTR
>>> extern char * strnstr(const char *, const char *, size_t);
>>> +char *__strnstr(const char *, const char *, size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRLEN
>>> extern __kernel_size_t strlen(const char *);
>>> +__kernel_size_t __strlen(const char *);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRNLEN
>>> extern __kernel_size_t strnlen(const char *,__kernel_size_t);
>>> +__kernel_size_t __strnlen(const char *, __kernel_size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRPBRK
>>> extern char * strpbrk(const char *,const char *);
>>> +char *__strpbrk(const char *, const char *);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRSEP
>>> extern char * strsep(char **,const char *);
>>> +char *__strsep(char **, const char *);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRSPN
>>> extern __kernel_size_t strspn(const char *,const char *);
>>> +__kernel_size_t __strspn(const char *, const char *);
>>> #endif
>>> #ifndef __HAVE_ARCH_STRCSPN
>>> extern __kernel_size_t strcspn(const char *,const char *);
>>> +__kernel_size_t __strcspn(const char *, const char *);
>>> #endif
>>>
>>> #ifndef __HAVE_ARCH_MEMSET
>>> @@ -104,14 +175,17 @@ extern void * memset(void *,int,__kernel_size_t);
>>>
>>> #ifndef __HAVE_ARCH_MEMSET16
>>> extern void *memset16(uint16_t *, uint16_t, __kernel_size_t);
>>> +void *__memset16(uint16_t *, uint16_t, __kernel_size_t);
>>> #endif
>>>
>>> #ifndef __HAVE_ARCH_MEMSET32
>>> extern void *memset32(uint32_t *, uint32_t, __kernel_size_t);
>>> +void *__memset32(uint32_t *, uint32_t, __kernel_size_t);
>>> #endif
>>>
>>> #ifndef __HAVE_ARCH_MEMSET64
>>> extern void *memset64(uint64_t *, uint64_t, __kernel_size_t);
>>> +void *__memset64(uint64_t *, uint64_t, __kernel_size_t);
>>> #endif
>>>
>>> static inline void *memset_l(unsigned long *p, unsigned long v,
>>> @@ -146,12 +220,15 @@ extern void * memmove(void *,const void *,__kernel_size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_MEMSCAN
>>> extern void * memscan(void *,int,__kernel_size_t);
>>> +void *__memscan(void *, int, __kernel_size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_MEMCMP
>>> extern int memcmp(const void *,const void *,__kernel_size_t);
>>> +int __memcmp(const void *, const void *, __kernel_size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_MEMCHR
>>> extern void * memchr(const void *,int,__kernel_size_t);
>>> +void *__memchr(const void *, int, __kernel_size_t);
>>> #endif
>>> #ifndef __HAVE_ARCH_MEMCPY_MCSAFE
>>> static inline __must_check unsigned long memcpy_mcsafe(void *dst,
>>> @@ -168,7 +245,9 @@ static inline void memcpy_flushcache(void *dst, const void *src, size_t cnt)
>>> }
>>> #endif
>>> void *memchr_inv(const void *s, int c, size_t n);
>>> +void *__memchr_inv(const void *s, int c, size_t n);
>>> char *strreplace(char *s, char old, char new);
>>> +char *__strreplace(char *s, char old, char new);
>>>
>>> extern void kfree_const(const void *x);
>>>
>>> diff --git a/lib/Makefile b/lib/Makefile
>>> index 30b9b0bfbba9..19d0237f9b9c 100644
>>> --- a/lib/Makefile
>>> +++ b/lib/Makefile
>>> @@ -18,6 +18,8 @@ KCOV_INSTRUMENT_list_debug.o := n
>>> KCOV_INSTRUMENT_debugobjects.o := n
>>> KCOV_INSTRUMENT_dynamic_debug.o := n
>>>
>>> +KASAN_SANITIZE_string.o := n
>>> +
>>> lib-y := ctype.o string.o string_sysfs.o vsprintf.o cmdline.o \
>>> rbtree.o radix-tree.o timerqueue.o xarray.o \
>>> idr.o int_sqrt.o extable.o \
>>> diff --git a/lib/string.c b/lib/string.c
>>> index f3886c5175ac..31a253201bba 100644
>>> --- a/lib/string.c
>>> +++ b/lib/string.c
>>> @@ -85,7 +85,9 @@ EXPORT_SYMBOL(strcasecmp);
>>> * @dest: Where to copy the string to
>>> * @src: Where to copy the string from
>>> */
>>> +#ifndef CONFIG_KASAN
>>> #undef strcpy
>>> +#endif
>>> char *strcpy(char *dest, const char *src)
>>> {
>>> char *tmp = dest;
>>> @@ -243,7 +245,9 @@ EXPORT_SYMBOL(strscpy);
>>> * @dest: The string to be appended to
>>> * @src: The string to append to it
>>> */
>>> +#ifndef CONFIG_KASAN
>>> #undef strcat
>>> +#endif
>>> char *strcat(char *dest, const char *src)
>>> {
>>> char *tmp = dest;
>>> @@ -319,7 +323,9 @@ EXPORT_SYMBOL(strlcat);
>>> * @cs: One string
>>> * @ct: Another string
>>> */
>>> +#ifndef CONFIG_KASAN
>>> #undef strcmp
>>> +#endif
>>> int strcmp(const char *cs, const char *ct)
>>> {
>>> unsigned char c1, c2;
>>> @@ -773,7 +779,9 @@ EXPORT_SYMBOL(memmove);
>>> * @ct: Another area of memory
>>> * @count: The size of the area.
>>> */
>>> +#ifndef CONFIG_KASAN
>>> #undef memcmp
>>> +#endif
>>> __visible int memcmp(const void *cs, const void *ct, size_t count)
>>> {
>>> const unsigned char *su1, *su2;
>>> diff --git a/mm/kasan/string.c b/mm/kasan/string.c
>>> index 083b967255a2..0db31bbbf643 100644
>>> --- a/mm/kasan/string.c
>>> +++ b/mm/kasan/string.c
>>> @@ -35,6 +35,42 @@ void *memset(void *addr, int c, size_t len)
>>> return __memset(addr, c, len);
>>> }
>>>
>>> +#undef memset16
>>> +void *memset16(uint16_t *s, uint16_t v, size_t count)
>>> +{
>>> + check_memory_region((unsigned long)s, count << 1, true, _RET_IP_);
>>> +
>>> + return __memset16(s, v, count);
>>> +}
>>> +EXPORT_SYMBOL(memset16);
>>> +
>>> +#undef memset32
>>> +void *memset32(uint32_t *s, uint32_t v, size_t count)
>>> +{
>>> + check_memory_region((unsigned long)s, count << 2, true, _RET_IP_);
>>> +
>>> + return __memset32(s, v, count);
>>> +}
>>> +EXPORT_SYMBOL(memset32);
>>> +
>>> +#undef memset64
>>> +void *memset64(uint64_t *s, uint64_t v, size_t count)
>>> +{
>>> + check_memory_region((unsigned long)s, count << 3, true, _RET_IP_);
>>> +
>>> + return __memset64(s, v, count);
>>> +}
>>> +EXPORT_SYMBOL(memset64);
>>> +
>>> +#undef memzero_explicit
>>> +void memzero_explicit(void *s, size_t count)
>>> +{
>>> + check_memory_region((unsigned long)s, count, true, _RET_IP_);
>>> +
>>> + return __memzero_explicit(s, count);
>>> +}
>>> +EXPORT_SYMBOL(memzero_explicit);
>>> +
>>> #undef memmove
>>> void *memmove(void *dest, const void *src, size_t len)
>>> {
>>> @@ -52,3 +88,361 @@ void *memcpy(void *dest, const void *src, size_t len)
>>>
>>> return __memcpy(dest, src, len);
>>> }
>>> +
>>> +#undef strcpy
>>> +char *strcpy(char *dest, const char *src)
>>> +{
>>> + size_t len = __strlen(src) + 1;
>>> +
>>> + check_memory_region((unsigned long)src, len, false, _RET_IP_);
>>> + check_memory_region((unsigned long)dest, len, true, _RET_IP_);
>>> +
>>> + return __strcpy(dest, src);
>>> +}
>>> +EXPORT_SYMBOL(strcpy);
>>> +
>>> +#undef strncpy
>>> +char *strncpy(char *dest, const char *src, size_t count)
>>> +{
>>> + size_t len = min(__strlen(src) + 1, count);
>>> +
>>> + check_memory_region((unsigned long)src, len, false, _RET_IP_);
>>> + check_memory_region((unsigned long)dest, count, true, _RET_IP_);
>>> +
>>> + return __strncpy(dest, src, count);
>>> +}
>>> +EXPORT_SYMBOL(strncpy);
>>> +
>>> +#undef strlcpy
>>> +size_t strlcpy(char *dest, const char *src, size_t size)
>>> +{
>>> + size_t len = __strlen(src) + 1;
>>> +
>>> + check_memory_region((unsigned long)src, len, false, _RET_IP_);
>>> + check_memory_region((unsigned long)dest, min(len, size), true, _RET_IP_);
>>> +
>>> + return __strlcpy(dest, src, size);
>>> +}
>>> +EXPORT_SYMBOL(strlcpy);
>>> +
>>> +#undef strscpy
>>> +ssize_t strscpy(char *dest, const char *src, size_t count)
>>> +{
>>> + int len = min(__strlen(src) + 1, count);
>>> +
>>> + check_memory_region((unsigned long)src, len, false, _RET_IP_);
>>> + check_memory_region((unsigned long)dest, len, true, _RET_IP_);
>>> +
>>> + return __strscpy(dest, src, count);
>>> +}
>>> +EXPORT_SYMBOL(strscpy);
>>> +
>>> +#undef strcat
>>> +char *strcat(char *dest, const char *src)
>>> +{
>>> + size_t slen = __strlen(src) + 1;
>>> + size_t dlen = __strlen(dest);
>>> +
>>> + check_memory_region((unsigned long)src, slen, false, _RET_IP_);
>>> + check_memory_region((unsigned long)dest, dlen, false, _RET_IP_);
>>> + check_memory_region((unsigned long)(dest + dlen), slen, true, _RET_IP_);
>>> +
>>> + return __strcat(dest, src);
>>> +}
>>> +EXPORT_SYMBOL(strcat);
>>> +
>>> +#undef strncat
>>> +char *strncat(char *dest, const char *src, size_t count)
>>> +{
>>> + size_t slen = min(__strlen(src) + 1, count);
>>> + size_t dlen = __strlen(dest);
>>> +
>>> + check_memory_region((unsigned long)src, slen, false, _RET_IP_);
>>> + check_memory_region((unsigned long)dest, dlen, false, _RET_IP_);
>>> + check_memory_region((unsigned long)(dest + dlen), slen, true, _RET_IP_);
>>> +
>>> + return __strncat(dest, src, count);
>>> +}
>>> +EXPORT_SYMBOL(strncat);
>>> +
>>> +#undef strlcat
>>> +size_t strlcat(char *dest, const char *src, size_t count)
>>> +{
>>> + size_t slen = min(__strlen(src) + 1, count);
>>> + size_t dlen = __strlen(dest);
>>> +
>>> + check_memory_region((unsigned long)src, slen, false, _RET_IP_);
>>> + check_memory_region((unsigned long)dest, dlen, false, _RET_IP_);
>>> + check_memory_region((unsigned long)(dest + dlen), slen, true, _RET_IP_);
>>> +
>>> + return __strlcat(dest, src, count);
>>> +}
>>> +EXPORT_SYMBOL(strlcat);
>>> +
>>> +#undef strcmp
>>> +int strcmp(const char *cs, const char *ct)
>>> +{
>>> + size_t len = min(__strlen(cs) + 1, __strlen(ct) + 1);
>>> +
>>> + check_memory_region((unsigned long)cs, len, false, _RET_IP_);
>>> + check_memory_region((unsigned long)ct, len, false, _RET_IP_);
>>> +
>>> + return __strcmp(cs, ct);
>>> +}
>>> +EXPORT_SYMBOL(strcmp);
>>> +
>>> +#undef strncmp
>>> +int strncmp(const char *cs, const char *ct, size_t count)
>>> +{
>>> + size_t len = min3(__strlen(cs) + 1, __strlen(ct) + 1, count);
>>> +
>>> + check_memory_region((unsigned long)cs, len, false, _RET_IP_);
>>> + check_memory_region((unsigned long)ct, len, false, _RET_IP_);
>>> +
>>> + return __strncmp(cs, ct, count);
>>> +}
>>> +EXPORT_SYMBOL(strncmp);
>>> +
>>> +#undef strcasecmp
>>> +int strcasecmp(const char *s1, const char *s2)
>>> +{
>>> + size_t len = min(__strlen(s1) + 1, __strlen(s2) + 1);
>>> +
>>> + check_memory_region((unsigned long)s1, len, false, _RET_IP_);
>>> + check_memory_region((unsigned long)s2, len, false, _RET_IP_);
>>> +
>>> + return __strcasecmp(s1, s2);
>>> +}
>>> +EXPORT_SYMBOL(strcasecmp);
>>> +
>>> +#undef strncasecmp
>>> +int strncasecmp(const char *s1, const char *s2, size_t len)
>>> +{
>>> + size_t sz = min3(__strlen(s1) + 1, __strlen(s2) + 1, len);
>>> +
>>> + check_memory_region((unsigned long)s1, sz, false, _RET_IP_);
>>> + check_memory_region((unsigned long)s2, sz, false, _RET_IP_);
>>> +
>>> + return __strncasecmp(s1, s2, len);
>>> +}
>>> +EXPORT_SYMBOL(strncasecmp);
>>> +
>>> +#undef strchr
>>> +char *strchr(const char *s, int c)
>>> +{
>>> + size_t len = __strlen(s) + 1;
>>> +
>>> + check_memory_region((unsigned long)s, len, false, _RET_IP_);
>>> +
>>> + return __strchr(s, c);
>>> +}
>>> +EXPORT_SYMBOL(strchr);
>>> +
>>> +#undef strchrnul
>>> +char *strchrnul(const char *s, int c)
>>> +{
>>> + size_t len = __strlen(s) + 1;
>>> +
>>> + check_memory_region((unsigned long)s, len, false, _RET_IP_);
>>> +
>>> + return __strchrnul(s, c);
>>> +}
>>> +EXPORT_SYMBOL(strchrnul);
>>> +
>>> +#undef strrchr
>>> +char *strrchr(const char *s, int c)
>>> +{
>>> + size_t len = __strlen(s) + 1;
>>> +
>>> + check_memory_region((unsigned long)s, len, false, _RET_IP_);
>>> +
>>> + return __strrchr(s, c);
>>> +}
>>> +EXPORT_SYMBOL(strrchr);
>>> +
>>> +#undef strnchr
>>> +char *strnchr(const char *s, size_t count, int c)
>>> +{
>>> + size_t len = __strlen(s) + 1;
>>> +
>>> + check_memory_region((unsigned long)s, len, false, _RET_IP_);
>>> +
>>> + return __strnchr(s, count, c);
>>> +}
>>> +EXPORT_SYMBOL(strnchr);
>>> +
>>> +#undef skip_spaces
>>> +char *skip_spaces(const char *str)
>>> +{
>>> + size_t len = __strlen(str) + 1;
>>> +
>>> + check_memory_region((unsigned long)str, len, false, _RET_IP_);
>>> +
>>> + return __skip_spaces(str);
>>> +}
>>> +EXPORT_SYMBOL(skip_spaces);
>>> +
>>> +#undef strim
>>> +char *strim(char *s)
>>> +{
>>> + size_t len = __strlen(s) + 1;
>>> +
>>> + check_memory_region((unsigned long)s, len, false, _RET_IP_);
>>> +
>>> + return __strim(s);
>>> +}
>>> +EXPORT_SYMBOL(strim);
>>> +
>>> +#undef strstr
>>> +char *strstr(const char *s1, const char *s2)
>>> +{
>>> + size_t l1 = __strlen(s1) + 1;
>>> + size_t l2 = __strlen(s2) + 1;
>>> +
>>> + check_memory_region((unsigned long)s1, l1, false, _RET_IP_);
>>> + check_memory_region((unsigned long)s2, l2, false, _RET_IP_);
>>> +
>>> + return __strstr(s1, s2);
>>> +}
>>> +EXPORT_SYMBOL(strstr);
>>> +
>>> +#undef strnstr
>>> +char *strnstr(const char *s1, const char *s2, size_t len)
>>> +{
>>> + size_t l1 = min(__strlen(s1) + 1, len);
>>> + size_t l2 = __strlen(s2) + 1;
>>> +
>>> + check_memory_region((unsigned long)s1, l1, false, _RET_IP_);
>>> + check_memory_region((unsigned long)s2, l2, false, _RET_IP_);
>>> +
>>> + return __strnstr(s1, s2, len);
>>> +}
>>> +EXPORT_SYMBOL(strnstr);
>>> +
>>> +#undef strlen
>>> +size_t strlen(const char *s)
>>> +{
>>> + size_t len = __strlen(s);
>>> +
>>> + check_memory_region((unsigned long)s, len + 1, false, _RET_IP_);
>>> +
>>> + return len;
>>> +}
>>> +EXPORT_SYMBOL(strlen);
>>> +
>>> +#undef strnlen
>>> +size_t strnlen(const char *s, size_t count)
>>> +{
>>> + size_t len = __strnlen(s, count);
>>> +
>>> + check_memory_region((unsigned long)s, min(len + 1, count), false, _RET_IP_);
>>> +
>>> + return len;
>>> +}
>>> +EXPORT_SYMBOL(strnlen);
>>> +
>>> +#undef strpbrk
>>> +char *strpbrk(const char *cs, const char *ct)
>>> +{
>>> + size_t ls = __strlen(cs) + 1;
>>> + size_t lt = __strlen(ct) + 1;
>>> +
>>> + check_memory_region((unsigned long)cs, ls, false, _RET_IP_);
>>> + check_memory_region((unsigned long)ct, lt, false, _RET_IP_);
>>> +
>>> + return __strpbrk(cs, ct);
>>> +}
>>> +EXPORT_SYMBOL(strpbrk);
>>> +
>>> +#undef strsep
>>> +char *strsep(char **s, const char *ct)
>>> +{
>>> + char *cs = *s;
>>> +
>>> + check_memory_region((unsigned long)s, sizeof(*s), true, _RET_IP_);
>>> +
>>> + if (cs) {
>>> + int ls = __strlen(cs) + 1;
>>> + int lt = __strlen(ct) + 1;
>>> +
>>> + check_memory_region((unsigned long)cs, ls, false, _RET_IP_);
>>> + check_memory_region((unsigned long)ct, lt, false, _RET_IP_);
>>> + }
>>> +
>>> + return __strsep(s, ct);
>>> +}
>>> +EXPORT_SYMBOL(strsep);
>>> +
>>> +#undef strspn
>>> +size_t strspn(const char *s, const char *accept)
>>> +{
>>> + size_t ls = __strlen(s) + 1;
>>> + size_t la = __strlen(accept) + 1;
>>> +
>>> + check_memory_region((unsigned long)s, ls, false, _RET_IP_);
>>> + check_memory_region((unsigned long)accept, la, false, _RET_IP_);
>>> +
>>> + return __strspn(s, accept);
>>> +}
>>> +EXPORT_SYMBOL(strspn);
>>> +
>>> +#undef strcspn
>>> +size_t strcspn(const char *s, const char *reject)
>>> +{
>>> + size_t ls = __strlen(s) + 1;
>>> + size_t lr = __strlen(reject) + 1;
>>> +
>>> + check_memory_region((unsigned long)s, ls, false, _RET_IP_);
>>> + check_memory_region((unsigned long)reject, lr, false, _RET_IP_);
>>> +
>>> + return __strcspn(s, reject);
>>> +}
>>> +EXPORT_SYMBOL(strcspn);
>>> +
>>> +#undef memscan
>>> +void *memscan(void *addr, int c, size_t size)
>>> +{
>>> + check_memory_region((unsigned long)addr, size, false, _RET_IP_);
>>> +
>>> + return __memscan(addr, c, size);
>>> +}
>>> +EXPORT_SYMBOL(memscan);
>>> +
>>> +#undef memcmp
>>> +int memcmp(const void *cs, const void *ct, size_t count)
>>> +{
>>> + check_memory_region((unsigned long)cs, count, false, _RET_IP_);
>>> + check_memory_region((unsigned long)ct, count, false, _RET_IP_);
>>> +
>>> + return __memcmp(cs, ct, count);
>>> +}
>>> +EXPORT_SYMBOL(memcmp);
>>> +
>>> +#undef memchr
>>> +void *memchr(const void *s, int c, size_t n)
>>> +{
>>> + check_memory_region((unsigned long)s, n, false, _RET_IP_);
>>> +
>>> + return __memchr(s, c, n);
>>> +}
>>> +EXPORT_SYMBOL(memchr);
>>> +
>>> +#undef memchr_inv
>>> +void *memchr_inv(const void *start, int c, size_t bytes)
>>> +{
>>> + check_memory_region((unsigned long)start, bytes, false, _RET_IP_);
>>> +
>>> + return __memchr_inv(start, c, bytes);
>>> +}
>>> +EXPORT_SYMBOL(memchr_inv);
>>> +
>>> +#undef strreplace
>>> +char *strreplace(char *s, char old, char new)
>>> +{
>>> + size_t len = __strlen(s) + 1;
>>> +
>>> + check_memory_region((unsigned long)s, len, true, _RET_IP_);
>>> +
>>> + return __strreplace(s, old, new);
>>> +}
>>> +EXPORT_SYMBOL(strreplace);
>>>
^ permalink raw reply
* [RFC PATCH] powerpc/mm: Reduce memory usage for mm_context_t for radix
From: Aneesh Kumar K.V @ 2019-04-02 14:34 UTC (permalink / raw)
To: npiggin, benh, paulus, mpe, Christophe Leroy
Cc: Aneesh Kumar K.V, linuxppc-dev
Currently, our mm_context_t on book3s64 include all hash specific
context details like slice mask, subpage protection details. We
can skip allocating those on radix. This will help us to save
8K per mm_context with radix translation.
With the patch applied we have
sizeof(mm_context_t) = 136
sizeof(struct hash_mm_context) = 8288
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
NOTE:
If we want to do this, I am still trying to figure out how best we can do this
without all the #ifdef and other overhead for 8xx book3e
arch/powerpc/include/asm/book3s/64/mmu-hash.h | 2 +-
arch/powerpc/include/asm/book3s/64/mmu.h | 48 +++++++++++--------
arch/powerpc/include/asm/book3s/64/slice.h | 6 +--
arch/powerpc/kernel/paca.c | 9 ++--
arch/powerpc/kernel/setup-common.c | 7 ++-
arch/powerpc/mm/hash_utils_64.c | 10 ++--
arch/powerpc/mm/mmu_context_book3s64.c | 16 ++++++-
arch/powerpc/mm/slb.c | 2 +-
arch/powerpc/mm/slice.c | 48 +++++++++----------
arch/powerpc/mm/subpage-prot.c | 8 ++--
10 files changed, 91 insertions(+), 65 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/mmu-hash.h b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
index a28a28079edb..d801be977623 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu-hash.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu-hash.h
@@ -657,7 +657,7 @@ extern void slb_set_size(u16 size);
/* 4 bits per slice and we have one slice per 1TB */
#define SLICE_ARRAY_SIZE (H_PGTABLE_RANGE >> 41)
-#define TASK_SLICE_ARRAY_SZ(x) ((x)->context.slb_addr_limit >> 41)
+#define TASK_SLICE_ARRAY_SZ(x) ((x)->context.hash_context->slb_addr_limit >> 41)
#ifndef __ASSEMBLY__
diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
index a809bdd77322..07e76e304a3b 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu.h
@@ -114,6 +114,33 @@ struct slice_mask {
DECLARE_BITMAP(high_slices, SLICE_NUM_HIGH);
};
+struct hash_mm_context {
+
+ u16 user_psize; /* page size index */
+
+#ifdef CONFIG_PPC_MM_SLICES
+ /* SLB page size encodings*/
+ unsigned char low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE];
+ unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
+ unsigned long slb_addr_limit;
+#ifdef CONFIG_PPC_64K_PAGES
+ struct slice_mask mask_64k;
+#endif
+ struct slice_mask mask_4k;
+#ifdef CONFIG_HUGETLB_PAGE
+ struct slice_mask mask_16m;
+ struct slice_mask mask_16g;
+#endif
+#else
+ u16 sllp; /* SLB page size encoding */
+#endif
+
+#ifdef CONFIG_PPC_SUBPAGE_PROT
+ struct subpage_prot_table spt;
+#endif /* CONFIG_PPC_SUBPAGE_PROT */
+
+};
+
typedef struct {
union {
/*
@@ -127,7 +154,6 @@ typedef struct {
mm_context_id_t id;
mm_context_id_t extended_id[TASK_SIZE_USER64/TASK_CONTEXT_SIZE];
};
- u16 user_psize; /* page size index */
/* Number of bits in the mm_cpumask */
atomic_t active_cpus;
@@ -137,27 +163,9 @@ typedef struct {
/* NPU NMMU context */
struct npu_context *npu_context;
+ struct hash_mm_context *hash_context;
-#ifdef CONFIG_PPC_MM_SLICES
- /* SLB page size encodings*/
- unsigned char low_slices_psize[BITS_PER_LONG / BITS_PER_BYTE];
- unsigned char high_slices_psize[SLICE_ARRAY_SIZE];
- unsigned long slb_addr_limit;
-# ifdef CONFIG_PPC_64K_PAGES
- struct slice_mask mask_64k;
-# endif
- struct slice_mask mask_4k;
-# ifdef CONFIG_HUGETLB_PAGE
- struct slice_mask mask_16m;
- struct slice_mask mask_16g;
-# endif
-#else
- u16 sllp; /* SLB page size encoding */
-#endif
unsigned long vdso_base;
-#ifdef CONFIG_PPC_SUBPAGE_PROT
- struct subpage_prot_table spt;
-#endif /* CONFIG_PPC_SUBPAGE_PROT */
/*
* pagetable fragment support
*/
diff --git a/arch/powerpc/include/asm/book3s/64/slice.h b/arch/powerpc/include/asm/book3s/64/slice.h
index db0dedab65ee..3ca1bebe258e 100644
--- a/arch/powerpc/include/asm/book3s/64/slice.h
+++ b/arch/powerpc/include/asm/book3s/64/slice.h
@@ -15,11 +15,11 @@
#else /* CONFIG_PPC_MM_SLICES */
-#define get_slice_psize(mm, addr) ((mm)->context.user_psize)
+#define get_slice_psize(mm, addr) ((mm)->context.hash_context->user_psize)
#define slice_set_user_psize(mm, psize) \
do { \
- (mm)->context.user_psize = (psize); \
- (mm)->context.sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
+ (mm)->context.hash_context->user_psize = (psize); \
+ (mm)->context.hash_context->sllp = SLB_VSID_USER | mmu_psize_defs[(psize)].sllp; \
} while (0)
#endif /* CONFIG_PPC_MM_SLICES */
diff --git a/arch/powerpc/kernel/paca.c b/arch/powerpc/kernel/paca.c
index e7382abee868..9f1e5d08fa74 100644
--- a/arch/powerpc/kernel/paca.c
+++ b/arch/powerpc/kernel/paca.c
@@ -267,12 +267,13 @@ void copy_mm_to_paca(struct mm_struct *mm)
get_paca()->mm_ctx_id = context->id;
#ifdef CONFIG_PPC_MM_SLICES
- VM_BUG_ON(!mm->context.slb_addr_limit);
- get_paca()->mm_ctx_slb_addr_limit = mm->context.slb_addr_limit;
+ VM_BUG_ON(!mm->context.hash_context->slb_addr_limit);
+ get_paca()->mm_ctx_slb_addr_limit = mm->context.hash_context->slb_addr_limit;
memcpy(&get_paca()->mm_ctx_low_slices_psize,
- &context->low_slices_psize, sizeof(context->low_slices_psize));
+ &context->hash_context->low_slices_psize,
+ sizeof(context->hash_context->low_slices_psize));
memcpy(&get_paca()->mm_ctx_high_slices_psize,
- &context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm));
+ &context->hash_context->high_slices_psize, TASK_SLICE_ARRAY_SZ(mm));
#else /* CONFIG_PPC_MM_SLICES */
get_paca()->mm_ctx_user_psize = context->user_psize;
get_paca()->mm_ctx_sllp = context->sllp;
diff --git a/arch/powerpc/kernel/setup-common.c b/arch/powerpc/kernel/setup-common.c
index 2e5dfb6e0823..40290d3d95b0 100644
--- a/arch/powerpc/kernel/setup-common.c
+++ b/arch/powerpc/kernel/setup-common.c
@@ -862,6 +862,7 @@ static void smp_setup_pacas(void)
}
#endif
+struct hash_mm_context init_hash_mm_context;
/*
* Called into from start_kernel this initializes memblock, which is used
* to manage page allocation until mem_init is called.
@@ -949,8 +950,10 @@ void __init setup_arch(char **cmdline_p)
#ifdef CONFIG_PPC_MM_SLICES
#ifdef CONFIG_PPC64
- if (!radix_enabled())
- init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
+ if (!radix_enabled()) {
+ init_mm.context.hash_context = &init_hash_mm_context;
+ init_mm.context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
+ }
#elif defined(CONFIG_PPC_8xx)
init_mm.context.slb_addr_limit = DEFAULT_MAP_WINDOW;
#else
diff --git a/arch/powerpc/mm/hash_utils_64.c b/arch/powerpc/mm/hash_utils_64.c
index 0a4f939a8161..df035c3ebb4b 100644
--- a/arch/powerpc/mm/hash_utils_64.c
+++ b/arch/powerpc/mm/hash_utils_64.c
@@ -1147,7 +1147,7 @@ void demote_segment_4k(struct mm_struct *mm, unsigned long addr)
*/
static int subpage_protection(struct mm_struct *mm, unsigned long ea)
{
- struct subpage_prot_table *spt = &mm->context.spt;
+ struct subpage_prot_table *spt = &mm->context.hash_context->spt;
u32 spp = 0;
u32 **sbpm, *sbpp;
@@ -1470,7 +1470,7 @@ static bool should_hash_preload(struct mm_struct *mm, unsigned long ea)
int psize = get_slice_psize(mm, ea);
/* We only prefault standard pages for now */
- if (unlikely(psize != mm->context.user_psize))
+ if (unlikely(psize != mm->context.hash_context->user_psize))
return false;
/*
@@ -1549,7 +1549,7 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
/* Hash it in */
#ifdef CONFIG_PPC_64K_PAGES
- if (mm->context.user_psize == MMU_PAGE_64K)
+ if (mm->context.hash_context->user_psize == MMU_PAGE_64K)
rc = __hash_page_64K(ea, access, vsid, ptep, trap,
update_flags, ssize);
else
@@ -1562,8 +1562,8 @@ void hash_preload(struct mm_struct *mm, unsigned long ea,
*/
if (rc == -1)
hash_failure_debug(ea, access, vsid, trap, ssize,
- mm->context.user_psize,
- mm->context.user_psize,
+ mm->context.hash_context->user_psize,
+ mm->context.hash_context->user_psize,
pte_val(*ptep));
out_exit:
local_irq_restore(flags);
diff --git a/arch/powerpc/mm/mmu_context_book3s64.c b/arch/powerpc/mm/mmu_context_book3s64.c
index f720c5cc0b5e..6eef5a36b2e9 100644
--- a/arch/powerpc/mm/mmu_context_book3s64.c
+++ b/arch/powerpc/mm/mmu_context_book3s64.c
@@ -63,6 +63,12 @@ static int hash__init_new_context(struct mm_struct *mm)
if (index < 0)
return index;
+ mm->context.hash_context = kmalloc(sizeof(struct hash_mm_context), GFP_KERNEL);
+ if (!mm->context.hash_context) {
+ ida_free(&mmu_context_ida, index);
+ return -ENOMEM;
+ }
+
/*
* The old code would re-promote on fork, we don't do that when using
* slices as it could cause problem promoting slices that have been
@@ -77,8 +83,14 @@ static int hash__init_new_context(struct mm_struct *mm)
* We should not be calling init_new_context() on init_mm. Hence a
* check against 0 is OK.
*/
- if (mm->context.id == 0)
+ if (mm->context.id == 0) {
+ memset(mm->context.hash_context, 0, sizeof(struct hash_mm_context));
slice_init_new_context_exec(mm);
+ } else {
+ /* This is fork. Copy hash_context details from current->mm */
+ memcpy(mm->context.hash_context, current->mm->context.hash_context, sizeof(struct hash_mm_context));
+
+ }
subpage_prot_init_new_context(mm);
@@ -118,6 +130,7 @@ static int radix__init_new_context(struct mm_struct *mm)
asm volatile("ptesync;isync" : : : "memory");
mm->context.npu_context = NULL;
+ mm->context.hash_context = NULL;
return index;
}
@@ -162,6 +175,7 @@ static void destroy_contexts(mm_context_t *ctx)
if (context_id)
ida_free(&mmu_context_ida, context_id);
}
+ kfree(ctx->hash_context);
}
static void pmd_frag_destroy(void *pmd_frag)
diff --git a/arch/powerpc/mm/slb.c b/arch/powerpc/mm/slb.c
index 5986df48359b..2b128939e2e7 100644
--- a/arch/powerpc/mm/slb.c
+++ b/arch/powerpc/mm/slb.c
@@ -739,7 +739,7 @@ static long slb_allocate_user(struct mm_struct *mm, unsigned long ea)
* consider this as bad access if we take a SLB miss
* on an address above addr limit.
*/
- if (ea >= mm->context.slb_addr_limit)
+ if (ea >= mm->context.hash_context->slb_addr_limit)
return -EFAULT;
context = get_user_context(&mm->context, ea);
diff --git a/arch/powerpc/mm/slice.c b/arch/powerpc/mm/slice.c
index aec91dbcdc0b..84b200429464 100644
--- a/arch/powerpc/mm/slice.c
+++ b/arch/powerpc/mm/slice.c
@@ -101,7 +101,7 @@ static int slice_area_is_free(struct mm_struct *mm, unsigned long addr,
{
struct vm_area_struct *vma;
- if ((mm->context.slb_addr_limit - len) < addr)
+ if ((mm->context.hash_context->slb_addr_limit - len) < addr)
return 0;
vma = find_vma(mm, addr);
return (!vma || (addr + len) <= vm_start_gap(vma));
@@ -155,15 +155,15 @@ static struct slice_mask *slice_mask_for_size(struct mm_struct *mm, int psize)
{
#ifdef CONFIG_PPC_64K_PAGES
if (psize == MMU_PAGE_64K)
- return &mm->context.mask_64k;
+ return &mm->context.hash_context->mask_64k;
#endif
if (psize == MMU_PAGE_4K)
- return &mm->context.mask_4k;
+ return &mm->context.hash_context->mask_4k;
#ifdef CONFIG_HUGETLB_PAGE
if (psize == MMU_PAGE_16M)
- return &mm->context.mask_16m;
+ return &mm->context.hash_context->mask_16m;
if (psize == MMU_PAGE_16G)
- return &mm->context.mask_16g;
+ return &mm->context.hash_context->mask_16g;
#endif
BUG();
}
@@ -253,7 +253,7 @@ static void slice_convert(struct mm_struct *mm,
*/
spin_lock_irqsave(&slice_convert_lock, flags);
- lpsizes = mm->context.low_slices_psize;
+ lpsizes = mm->context.hash_context->low_slices_psize;
for (i = 0; i < SLICE_NUM_LOW; i++) {
if (!(mask->low_slices & (1u << i)))
continue;
@@ -272,8 +272,8 @@ static void slice_convert(struct mm_struct *mm,
(((unsigned long)psize) << (mask_index * 4));
}
- hpsizes = mm->context.high_slices_psize;
- for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.slb_addr_limit); i++) {
+ hpsizes = mm->context.hash_context->high_slices_psize;
+ for (i = 0; i < GET_HIGH_SLICE_INDEX(mm->context.hash_context->slb_addr_limit); i++) {
if (!test_bit(i, mask->high_slices))
continue;
@@ -292,8 +292,8 @@ static void slice_convert(struct mm_struct *mm,
}
slice_dbg(" lsps=%lx, hsps=%lx\n",
- (unsigned long)mm->context.low_slices_psize,
- (unsigned long)mm->context.high_slices_psize);
+ (unsigned long)mm->context.hash_context->low_slices_psize,
+ (unsigned long)mm->context.hash_context->high_slices_psize);
spin_unlock_irqrestore(&slice_convert_lock, flags);
@@ -393,7 +393,7 @@ static unsigned long slice_find_area_topdown(struct mm_struct *mm,
* DEFAULT_MAP_WINDOW we should apply this.
*/
if (high_limit > DEFAULT_MAP_WINDOW)
- addr += mm->context.slb_addr_limit - DEFAULT_MAP_WINDOW;
+ addr += mm->context.hash_context->slb_addr_limit - DEFAULT_MAP_WINDOW;
while (addr > min_addr) {
info.high_limit = addr;
@@ -505,20 +505,20 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
return -ENOMEM;
}
- if (high_limit > mm->context.slb_addr_limit) {
+ if (high_limit > mm->context.hash_context->slb_addr_limit) {
/*
* Increasing the slb_addr_limit does not require
* slice mask cache to be recalculated because it should
* be already initialised beyond the old address limit.
*/
- mm->context.slb_addr_limit = high_limit;
+ mm->context.hash_context->slb_addr_limit = high_limit;
on_each_cpu(slice_flush_segments, mm, 1);
}
/* Sanity checks */
BUG_ON(mm->task_size == 0);
- BUG_ON(mm->context.slb_addr_limit == 0);
+ BUG_ON(mm->context.hash_context->slb_addr_limit == 0);
VM_BUG_ON(radix_enabled());
slice_dbg("slice_get_unmapped_area(mm=%p, psize=%d...\n", mm, psize);
@@ -696,7 +696,7 @@ unsigned long arch_get_unmapped_area(struct file *filp,
unsigned long flags)
{
return slice_get_unmapped_area(addr, len, flags,
- current->mm->context.user_psize, 0);
+ current->mm->context.hash_context->user_psize, 0);
}
unsigned long arch_get_unmapped_area_topdown(struct file *filp,
@@ -706,7 +706,7 @@ unsigned long arch_get_unmapped_area_topdown(struct file *filp,
const unsigned long flags)
{
return slice_get_unmapped_area(addr0, len, flags,
- current->mm->context.user_psize, 1);
+ current->mm->context.hash_context->user_psize, 1);
}
unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
@@ -717,10 +717,10 @@ unsigned int get_slice_psize(struct mm_struct *mm, unsigned long addr)
VM_BUG_ON(radix_enabled());
if (slice_addr_is_low(addr)) {
- psizes = mm->context.low_slices_psize;
+ psizes = mm->context.hash_context->low_slices_psize;
index = GET_LOW_SLICE_INDEX(addr);
} else {
- psizes = mm->context.high_slices_psize;
+ psizes = mm->context.hash_context->high_slices_psize;
index = GET_HIGH_SLICE_INDEX(addr);
}
mask_index = index & 0x1;
@@ -742,20 +742,20 @@ void slice_init_new_context_exec(struct mm_struct *mm)
* duplicated.
*/
#ifdef CONFIG_PPC64
- mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
+ mm->context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW_USER64;
#else
mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW;
#endif
- mm->context.user_psize = psize;
+ mm->context.hash_context->user_psize = psize;
/*
* Set all slice psizes to the default.
*/
- lpsizes = mm->context.low_slices_psize;
+ lpsizes = mm->context.hash_context->low_slices_psize;
memset(lpsizes, (psize << 4) | psize, SLICE_NUM_LOW >> 1);
- hpsizes = mm->context.high_slices_psize;
+ hpsizes = mm->context.hash_context->high_slices_psize;
memset(hpsizes, (psize << 4) | psize, SLICE_NUM_HIGH >> 1);
/*
@@ -777,7 +777,7 @@ void slice_setup_new_exec(void)
if (!is_32bit_task())
return;
- mm->context.slb_addr_limit = DEFAULT_MAP_WINDOW;
+ mm->context.hash_context->slb_addr_limit = DEFAULT_MAP_WINDOW;
}
#endif
@@ -816,7 +816,7 @@ int slice_is_hugepage_only_range(struct mm_struct *mm, unsigned long addr,
unsigned long len)
{
const struct slice_mask *maskp;
- unsigned int psize = mm->context.user_psize;
+ unsigned int psize = mm->context.hash_context->user_psize;
VM_BUG_ON(radix_enabled());
diff --git a/arch/powerpc/mm/subpage-prot.c b/arch/powerpc/mm/subpage-prot.c
index 5e4178790dee..3a13cbcb6f97 100644
--- a/arch/powerpc/mm/subpage-prot.c
+++ b/arch/powerpc/mm/subpage-prot.c
@@ -25,7 +25,7 @@
*/
void subpage_prot_free(struct mm_struct *mm)
{
- struct subpage_prot_table *spt = &mm->context.spt;
+ struct subpage_prot_table *spt = &mm->context.hash_context->spt;
unsigned long i, j, addr;
u32 **p;
@@ -52,7 +52,7 @@ void subpage_prot_free(struct mm_struct *mm)
void subpage_prot_init_new_context(struct mm_struct *mm)
{
- struct subpage_prot_table *spt = &mm->context.spt;
+ struct subpage_prot_table *spt = &mm->context.hash_context->spt;
memset(spt, 0, sizeof(*spt));
}
@@ -93,7 +93,7 @@ static void hpte_flush_range(struct mm_struct *mm, unsigned long addr,
static void subpage_prot_clear(unsigned long addr, unsigned long len)
{
struct mm_struct *mm = current->mm;
- struct subpage_prot_table *spt = &mm->context.spt;
+ struct subpage_prot_table *spt = &mm->context.hash_context->spt;
u32 **spm, *spp;
unsigned long i;
size_t nw;
@@ -189,7 +189,7 @@ SYSCALL_DEFINE3(subpage_prot, unsigned long, addr,
unsigned long, len, u32 __user *, map)
{
struct mm_struct *mm = current->mm;
- struct subpage_prot_table *spt = &mm->context.spt;
+ struct subpage_prot_table *spt = &mm->context.hash_context->spt;
u32 **spm, *spp;
unsigned long i;
size_t nw;
--
2.20.1
^ permalink raw reply related
* [PATCH 3.16 92/99] block/swim3: Fix -EBUSY error when re-opening device after unmount
From: Ben Hutchings @ 2019-04-02 13:38 UTC (permalink / raw)
To: linux-kernel, stable
Cc: Jens Axboe, akpm, linuxppc-dev, Denis Kirjanov, Finn Thain
In-Reply-To: <lsq.1554212307.17110877@decadent.org.uk>
3.16.65-rc1 review patch. If anyone has any objections, please let me know.
------------------
From: Finn Thain <fthain@telegraphics.com.au>
commit 296dcc40f2f2e402facf7cd26cf3f2c8f4b17d47 upstream.
When the block device is opened with FMODE_EXCL, ref_count is set to -1.
This value doesn't get reset when the device is closed which means the
device cannot be opened again. Fix this by checking for refcount <= 0
in the release method.
Reported-and-tested-by: Stan Johnson <userm57@yahoo.com>
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: linuxppc-dev@lists.ozlabs.org
Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
---
drivers/block/swim3.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
--- a/drivers/block/swim3.c
+++ b/drivers/block/swim3.c
@@ -1027,7 +1027,11 @@ static void floppy_release(struct gendis
struct swim3 __iomem *sw = fs->swim3;
mutex_lock(&swim3_mutex);
- if (fs->ref_count > 0 && --fs->ref_count == 0) {
+ if (fs->ref_count > 0)
+ --fs->ref_count;
+ else if (fs->ref_count == -1)
+ fs->ref_count = 0;
+ if (fs->ref_count == 0) {
swim3_action(fs, MOTOR_OFF);
out_8(&sw->control_bic, 0xff);
swim3_select(fs, RELAX);
^ permalink raw reply
* VLC doesn't play videos anymore since the PowerPC fixes 5.1-3
From: Christian Zigotzky @ 2019-04-02 13:37 UTC (permalink / raw)
To: linuxppc-dev
Hi All,
I figured out, that the VLC player doesn't play videos anymore since the
PowerPC fixes 5.1-3 [1]. VLC plays videos with the RC1 of kernel 5.1
without any problems.
VLC error messages:
[100ea580] ts demux warning: first packet for pid=1104 cc=0xe
[100ea580] ts demux warning: first packet for pid=1102 cc=0x4
[100ea580] ts demux warning: first packet for pid=1101 cc=0x8
[10109218] core decoder warning: can't get output picture
[10109218] avcodec decoder warning: disabling direct rendering
[10109218] core decoder warning: can't get output picture
----
dmesg: https://bugs.freedesktop.org/attachment.cgi?id=143840
I created a bug report because of the VLC issue with the kernel 5.1-rc2
and higher today [2]. I got an answer from Michel Dänzer today.
Quote Michel Dänzer:
None of them directly affect the radeon driver.
It's quite likely that this is a PPC specific issue. Your best bet is
bisecting between rc1 and rc2.
I haven't seen any other similar reports.
----
I was able to remove the PowerPC fixes 5.1-4 and 5.1-3 with the
following commands:
git revert 6536c5f2c8cf79db0d37e79afcdb227dc854509c -m 1
Output: [master 4b4a8cf] Revert "Merge tag 'powerpc-5.1-4' of
git://git.kernel.org/pub/scm/linux/kern ... erpc/linux"
git revert a5ed1e96cafde5ba48638f486bfca0685dc6ddc9 -m 1
Output: [master 0c70b7b] Revert "Merge tag 'powerpc-5.1-3' of
git://git.kernel.org/pub/scm/linux/kern ... erpc/linux"
The removing of the PowerPC fixes 5.1-4 and 5.1-3 has solved the VLC issue.
The problematic code is definitely in the PowerPC fixes 5.1-3 [1].
Please check the PowerPC fixes 5.1-3 [1].
Thanks,
Christian
[1]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v5.1-rc2&id=a5ed1e96cafde5ba48638f486bfca0685dc6ddc9
[2] https://bugs.freedesktop.org/show_bug.cgi?id=110304
^ permalink raw reply
* Re: [RFC PATCH v2 3/3] kasan: add interceptors for all string functions
From: Dmitry Vyukov @ 2019-04-02 12:58 UTC (permalink / raw)
To: Christophe Leroy
Cc: LKML, Nicholas Piggin, Linux-MM, Paul Mackerras, Aneesh Kumar K.V,
Andrey Ryabinin, Alexander Potapenko, kasan-dev, linuxppc-dev,
Daniel Axtens
In-Reply-To: <3211b0f8-7b52-01b7-8208-65d746969248@c-s.fr>
On Tue, Apr 2, 2019 at 11:43 AM Christophe Leroy
<christophe.leroy@c-s.fr> wrote:
>
> Hi Dmitry, Andrey and others,
>
> Do you have any comments to this series ?
>
> I'd like to know if this approach is ok or if it is better to keep doing
> as in https://patchwork.ozlabs.org/patch/1055788/
Hi Christophe,
Forking every kernel function does not look like a scalable approach
to me. There is not much special about str* functions. There is
something a bit special about memset/memcpy as compiler emits them for
struct set/copy.
Could powerpc do the same as x86 and map some shadow early enough
(before "prom")? Then we would not need anything of this? Sorry if we
already discussed this, I am losing context quickly.
> Thanks
> Christophe
>
> Le 28/03/2019 à 16:00, Christophe Leroy a écrit :
> > In the same spirit as commit 393f203f5fd5 ("x86_64: kasan: add
> > interceptors for memset/memmove/memcpy functions"), this patch
> > adds interceptors for string manipulation functions so that we
> > can compile lib/string.o without kasan support hence allow the
> > string functions to also be used from places where kasan has
> > to be disabled.
> >
> > Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
> > ---
> > v2: Fixed a few checkpatch stuff and added missing EXPORT_SYMBOL() and missing #undefs
> >
> > include/linux/string.h | 79 ++++++++++
> > lib/Makefile | 2 +
> > lib/string.c | 8 +
> > mm/kasan/string.c | 394 +++++++++++++++++++++++++++++++++++++++++++++++++
> > 4 files changed, 483 insertions(+)
> >
> > diff --git a/include/linux/string.h b/include/linux/string.h
> > index 7927b875f80c..3d2aff2ed402 100644
> > --- a/include/linux/string.h
> > +++ b/include/linux/string.h
> > @@ -19,54 +19,117 @@ extern void *memdup_user_nul(const void __user *, size_t);
> > */
> > #include <asm/string.h>
> >
> > +#if defined(CONFIG_KASAN) && !defined(__SANITIZE_ADDRESS__)
> > +/*
> > + * For files that are not instrumented (e.g. mm/slub.c) we
> > + * should use not instrumented version of mem* functions.
> > + */
> > +#define memset16 __memset16
> > +#define memset32 __memset32
> > +#define memset64 __memset64
> > +#define memzero_explicit __memzero_explicit
> > +#define strcpy __strcpy
> > +#define strncpy __strncpy
> > +#define strlcpy __strlcpy
> > +#define strscpy __strscpy
> > +#define strcat __strcat
> > +#define strncat __strncat
> > +#define strlcat __strlcat
> > +#define strcmp __strcmp
> > +#define strncmp __strncmp
> > +#define strcasecmp __strcasecmp
> > +#define strncasecmp __strncasecmp
> > +#define strchr __strchr
> > +#define strchrnul __strchrnul
> > +#define strrchr __strrchr
> > +#define strnchr __strnchr
> > +#define skip_spaces __skip_spaces
> > +#define strim __strim
> > +#define strstr __strstr
> > +#define strnstr __strnstr
> > +#define strlen __strlen
> > +#define strnlen __strnlen
> > +#define strpbrk __strpbrk
> > +#define strsep __strsep
> > +#define strspn __strspn
> > +#define strcspn __strcspn
> > +#define memscan __memscan
> > +#define memcmp __memcmp
> > +#define memchr __memchr
> > +#define memchr_inv __memchr_inv
> > +#define strreplace __strreplace
> > +
> > +#ifndef __NO_FORTIFY
> > +#define __NO_FORTIFY /* FORTIFY_SOURCE uses __builtin_memcpy, etc. */
> > +#endif
> > +
> > +#endif
> > +
> > #ifndef __HAVE_ARCH_STRCPY
> > extern char * strcpy(char *,const char *);
> > +char *__strcpy(char *, const char *);
> > #endif
> > #ifndef __HAVE_ARCH_STRNCPY
> > extern char * strncpy(char *,const char *, __kernel_size_t);
> > +char *__strncpy(char *, const char *, __kernel_size_t);
> > #endif
> > #ifndef __HAVE_ARCH_STRLCPY
> > size_t strlcpy(char *, const char *, size_t);
> > +size_t __strlcpy(char *, const char *, size_t);
> > #endif
> > #ifndef __HAVE_ARCH_STRSCPY
> > ssize_t strscpy(char *, const char *, size_t);
> > +ssize_t __strscpy(char *, const char *, size_t);
> > #endif
> > #ifndef __HAVE_ARCH_STRCAT
> > extern char * strcat(char *, const char *);
> > +char *__strcat(char *, const char *);
> > #endif
> > #ifndef __HAVE_ARCH_STRNCAT
> > extern char * strncat(char *, const char *, __kernel_size_t);
> > +char *__strncat(char *, const char *, __kernel_size_t);
> > #endif
> > #ifndef __HAVE_ARCH_STRLCAT
> > extern size_t strlcat(char *, const char *, __kernel_size_t);
> > +size_t __strlcat(char *, const char *, __kernel_size_t);
> > #endif
> > #ifndef __HAVE_ARCH_STRCMP
> > extern int strcmp(const char *,const char *);
> > +int __strcmp(const char *, const char *);
> > #endif
> > #ifndef __HAVE_ARCH_STRNCMP
> > extern int strncmp(const char *,const char *,__kernel_size_t);
> > +int __strncmp(const char *, const char *, __kernel_size_t);
> > #endif
> > #ifndef __HAVE_ARCH_STRCASECMP
> > extern int strcasecmp(const char *s1, const char *s2);
> > +int __strcasecmp(const char *s1, const char *s2);
> > #endif
> > #ifndef __HAVE_ARCH_STRNCASECMP
> > extern int strncasecmp(const char *s1, const char *s2, size_t n);
> > +int __strncasecmp(const char *s1, const char *s2, size_t n);
> > #endif
> > #ifndef __HAVE_ARCH_STRCHR
> > extern char * strchr(const char *,int);
> > +char *__strchr(const char *, int);
> > #endif
> > #ifndef __HAVE_ARCH_STRCHRNUL
> > extern char * strchrnul(const char *,int);
> > +char *__strchrnul(const char *, int);
> > #endif
> > #ifndef __HAVE_ARCH_STRNCHR
> > extern char * strnchr(const char *, size_t, int);
> > +char *__strnchr(const char *, size_t, int);
> > #endif
> > #ifndef __HAVE_ARCH_STRRCHR
> > extern char * strrchr(const char *,int);
> > +char *__strrchr(const char *, int);
> > #endif
> > extern char * __must_check skip_spaces(const char *);
> > +char * __must_check __skip_spaces(const char *);
> >
> > extern char *strim(char *);
> > +char *__strim(char *);
> >
> > static inline __must_check char *strstrip(char *str)
> > {
> > @@ -75,27 +138,35 @@ static inline __must_check char *strstrip(char *str)
> >
> > #ifndef __HAVE_ARCH_STRSTR
> > extern char * strstr(const char *, const char *);
> > +char *__strstr(const char *, const char *);
> > #endif
> > #ifndef __HAVE_ARCH_STRNSTR
> > extern char * strnstr(const char *, const char *, size_t);
> > +char *__strnstr(const char *, const char *, size_t);
> > #endif
> > #ifndef __HAVE_ARCH_STRLEN
> > extern __kernel_size_t strlen(const char *);
> > +__kernel_size_t __strlen(const char *);
> > #endif
> > #ifndef __HAVE_ARCH_STRNLEN
> > extern __kernel_size_t strnlen(const char *,__kernel_size_t);
> > +__kernel_size_t __strnlen(const char *, __kernel_size_t);
> > #endif
> > #ifndef __HAVE_ARCH_STRPBRK
> > extern char * strpbrk(const char *,const char *);
> > +char *__strpbrk(const char *, const char *);
> > #endif
> > #ifndef __HAVE_ARCH_STRSEP
> > extern char * strsep(char **,const char *);
> > +char *__strsep(char **, const char *);
> > #endif
> > #ifndef __HAVE_ARCH_STRSPN
> > extern __kernel_size_t strspn(const char *,const char *);
> > +__kernel_size_t __strspn(const char *, const char *);
> > #endif
> > #ifndef __HAVE_ARCH_STRCSPN
> > extern __kernel_size_t strcspn(const char *,const char *);
> > +__kernel_size_t __strcspn(const char *, const char *);
> > #endif
> >
> > #ifndef __HAVE_ARCH_MEMSET
> > @@ -104,14 +175,17 @@ extern void * memset(void *,int,__kernel_size_t);
> >
> > #ifndef __HAVE_ARCH_MEMSET16
> > extern void *memset16(uint16_t *, uint16_t, __kernel_size_t);
> > +void *__memset16(uint16_t *, uint16_t, __kernel_size_t);
> > #endif
> >
> > #ifndef __HAVE_ARCH_MEMSET32
> > extern void *memset32(uint32_t *, uint32_t, __kernel_size_t);
> > +void *__memset32(uint32_t *, uint32_t, __kernel_size_t);
> > #endif
> >
> > #ifndef __HAVE_ARCH_MEMSET64
> > extern void *memset64(uint64_t *, uint64_t, __kernel_size_t);
> > +void *__memset64(uint64_t *, uint64_t, __kernel_size_t);
> > #endif
> >
> > static inline void *memset_l(unsigned long *p, unsigned long v,
> > @@ -146,12 +220,15 @@ extern void * memmove(void *,const void *,__kernel_size_t);
> > #endif
> > #ifndef __HAVE_ARCH_MEMSCAN
> > extern void * memscan(void *,int,__kernel_size_t);
> > +void *__memscan(void *, int, __kernel_size_t);
> > #endif
> > #ifndef __HAVE_ARCH_MEMCMP
> > extern int memcmp(const void *,const void *,__kernel_size_t);
> > +int __memcmp(const void *, const void *, __kernel_size_t);
> > #endif
> > #ifndef __HAVE_ARCH_MEMCHR
> > extern void * memchr(const void *,int,__kernel_size_t);
> > +void *__memchr(const void *, int, __kernel_size_t);
> > #endif
> > #ifndef __HAVE_ARCH_MEMCPY_MCSAFE
> > static inline __must_check unsigned long memcpy_mcsafe(void *dst,
> > @@ -168,7 +245,9 @@ static inline void memcpy_flushcache(void *dst, const void *src, size_t cnt)
> > }
> > #endif
> > void *memchr_inv(const void *s, int c, size_t n);
> > +void *__memchr_inv(const void *s, int c, size_t n);
> > char *strreplace(char *s, char old, char new);
> > +char *__strreplace(char *s, char old, char new);
> >
> > extern void kfree_const(const void *x);
> >
> > diff --git a/lib/Makefile b/lib/Makefile
> > index 30b9b0bfbba9..19d0237f9b9c 100644
> > --- a/lib/Makefile
> > +++ b/lib/Makefile
> > @@ -18,6 +18,8 @@ KCOV_INSTRUMENT_list_debug.o := n
> > KCOV_INSTRUMENT_debugobjects.o := n
> > KCOV_INSTRUMENT_dynamic_debug.o := n
> >
> > +KASAN_SANITIZE_string.o := n
> > +
> > lib-y := ctype.o string.o string_sysfs.o vsprintf.o cmdline.o \
> > rbtree.o radix-tree.o timerqueue.o xarray.o \
> > idr.o int_sqrt.o extable.o \
> > diff --git a/lib/string.c b/lib/string.c
> > index f3886c5175ac..31a253201bba 100644
> > --- a/lib/string.c
> > +++ b/lib/string.c
> > @@ -85,7 +85,9 @@ EXPORT_SYMBOL(strcasecmp);
> > * @dest: Where to copy the string to
> > * @src: Where to copy the string from
> > */
> > +#ifndef CONFIG_KASAN
> > #undef strcpy
> > +#endif
> > char *strcpy(char *dest, const char *src)
> > {
> > char *tmp = dest;
> > @@ -243,7 +245,9 @@ EXPORT_SYMBOL(strscpy);
> > * @dest: The string to be appended to
> > * @src: The string to append to it
> > */
> > +#ifndef CONFIG_KASAN
> > #undef strcat
> > +#endif
> > char *strcat(char *dest, const char *src)
> > {
> > char *tmp = dest;
> > @@ -319,7 +323,9 @@ EXPORT_SYMBOL(strlcat);
> > * @cs: One string
> > * @ct: Another string
> > */
> > +#ifndef CONFIG_KASAN
> > #undef strcmp
> > +#endif
> > int strcmp(const char *cs, const char *ct)
> > {
> > unsigned char c1, c2;
> > @@ -773,7 +779,9 @@ EXPORT_SYMBOL(memmove);
> > * @ct: Another area of memory
> > * @count: The size of the area.
> > */
> > +#ifndef CONFIG_KASAN
> > #undef memcmp
> > +#endif
> > __visible int memcmp(const void *cs, const void *ct, size_t count)
> > {
> > const unsigned char *su1, *su2;
> > diff --git a/mm/kasan/string.c b/mm/kasan/string.c
> > index 083b967255a2..0db31bbbf643 100644
> > --- a/mm/kasan/string.c
> > +++ b/mm/kasan/string.c
> > @@ -35,6 +35,42 @@ void *memset(void *addr, int c, size_t len)
> > return __memset(addr, c, len);
> > }
> >
> > +#undef memset16
> > +void *memset16(uint16_t *s, uint16_t v, size_t count)
> > +{
> > + check_memory_region((unsigned long)s, count << 1, true, _RET_IP_);
> > +
> > + return __memset16(s, v, count);
> > +}
> > +EXPORT_SYMBOL(memset16);
> > +
> > +#undef memset32
> > +void *memset32(uint32_t *s, uint32_t v, size_t count)
> > +{
> > + check_memory_region((unsigned long)s, count << 2, true, _RET_IP_);
> > +
> > + return __memset32(s, v, count);
> > +}
> > +EXPORT_SYMBOL(memset32);
> > +
> > +#undef memset64
> > +void *memset64(uint64_t *s, uint64_t v, size_t count)
> > +{
> > + check_memory_region((unsigned long)s, count << 3, true, _RET_IP_);
> > +
> > + return __memset64(s, v, count);
> > +}
> > +EXPORT_SYMBOL(memset64);
> > +
> > +#undef memzero_explicit
> > +void memzero_explicit(void *s, size_t count)
> > +{
> > + check_memory_region((unsigned long)s, count, true, _RET_IP_);
> > +
> > + return __memzero_explicit(s, count);
> > +}
> > +EXPORT_SYMBOL(memzero_explicit);
> > +
> > #undef memmove
> > void *memmove(void *dest, const void *src, size_t len)
> > {
> > @@ -52,3 +88,361 @@ void *memcpy(void *dest, const void *src, size_t len)
> >
> > return __memcpy(dest, src, len);
> > }
> > +
> > +#undef strcpy
> > +char *strcpy(char *dest, const char *src)
> > +{
> > + size_t len = __strlen(src) + 1;
> > +
> > + check_memory_region((unsigned long)src, len, false, _RET_IP_);
> > + check_memory_region((unsigned long)dest, len, true, _RET_IP_);
> > +
> > + return __strcpy(dest, src);
> > +}
> > +EXPORT_SYMBOL(strcpy);
> > +
> > +#undef strncpy
> > +char *strncpy(char *dest, const char *src, size_t count)
> > +{
> > + size_t len = min(__strlen(src) + 1, count);
> > +
> > + check_memory_region((unsigned long)src, len, false, _RET_IP_);
> > + check_memory_region((unsigned long)dest, count, true, _RET_IP_);
> > +
> > + return __strncpy(dest, src, count);
> > +}
> > +EXPORT_SYMBOL(strncpy);
> > +
> > +#undef strlcpy
> > +size_t strlcpy(char *dest, const char *src, size_t size)
> > +{
> > + size_t len = __strlen(src) + 1;
> > +
> > + check_memory_region((unsigned long)src, len, false, _RET_IP_);
> > + check_memory_region((unsigned long)dest, min(len, size), true, _RET_IP_);
> > +
> > + return __strlcpy(dest, src, size);
> > +}
> > +EXPORT_SYMBOL(strlcpy);
> > +
> > +#undef strscpy
> > +ssize_t strscpy(char *dest, const char *src, size_t count)
> > +{
> > + int len = min(__strlen(src) + 1, count);
> > +
> > + check_memory_region((unsigned long)src, len, false, _RET_IP_);
> > + check_memory_region((unsigned long)dest, len, true, _RET_IP_);
> > +
> > + return __strscpy(dest, src, count);
> > +}
> > +EXPORT_SYMBOL(strscpy);
> > +
> > +#undef strcat
> > +char *strcat(char *dest, const char *src)
> > +{
> > + size_t slen = __strlen(src) + 1;
> > + size_t dlen = __strlen(dest);
> > +
> > + check_memory_region((unsigned long)src, slen, false, _RET_IP_);
> > + check_memory_region((unsigned long)dest, dlen, false, _RET_IP_);
> > + check_memory_region((unsigned long)(dest + dlen), slen, true, _RET_IP_);
> > +
> > + return __strcat(dest, src);
> > +}
> > +EXPORT_SYMBOL(strcat);
> > +
> > +#undef strncat
> > +char *strncat(char *dest, const char *src, size_t count)
> > +{
> > + size_t slen = min(__strlen(src) + 1, count);
> > + size_t dlen = __strlen(dest);
> > +
> > + check_memory_region((unsigned long)src, slen, false, _RET_IP_);
> > + check_memory_region((unsigned long)dest, dlen, false, _RET_IP_);
> > + check_memory_region((unsigned long)(dest + dlen), slen, true, _RET_IP_);
> > +
> > + return __strncat(dest, src, count);
> > +}
> > +EXPORT_SYMBOL(strncat);
> > +
> > +#undef strlcat
> > +size_t strlcat(char *dest, const char *src, size_t count)
> > +{
> > + size_t slen = min(__strlen(src) + 1, count);
> > + size_t dlen = __strlen(dest);
> > +
> > + check_memory_region((unsigned long)src, slen, false, _RET_IP_);
> > + check_memory_region((unsigned long)dest, dlen, false, _RET_IP_);
> > + check_memory_region((unsigned long)(dest + dlen), slen, true, _RET_IP_);
> > +
> > + return __strlcat(dest, src, count);
> > +}
> > +EXPORT_SYMBOL(strlcat);
> > +
> > +#undef strcmp
> > +int strcmp(const char *cs, const char *ct)
> > +{
> > + size_t len = min(__strlen(cs) + 1, __strlen(ct) + 1);
> > +
> > + check_memory_region((unsigned long)cs, len, false, _RET_IP_);
> > + check_memory_region((unsigned long)ct, len, false, _RET_IP_);
> > +
> > + return __strcmp(cs, ct);
> > +}
> > +EXPORT_SYMBOL(strcmp);
> > +
> > +#undef strncmp
> > +int strncmp(const char *cs, const char *ct, size_t count)
> > +{
> > + size_t len = min3(__strlen(cs) + 1, __strlen(ct) + 1, count);
> > +
> > + check_memory_region((unsigned long)cs, len, false, _RET_IP_);
> > + check_memory_region((unsigned long)ct, len, false, _RET_IP_);
> > +
> > + return __strncmp(cs, ct, count);
> > +}
> > +EXPORT_SYMBOL(strncmp);
> > +
> > +#undef strcasecmp
> > +int strcasecmp(const char *s1, const char *s2)
> > +{
> > + size_t len = min(__strlen(s1) + 1, __strlen(s2) + 1);
> > +
> > + check_memory_region((unsigned long)s1, len, false, _RET_IP_);
> > + check_memory_region((unsigned long)s2, len, false, _RET_IP_);
> > +
> > + return __strcasecmp(s1, s2);
> > +}
> > +EXPORT_SYMBOL(strcasecmp);
> > +
> > +#undef strncasecmp
> > +int strncasecmp(const char *s1, const char *s2, size_t len)
> > +{
> > + size_t sz = min3(__strlen(s1) + 1, __strlen(s2) + 1, len);
> > +
> > + check_memory_region((unsigned long)s1, sz, false, _RET_IP_);
> > + check_memory_region((unsigned long)s2, sz, false, _RET_IP_);
> > +
> > + return __strncasecmp(s1, s2, len);
> > +}
> > +EXPORT_SYMBOL(strncasecmp);
> > +
> > +#undef strchr
> > +char *strchr(const char *s, int c)
> > +{
> > + size_t len = __strlen(s) + 1;
> > +
> > + check_memory_region((unsigned long)s, len, false, _RET_IP_);
> > +
> > + return __strchr(s, c);
> > +}
> > +EXPORT_SYMBOL(strchr);
> > +
> > +#undef strchrnul
> > +char *strchrnul(const char *s, int c)
> > +{
> > + size_t len = __strlen(s) + 1;
> > +
> > + check_memory_region((unsigned long)s, len, false, _RET_IP_);
> > +
> > + return __strchrnul(s, c);
> > +}
> > +EXPORT_SYMBOL(strchrnul);
> > +
> > +#undef strrchr
> > +char *strrchr(const char *s, int c)
> > +{
> > + size_t len = __strlen(s) + 1;
> > +
> > + check_memory_region((unsigned long)s, len, false, _RET_IP_);
> > +
> > + return __strrchr(s, c);
> > +}
> > +EXPORT_SYMBOL(strrchr);
> > +
> > +#undef strnchr
> > +char *strnchr(const char *s, size_t count, int c)
> > +{
> > + size_t len = __strlen(s) + 1;
> > +
> > + check_memory_region((unsigned long)s, len, false, _RET_IP_);
> > +
> > + return __strnchr(s, count, c);
> > +}
> > +EXPORT_SYMBOL(strnchr);
> > +
> > +#undef skip_spaces
> > +char *skip_spaces(const char *str)
> > +{
> > + size_t len = __strlen(str) + 1;
> > +
> > + check_memory_region((unsigned long)str, len, false, _RET_IP_);
> > +
> > + return __skip_spaces(str);
> > +}
> > +EXPORT_SYMBOL(skip_spaces);
> > +
> > +#undef strim
> > +char *strim(char *s)
> > +{
> > + size_t len = __strlen(s) + 1;
> > +
> > + check_memory_region((unsigned long)s, len, false, _RET_IP_);
> > +
> > + return __strim(s);
> > +}
> > +EXPORT_SYMBOL(strim);
> > +
> > +#undef strstr
> > +char *strstr(const char *s1, const char *s2)
> > +{
> > + size_t l1 = __strlen(s1) + 1;
> > + size_t l2 = __strlen(s2) + 1;
> > +
> > + check_memory_region((unsigned long)s1, l1, false, _RET_IP_);
> > + check_memory_region((unsigned long)s2, l2, false, _RET_IP_);
> > +
> > + return __strstr(s1, s2);
> > +}
> > +EXPORT_SYMBOL(strstr);
> > +
> > +#undef strnstr
> > +char *strnstr(const char *s1, const char *s2, size_t len)
> > +{
> > + size_t l1 = min(__strlen(s1) + 1, len);
> > + size_t l2 = __strlen(s2) + 1;
> > +
> > + check_memory_region((unsigned long)s1, l1, false, _RET_IP_);
> > + check_memory_region((unsigned long)s2, l2, false, _RET_IP_);
> > +
> > + return __strnstr(s1, s2, len);
> > +}
> > +EXPORT_SYMBOL(strnstr);
> > +
> > +#undef strlen
> > +size_t strlen(const char *s)
> > +{
> > + size_t len = __strlen(s);
> > +
> > + check_memory_region((unsigned long)s, len + 1, false, _RET_IP_);
> > +
> > + return len;
> > +}
> > +EXPORT_SYMBOL(strlen);
> > +
> > +#undef strnlen
> > +size_t strnlen(const char *s, size_t count)
> > +{
> > + size_t len = __strnlen(s, count);
> > +
> > + check_memory_region((unsigned long)s, min(len + 1, count), false, _RET_IP_);
> > +
> > + return len;
> > +}
> > +EXPORT_SYMBOL(strnlen);
> > +
> > +#undef strpbrk
> > +char *strpbrk(const char *cs, const char *ct)
> > +{
> > + size_t ls = __strlen(cs) + 1;
> > + size_t lt = __strlen(ct) + 1;
> > +
> > + check_memory_region((unsigned long)cs, ls, false, _RET_IP_);
> > + check_memory_region((unsigned long)ct, lt, false, _RET_IP_);
> > +
> > + return __strpbrk(cs, ct);
> > +}
> > +EXPORT_SYMBOL(strpbrk);
> > +
> > +#undef strsep
> > +char *strsep(char **s, const char *ct)
> > +{
> > + char *cs = *s;
> > +
> > + check_memory_region((unsigned long)s, sizeof(*s), true, _RET_IP_);
> > +
> > + if (cs) {
> > + int ls = __strlen(cs) + 1;
> > + int lt = __strlen(ct) + 1;
> > +
> > + check_memory_region((unsigned long)cs, ls, false, _RET_IP_);
> > + check_memory_region((unsigned long)ct, lt, false, _RET_IP_);
> > + }
> > +
> > + return __strsep(s, ct);
> > +}
> > +EXPORT_SYMBOL(strsep);
> > +
> > +#undef strspn
> > +size_t strspn(const char *s, const char *accept)
> > +{
> > + size_t ls = __strlen(s) + 1;
> > + size_t la = __strlen(accept) + 1;
> > +
> > + check_memory_region((unsigned long)s, ls, false, _RET_IP_);
> > + check_memory_region((unsigned long)accept, la, false, _RET_IP_);
> > +
> > + return __strspn(s, accept);
> > +}
> > +EXPORT_SYMBOL(strspn);
> > +
> > +#undef strcspn
> > +size_t strcspn(const char *s, const char *reject)
> > +{
> > + size_t ls = __strlen(s) + 1;
> > + size_t lr = __strlen(reject) + 1;
> > +
> > + check_memory_region((unsigned long)s, ls, false, _RET_IP_);
> > + check_memory_region((unsigned long)reject, lr, false, _RET_IP_);
> > +
> > + return __strcspn(s, reject);
> > +}
> > +EXPORT_SYMBOL(strcspn);
> > +
> > +#undef memscan
> > +void *memscan(void *addr, int c, size_t size)
> > +{
> > + check_memory_region((unsigned long)addr, size, false, _RET_IP_);
> > +
> > + return __memscan(addr, c, size);
> > +}
> > +EXPORT_SYMBOL(memscan);
> > +
> > +#undef memcmp
> > +int memcmp(const void *cs, const void *ct, size_t count)
> > +{
> > + check_memory_region((unsigned long)cs, count, false, _RET_IP_);
> > + check_memory_region((unsigned long)ct, count, false, _RET_IP_);
> > +
> > + return __memcmp(cs, ct, count);
> > +}
> > +EXPORT_SYMBOL(memcmp);
> > +
> > +#undef memchr
> > +void *memchr(const void *s, int c, size_t n)
> > +{
> > + check_memory_region((unsigned long)s, n, false, _RET_IP_);
> > +
> > + return __memchr(s, c, n);
> > +}
> > +EXPORT_SYMBOL(memchr);
> > +
> > +#undef memchr_inv
> > +void *memchr_inv(const void *start, int c, size_t bytes)
> > +{
> > + check_memory_region((unsigned long)start, bytes, false, _RET_IP_);
> > +
> > + return __memchr_inv(start, c, bytes);
> > +}
> > +EXPORT_SYMBOL(memchr_inv);
> > +
> > +#undef strreplace
> > +char *strreplace(char *s, char old, char new)
> > +{
> > + size_t len = __strlen(s) + 1;
> > +
> > + check_memory_region((unsigned long)s, len, true, _RET_IP_);
> > +
> > + return __strreplace(s, old, new);
> > +}
> > +EXPORT_SYMBOL(strreplace);
> >
^ permalink raw reply
* Re: powerpc/mm: Only define MAX_PHYSMEM_BITS in SPARSEMEM configurations
From: Aneesh Kumar K.V @ 2019-04-02 12:57 UTC (permalink / raw)
To: Michael Ellerman, Ben Hutchings, Andreas Schwab
Cc: linuxppc-dev, Paul Mackerras
In-Reply-To: <87a7hjp4oi.fsf@concordia.ellerman.id.au>
Michael Ellerman <mpe@ellerman.id.au> writes:
> Ben Hutchings <ben@decadent.org.uk> writes:
>> On Mon, 2019-03-25 at 01:03 +0100, Andreas Schwab wrote:
>>> On Mär 24 2019, Ben Hutchings <ben@decadent.org.uk> wrote:
>>>
>>> > Presumably you have CONFIG_PPC_BOOK3S_64 enabled and
>>> > CONFIG_SPARSEMEM
>>> > disabled? Was this configuration actually usable?
>>>
>>> Why not?
>>
>> I assume that CONFIG_SPARSEMEM is the default for a good reason.
>> What I don't know is how strong that reason is (I am not a Power expert
>> at all). Looking a bit further, it seems to be related to CONFIG_NUMA
>> in that you can enable CONFIG_FLATMEM if and only if that's disabled.
>> So I suppose the configuration you used works for non-NUMA systems.
>
> Aneesh pointed out this fix would break FLATMEM after I'd merged it, but
> it didn't break any of our defconfigs so I wondered if anyone would
> notice.
>
> I checked today and a G5 will boot with FLATMEM, which I assume is what
> Andreas is using.
>
> I guess we should fix this build break for now.
>
> Even some G5's have discontiguous memory, so FLATMEM is not clearly a
> good choice even for all G5's, and actually a fresh g5_defconfig uses
> SPARSEMEM.
>
> So I'm inclined to just switch to always using SPARSEMEM on 64-bit
> Book3S, because that's what's well tested and we hardly need more code
> paths to test. Unless anyone has a strong objection, I haven't actually
> benchmarked FLATMEM vs SPARSEMEM on a G5.
>
How about
From 207fb0036065d8db44853e63bb858c4fd9952106 Mon Sep 17 00:00:00 2001
From: "Aneesh Kumar K.V" <aneesh.kumar@linux.ibm.com>
Date: Mon, 1 Apr 2019 17:51:17 +0530
Subject: [PATCH] powerpc/mm: Fix build error
The current value of MAX_PHYSMEM_BITS cannot work with 32 bit configs.
We used to have MAX_PHYSMEM_BITS not defined without SPARSEMEM and 32
bit configs never expected a value to be set for MAX_PHYSMEM_BITS.
Dependent code such as zsmalloc derived the right values based on other
fields. Instead of finding a value that works with different configs,
use new values only for book3s_64. For 64 bit booke, use the definition
of MAX_PHYSMEM_BITS as per commit a7df61a0e2b6 ("[PATCH] ppc64: Increase sparsemem defaults")
That change was done in 2005 and hopefully will work with book3e 64.
Fixes: 4ffe713b7587 ("powerpc/mm: Increase the max addressable memory to 2PB")
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
arch/powerpc/include/asm/book3s/64/mmu.h | 15 +++++++++++++++
arch/powerpc/include/asm/mmu.h | 15 ---------------
arch/powerpc/include/asm/nohash/64/mmu.h | 2 ++
3 files changed, 17 insertions(+), 15 deletions(-)
diff --git a/arch/powerpc/include/asm/book3s/64/mmu.h b/arch/powerpc/include/asm/book3s/64/mmu.h
index 1ceee000c18d..a809bdd77322 100644
--- a/arch/powerpc/include/asm/book3s/64/mmu.h
+++ b/arch/powerpc/include/asm/book3s/64/mmu.h
@@ -35,6 +35,21 @@ typedef pte_t *pgtable_t;
#endif /* __ASSEMBLY__ */
+/*
+ * If we store section details in page->flags we can't increase the MAX_PHYSMEM_BITS
+ * if we increase SECTIONS_WIDTH we will not store node details in page->flags and
+ * page_to_nid does a page->section->node lookup
+ * Hence only increase for VMEMMAP. Further depending on SPARSEMEM_EXTREME reduce
+ * memory requirements with large number of sections.
+ * 51 bits is the max physical real address on POWER9
+ */
+#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_SPARSEMEM_EXTREME) && \
+ defined(CONFIG_PPC_64K_PAGES)
+#define MAX_PHYSMEM_BITS 51
+#else
+#define MAX_PHYSMEM_BITS 46
+#endif
+
/* 64-bit classic hash table MMU */
#include <asm/book3s/64/mmu-hash.h>
diff --git a/arch/powerpc/include/asm/mmu.h b/arch/powerpc/include/asm/mmu.h
index 598cdcdd1355..78d53c4396ac 100644
--- a/arch/powerpc/include/asm/mmu.h
+++ b/arch/powerpc/include/asm/mmu.h
@@ -341,21 +341,6 @@ static inline bool strict_kernel_rwx_enabled(void)
*/
#define MMU_PAGE_COUNT 16
-/*
- * If we store section details in page->flags we can't increase the MAX_PHYSMEM_BITS
- * if we increase SECTIONS_WIDTH we will not store node details in page->flags and
- * page_to_nid does a page->section->node lookup
- * Hence only increase for VMEMMAP. Further depending on SPARSEMEM_EXTREME reduce
- * memory requirements with large number of sections.
- * 51 bits is the max physical real address on POWER9
- */
-#if defined(CONFIG_SPARSEMEM_VMEMMAP) && defined(CONFIG_SPARSEMEM_EXTREME) && \
- defined (CONFIG_PPC_64K_PAGES)
-#define MAX_PHYSMEM_BITS 51
-#elif defined(CONFIG_SPARSEMEM)
-#define MAX_PHYSMEM_BITS 46
-#endif
-
#ifdef CONFIG_PPC_BOOK3S_64
#include <asm/book3s/64/mmu.h>
#else /* CONFIG_PPC_BOOK3S_64 */
diff --git a/arch/powerpc/include/asm/nohash/64/mmu.h b/arch/powerpc/include/asm/nohash/64/mmu.h
index e6585480dfc4..81cf30c370e5 100644
--- a/arch/powerpc/include/asm/nohash/64/mmu.h
+++ b/arch/powerpc/include/asm/nohash/64/mmu.h
@@ -2,6 +2,8 @@
#ifndef _ASM_POWERPC_NOHASH_64_MMU_H_
#define _ASM_POWERPC_NOHASH_64_MMU_H_
+#define MAX_PHYSMEM_BITS 44
+
/* Freescale Book-E software loaded TLB or Book-3e (ISA 2.06+) MMU */
#include <asm/nohash/mmu-book3e.h>
--
2.20.1
^ permalink raw reply related
* [PATCH v2] mm: Fix modifying of page protection by insert_pfn_pmd()
From: Aneesh Kumar K.V @ 2019-04-02 11:51 UTC (permalink / raw)
To: dan.j.williams, akpm, Jan Kara
Cc: linux-nvdimm, Aneesh Kumar K.V, stable, linux-mm,
Chandan Rajendra, linuxppc-dev
With some architectures like ppc64, set_pmd_at() cannot cope with
a situation where there is already some (different) valid entry present.
Use pmdp_set_access_flags() instead to modify the pfn which is built to
deal with modifying existing PMD entries.
This is similar to
commit cae85cb8add3 ("mm/memory.c: fix modifying of page protection by insert_pfn()")
We also do similar update w.r.t insert_pfn_pud eventhough ppc64 don't support
pud pfn entries now.
Without this patch we also see the below message in kernel log
"BUG: non-zero pgtables_bytes on freeing mm:"
CC: stable@vger.kernel.org
Reported-by: Chandan Rajendra <chandan@linux.ibm.com>
Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
---
Changes from v1:
* Fix the pgtable leak
mm/huge_memory.c | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index 404acdcd0455..165ea46bf149 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -755,6 +755,21 @@ static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
spinlock_t *ptl;
ptl = pmd_lock(mm, pmd);
+ if (!pmd_none(*pmd)) {
+ if (write) {
+ if (pmd_pfn(*pmd) != pfn_t_to_pfn(pfn)) {
+ WARN_ON_ONCE(!is_huge_zero_pmd(*pmd));
+ goto out_unlock;
+ }
+ entry = pmd_mkyoung(*pmd);
+ entry = maybe_pmd_mkwrite(pmd_mkdirty(entry), vma);
+ if (pmdp_set_access_flags(vma, addr, pmd, entry, 1))
+ update_mmu_cache_pmd(vma, addr, pmd);
+ }
+
+ goto out_unlock;
+ }
+
entry = pmd_mkhuge(pfn_t_pmd(pfn, prot));
if (pfn_t_devmap(pfn))
entry = pmd_mkdevmap(entry);
@@ -766,11 +781,16 @@ static void insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
if (pgtable) {
pgtable_trans_huge_deposit(mm, pmd, pgtable);
mm_inc_nr_ptes(mm);
+ pgtable = NULL;
}
set_pmd_at(mm, addr, pmd, entry);
update_mmu_cache_pmd(vma, addr, pmd);
+
+out_unlock:
spin_unlock(ptl);
+ if (pgtable)
+ pte_free(mm, pgtable);
}
vm_fault_t vmf_insert_pfn_pmd(struct vm_area_struct *vma, unsigned long addr,
@@ -821,6 +841,20 @@ static void insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
spinlock_t *ptl;
ptl = pud_lock(mm, pud);
+ if (!pud_none(*pud)) {
+ if (write) {
+ if (pud_pfn(*pud) != pfn_t_to_pfn(pfn)) {
+ WARN_ON_ONCE(!is_huge_zero_pud(*pud));
+ goto out_unlock;
+ }
+ entry = pud_mkyoung(*pud);
+ entry = maybe_pud_mkwrite(pud_mkdirty(entry), vma);
+ if (pudp_set_access_flags(vma, addr, pud, entry, 1))
+ update_mmu_cache_pud(vma, addr, pud);
+ }
+ goto out_unlock;
+ }
+
entry = pud_mkhuge(pfn_t_pud(pfn, prot));
if (pfn_t_devmap(pfn))
entry = pud_mkdevmap(entry);
@@ -830,6 +864,8 @@ static void insert_pfn_pud(struct vm_area_struct *vma, unsigned long addr,
}
set_pud_at(mm, addr, pud, entry);
update_mmu_cache_pud(vma, addr, pud);
+
+out_unlock:
spin_unlock(ptl);
}
--
2.20.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox