2020-05-04 01:15:05

by Ira Weiny

[permalink] [raw]
Subject: [PATCH V2 00/11] Subject: Remove duplicated kmap code

From: Ira Weiny <[email protected]>

The kmap infrastructure has been copied almost verbatim to every architecture.
This series consolidates obvious duplicated code by defining core functions
which call into the architectures only when needed.

Some of the k[un]map_atomic() implementations have some similarities but the
similarities were not sufficient to warrant further changes.

In addition we remove a duplicate implementation of kmap() in DRM.

Testing was done by 0day to cover all the architectures I can't readily
build/test.

---
Changes from V1:
Fix bisect-ability
Update commit message and fix line lengths
Remove unneded kunmap_atomic_high() declarations
Remove unneded kmap_atomic_high() declarations
collect reviews
rebase to 5.7-rc4

Changes from V0:
Define kmap_flush_tlb() and make kmap() truely arch independent.
Redefine the k[un]map_atomic_* code to call into the architectures for
high mem pages
Ensure all architectures define kmap_prot, use it appropriately, and
define kmap_atomic_prot()
Remove drm implementation of kmap_atomic()

Ira Weiny (11):
arch/kmap: Remove BUG_ON()
arch/xtensa: Move kmap build bug out of the way
arch/kmap: Remove redundant arch specific kmaps
arch/kunmap: Remove duplicate kunmap implementations
{x86,powerpc,microblaze}/kmap: Move preempt disable
arch/kmap_atomic: Consolidate duplicate code
arch/kunmap_atomic: Consolidate duplicate code
arch/kmap: Ensure kmap_prot visibility
arch/kmap: Don't hard code kmap_prot values
arch/kmap: Define kmap_atomic_prot() for all arch's
drm: Remove drm specific kmap_atomic code

arch/arc/include/asm/highmem.h | 15 -------
arch/arc/mm/highmem.c | 28 +++---------
arch/arm/include/asm/highmem.h | 7 ---
arch/arm/mm/highmem.c | 35 +++------------
arch/csky/include/asm/highmem.h | 9 +---
arch/csky/mm/highmem.c | 43 +++++--------------
arch/microblaze/include/asm/highmem.h | 28 +-----------
arch/microblaze/mm/highmem.c | 16 ++-----
arch/microblaze/mm/init.c | 3 --
arch/mips/include/asm/highmem.h | 9 +---
arch/mips/mm/cache.c | 6 +--
arch/mips/mm/highmem.c | 49 ++++-----------------
arch/nds32/include/asm/highmem.h | 7 ---
arch/nds32/mm/highmem.c | 39 +++--------------
arch/parisc/include/asm/cacheflush.h | 4 +-
arch/powerpc/include/asm/highmem.h | 29 +------------
arch/powerpc/mm/highmem.c | 21 ++-------
arch/powerpc/mm/mem.c | 3 --
arch/sparc/include/asm/highmem.h | 22 ----------
arch/sparc/mm/highmem.c | 18 +++-----
arch/x86/include/asm/highmem.h | 9 ----
arch/x86/mm/highmem_32.c | 50 ++-------------------
arch/xtensa/include/asm/highmem.h | 27 ------------
arch/xtensa/mm/highmem.c | 22 ++++------
drivers/gpu/drm/ttm/ttm_bo_util.c | 56 ++----------------------
drivers/gpu/drm/vmwgfx/vmwgfx_blit.c | 16 +++----
include/drm/ttm/ttm_bo_api.h | 4 --
include/linux/highmem.h | 62 +++++++++++++++++++++++++--
28 files changed, 140 insertions(+), 497 deletions(-)

--
2.25.1


2020-05-04 01:15:06

by Ira Weiny

[permalink] [raw]
Subject: [PATCH V2 03/11] arch/kmap: Remove redundant arch specific kmaps

From: Ira Weiny <[email protected]>

The kmap code for all the architectures is almost 100% identical.

Lift the common code to the core. Use ARCH_HAS_KMAP_FLUSH_TLB to
indicate if an arch defines kmap_flush_tlb() and call if if needed.

This also has the benefit of changing kmap() on a number of
architectures to be an inline call rather than an actual function.

Reviewed-by: Christoph Hellwig <[email protected]>
Signed-off-by: Ira Weiny <[email protected]>
---
arch/arc/include/asm/highmem.h | 2 --
arch/arc/mm/highmem.c | 10 ----------
arch/arm/include/asm/highmem.h | 2 --
arch/arm/mm/highmem.c | 9 ---------
arch/csky/include/asm/highmem.h | 4 ++--
arch/csky/mm/highmem.c | 14 ++++----------
arch/microblaze/include/asm/highmem.h | 9 ---------
arch/mips/include/asm/highmem.h | 4 ++--
arch/mips/mm/highmem.c | 14 +++-----------
arch/nds32/include/asm/highmem.h | 2 --
arch/nds32/mm/highmem.c | 12 ------------
arch/powerpc/include/asm/highmem.h | 9 ---------
arch/sparc/include/asm/highmem.h | 9 ---------
arch/x86/include/asm/highmem.h | 2 --
arch/x86/mm/highmem_32.c | 9 ---------
arch/xtensa/include/asm/highmem.h | 9 ---------
include/linux/highmem.h | 18 ++++++++++++++++++
17 files changed, 29 insertions(+), 109 deletions(-)

diff --git a/arch/arc/include/asm/highmem.h b/arch/arc/include/asm/highmem.h
index 042e92921c4c..96eb67c86961 100644
--- a/arch/arc/include/asm/highmem.h
+++ b/arch/arc/include/asm/highmem.h
@@ -30,8 +30,6 @@

#include <asm/cacheflush.h>

-extern void *kmap(struct page *page);
-extern void *kmap_high(struct page *page);
extern void *kmap_atomic(struct page *page);
extern void __kunmap_atomic(void *kvaddr);
extern void kunmap_high(struct page *page);
diff --git a/arch/arc/mm/highmem.c b/arch/arc/mm/highmem.c
index 39ef7b9a3aa9..4db13a6b9f3b 100644
--- a/arch/arc/mm/highmem.c
+++ b/arch/arc/mm/highmem.c
@@ -49,16 +49,6 @@
extern pte_t * pkmap_page_table;
static pte_t * fixmap_page_table;

-void *kmap(struct page *page)
-{
- might_sleep();
- if (!PageHighMem(page))
- return page_address(page);
-
- return kmap_high(page);
-}
-EXPORT_SYMBOL(kmap);
-
void *kmap_atomic(struct page *page)
{
int idx, cpu_idx;
diff --git a/arch/arm/include/asm/highmem.h b/arch/arm/include/asm/highmem.h
index eb4e4207cd3c..c917522541de 100644
--- a/arch/arm/include/asm/highmem.h
+++ b/arch/arm/include/asm/highmem.h
@@ -20,7 +20,6 @@

extern pte_t *pkmap_page_table;

-extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);

/*
@@ -63,7 +62,6 @@ static inline void *kmap_high_get(struct page *page)
* when CONFIG_HIGHMEM is not set.
*/
#ifdef CONFIG_HIGHMEM
-extern void *kmap(struct page *page);
extern void kunmap(struct page *page);
extern void *kmap_atomic(struct page *page);
extern void __kunmap_atomic(void *kvaddr);
diff --git a/arch/arm/mm/highmem.c b/arch/arm/mm/highmem.c
index cc6eb79ef20c..e8ba37c36590 100644
--- a/arch/arm/mm/highmem.c
+++ b/arch/arm/mm/highmem.c
@@ -31,15 +31,6 @@ static inline pte_t get_fixmap_pte(unsigned long vaddr)
return *ptep;
}

-void *kmap(struct page *page)
-{
- might_sleep();
- if (!PageHighMem(page))
- return page_address(page);
- return kmap_high(page);
-}
-EXPORT_SYMBOL(kmap);
-
void kunmap(struct page *page)
{
might_sleep();
diff --git a/arch/csky/include/asm/highmem.h b/arch/csky/include/asm/highmem.h
index a345a2f2c22e..9d0516e38110 100644
--- a/arch/csky/include/asm/highmem.h
+++ b/arch/csky/include/asm/highmem.h
@@ -30,10 +30,10 @@ extern pte_t *pkmap_page_table;
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))

-extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);

-extern void *kmap(struct page *page);
+#define ARCH_HAS_KMAP_FLUSH_TLB
+extern void kmap_flush_tlb(unsigned long addr);
extern void kunmap(struct page *page);
extern void *kmap_atomic(struct page *page);
extern void __kunmap_atomic(void *kvaddr);
diff --git a/arch/csky/mm/highmem.c b/arch/csky/mm/highmem.c
index 690d678649d1..4a3c273bc8b9 100644
--- a/arch/csky/mm/highmem.c
+++ b/arch/csky/mm/highmem.c
@@ -13,18 +13,12 @@ static pte_t *kmap_pte;

unsigned long highstart_pfn, highend_pfn;

-void *kmap(struct page *page)
+void kmap_flush_tlb(unsigned long addr)
{
- void *addr;
-
- might_sleep();
- if (!PageHighMem(page))
- return page_address(page);
- addr = kmap_high(page);
- flush_tlb_one((unsigned long)addr);
-
- return addr;
+ flush_tlb_one(addr);
}
+EXPORT_SYMBOL(kmap_flush_tlb);
+
EXPORT_SYMBOL(kmap);

void kunmap(struct page *page)
diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h
index 99ced7278b5c..8c5bfd228bd8 100644
--- a/arch/microblaze/include/asm/highmem.h
+++ b/arch/microblaze/include/asm/highmem.h
@@ -51,19 +51,10 @@ extern pte_t *pkmap_page_table;
#define PKMAP_NR(virt) ((virt - PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))

-extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
extern void *kmap_atomic_prot(struct page *page, pgprot_t prot);
extern void __kunmap_atomic(void *kvaddr);

-static inline void *kmap(struct page *page)
-{
- might_sleep();
- if (!PageHighMem(page))
- return page_address(page);
- return kmap_high(page);
-}
-
static inline void kunmap(struct page *page)
{
might_sleep();
diff --git a/arch/mips/include/asm/highmem.h b/arch/mips/include/asm/highmem.h
index 9d84aafc33d0..1f741e3ecabf 100644
--- a/arch/mips/include/asm/highmem.h
+++ b/arch/mips/include/asm/highmem.h
@@ -46,10 +46,10 @@ extern pte_t *pkmap_page_table;
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))

-extern void * kmap_high(struct page *page);
extern void kunmap_high(struct page *page);

-extern void *kmap(struct page *page);
+#define ARCH_HAS_KMAP_FLUSH_TLB
+extern void kmap_flush_tlb(unsigned long addr);
extern void kunmap(struct page *page);
extern void *kmap_atomic(struct page *page);
extern void __kunmap_atomic(void *kvaddr);
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c
index edd889f6cede..c72058bfead6 100644
--- a/arch/mips/mm/highmem.c
+++ b/arch/mips/mm/highmem.c
@@ -12,19 +12,11 @@ static pte_t *kmap_pte;

unsigned long highstart_pfn, highend_pfn;

-void *kmap(struct page *page)
+void kmap_flush_tlb(unsigned long addr)
{
- void *addr;
-
- might_sleep();
- if (!PageHighMem(page))
- return page_address(page);
- addr = kmap_high(page);
- flush_tlb_one((unsigned long)addr);
-
- return addr;
+ flush_tlb_one(addr);
}
-EXPORT_SYMBOL(kmap);
+EXPORT_SYMBOL(kmap_flush_tlb);

void kunmap(struct page *page)
{
diff --git a/arch/nds32/include/asm/highmem.h b/arch/nds32/include/asm/highmem.h
index b3a82c97ded3..b13654a79069 100644
--- a/arch/nds32/include/asm/highmem.h
+++ b/arch/nds32/include/asm/highmem.h
@@ -44,7 +44,6 @@ extern unsigned long highstart_pfn, highend_pfn;

extern pte_t *pkmap_page_table;

-extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);

extern void kmap_init(void);
@@ -54,7 +53,6 @@ extern void kmap_init(void);
* when CONFIG_HIGHMEM is not set.
*/
#ifdef CONFIG_HIGHMEM
-extern void *kmap(struct page *page);
extern void kunmap(struct page *page);
extern void *kmap_atomic(struct page *page);
extern void __kunmap_atomic(void *kvaddr);
diff --git a/arch/nds32/mm/highmem.c b/arch/nds32/mm/highmem.c
index 4c7c28e994ea..d0cde53b84ae 100644
--- a/arch/nds32/mm/highmem.c
+++ b/arch/nds32/mm/highmem.c
@@ -10,18 +10,6 @@
#include <asm/fixmap.h>
#include <asm/tlbflush.h>

-void *kmap(struct page *page)
-{
- unsigned long vaddr;
- might_sleep();
- if (!PageHighMem(page))
- return page_address(page);
- vaddr = (unsigned long)kmap_high(page);
- return (void *)vaddr;
-}
-
-EXPORT_SYMBOL(kmap);
-
void kunmap(struct page *page)
{
might_sleep();
diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h
index 529512f6d65a..f14e4feef6d5 100644
--- a/arch/powerpc/include/asm/highmem.h
+++ b/arch/powerpc/include/asm/highmem.h
@@ -59,19 +59,10 @@ extern pte_t *pkmap_page_table;
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))

-extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);
extern void *kmap_atomic_prot(struct page *page, pgprot_t prot);
extern void __kunmap_atomic(void *kvaddr);

-static inline void *kmap(struct page *page)
-{
- might_sleep();
- if (!PageHighMem(page))
- return page_address(page);
- return kmap_high(page);
-}
-
static inline void kunmap(struct page *page)
{
might_sleep();
diff --git a/arch/sparc/include/asm/highmem.h b/arch/sparc/include/asm/highmem.h
index 7dd2d4b3f980..2ff1192047f7 100644
--- a/arch/sparc/include/asm/highmem.h
+++ b/arch/sparc/include/asm/highmem.h
@@ -50,17 +50,8 @@ void kmap_init(void) __init;

#define PKMAP_END (PKMAP_ADDR(LAST_PKMAP))

-void *kmap_high(struct page *page);
void kunmap_high(struct page *page);

-static inline void *kmap(struct page *page)
-{
- might_sleep();
- if (!PageHighMem(page))
- return page_address(page);
- return kmap_high(page);
-}
-
static inline void kunmap(struct page *page)
{
might_sleep();
diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h
index a8059930056d..c916a28a9738 100644
--- a/arch/x86/include/asm/highmem.h
+++ b/arch/x86/include/asm/highmem.h
@@ -58,10 +58,8 @@ extern unsigned long highstart_pfn, highend_pfn;
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
#define PKMAP_ADDR(nr) (PKMAP_BASE + ((nr) << PAGE_SHIFT))

-extern void *kmap_high(struct page *page);
extern void kunmap_high(struct page *page);

-void *kmap(struct page *page);
void kunmap(struct page *page);

void *kmap_atomic_prot(struct page *page, pgprot_t prot);
diff --git a/arch/x86/mm/highmem_32.c b/arch/x86/mm/highmem_32.c
index 8af66382672b..12591a81b85c 100644
--- a/arch/x86/mm/highmem_32.c
+++ b/arch/x86/mm/highmem_32.c
@@ -4,15 +4,6 @@
#include <linux/swap.h> /* for totalram_pages */
#include <linux/memblock.h>

-void *kmap(struct page *page)
-{
- might_sleep();
- if (!PageHighMem(page))
- return page_address(page);
- return kmap_high(page);
-}
-EXPORT_SYMBOL(kmap);
-
void kunmap(struct page *page)
{
might_sleep();
diff --git a/arch/xtensa/include/asm/highmem.h b/arch/xtensa/include/asm/highmem.h
index a9587c85be85..2546b88ddecf 100644
--- a/arch/xtensa/include/asm/highmem.h
+++ b/arch/xtensa/include/asm/highmem.h
@@ -63,17 +63,8 @@ static inline wait_queue_head_t *get_pkmap_wait_queue_head(unsigned int color)

extern pte_t *pkmap_page_table;

-void *kmap_high(struct page *page);
void kunmap_high(struct page *page);

-static inline void *kmap(struct page *page)
-{
- might_sleep();
- if (!PageHighMem(page))
- return page_address(page);
- return kmap_high(page);
-}
-
static inline void kunmap(struct page *page)
{
might_sleep();
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index ea5cdbd8c2c3..fc3adc51254a 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -34,6 +34,24 @@ static inline void invalidate_kernel_vmap_range(void *vaddr, int size)
#ifdef CONFIG_HIGHMEM
#include <asm/highmem.h>

+#ifndef ARCH_HAS_KMAP_FLUSH_TLB
+static inline void kmap_flush_tlb(unsigned long addr) { }
+#endif
+
+void *kmap_high(struct page *page);
+static inline void *kmap(struct page *page)
+{
+ void *addr;
+
+ might_sleep();
+ if (!PageHighMem(page))
+ addr = page_address(page);
+ else
+ addr = kmap_high(page);
+ kmap_flush_tlb((unsigned long)addr);
+ return addr;
+}
+
/* declarations for linux/mm/highmem.c */
unsigned int nr_free_highpages(void);
extern atomic_long_t _totalhigh_pages;
--
2.25.1

2020-05-04 01:15:23

by Ira Weiny

[permalink] [raw]
Subject: [PATCH V2 02/11] arch/xtensa: Move kmap build bug out of the way

From: Ira Weiny <[email protected]>

Move the kmap() build bug to kmap_init() to facilitate patches to lift
kmap() to the core.

Reviewed-by: Christoph Hellwig <[email protected]>
Signed-off-by: Ira Weiny <[email protected]>

---
Changes from V1:
combine code onto 1 line.
---
arch/xtensa/include/asm/highmem.h | 5 -----
arch/xtensa/mm/highmem.c | 4 ++++
2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/arch/xtensa/include/asm/highmem.h b/arch/xtensa/include/asm/highmem.h
index 413848cc1e56..a9587c85be85 100644
--- a/arch/xtensa/include/asm/highmem.h
+++ b/arch/xtensa/include/asm/highmem.h
@@ -68,11 +68,6 @@ void kunmap_high(struct page *page);

static inline void *kmap(struct page *page)
{
- /* Check if this memory layout is broken because PKMAP overlaps
- * page table.
- */
- BUILD_BUG_ON(PKMAP_BASE <
- TLBTEMP_BASE_1 + TLBTEMP_SIZE);
might_sleep();
if (!PageHighMem(page))
return page_address(page);
diff --git a/arch/xtensa/mm/highmem.c b/arch/xtensa/mm/highmem.c
index 184ceadccc1a..da734a2ed641 100644
--- a/arch/xtensa/mm/highmem.c
+++ b/arch/xtensa/mm/highmem.c
@@ -88,6 +88,10 @@ void __init kmap_init(void)
{
unsigned long kmap_vstart;

+ /* Check if this memory layout is broken because PKMAP overlaps
+ * page table.
+ */
+ BUILD_BUG_ON(PKMAP_BASE < TLBTEMP_BASE_1 + TLBTEMP_SIZE);
/* cache the first kmap pte */
kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN);
kmap_pte = kmap_get_fixmap_pte(kmap_vstart);
--
2.25.1

2020-05-04 01:35:08

by Ira Weiny

[permalink] [raw]
Subject: [PATCH V2 09/11] arch/kmap: Don't hard code kmap_prot values

From: Ira Weiny <[email protected]>

To support kmap_atomic_prot() on all architectures each arch must
support protections passed in to them.

Change csky, mips, nds32 and xtensa to use their global constant
kmap_prot rather than a hard coded value which was equal.

Reviewed-by: Christoph Hellwig <[email protected]>
Signed-off-by: Ira Weiny <[email protected]>

---
changes from V1:
Mention that kmap_prot is a constant in commit message
---
arch/csky/mm/highmem.c | 2 +-
arch/mips/mm/highmem.c | 2 +-
arch/nds32/mm/highmem.c | 2 +-
arch/xtensa/mm/highmem.c | 2 +-
4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/csky/mm/highmem.c b/arch/csky/mm/highmem.c
index 0aafbbbe651c..f4311669b5bb 100644
--- a/arch/csky/mm/highmem.c
+++ b/arch/csky/mm/highmem.c
@@ -32,7 +32,7 @@ void *kmap_atomic_high(struct page *page)
#ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON(!pte_none(*(kmap_pte - idx)));
#endif
- set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL));
+ set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
flush_tlb_one((unsigned long)vaddr);

return (void *)vaddr;
diff --git a/arch/mips/mm/highmem.c b/arch/mips/mm/highmem.c
index 155fbb107b35..87023bd1a33c 100644
--- a/arch/mips/mm/highmem.c
+++ b/arch/mips/mm/highmem.c
@@ -29,7 +29,7 @@ void *kmap_atomic_high(struct page *page)
#ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON(!pte_none(*(kmap_pte - idx)));
#endif
- set_pte(kmap_pte-idx, mk_pte(page, PAGE_KERNEL));
+ set_pte(kmap_pte-idx, mk_pte(page, kmap_prot));
local_flush_tlb_one((unsigned long)vaddr);

return (void*) vaddr;
diff --git a/arch/nds32/mm/highmem.c b/arch/nds32/mm/highmem.c
index f6e6915c0d31..809f8c830f06 100644
--- a/arch/nds32/mm/highmem.c
+++ b/arch/nds32/mm/highmem.c
@@ -21,7 +21,7 @@ void *kmap_atomic_high(struct page *page)

idx = type + KM_TYPE_NR * smp_processor_id();
vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
- pte = (page_to_pfn(page) << PAGE_SHIFT) | (PAGE_KERNEL);
+ pte = (page_to_pfn(page) << PAGE_SHIFT) | (kmap_prot);
ptep = pte_offset_kernel(pmd_off_k(vaddr), vaddr);
set_pte(ptep, pte);

diff --git a/arch/xtensa/mm/highmem.c b/arch/xtensa/mm/highmem.c
index 4de323e43682..50168b09510a 100644
--- a/arch/xtensa/mm/highmem.c
+++ b/arch/xtensa/mm/highmem.c
@@ -48,7 +48,7 @@ void *kmap_atomic_high(struct page *page)
#ifdef CONFIG_DEBUG_HIGHMEM
BUG_ON(!pte_none(*(kmap_pte + idx)));
#endif
- set_pte(kmap_pte + idx, mk_pte(page, PAGE_KERNEL_EXEC));
+ set_pte(kmap_pte + idx, mk_pte(page, kmap_prot));

return (void *)vaddr;
}
--
2.25.1

2020-05-04 01:36:37

by Ira Weiny

[permalink] [raw]
Subject: [PATCH V2 08/11] arch/kmap: Ensure kmap_prot visibility

From: Ira Weiny <[email protected]>

We want to support kmap_atomic_prot() on all architectures and it makes
sense to define kmap_atomic() to use the default kmap_prot.

So we ensure all arch's have a globally available kmap_prot either as a
define or exported symbol.

Signed-off-by: Ira Weiny <[email protected]>
---
arch/microblaze/include/asm/highmem.h | 2 +-
arch/microblaze/mm/init.c | 3 ---
arch/powerpc/include/asm/highmem.h | 2 +-
arch/powerpc/mm/mem.c | 3 ---
arch/sparc/mm/highmem.c | 1 +
5 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/arch/microblaze/include/asm/highmem.h b/arch/microblaze/include/asm/highmem.h
index 1b8a3c5102bd..033ac5b5c2da 100644
--- a/arch/microblaze/include/asm/highmem.h
+++ b/arch/microblaze/include/asm/highmem.h
@@ -25,8 +25,8 @@
#include <linux/uaccess.h>
#include <asm/fixmap.h>

+#define kmap_prot PAGE_KERNEL
extern pte_t *kmap_pte;
-extern pgprot_t kmap_prot;
extern pte_t *pkmap_page_table;

/*
diff --git a/arch/microblaze/mm/init.c b/arch/microblaze/mm/init.c
index 1ffbfa96b9b8..a467686c13af 100644
--- a/arch/microblaze/mm/init.c
+++ b/arch/microblaze/mm/init.c
@@ -49,8 +49,6 @@ unsigned long lowmem_size;
#ifdef CONFIG_HIGHMEM
pte_t *kmap_pte;
EXPORT_SYMBOL(kmap_pte);
-pgprot_t kmap_prot;
-EXPORT_SYMBOL(kmap_prot);

static inline pte_t *virt_to_kpte(unsigned long vaddr)
{
@@ -68,7 +66,6 @@ static void __init highmem_init(void)
pkmap_page_table = virt_to_kpte(PKMAP_BASE);

kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN));
- kmap_prot = PAGE_KERNEL;
}

static void highmem_setup(void)
diff --git a/arch/powerpc/include/asm/highmem.h b/arch/powerpc/include/asm/highmem.h
index 373a470df205..ee5de974c5ef 100644
--- a/arch/powerpc/include/asm/highmem.h
+++ b/arch/powerpc/include/asm/highmem.h
@@ -29,8 +29,8 @@
#include <asm/page.h>
#include <asm/fixmap.h>

+#define kmap_prot PAGE_KERNEL
extern pte_t *kmap_pte;
-extern pgprot_t kmap_prot;
extern pte_t *pkmap_page_table;

/*
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c
index 041ed7cfd341..3f642b058731 100644
--- a/arch/powerpc/mm/mem.c
+++ b/arch/powerpc/mm/mem.c
@@ -64,8 +64,6 @@ bool init_mem_is_free;
#ifdef CONFIG_HIGHMEM
pte_t *kmap_pte;
EXPORT_SYMBOL(kmap_pte);
-pgprot_t kmap_prot;
-EXPORT_SYMBOL(kmap_prot);
#endif

pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
@@ -245,7 +243,6 @@ void __init paging_init(void)
pkmap_page_table = virt_to_kpte(PKMAP_BASE);

kmap_pte = virt_to_kpte(__fix_to_virt(FIX_KMAP_BEGIN));
- kmap_prot = PAGE_KERNEL;
#endif /* CONFIG_HIGHMEM */

printk(KERN_DEBUG "Top of RAM: 0x%llx, Total RAM: 0x%llx\n",
diff --git a/arch/sparc/mm/highmem.c b/arch/sparc/mm/highmem.c
index 469786bc430f..9f06d75e88e1 100644
--- a/arch/sparc/mm/highmem.c
+++ b/arch/sparc/mm/highmem.c
@@ -33,6 +33,7 @@
#include <asm/vaddrs.h>

pgprot_t kmap_prot;
+EXPORT_SYMBOL(kmap_prot);

static pte_t *kmap_pte;

--
2.25.1

2020-05-04 01:50:39

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH V2 00/11] Subject: Remove duplicated kmap code

On Sun, May 03, 2020 at 06:09:01PM -0700, [email protected] wrote:
> From: Ira Weiny <[email protected]>
>
> The kmap infrastructure has been copied almost verbatim to every architecture.
> This series consolidates obvious duplicated code by defining core functions
> which call into the architectures only when needed.
>
> Some of the k[un]map_atomic() implementations have some similarities but the
> similarities were not sufficient to warrant further changes.
>
> In addition we remove a duplicate implementation of kmap() in DRM.
>
> Testing was done by 0day to cover all the architectures I can't readily
> build/test.

OK... Looking through my old notes on kmap unification (this winter, never
went anywhere),

* arch/mips/mm/cache.c ought to use linux/highmem.h, not asm/highmem.h
I suspect that your series doesn't build on some configs there. Hadn't
verified that, though.

* kmap_atomic_to_page() is dead, but not quite gone - csky and nds32 brought
the damn thing back (nds32 - only an extern). It needs killin'...

* parisc is (arguably) abusing kunmap()/kunmap_atomic() for cache flushing.
Replace the bulk of its highmem.h with
#define ARCH_HAS_FLUSH_ON_KUNMAP
#define arch_before_kunmap flush_kernel_dcache_page_addr
and have default kunmap()/kunmap_atomic() do
#ifdef ARCH_HAS_FLUSH_ON_KUNMAP
arch_before_kunmap(page_address(page));
#endif
and
#ifdef ARCH_HAS_FLUSH_ON_KUNMAP
arch_before_kunmap(addr);
#endif
resp. Kills ARCH_HAS_KMAP along with ifdefs on it, makes parisc use somewhat
less hacky.

I'd suggest checking various configs on mips - that's likely to cause headache.
Said that, my analysis of include chains back then is pretty much worthless
by now - I really hate the amount of indirect include chains leading to that
sucker on some, but not all configs ;-/ IIRC, the proof that everything
using kmap*/kunmap* would pull linux/highmem.h regardless of config took several
hours of digging, ran for several pages and had been hopelessly brittle.
arch/mips/mm/cache.c was the only exception caught by it, but these days
there might be more.

2020-05-04 05:35:49

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH V2 00/11] Subject: Remove duplicated kmap code

On Sun, May 03, 2020 at 10:04:47PM -0700, Ira Weiny wrote:

> Grepping for 'asm/highmem.h' and investigations don't reveal any issues... But
> you do have me worried. That said 0-day has been crunching on multiple
> versions of this series without issues such as this (save the mips issue
> above).
>
> I have to say it would be nice if the relation between linux/highmem.h and
> asm/highmem.h was more straightforward.

IIRC, the headache was due to asm/pgtable.h on several architectures and
asm/cacheflush.h on parisc.

<digs the notes out>

|| IOW, there's one in linux/highmem.h (conditional on !CONFIG_HIGHMEM,
|| !ARCH_HAS_KMAP) and several per-architecture variants, usually declared in
|| their asm/highmem.h. In three of those (microblaze, parisc and powerpc) these
|| are inlines (parisc one identical to linux/highmem.h, lives in asm/cacheflush.h,
|| powerpc and microblaze ones calling kmap_atomic_prot() which is defined in
|| arch/$ARCH/mm/highmem.c).
||
|| parisc case is weird - essentially, they want to call
|| flush_kernel_dcache_page_addr() at the places where kunmap/kunmap_atomic
|| is done. And they do so despite not selecting HIGHMEM, with definitions
|| in usual place. They do have ARCH_HAS_KMAP defined, which prevents
|| getting buggered in linux/highmem.h. ARCH_HAS_KMAP is parisc-unique,
|| BTW, and checked only in linux/highmem.h.
||
|| All genuine arch-specific variants are defined in (or call functions
|| defined in) translation units that are only included CONFIG_HIGHMEM builds.
||
|| It would be tempting to consolidate those, e.g. by adding __kmap_atomic()
|| and __kmap_atomic_prot() without that boilerplate, with universal kmap_atomic()
|| and kmap_atomic_prot() in linux/highmem.h. Potential problem with that would
|| be something that pulls ash/highmem.h (or asm/cacheflush.h in case of parisc)
|| directly and uses kmap_atomic/kmap_atomic_prot. There's not a lot places
|| pulling asm/highmem.h, and many of them are not even in includes:
||
|| arch/arm/include/asm/efi.h:13:#include <asm/highmem.h>
|| arch/arm/mm/dma-mapping.c:31:#include <asm/highmem.h>
|| arch/arm/mm/flush.c:14:#include <asm/highmem.h>
|| arch/arm/mm/mmu.c:27:#include <asm/highmem.h>
|| arch/mips/include/asm/pgtable-32.h:22:#include <asm/highmem.h>
|| arch/mips/mm/cache.c:19:#include <asm/highmem.h>
|| arch/mips/mm/fault.c:28:#include <asm/highmem.h> /* For VMALLOC_END */
|| arch/nds32/include/asm/pgtable.h:60:#include <asm/highmem.h>
|| arch/x86/kernel/setup_percpu.c:20:#include <asm/highmem.h>
|| include/linux/highmem.h:35:#include <asm/highmem.h>
||
|| Users of asm/cacheflush.h are rather more numerous; however, anything
|| outside of parisc-specific code has to pull linux/highmem.h, or it won't see
|| the definitions of kmap_atomic/kmap_atomic_prot at all. arch/parisc itself
|| has no callers of those.
||
|| Outside of arch/* there is a plenty of callers. However, the following is
|| true: all instances of kmap_atomic or kmap_atomic_prot outside of arch/*
|| are either inside the linux/highmem.h or are preceded by include of
|| linux/highmem.h on any build that sees them (there is a common include
|| chain that is conditional upon CONFIG_BLOCK, but it's only needed in
|| drivers that are BLOCK-dependent). It was not fun to verify, to put
|| it mildly...
||
|| So for parisc we have no problem - leaving __kmap_atomic()/__kmap_atomic_prot()
|| in asm/cachefile.h and adding universal wrappers in linux/highmem.h will be
|| fine. For other architectures the things might be trickier.
||
|| * arc: all users in arch/arc/ are within arch/arc/mm/{cache,highmem}.c;
|| both pull linux/highmem.h. We are fine.
||
|| * arm: much, much worse. We have several files that pull linux/highmem.h:
|| arch/arm/mm/cache-feroceon-l2.c, arch/arm/mm/cache-xsc3l2.c,
|| arch/arm/mm/copypage-*.c, arch/arm/mm/dma-mapping.c, arch/arm/mm/flush.c,
|| arch/arm/mm/highmem.c, arch/arm/probes/uprobes/core.c,
|| arch/arm/include/asm/kvm_mmu.h (kmap_atomic_pfn()).
|| Those are fine, but we also have this:
|| arch/arm/include/asm/pgtable.h:200:#define __pte_map(pmd) (pte_t *)kmap_atomic(pmd_page(*(pmd)))
|| arch/arm/include/asm/pgtable.h:208:#define pte_offset_map(pmd,addr) (__pte_map(pmd) + pte_index(addr))
|| and sure as hell, asm/pgtable.h does *NOT* pull linux/highmem.h.
||
|| Fortunately, the users of pte_offset_map() (__pte_map() has no other users)
|| are few, both in arch/arm and outside of arch. All arm ones are pulling
|| linux/highmem (arch/arm/mm/{pgd,fault*}.c). Outside of arch we have several
|| that pull highmem.h (by way of rmap.h or pagemap.h, usually):
|| fs/userfaultfd.c, mm/gup.c, mm/hmm.c, mm/huge_memory.c,
|| mm/khugepaged.c, mm/memory-failure.c, mm/memory.c, mm/migrate.c,
|| mm/mremap.c, mm/page_vma_mapped.c, mm/swap_state.c, mm/swapfile.c,
|| mm/vmalloc.c
|| and then there are these in linux/mm.h:
||
|| #define pte_offset_map_lock(mm, pmd, address, ptlp) \
|| ({ \
|| spinlock_t *__ptl = pte_lockptr(mm, pmd); \
|| pte_t *__pte = pte_offset_map(pmd, address); \
|| *(ptlp) = __ptl; \
|| spin_lock(__ptl); \
|| __pte; \
|| })
|| #define pte_alloc_map(mm, pmd, address) \
|| (pte_alloc(mm, pmd) ? NULL : pte_offset_map(pmd, address))
|| #define pte_alloc_map_lock(mm, pmd, address, ptlp) \
|| (pte_alloc(mm, pmd) ? \
|| NULL : pte_offset_map_lock(mm, pmd, address, ptlp))
||
|| These have two users in arch/arm (arch/arm/mm/pgd.c and
|| arch/arm/lib/uaccess_with_memcpy.c, both pulling highmem.h). Outside of
|| arch there are several new files (plus a lot of what we'd already seen
|| in mm/*.c, unsurprisingly):
|| fs/proc/task_mmu.c, mm/ksm.c, mm/madvise.c, mm/memcontrol.c,
|| mm/mempolicy.c, mm/mincore.c, mm/mprotect.c, mm/pagewalk.c,
|| mm/shmem.c, mm/userfaultfd.c,
|| all pulling linux/highmem.h, as pretty much all core VM does. So we are
|| still fine.
||
|| * csky: users in arch/csky/abiv2/cacheflush.c, arch/csky/mm/dma-mapping.c,
|| arch/csky/mm/highmem.c, all pulling linux/highmem.h
||
|| * microblaze: users in arch/microblaze/mm/highmem.c (pulls linux/highmem.h) and,
|| arch/microblaze/include/asm/pgtable.h, this:
|| #define pte_offset_map(dir, addr) \
|| ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
|| One pte_offset_map user in arch/microblaze:
|| arch/microblaze/kernel/signal.c:207: ptep = pte_offset_map(pmdp, address);
|| Messy, but doesn't require any changes (we have asm/pgalloc.h included
|| there, and that pull linux/highmem.h).
|| Outside of arch we'd already sorted it out when looking at arm.
||
|| * mips: users in arch/mips/kernel/crash_dump.c, arch/mips/kernel/uprobes.c,
|| arch/mips/mm/c-r4k.c, arch/mips/mm/dma-noncoherent.c, arch/mips/mm/highmem.c,
|| and arch/mips/mm/init.c (all pulling linux/highmem.h) plus this
|| arch/mips/mm/cache.c, which relies upon asm/highmem.h. This can be switched
|| to linux/highmem.h. On !CONFIG_HIGHMEM builds the call of kmap_atomic() in
|| there is eliminated, since it's conditional upon PageHighMem(). IOW, even
|| though we get a call of (inexistent) out-of-line version, it's not going to
|| survive into object file. With linux/highmem.h use it will be an equally
|| eliminated call of inlined version.
|| XXX: arch/mips/mm/cache.c
||
|| * nds32: users in arch/nds32/kernel/dma.c, arch/nds32/mm/cacheflush.c and
|| arch/nds32/mm/highmem.c, all pulling linux/highmem.h
||
|| * powerpc: users in arch/powerpc/kvm/book3s_pr.c,
|| arch/powerpc/kvm/e500_mmu_host.c, arch/powerpc/mm/dma-noncoherent.c,
|| arch/powerpc/mm/highmem.c and arch/powerpc/mm/mem.c, all pulling
|| linux/highmem.h, a user in arch/powerpc/mm/hugetlbpage.c pulling it
|| via asm/tlb.h -> linux/pagemap.h -> linux/highmem.h and
|| macros for pte_offset_map in arch/powerpc/include/asm/*/32/pgtable.h.
|| Users of that within arch/powerpc are either 64bit-only or
|| pull linux/highmem.h (arch/powerpc/mm/pgtable_32.c and
|| arch/powerpc/xmon/xmon.c). Users outside of arch - same as for arm.
||
|| * sparc: users in arch/sparc/kernel/uprobes.c and arch/sparc/mm/highmem.c
|| (both pulling linux/highmem.h directly) + arch/sparc/mm/init_64.c pulling
|| it via linux/pagemap.h. Strangely, arch/sparc/mm/io-unit.c and
|| arch/sparc/mm/iommu.c both include linux/highmem.h with odd comment
|| that seems to indicate that once upon a time pte_offset_map() used to
|| requite kmap_atomic() there... Right, it used to - until 2002.
|| These includes are pointless, then...
||
|| * x86: users in arch/x86/kernel/crash_dump_32.c, arch/x86/kvm/svm.c,
|| arch/x86/lib/usercopy_64.c, arch/x86/mm/highmem_32.c and arch/x86/mm/iomap_32.c,
|| all pulling linux/highmem.h, users in paging_tmpl.h (included from
|| arch/x86/kvm/mmu/mmu.c, which has pulled linux/highmem.h prior to that)
|| and definition of pte_offset_map() (in asm/pgtable_32.h)
|| Users of pte_offset_map() and friends in arch/x86 are in
|| arch/x86/kernel/vm86_32.c and arch/x86/mm/dump_pagetables.c (both
|| pulling linux/highmem.h), in arch/x86/mm/mem_encrypt_identity.c
|| (64bit-only, pte_offset_map() doesn't use kmap_atomic() there) and
|| arch/x86/kernel/tboot.c (pulls linux/highmem.h via asm/pgalloc.h
|| and linux/pagemap.h)
||
|| * xtensa: users in arch/xtensa/kernel/pci-dma.c, arch/xtensa/mm/highmem.c,
|| arch/xtensa/mm/cache.c and arch/xtensa/platforms/iss/simdisk.c (all pull
|| linux/highmem.h).

2020-05-04 05:46:57

by Ira Weiny

[permalink] [raw]
Subject: Re: [PATCH V2 00/11] Subject: Remove duplicated kmap code

On Mon, May 04, 2020 at 02:35:09AM +0100, Al Viro wrote:
> On Sun, May 03, 2020 at 06:09:01PM -0700, [email protected] wrote:
> > From: Ira Weiny <[email protected]>
> >
> > The kmap infrastructure has been copied almost verbatim to every architecture.
> > This series consolidates obvious duplicated code by defining core functions
> > which call into the architectures only when needed.
> >
> > Some of the k[un]map_atomic() implementations have some similarities but the
> > similarities were not sufficient to warrant further changes.
> >
> > In addition we remove a duplicate implementation of kmap() in DRM.
> >
> > Testing was done by 0day to cover all the architectures I can't readily
> > build/test.
>
> OK... Looking through my old notes on kmap unification (this winter, never
> went anywhere),
>
> * arch/mips/mm/cache.c ought to use linux/highmem.h, not asm/highmem.h
> I suspect that your series doesn't build on some configs there. Hadn't
> verified that, though.

Yes patch 6 makes the change because kmap_atomic() was no longer declared in
asm/highmem.h. I'm pretty sure 0-day caught that ... but I seem to remember
noticing some oddness in that file and I did go through it by hand.

>
> * kmap_atomic_to_page() is dead, but not quite gone - csky and nds32 brought
> the damn thing back (nds32 - only an extern). It needs killin'...

Easy enough. Added as a follow on patch.

>
> * parisc is (arguably) abusing kunmap()/kunmap_atomic() for cache flushing.
> Replace the bulk of its highmem.h with
> #define ARCH_HAS_FLUSH_ON_KUNMAP
> #define arch_before_kunmap flush_kernel_dcache_page_addr
> and have default kunmap()/kunmap_atomic() do
> #ifdef ARCH_HAS_FLUSH_ON_KUNMAP
> arch_before_kunmap(page_address(page));
> #endif
> and
> #ifdef ARCH_HAS_FLUSH_ON_KUNMAP
> arch_before_kunmap(addr);
> #endif
> resp. Kills ARCH_HAS_KMAP along with ifdefs on it, makes parisc use somewhat
> less hacky.

Agreed. Done in a follow on patch.

>
> I'd suggest checking various configs on mips - that's likely to cause headache.
> Said that, my analysis of include chains back then is pretty much worthless
> by now - I really hate the amount of indirect include chains leading to that
> sucker on some, but not all configs ;-/ IIRC, the proof that everything
> using kmap*/kunmap* would pull linux/highmem.h regardless of config took several
> hours of digging, ran for several pages and had been hopelessly brittle.
> arch/mips/mm/cache.c was the only exception caught by it, but these days
> there might be more.

Grepping for 'asm/highmem.h' and investigations don't reveal any issues... But
you do have me worried. That said 0-day has been crunching on multiple
versions of this series without issues such as this (save the mips issue
above).

I have to say it would be nice if the relation between linux/highmem.h and
asm/highmem.h was more straightforward.

Ira

2020-05-04 20:20:29

by Ira Weiny

[permalink] [raw]
Subject: Re: [PATCH V2 00/11] Subject: Remove duplicated kmap code

On Mon, May 04, 2020 at 06:33:57AM +0100, Al Viro wrote:
> On Sun, May 03, 2020 at 10:04:47PM -0700, Ira Weiny wrote:
>
> > Grepping for 'asm/highmem.h' and investigations don't reveal any issues... But
> > you do have me worried. That said 0-day has been crunching on multiple
> > versions of this series without issues such as this (save the mips issue
> > above).
> >
> > I have to say it would be nice if the relation between linux/highmem.h and
> > asm/highmem.h was more straightforward.
>
> IIRC, the headache was due to asm/pgtable.h on several architectures and
> asm/cacheflush.h on parisc.
>
> <digs the notes out>
>
> || IOW, there's one in linux/highmem.h (conditional on !CONFIG_HIGHMEM,
> || !ARCH_HAS_KMAP) and several per-architecture variants, usually declared in
> || their asm/highmem.h. In three of those (microblaze, parisc and powerpc) these
> || are inlines (parisc one identical to linux/highmem.h, lives in asm/cacheflush.h,
> || powerpc and microblaze ones calling kmap_atomic_prot() which is defined in
> || arch/$ARCH/mm/highmem.c).
> ||
> || parisc case is weird - essentially, they want to call
> || flush_kernel_dcache_page_addr() at the places where kunmap/kunmap_atomic
> || is done. And they do so despite not selecting HIGHMEM, with definitions
> || in usual place. They do have ARCH_HAS_KMAP defined, which prevents
> || getting buggered in linux/highmem.h. ARCH_HAS_KMAP is parisc-unique,
> || BTW, and checked only in linux/highmem.h.
> ||
> || All genuine arch-specific variants are defined in (or call functions
> || defined in) translation units that are only included CONFIG_HIGHMEM builds.

I agree with this statement. But IMO additional confusion is caused by the
fact that some arch's condition the declarations on CONFIG_HIGHMEM within
asm/highmem.h (arc, arm, nds32) while others depend on linux/highmem.h (and
elsewhere) to do so (csky, microblaze, mips, powerpc, sparc, x86, xtensa).

Why?

I think (perhaps naive) over time asm/highmem.h needs to be isolated to being
included in linux/highmem.h. But as you point out below that is not so easy.
I think that this series helps toward that goal.

> ||
> || It would be tempting to consolidate those, e.g. by adding __kmap_atomic()
> || and __kmap_atomic_prot() without that boilerplate, with universal kmap_atomic()
> || and kmap_atomic_prot() in linux/highmem.h. Potential problem with that would
> || be something that pulls ash/highmem.h (or asm/cacheflush.h in case of parisc)
> || directly and uses kmap_atomic/kmap_atomic_prot. There's not a lot places
> || pulling asm/highmem.h, and many of them are not even in includes:
> ||
> || arch/arm/include/asm/efi.h:13:#include <asm/highmem.h>
> || arch/arm/mm/dma-mapping.c:31:#include <asm/highmem.h>
> || arch/arm/mm/flush.c:14:#include <asm/highmem.h>
> || arch/arm/mm/mmu.c:27:#include <asm/highmem.h>
> || arch/mips/include/asm/pgtable-32.h:22:#include <asm/highmem.h>
> || arch/mips/mm/cache.c:19:#include <asm/highmem.h>
> || arch/mips/mm/fault.c:28:#include <asm/highmem.h> /* For VMALLOC_END */
> || arch/nds32/include/asm/pgtable.h:60:#include <asm/highmem.h>
> || arch/x86/kernel/setup_percpu.c:20:#include <asm/highmem.h>
> || include/linux/highmem.h:35:#include <asm/highmem.h>
> ||
> || Users of asm/cacheflush.h are rather more numerous; however, anything
> || outside of parisc-specific code has to pull linux/highmem.h, or it won't see
> || the definitions of kmap_atomic/kmap_atomic_prot at all. arch/parisc itself
> || has no callers of those.
> ||
> || Outside of arch/* there is a plenty of callers. However, the following is
> || true: all instances of kmap_atomic or kmap_atomic_prot outside of arch/*
> || are either inside the linux/highmem.h or are preceded by include of
> || linux/highmem.h on any build that sees them (there is a common include
> || chain that is conditional upon CONFIG_BLOCK, but it's only needed in
> || drivers that are BLOCK-dependent). It was not fun to verify, to put
> || it mildly...
> ||
> || So for parisc we have no problem - leaving __kmap_atomic()/__kmap_atomic_prot()
> || in asm/cachefile.h and adding universal wrappers in linux/highmem.h will be
> || fine. For other architectures the things might be trickier.

And the follow up series removes kmap_* from asm/cachefile.h in parisc which
should be cleaner going forward.

> ||
> || * arc: all users in arch/arc/ are within arch/arc/mm/{cache,highmem}.c;
> || both pull linux/highmem.h. We are fine.

Still fine.

> ||
> || * arm: much, much worse. We have several files that pull linux/highmem.h:
> || arch/arm/mm/cache-feroceon-l2.c, arch/arm/mm/cache-xsc3l2.c,
> || arch/arm/mm/copypage-*.c, arch/arm/mm/dma-mapping.c, arch/arm/mm/flush.c,
> || arch/arm/mm/highmem.c, arch/arm/probes/uprobes/core.c,
> || arch/arm/include/asm/kvm_mmu.h (kmap_atomic_pfn()).
> || Those are fine, but we also have this:
> || arch/arm/include/asm/pgtable.h:200:#define __pte_map(pmd) (pte_t *)kmap_atomic(pmd_page(*(pmd)))
> || arch/arm/include/asm/pgtable.h:208:#define pte_offset_map(pmd,addr) (__pte_map(pmd) + pte_index(addr))
> || and sure as hell, asm/pgtable.h does *NOT* pull linux/highmem.h.

It does not pull asm/highmem.h either...

> ||
> || Fortunately, the users of pte_offset_map() (__pte_map() has no other users)
> || are few, both in arch/arm and outside of arch. All arm ones are pulling
> || linux/highmem (arch/arm/mm/{pgd,fault*}.c). Outside of arch we have several
> || that pull highmem.h (by way of rmap.h or pagemap.h, usually):
> || fs/userfaultfd.c, mm/gup.c, mm/hmm.c, mm/huge_memory.c,
> || mm/khugepaged.c, mm/memory-failure.c, mm/memory.c, mm/migrate.c,
> || mm/mremap.c, mm/page_vma_mapped.c, mm/swap_state.c, mm/swapfile.c,
> || mm/vmalloc.c
> || and then there are these in linux/mm.h:
> ||
> || #define pte_offset_map_lock(mm, pmd, address, ptlp) \
> || ({ \
> || spinlock_t *__ptl = pte_lockptr(mm, pmd); \
> || pte_t *__pte = pte_offset_map(pmd, address); \
> || *(ptlp) = __ptl; \
> || spin_lock(__ptl); \
> || __pte; \
> || })
> || #define pte_alloc_map(mm, pmd, address) \
> || (pte_alloc(mm, pmd) ? NULL : pte_offset_map(pmd, address))
> || #define pte_alloc_map_lock(mm, pmd, address, ptlp) \
> || (pte_alloc(mm, pmd) ? \
> || NULL : pte_offset_map_lock(mm, pmd, address, ptlp))
> ||
> || These have two users in arch/arm (arch/arm/mm/pgd.c and
> || arch/arm/lib/uaccess_with_memcpy.c, both pulling highmem.h). Outside of
> || arch there are several new files (plus a lot of what we'd already seen
> || in mm/*.c, unsurprisingly):
> || fs/proc/task_mmu.c, mm/ksm.c, mm/madvise.c, mm/memcontrol.c,
> || mm/mempolicy.c, mm/mincore.c, mm/mprotect.c, mm/pagewalk.c,
> || mm/shmem.c, mm/userfaultfd.c,
> || all pulling linux/highmem.h, as pretty much all core VM does. So we are
> || still fine.

This all seems the same now.

> ||
> || * csky: users in arch/csky/abiv2/cacheflush.c, arch/csky/mm/dma-mapping.c,
> || arch/csky/mm/highmem.c, all pulling linux/highmem.h

Yes still are.

> ||
> || * microblaze: users in arch/microblaze/mm/highmem.c (pulls linux/highmem.h) and,
> || arch/microblaze/include/asm/pgtable.h, this:
> || #define pte_offset_map(dir, addr) \
> || ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
> || One pte_offset_map user in arch/microblaze:
> || arch/microblaze/kernel/signal.c:207: ptep = pte_offset_map(pmdp, address);
> || Messy, but doesn't require any changes (we have asm/pgalloc.h included
> || there, and that pull linux/highmem.h).

AFAICS asm/pgtable.h does not include asm/highmem.h here...

So looks like arch/microblaze/kernel/signal.c will need linux/highmem.h

> || Outside of arch we'd already sorted it out when looking at arm.
> ||
> || * mips: users in arch/mips/kernel/crash_dump.c, arch/mips/kernel/uprobes.c,
> || arch/mips/mm/c-r4k.c, arch/mips/mm/dma-noncoherent.c, arch/mips/mm/highmem.c,
> || and arch/mips/mm/init.c (all pulling linux/highmem.h) plus this
> || arch/mips/mm/cache.c, which relies upon asm/highmem.h. This can be switched
> || to linux/highmem.h. On !CONFIG_HIGHMEM builds the call of kmap_atomic() in
> || there is eliminated, since it's conditional upon PageHighMem(). IOW, even
> || though we get a call of (inexistent) out-of-line version, it's not going to
> || survive into object file. With linux/highmem.h use it will be an equally
> || eliminated call of inlined version.
> || XXX: arch/mips/mm/cache.c

Fixed as part of this series.

> ||
> || * nds32: users in arch/nds32/kernel/dma.c, arch/nds32/mm/cacheflush.c and
> || arch/nds32/mm/highmem.c, all pulling linux/highmem.h

Still looks ok.

> ||
> || * powerpc: users in arch/powerpc/kvm/book3s_pr.c,
> || arch/powerpc/kvm/e500_mmu_host.c, arch/powerpc/mm/dma-noncoherent.c,
> || arch/powerpc/mm/highmem.c and arch/powerpc/mm/mem.c, all pulling
> || linux/highmem.h,

still good

> a user in arch/powerpc/mm/hugetlbpage.c pulling it
> || via asm/tlb.h -> linux/pagemap.h -> linux/highmem.h

good

> and
> || macros for pte_offset_map in arch/powerpc/include/asm/*/32/pgtable.h.
> || Users of that within arch/powerpc are either 64bit-only or
> || pull linux/highmem.h (arch/powerpc/mm/pgtable_32.c and
> || arch/powerpc/xmon/xmon.c).
>

Looks ok.

> || Users outside of arch - same as for arm.
> ||
> || * sparc: users in arch/sparc/kernel/uprobes.c and arch/sparc/mm/highmem.c
> || (both pulling linux/highmem.h directly) + arch/sparc/mm/init_64.c pulling
> || it via linux/pagemap.h.

Looks ok.

> Strangely, arch/sparc/mm/io-unit.c and
> || arch/sparc/mm/iommu.c both include linux/highmem.h with odd comment
> || that seems to indicate that once upon a time pte_offset_map() used to
> || requite kmap_atomic() there... Right, it used to - until 2002.
> || These includes are pointless, then...

Looks like it...

I'll throw in a patch for that.

> ||
> || * x86: users in arch/x86/kernel/crash_dump_32.c, arch/x86/kvm/svm.c,
> || arch/x86/lib/usercopy_64.c, arch/x86/mm/highmem_32.c and arch/x86/mm/iomap_32.c,
> || all pulling linux/highmem.h, users in paging_tmpl.h (included from
> || arch/x86/kvm/mmu/mmu.c, which has pulled linux/highmem.h prior to that)
> || and definition of pte_offset_map() (in asm/pgtable_32.h)
> || Users of pte_offset_map() and friends in arch/x86 are in
> || arch/x86/kernel/vm86_32.c and arch/x86/mm/dump_pagetables.c (both
> || pulling linux/highmem.h), in arch/x86/mm/mem_encrypt_identity.c
> || (64bit-only, pte_offset_map() doesn't use kmap_atomic() there) and
> || arch/x86/kernel/tboot.c (pulls linux/highmem.h via asm/pgalloc.h
> || and linux/pagemap.h)

I've built these and they seem fine.

> ||
> || * xtensa: users in arch/xtensa/kernel/pci-dma.c, arch/xtensa/mm/highmem.c,
> || arch/xtensa/mm/cache.c and arch/xtensa/platforms/iss/simdisk.c (all pull
> || linux/highmem.h).

Actually

arch/xtensa/mm/cache.c gets linux/highmem.h from linux/pagemap.h

arch/xtensa/platforms/iss/simdisk.c may have an issue?
linux/blkdev.h -> CONFIG_BLOCK -> linux/pagemap.h -> linux/highmem.h
But simdisk.c requires BLK_DEV_SIMDISK -> CONFIG_BLOCK...
<sigh>

So xtensa still seems good AFAICS.


In summary it looks like the use of kmap_atomic() in pte_offset_map() is a
potential issue in microblaze. I've fixed that in my local tree.

Ira

2020-05-04 21:05:00

by Al Viro

[permalink] [raw]
Subject: Re: [PATCH V2 00/11] Subject: Remove duplicated kmap code

On Mon, May 04, 2020 at 01:17:41PM -0700, Ira Weiny wrote:

> > || * arm: much, much worse. We have several files that pull linux/highmem.h:
> > || arch/arm/mm/cache-feroceon-l2.c, arch/arm/mm/cache-xsc3l2.c,
> > || arch/arm/mm/copypage-*.c, arch/arm/mm/dma-mapping.c, arch/arm/mm/flush.c,
> > || arch/arm/mm/highmem.c, arch/arm/probes/uprobes/core.c,
> > || arch/arm/include/asm/kvm_mmu.h (kmap_atomic_pfn()).
> > || Those are fine, but we also have this:
> > || arch/arm/include/asm/pgtable.h:200:#define __pte_map(pmd) (pte_t *)kmap_atomic(pmd_page(*(pmd)))
> > || arch/arm/include/asm/pgtable.h:208:#define pte_offset_map(pmd,addr) (__pte_map(pmd) + pte_index(addr))
> > || and sure as hell, asm/pgtable.h does *NOT* pull linux/highmem.h.
>
> It does not pull asm/highmem.h either...

No, but the users of those macros need to be considered.

> > || #define pte_offset_map(dir, addr) \
> > || ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
> > || One pte_offset_map user in arch/microblaze:
> > || arch/microblaze/kernel/signal.c:207: ptep = pte_offset_map(pmdp, address);
> > || Messy, but doesn't require any changes (we have asm/pgalloc.h included
> > || there, and that pull linux/highmem.h).
>
> AFAICS asm/pgtable.h does not include asm/highmem.h here...
>
> So looks like arch/microblaze/kernel/signal.c will need linux/highmem.h

See above - line 39 in there is
#include <asm/pgalloc.h>
and line 14 in arch/microblaze/include/asm/pgalloc.h is
#include <linux/highmem.h>
It's conditional upon CONFIG_MMU in there, but so's the use of
pte_offset_map() in arch/microblaze/kernel/signal.c

So it shouldn't be a problem.

> > || * xtensa: users in arch/xtensa/kernel/pci-dma.c, arch/xtensa/mm/highmem.c,
> > || arch/xtensa/mm/cache.c and arch/xtensa/platforms/iss/simdisk.c (all pull
> > || linux/highmem.h).
>
> Actually
>
> arch/xtensa/mm/cache.c gets linux/highmem.h from linux/pagemap.h
>
> arch/xtensa/platforms/iss/simdisk.c may have an issue?
> linux/blkdev.h -> CONFIG_BLOCK -> linux/pagemap.h -> linux/highmem.h
> But simdisk.c requires BLK_DEV_SIMDISK -> CONFIG_BLOCK...
> <sigh>

Yep - see above re major chain of indirect includes conditional upon CONFIG_BLOCK
and its uses in places that only build with such configs. There's a plenty of
similar considerations outside of arch/*, unfortunately...

2020-05-04 23:29:23

by Ira Weiny

[permalink] [raw]
Subject: Re: [PATCH V2 00/11] Subject: Remove duplicated kmap code

On Mon, May 04, 2020 at 10:02:25PM +0100, Al Viro wrote:
> On Mon, May 04, 2020 at 01:17:41PM -0700, Ira Weiny wrote:
>
> > > || * arm: much, much worse. We have several files that pull linux/highmem.h:
> > > || arch/arm/mm/cache-feroceon-l2.c, arch/arm/mm/cache-xsc3l2.c,
> > > || arch/arm/mm/copypage-*.c, arch/arm/mm/dma-mapping.c, arch/arm/mm/flush.c,
> > > || arch/arm/mm/highmem.c, arch/arm/probes/uprobes/core.c,
> > > || arch/arm/include/asm/kvm_mmu.h (kmap_atomic_pfn()).
> > > || Those are fine, but we also have this:
> > > || arch/arm/include/asm/pgtable.h:200:#define __pte_map(pmd) (pte_t *)kmap_atomic(pmd_page(*(pmd)))
> > > || arch/arm/include/asm/pgtable.h:208:#define pte_offset_map(pmd,addr) (__pte_map(pmd) + pte_index(addr))
> > > || and sure as hell, asm/pgtable.h does *NOT* pull linux/highmem.h.
> >
> > It does not pull asm/highmem.h either...
>
> No, but the users of those macros need to be considered.

Agreed, I was trying to point out that highmem.h was being pulled from
somewhere else prior to my series, sorry.

>
> > > || #define pte_offset_map(dir, addr) \
> > > || ((pte_t *) kmap_atomic(pmd_page(*(dir))) + pte_index(addr))
> > > || One pte_offset_map user in arch/microblaze:
> > > || arch/microblaze/kernel/signal.c:207: ptep = pte_offset_map(pmdp, address);
> > > || Messy, but doesn't require any changes (we have asm/pgalloc.h included
> > > || there, and that pull linux/highmem.h).
> >
> > AFAICS asm/pgtable.h does not include asm/highmem.h here...
> >
> > So looks like arch/microblaze/kernel/signal.c will need linux/highmem.h
>
> See above - line 39 in there is
> #include <asm/pgalloc.h>
> and line 14 in arch/microblaze/include/asm/pgalloc.h is
> #include <linux/highmem.h>
> It's conditional upon CONFIG_MMU in there, but so's the use of
> pte_offset_map() in arch/microblaze/kernel/signal.c
>
> So it shouldn't be a problem.

Ah ok, I did not see that one. Ok I'll drop that change and this series should
be good.

I was setting up to submit another version with 3 more patches you have
suggested:

kmap: Remove kmap_atomic_to_page()
parisc/kmap: Remove duplicate kmap code
sparc: Remove unnecessary includes

Would you like to see those folded in? I submitted 2 of the above as a
separate series already.

>
> > > || * xtensa: users in arch/xtensa/kernel/pci-dma.c, arch/xtensa/mm/highmem.c,
> > > || arch/xtensa/mm/cache.c and arch/xtensa/platforms/iss/simdisk.c (all pull
> > > || linux/highmem.h).
> >
> > Actually
> >
> > arch/xtensa/mm/cache.c gets linux/highmem.h from linux/pagemap.h
> >
> > arch/xtensa/platforms/iss/simdisk.c may have an issue?
> > linux/blkdev.h -> CONFIG_BLOCK -> linux/pagemap.h -> linux/highmem.h
> > But simdisk.c requires BLK_DEV_SIMDISK -> CONFIG_BLOCK...
> > <sigh>
>
> Yep - see above re major chain of indirect includes conditional upon CONFIG_BLOCK
> and its uses in places that only build with such configs. There's a plenty of
> similar considerations outside of arch/*, unfortunately...

Indeed.

FWIW the last 2 versions of this series have had no build failures with 0-day.

This series in particular just finished 164 configs without issue.

Would you like me to submit a new series? With your additional patches?

Ira

2020-05-06 06:16:46

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH V2 08/11] arch/kmap: Ensure kmap_prot visibility

On Sun, May 03, 2020 at 06:09:09PM -0700, [email protected] wrote:
> From: Ira Weiny <[email protected]>
>
> We want to support kmap_atomic_prot() on all architectures and it makes
> sense to define kmap_atomic() to use the default kmap_prot.
>
> So we ensure all arch's have a globally available kmap_prot either as a
> define or exported symbol.

FYI, I still think a

#ifndef kmap_prot
#define kmap_prot PAGE_KERNEL
#endif

in linux/highmem.h would be nicer. Then only xtensa and sparc need
to override it and clearly stand out.

2020-05-07 02:35:43

by Ira Weiny

[permalink] [raw]
Subject: Re: [PATCH V2 08/11] arch/kmap: Ensure kmap_prot visibility

On Tue, May 05, 2020 at 11:13:26PM -0700, Christoph Hellwig wrote:
> On Sun, May 03, 2020 at 06:09:09PM -0700, [email protected] wrote:
> > From: Ira Weiny <[email protected]>
> >
> > We want to support kmap_atomic_prot() on all architectures and it makes
> > sense to define kmap_atomic() to use the default kmap_prot.
> >
> > So we ensure all arch's have a globally available kmap_prot either as a
> > define or exported symbol.
>
> FYI, I still think a
>
> #ifndef kmap_prot
> #define kmap_prot PAGE_KERNEL
> #endif
>
> in linux/highmem.h would be nicer. Then only xtensa and sparc need
> to override it and clearly stand out.

That would be nice... But... in this particular patch kmap_prot needs to be
in arch/microblaze/include/asm/highmem.h to preserve bisect-ability.

So there would be an inversion with this define and the core #ifndef...

I like the change but I'm going to add this change as a follow on patch because
at the end of the series microblaze no longer needs this.

If this is reasonable could I get a review on this patch to add to the next
series?

Ira

2020-05-07 05:00:21

by Christoph Hellwig

[permalink] [raw]
Subject: Re: [PATCH V2 08/11] arch/kmap: Ensure kmap_prot visibility

On Sun, May 03, 2020 at 06:09:09PM -0700, [email protected] wrote:
> From: Ira Weiny <[email protected]>
>
> We want to support kmap_atomic_prot() on all architectures and it makes
> sense to define kmap_atomic() to use the default kmap_prot.
>
> So we ensure all arch's have a globally available kmap_prot either as a
> define or exported symbol.
>
> Signed-off-by: Ira Weiny <[email protected]>

Looks good,

Reviewed-by: Christoph Hellwig <[email protected]>