2024-04-30 15:30:30

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 00/15] Fast kernel headers: split linux/mm.h

This patch set aims to clean up the linux/mm.h header and reduce
dependencies on it by moving parts out.

The goal was to eliminate dependencies on linux/mm.h from other
popular headers such as highmem.h and dma-mapping.h, and I started by
checking which symbols were really used and moved those declarations
to separate slim headers.

This patch set borrows the name "fast kernel headers" from Ingo
Molnar's effort a few years ago. While this kind of refactoring does
indeed improve build times because the amount of code that has to be
processed in each compilation unit is reduced, build speed is the
least important advantage.

Much more important is that this gives us greater confidence that the
code is correct: if we forget to include a header, it might (or might
not) already be included indirectly by some other header somewhere
down the large impenetrable include tree. Chances are almost 100%
that linux/kernel.h or linux/mm.h gets included somewhere, which then
in turn includes everything else. Now if this indirect include just
happens to be changed eventually, the build may suddenly fail at
remote places. Worse, an #ifdef may silently produce different code.
Therefore, at each source file, all the includes that are needed
should be included directly (but not more). This is only possible if
headers are small, and linux/mm.h and linux/kernel.h are large
offenders resisting the cleanup.

Therefore, splitting those is the first step towards leaner header
dependencies. This patch set starts with linux/mm.h, and I am already
preparing another patch set addressing linux/kernel.h.

Some of these changes were part of a previous, bigger patch set
(https://lore.kernel.org/lkml/[email protected]/)
but this patch set grew so large, it could not be reviewed. This is
an attempt to break the patch set into smaller pieces.

---
v1 -> v2: added more explanations to commit messages; renamed several
new headers from page_*.h to folio_*.h as suggested by Matthew
Wilcox; rebase on linux-next; fix build failures on architectures
um,nios2,hexagon by adding more missing includes
v2 -> v3: rebase on linux-next
v3 -> v4: rebase on linux-next; fix build failure on loongarch64
(reported by kernel test robot); add missing includes to
drivers/dma/bcm2835-dma.c and include/scsi/scsicam.h
v4 -> v5: rebase on linux-next; more text in cover letter as suggested
by David Hildrenbrand

Max Kellermann (15):
drivers: add missing includes on linux/mm.h (and others)
include/drm/drm_gem.h: add poll_table_struct forward declaration
include/scsi/scsicam.h: forward-declare struct block_device
linux/mm.h: move page_kasan_tag() to mm/page_kasan_tag.h
linux/mm.h: move section functions to mm/page_section.h
linux/mm.h: move page_address() and others to mm/page_address.h
linux/mm.h: move folio_size(), ... to mm/folio_size.h
linux/mm.h: move folio_next() to mm/folio_next.h
linux/mm.h: move devmap-related declarations to mm/devmap_managed.h
linux/mm.h: move usage count functions to mm/folio_usage.h
linux/mm.h: move page_zone_id() and more to mm/folio_zone.h
linux/mm.h: move pfmemalloc-related functions to pfmemalloc.h
linux/mm.h: move is_vmalloc_addr() to mm/vmalloc_addr.h
linux/mm.h: move high_memory to mm/high_memory.h
include: reduce dependencies on linux/mm.h

MAINTAINERS | 1 +
arch/arm/include/asm/memory.h | 4 +
arch/arm/include/asm/pgtable.h | 2 +
arch/arm/mm/iomap.c | 3 +
arch/csky/include/asm/page.h | 1 +
arch/hexagon/include/asm/mem-layout.h | 4 +
arch/m68k/include/asm/page_mm.h | 1 +
arch/m68k/include/asm/pgtable_mm.h | 1 +
arch/parisc/include/asm/floppy.h | 1 +
arch/powerpc/include/asm/book3s/32/pgtable.h | 4 +
arch/powerpc/include/asm/nohash/32/pgtable.h | 1 +
arch/powerpc/include/asm/page.h | 1 +
arch/x86/include/asm/floppy.h | 1 +
arch/x86/include/asm/pgtable_32_areas.h | 4 +
drivers/comedi/comedi_buf.c | 1 +
.../qat/qat_common/adf_gen4_pm_debugfs.c | 1 +
drivers/dma/bcm2835-dma.c | 1 +
drivers/dma/dma-axi-dmac.c | 1 +
drivers/dma/sh/rcar-dmac.c | 1 +
drivers/firmware/qcom/qcom_scm-legacy.c | 1 +
drivers/firmware/qcom/qcom_scm-smc.c | 1 +
drivers/firmware/raspberrypi.c | 1 +
drivers/iio/buffer/industrialio-buffer-dma.c | 1 +
drivers/iommu/iommufd/ioas.c | 2 +
drivers/iommu/iommufd/selftest.c | 1 +
drivers/media/platform/mediatek/vpu/mtk_vpu.c | 1 +
drivers/media/platform/ti/omap/omap_voutlib.c | 1 +
drivers/misc/bcm-vk/bcm_vk_dev.c | 1 +
drivers/misc/fastrpc.c | 1 +
drivers/misc/genwqe/card_dev.c | 1 +
drivers/misc/uacce/uacce.c | 1 +
drivers/mtd/nand/onenand/onenand_samsung.c | 1 +
drivers/mtd/spi-nor/core.h | 2 +
drivers/pci/p2pdma.c | 1 +
drivers/pci/pci.c | 1 +
drivers/remoteproc/remoteproc_core.c | 1 +
drivers/soc/qcom/rmtfs_mem.c | 1 +
drivers/spi/spi-aspeed-smc.c | 1 +
drivers/spi/spi-bcm2835.c | 2 +
drivers/spi/spi-intel.c | 1 +
drivers/virtio/virtio_ring.c | 1 +
include/drm/drm_file.h | 1 +
include/linux/bio.h | 2 +
include/linux/bpfptr.h | 1 -
include/linux/dma-mapping.h | 1 +
include/linux/highmem-internal.h | 2 +
include/linux/highmem.h | 4 +-
include/linux/huge_mm.h | 2 +
include/linux/iommu.h | 1 +
include/linux/mm.h | 598 +-----------------
include/linux/mm/devmap_managed.h | 32 +
include/linux/mm/folio_next.h | 27 +
include/linux/mm/folio_size.h | 150 +++++
include/linux/mm/folio_usage.h | 182 ++++++
include/linux/mm/folio_zone.h | 56 ++
include/linux/mm/high_memory.h | 7 +
include/linux/mm/page_address.h | 71 +++
include/linux/mm/page_kasan_tag.h | 66 ++
include/linux/mm/page_section.h | 23 +
include/linux/mm/pfmemalloc.h | 52 ++
include/linux/mm/vmalloc_addr.h | 33 +
include/linux/net.h | 2 +-
include/linux/nvme-keyring.h | 2 +
include/linux/oom.h | 2 +-
include/linux/page-flags.h | 3 +
include/linux/pagemap.h | 2 +-
include/linux/scatterlist.h | 8 +-
include/linux/skbuff.h | 4 +
include/linux/vmstat.h | 2 +
include/scsi/scsicam.h | 5 +
kernel/dma/ops_helpers.c | 1 +
kernel/dma/remap.c | 1 +
kernel/rcu/rcutorture.c | 1 +
lib/scatterlist.c | 1 +
mm/dmapool.c | 1 +
75 files changed, 810 insertions(+), 595 deletions(-)
create mode 100644 include/linux/mm/devmap_managed.h
create mode 100644 include/linux/mm/folio_next.h
create mode 100644 include/linux/mm/folio_size.h
create mode 100644 include/linux/mm/folio_usage.h
create mode 100644 include/linux/mm/folio_zone.h
create mode 100644 include/linux/mm/high_memory.h
create mode 100644 include/linux/mm/page_address.h
create mode 100644 include/linux/mm/page_kasan_tag.h
create mode 100644 include/linux/mm/page_section.h
create mode 100644 include/linux/mm/pfmemalloc.h
create mode 100644 include/linux/mm/vmalloc_addr.h

--
2.39.2



2024-04-30 15:30:32

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 04/15] linux/mm.h: move page_kasan_tag() to mm/page_kasan_tag.h

Prepare to reduce dependencies on linux/mm.h.

page_kasan_tag() is used by the page_to_virt() macro in ARM64 (but
asm/memory.h does not include linux/mm.h). Thus, in order to be able to use
anything that calls page_to_virt(), linux/mm.h needs to be included.

This would prevent us from moving page_address() to a separate header,
because it calls lowmem_page_address() which in turn calls
page_to_virt(). To prepare for this move, we move page_kasan_tag()
out of linux/mm.h into a separate lean header.

A side effect of this patch is that the <linux/kasan.h> include line
is moved inside the "#ifdef CONFIG_KASAN..." block, i.e. it is not
included at all if KASAN is disabled.

Signed-off-by: Max Kellermann <[email protected]>
---
MAINTAINERS | 1 +
include/linux/mm.h | 56 +-------------------------
include/linux/mm/page_kasan_tag.h | 66 +++++++++++++++++++++++++++++++
3 files changed, 68 insertions(+), 55 deletions(-)
create mode 100644 include/linux/mm/page_kasan_tag.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 1c4bc4b4e388..512f67555853 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14380,6 +14380,7 @@ F: include/linux/mempolicy.h
F: include/linux/mempool.h
F: include/linux/memremap.h
F: include/linux/mm.h
+F: include/linux/mm/*.h
F: include/linux/mm_*.h
F: include/linux/mmzone.h
F: include/linux/mmu_notifier.h
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9849dfda44d4..4a176690ab95 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2,6 +2,7 @@
#ifndef _LINUX_MM_H
#define _LINUX_MM_H

+#include <linux/mm/page_kasan_tag.h>
#include <linux/errno.h>
#include <linux/mmdebug.h>
#include <linux/gfp.h>
@@ -28,7 +29,6 @@
#include <linux/sizes.h>
#include <linux/sched.h>
#include <linux/pgtable.h>
-#include <linux/kasan.h>
#include <linux/memremap.h>
#include <linux/slab.h>

@@ -1820,60 +1820,6 @@ static inline void vma_set_access_pid_bit(struct vm_area_struct *vma)
}
#endif /* CONFIG_NUMA_BALANCING */

-#if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS)
-
-/*
- * KASAN per-page tags are stored xor'ed with 0xff. This allows to avoid
- * setting tags for all pages to native kernel tag value 0xff, as the default
- * value 0x00 maps to 0xff.
- */
-
-static inline u8 page_kasan_tag(const struct page *page)
-{
- u8 tag = KASAN_TAG_KERNEL;
-
- if (kasan_enabled()) {
- tag = (page->flags >> KASAN_TAG_PGSHIFT) & KASAN_TAG_MASK;
- tag ^= 0xff;
- }
-
- return tag;
-}
-
-static inline void page_kasan_tag_set(struct page *page, u8 tag)
-{
- unsigned long old_flags, flags;
-
- if (!kasan_enabled())
- return;
-
- tag ^= 0xff;
- old_flags = READ_ONCE(page->flags);
- do {
- flags = old_flags;
- flags &= ~(KASAN_TAG_MASK << KASAN_TAG_PGSHIFT);
- flags |= (tag & KASAN_TAG_MASK) << KASAN_TAG_PGSHIFT;
- } while (unlikely(!try_cmpxchg(&page->flags, &old_flags, flags)));
-}
-
-static inline void page_kasan_tag_reset(struct page *page)
-{
- if (kasan_enabled())
- page_kasan_tag_set(page, KASAN_TAG_KERNEL);
-}
-
-#else /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */
-
-static inline u8 page_kasan_tag(const struct page *page)
-{
- return 0xff;
-}
-
-static inline void page_kasan_tag_set(struct page *page, u8 tag) { }
-static inline void page_kasan_tag_reset(struct page *page) { }
-
-#endif /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */
-
static inline struct zone *page_zone(const struct page *page)
{
return &NODE_DATA(page_to_nid(page))->node_zones[page_zonenum(page)];
diff --git a/include/linux/mm/page_kasan_tag.h b/include/linux/mm/page_kasan_tag.h
new file mode 100644
index 000000000000..1210c62170a3
--- /dev/null
+++ b/include/linux/mm/page_kasan_tag.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_PAGE_KASAN_TAG_H
+#define _LINUX_MM_PAGE_KASAN_TAG_H
+
+#include <linux/types.h>
+
+struct page;
+
+#if defined(CONFIG_KASAN_SW_TAGS) || defined(CONFIG_KASAN_HW_TAGS)
+
+#include <linux/kasan.h>
+#include <linux/mm_types.h> // for struct page
+
+/*
+ * KASAN per-page tags are stored xor'ed with 0xff. This allows to avoid
+ * setting tags for all pages to native kernel tag value 0xff, as the default
+ * value 0x00 maps to 0xff.
+ */
+
+static inline u8 page_kasan_tag(const struct page *page)
+{
+ u8 tag = KASAN_TAG_KERNEL;
+
+ if (kasan_enabled()) {
+ tag = (page->flags >> KASAN_TAG_PGSHIFT) & KASAN_TAG_MASK;
+ tag ^= 0xff;
+ }
+
+ return tag;
+}
+
+static inline void page_kasan_tag_set(struct page *page, u8 tag)
+{
+ unsigned long old_flags, flags;
+
+ if (!kasan_enabled())
+ return;
+
+ tag ^= 0xff;
+ old_flags = READ_ONCE(page->flags);
+ do {
+ flags = old_flags;
+ flags &= ~(KASAN_TAG_MASK << KASAN_TAG_PGSHIFT);
+ flags |= (tag & KASAN_TAG_MASK) << KASAN_TAG_PGSHIFT;
+ } while (unlikely(!try_cmpxchg(&page->flags, &old_flags, flags)));
+}
+
+static inline void page_kasan_tag_reset(struct page *page)
+{
+ if (kasan_enabled())
+ page_kasan_tag_set(page, KASAN_TAG_KERNEL);
+}
+
+#else /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */
+
+static inline u8 page_kasan_tag(const struct page *page)
+{
+ return 0xff;
+}
+
+static inline void page_kasan_tag_set(struct page *page, u8 tag) { }
+static inline void page_kasan_tag_reset(struct page *page) { }
+
+#endif /* CONFIG_KASAN_SW_TAGS || CONFIG_KASAN_HW_TAGS */
+
+#endif /* _LINUX_MM_PAGE_KASAN_TAG_H */
--
2.39.2


2024-04-30 15:30:37

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 02/15] include/drm/drm_gem.h: add poll_table_struct forward declaration

After eliminating includes of linux/mm.h, the following build failure
occurred:

./include/drm/drm_file.h:443:45: warning: ‘struct poll_table_struct’ declared inside parameter list will not be visible outside of this definition or declaration
443 | __poll_t drm_poll(struct file *filp, struct poll_table_struct *wait);
| ^~~~~~~~~~~~~~~~~
In file included from drivers/gpu/drm/imagination/pvr_gem.h:12,
from drivers/gpu/drm/imagination/pvr_fw.h:9:
./include/drm/drm_gem.h:447:27: error: initialization of ‘__poll_t (*)(struct file *, struct poll_table_struct *)’ {aka ‘unsigned int (*)(struct file *, struct poll_table_struct *)’} from incompatible pointer type ‘__poll_t (*)(struct file *, struct poll_table_struct *)’ {aka ‘unsigned int (*)(struct file *, struct poll_table_struct *)’} [-Werror=incompatible-pointer-types]
447 | .poll = drm_poll,\
| ^~~~~~~~

The compiler is confused, and that can be fixed easily by
forward-declaring the struct expicitly.

Signed-off-by: Max Kellermann <[email protected]>
---
include/drm/drm_file.h | 1 +
1 file changed, 1 insertion(+)

diff --git a/include/drm/drm_file.h b/include/drm/drm_file.h
index ab230d3af138..f24ade9f766f 100644
--- a/include/drm/drm_file.h
+++ b/include/drm/drm_file.h
@@ -44,6 +44,7 @@ struct drm_device;
struct drm_printer;
struct device;
struct file;
+struct poll_table_struct;

/*
* FIXME: Not sure we want to have drm_minor here in the end, but to avoid
--
2.39.2


2024-04-30 15:31:13

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 06/15] linux/mm.h: move page_address() and others to mm/page_address.h

Prepare to reduce dependencies on linux/mm.h.

page_address() is used by the following popular headers:

- linux/bio.h
- linux/bvec.h
- linux/highmem.h
- linux/scatterlist.h
- linux/skbuff.h

Moving it to a separate lean header will allow us to avoid the
dependency on linux/mm.h.

Signed-off-by: Max Kellermann <[email protected]>
---
include/linux/mm.h | 56 +-------------------------
include/linux/mm/page_address.h | 71 +++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+), 55 deletions(-)
create mode 100644 include/linux/mm/page_address.h

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 84013f24a6a7..0dea734194aa 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2,7 +2,7 @@
#ifndef _LINUX_MM_H
#define _LINUX_MM_H

-#include <linux/mm/page_kasan_tag.h>
+#include <linux/mm/page_address.h>
#include <linux/mm/page_section.h>
#include <linux/errno.h>
#include <linux/mmdebug.h>
@@ -105,10 +105,6 @@ extern int mmap_rnd_compat_bits __read_mostly;
#define __pa_symbol(x) __pa(RELOC_HIDE((unsigned long)(x), 0))
#endif

-#ifndef page_to_virt
-#define page_to_virt(x) __va(PFN_PHYS(page_to_pfn(x)))
-#endif
-
#ifndef lm_alias
#define lm_alias(x) __va(__pa_symbol(x))
#endif
@@ -212,14 +208,6 @@ int overcommit_kbytes_handler(struct ctl_table *, int, void *, size_t *,
int overcommit_policy_handler(struct ctl_table *, int, void *, size_t *,
loff_t *);

-#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
-#define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n))
-#define folio_page_idx(folio, p) (page_to_pfn(p) - folio_pfn(folio))
-#else
-#define nth_page(page,n) ((page) + (n))
-#define folio_page_idx(folio, p) ((p) - &(folio)->page)
-#endif
-
/* to align the pointer to the (next) page boundary */
#define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE)

@@ -2182,44 +2170,6 @@ static inline int arch_make_folio_accessible(struct folio *folio)
*/
#include <linux/vmstat.h>

-#if defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL)
-#define HASHED_PAGE_VIRTUAL
-#endif
-
-#if defined(WANT_PAGE_VIRTUAL)
-static inline void *page_address(const struct page *page)
-{
- return page->virtual;
-}
-static inline void set_page_address(struct page *page, void *address)
-{
- page->virtual = address;
-}
-#define page_address_init() do { } while(0)
-#endif
-
-#if defined(HASHED_PAGE_VIRTUAL)
-void *page_address(const struct page *page);
-void set_page_address(struct page *page, void *virtual);
-void page_address_init(void);
-#endif
-
-static __always_inline void *lowmem_page_address(const struct page *page)
-{
- return page_to_virt(page);
-}
-
-#if !defined(HASHED_PAGE_VIRTUAL) && !defined(WANT_PAGE_VIRTUAL)
-#define page_address(page) lowmem_page_address(page)
-#define set_page_address(page, address) do { } while(0)
-#define page_address_init() do { } while(0)
-#endif
-
-static inline void *folio_address(const struct folio *folio)
-{
- return page_address(&folio->page);
-}
-
extern pgoff_t __page_file_index(struct page *page);

/*
@@ -2282,10 +2232,6 @@ static inline void clear_page_pfmemalloc(struct page *page)
*/
extern void pagefault_out_of_memory(void);

-#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
-#define offset_in_thp(page, p) ((unsigned long)(p) & (thp_size(page) - 1))
-#define offset_in_folio(folio, p) ((unsigned long)(p) & (folio_size(folio) - 1))
-
/*
* Parameter block passed down to zap_pte_range in exceptional cases.
*/
diff --git a/include/linux/mm/page_address.h b/include/linux/mm/page_address.h
new file mode 100644
index 000000000000..630fc4e2be95
--- /dev/null
+++ b/include/linux/mm/page_address.h
@@ -0,0 +1,71 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_PAGE_ADDRESS_H
+#define _LINUX_MM_PAGE_ADDRESS_H
+
+#include <linux/mm_types.h> // for struct page
+#include <linux/mm/page_kasan_tag.h> // needed by the page_to_virt() macro on some architectures (e.g. arm64)
+#include <asm/page.h> // for PAGE_MASK, page_to_virt()
+
+#if defined(CONFIG_FLATMEM)
+#include <linux/mmzone.h> // for memmap (used by __pfn_to_page())
+#elif defined(CONFIG_SPARSEMEM_VMEMMAP)
+#include <asm/pgtable.h> // for vmemmap (used by __pfn_to_page())
+#elif defined(CONFIG_SPARSEMEM)
+#include <linux/mm/page_section.h> // for page_to_section() (used by __page_to_pfn())
+#endif
+
+#ifndef page_to_virt
+#define page_to_virt(x) __va(PFN_PHYS(page_to_pfn(x)))
+#endif
+
+#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
+#define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n))
+#define folio_page_idx(folio, p) (page_to_pfn(p) - folio_pfn(folio))
+#else
+#define nth_page(page,n) ((page) + (n))
+#define folio_page_idx(folio, p) ((p) - &(folio)->page)
+#endif
+
+#if defined(CONFIG_HIGHMEM) && !defined(WANT_PAGE_VIRTUAL)
+#define HASHED_PAGE_VIRTUAL
+#endif
+
+#if defined(WANT_PAGE_VIRTUAL)
+static inline void *page_address(const struct page *page)
+{
+ return page->virtual;
+}
+static inline void set_page_address(struct page *page, void *address)
+{
+ page->virtual = address;
+}
+#define page_address_init() do { } while(0)
+#endif
+
+#if defined(HASHED_PAGE_VIRTUAL)
+void *page_address(const struct page *page);
+void set_page_address(struct page *page, void *virtual);
+void page_address_init(void);
+#endif
+
+static __always_inline void *lowmem_page_address(const struct page *page)
+{
+ return page_to_virt(page);
+}
+
+#if !defined(HASHED_PAGE_VIRTUAL) && !defined(WANT_PAGE_VIRTUAL)
+#define page_address(page) lowmem_page_address(page)
+#define set_page_address(page, address) do { } while(0)
+#define page_address_init() do { } while(0)
+#endif
+
+static inline void *folio_address(const struct folio *folio)
+{
+ return page_address(&folio->page);
+}
+
+#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK)
+#define offset_in_thp(page, p) ((unsigned long)(p) & (thp_size(page) - 1))
+#define offset_in_folio(folio, p) ((unsigned long)(p) & (folio_size(folio) - 1))
+
+#endif /* _LINUX_MM_PAGE_ADDRESS_H */
--
2.39.2


2024-04-30 15:40:26

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 09/15] linux/mm.h: move devmap-related declarations to mm/devmap_managed.h

Prepare to reduce dependencies on linux/mm.h.

put_devmap_managed_page() is called by put_page(). Moving it to a
separate header allows us to move put_page() to a separate lean header
as well.

Signed-off-by: Max Kellermann <[email protected]>
---
include/linux/mm.h | 20 +------------------
include/linux/mm/devmap_managed.h | 32 +++++++++++++++++++++++++++++++
2 files changed, 33 insertions(+), 19 deletions(-)
create mode 100644 include/linux/mm/devmap_managed.h

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 5b3d56454344..9539ba12b99d 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2,6 +2,7 @@
#ifndef _LINUX_MM_H
#define _LINUX_MM_H

+#include <linux/mm/devmap_managed.h>
#include <linux/mm/folio_next.h>
#include <linux/mm/folio_size.h>
#include <linux/mm/page_address.h>
@@ -1364,25 +1365,6 @@ vm_fault_t finish_fault(struct vm_fault *vmf);
* back into memory.
*/

-#if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_FS_DAX)
-DECLARE_STATIC_KEY_FALSE(devmap_managed_key);
-
-bool __put_devmap_managed_folio_refs(struct folio *folio, int refs);
-static inline bool put_devmap_managed_folio_refs(struct folio *folio, int refs)
-{
- if (!static_branch_unlikely(&devmap_managed_key))
- return false;
- if (!folio_is_zone_device(folio))
- return false;
- return __put_devmap_managed_folio_refs(folio, refs);
-}
-#else /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */
-static inline bool put_devmap_managed_folio_refs(struct folio *folio, int refs)
-{
- return false;
-}
-#endif /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */
-
/* 127: arbitrary random number, small enough to assemble well */
#define folio_ref_zero_or_close_to_overflow(folio) \
((unsigned int) folio_ref_count(folio) + 127u <= 127u)
diff --git a/include/linux/mm/devmap_managed.h b/include/linux/mm/devmap_managed.h
new file mode 100644
index 000000000000..50357b304d68
--- /dev/null
+++ b/include/linux/mm/devmap_managed.h
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_DEVMAP_MANAGED_H
+#define _LINUX_MM_DEVMAP_MANAGED_H
+
+#include <linux/types.h> // for bool
+
+struct page;
+
+#if defined(CONFIG_ZONE_DEVICE) && defined(CONFIG_FS_DAX)
+
+#include <linux/jump_label.h> // for DECLARE_STATIC_KEY_FALSE(), static_branch_unlikely()
+#include <linux/mmzone.h> // folio_is_zone_device()
+
+DECLARE_STATIC_KEY_FALSE(devmap_managed_key);
+
+bool __put_devmap_managed_folio_refs(struct folio *folio, int refs);
+static inline bool put_devmap_managed_folio_refs(struct folio *folio, int refs)
+{
+ if (!static_branch_unlikely(&devmap_managed_key))
+ return false;
+ if (!folio_is_zone_device(folio))
+ return false;
+ return __put_devmap_managed_folio_refs(folio, refs);
+}
+#else /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */
+static inline bool put_devmap_managed_folio_refs(struct folio *folio, int refs)
+{
+ return false;
+}
+#endif /* CONFIG_ZONE_DEVICE && CONFIG_FS_DAX */
+
+#endif /* _LINUX_MM_DEVMAP_MANAGED_H */
--
2.39.2


2024-04-30 15:41:52

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 11/15] linux/mm.h: move page_zone_id() and more to mm/folio_zone.h

This is needed to eliminate linux/skbuff.h's dependency on linux/mm.h.

Signed-off-by: Max Kellermann <[email protected]>
---
include/linux/mm.h | 48 +-----------------------------
include/linux/mm/folio_zone.h | 56 +++++++++++++++++++++++++++++++++++
2 files changed, 57 insertions(+), 47 deletions(-)
create mode 100644 include/linux/mm/folio_zone.h

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 035e56e203df..7af85220711c 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -5,6 +5,7 @@
#include <linux/mm/folio_next.h>
#include <linux/mm/folio_size.h>
#include <linux/mm/folio_usage.h>
+#include <linux/mm/folio_zone.h>
#include <linux/mm/page_address.h>
#include <linux/mm/page_section.h>
#include <linux/errno.h>
@@ -1377,33 +1378,6 @@ static inline bool is_nommu_shared_mapping(vm_flags_t flags)
}
#endif

-/*
- * The identification function is mainly used by the buddy allocator for
- * determining if two pages could be buddies. We are not really identifying
- * the zone since we could be using the section number id if we do not have
- * node id available in page flags.
- * We only guarantee that it will return the same value for two combinable
- * pages in a zone.
- */
-static inline int page_zone_id(struct page *page)
-{
- return (page->flags >> ZONEID_PGSHIFT) & ZONEID_MASK;
-}
-
-#ifdef NODE_NOT_IN_PAGE_FLAGS
-int page_to_nid(const struct page *page);
-#else
-static inline int page_to_nid(const struct page *page)
-{
- return (PF_POISONED_CHECK(page)->flags >> NODES_PGSHIFT) & NODES_MASK;
-}
-#endif
-
-static inline int folio_nid(const struct folio *folio)
-{
- return page_to_nid(&folio->page);
-}
-
#ifdef CONFIG_NUMA_BALANCING
/* page access time bits needs to hold at least 4 seconds */
#define PAGE_ACCESS_TIME_MIN_BITS 12
@@ -1554,26 +1528,6 @@ static inline void vma_set_access_pid_bit(struct vm_area_struct *vma)
}
#endif /* CONFIG_NUMA_BALANCING */

-static inline struct zone *page_zone(const struct page *page)
-{
- return &NODE_DATA(page_to_nid(page))->node_zones[page_zonenum(page)];
-}
-
-static inline pg_data_t *page_pgdat(const struct page *page)
-{
- return NODE_DATA(page_to_nid(page));
-}
-
-static inline struct zone *folio_zone(const struct folio *folio)
-{
- return page_zone(&folio->page);
-}
-
-static inline pg_data_t *folio_pgdat(const struct folio *folio)
-{
- return page_pgdat(&folio->page);
-}
-
/**
* folio_pfn - Return the Page Frame Number of a folio.
* @folio: The folio.
diff --git a/include/linux/mm/folio_zone.h b/include/linux/mm/folio_zone.h
new file mode 100644
index 000000000000..3f3e4284b911
--- /dev/null
+++ b/include/linux/mm/folio_zone.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_FOLIO_ZONE_H
+#define _LINUX_MM_FOLIO_ZONE_H
+
+#include <linux/mm_types.h> // for struct page, struct folio
+#include <linux/mmzone.h> // for ZONEID_*, NODES_*
+#include <linux/page-flags.h> // for PF_POISONED_CHECK()
+
+/*
+ * The identification function is mainly used by the buddy allocator for
+ * determining if two pages could be buddies. We are not really identifying
+ * the zone since we could be using the section number id if we do not have
+ * node id available in page flags.
+ * We only guarantee that it will return the same value for two combinable
+ * pages in a zone.
+ */
+static inline int page_zone_id(struct page *page)
+{
+ return (page->flags >> ZONEID_PGSHIFT) & ZONEID_MASK;
+}
+
+#ifdef NODE_NOT_IN_PAGE_FLAGS
+int page_to_nid(const struct page *page);
+#else
+static inline int page_to_nid(const struct page *page)
+{
+ return (PF_POISONED_CHECK(page)->flags >> NODES_PGSHIFT) & NODES_MASK;
+}
+#endif
+
+static inline int folio_nid(const struct folio *folio)
+{
+ return page_to_nid(&folio->page);
+}
+
+static inline struct zone *page_zone(const struct page *page)
+{
+ return &NODE_DATA(page_to_nid(page))->node_zones[page_zonenum(page)];
+}
+
+static inline pg_data_t *page_pgdat(const struct page *page)
+{
+ return NODE_DATA(page_to_nid(page));
+}
+
+static inline struct zone *folio_zone(const struct folio *folio)
+{
+ return page_zone(&folio->page);
+}
+
+static inline pg_data_t *folio_pgdat(const struct folio *folio)
+{
+ return page_pgdat(&folio->page);
+}
+
+#endif /* _LINUX_MM_FOLIO_ZONE_H */
--
2.39.2


2024-04-30 15:41:57

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 10/15] linux/mm.h: move usage count functions to mm/folio_usage.h

Prepare to reduce dependencies on linux/mm.h.

This new header contains wrappers for the low-level functions from
page_ref.h. By having those higher-level functions in a separate
header, we can avoid their additional dependencies in the page_ref.h.

Having these in a separate header will allow eliminating the
dependency on linux/mm.h from these headers:

- linux/skbuff.h
- linux/swap.h

Signed-off-by: Max Kellermann <[email protected]>
---
include/linux/mm.h | 172 +------------------------------
include/linux/mm/folio_usage.h | 182 +++++++++++++++++++++++++++++++++
2 files changed, 183 insertions(+), 171 deletions(-)
create mode 100644 include/linux/mm/folio_usage.h

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 9539ba12b99d..035e56e203df 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2,9 +2,9 @@
#ifndef _LINUX_MM_H
#define _LINUX_MM_H

-#include <linux/mm/devmap_managed.h>
#include <linux/mm/folio_next.h>
#include <linux/mm/folio_size.h>
+#include <linux/mm/folio_usage.h>
#include <linux/mm/page_address.h>
#include <linux/mm/page_section.h>
#include <linux/errno.h>
@@ -1074,51 +1074,6 @@ struct inode;

#include <linux/huge_mm.h>

-/*
- * Methods to modify the page usage count.
- *
- * What counts for a page usage:
- * - cache mapping (page->mapping)
- * - private data (page->private)
- * - page mapped in a task's page tables, each mapping
- * is counted separately
- *
- * Also, many kernel routines increase the page count before a critical
- * routine so they can be sure the page doesn't go away from under them.
- */
-
-/*
- * Drop a ref, return true if the refcount fell to zero (the page has no users)
- */
-static inline int put_page_testzero(struct page *page)
-{
- VM_BUG_ON_PAGE(page_ref_count(page) == 0, page);
- return page_ref_dec_and_test(page);
-}
-
-static inline int folio_put_testzero(struct folio *folio)
-{
- return put_page_testzero(&folio->page);
-}
-
-/*
- * Try to grab a ref unless the page has a refcount of zero, return false if
- * that is the case.
- * This can be called when MMU is off so it must not access
- * any of the virtual mappings.
- */
-static inline bool get_page_unless_zero(struct page *page)
-{
- return page_ref_add_unless(page, 1, 0);
-}
-
-static inline struct folio *folio_get_nontail_page(struct page *page)
-{
- if (unlikely(!get_page_unless_zero(page)))
- return NULL;
- return (struct folio *)page;
-}
-
extern int page_is_ram(unsigned long pfn);

enum {
@@ -1275,8 +1230,6 @@ static inline struct folio *virt_to_folio(const void *x)
return page_folio(page);
}

-void __folio_put(struct folio *folio);
-
void put_pages_list(struct list_head *pages);

void split_page(struct page *page, unsigned int order);
@@ -1365,129 +1318,6 @@ vm_fault_t finish_fault(struct vm_fault *vmf);
* back into memory.
*/

-/* 127: arbitrary random number, small enough to assemble well */
-#define folio_ref_zero_or_close_to_overflow(folio) \
- ((unsigned int) folio_ref_count(folio) + 127u <= 127u)
-
-/**
- * folio_get - Increment the reference count on a folio.
- * @folio: The folio.
- *
- * Context: May be called in any context, as long as you know that
- * you have a refcount on the folio. If you do not already have one,
- * folio_try_get() may be the right interface for you to use.
- */
-static inline void folio_get(struct folio *folio)
-{
- VM_BUG_ON_FOLIO(folio_ref_zero_or_close_to_overflow(folio), folio);
- folio_ref_inc(folio);
-}
-
-static inline void get_page(struct page *page)
-{
- folio_get(page_folio(page));
-}
-
-static inline __must_check bool try_get_page(struct page *page)
-{
- page = compound_head(page);
- if (WARN_ON_ONCE(page_ref_count(page) <= 0))
- return false;
- page_ref_inc(page);
- return true;
-}
-
-/**
- * folio_put - Decrement the reference count on a folio.
- * @folio: The folio.
- *
- * If the folio's reference count reaches zero, the memory will be
- * released back to the page allocator and may be used by another
- * allocation immediately. Do not access the memory or the struct folio
- * after calling folio_put() unless you can be sure that it wasn't the
- * last reference.
- *
- * Context: May be called in process or interrupt context, but not in NMI
- * context. May be called while holding a spinlock.
- */
-static inline void folio_put(struct folio *folio)
-{
- if (folio_put_testzero(folio))
- __folio_put(folio);
-}
-
-/**
- * folio_put_refs - Reduce the reference count on a folio.
- * @folio: The folio.
- * @refs: The amount to subtract from the folio's reference count.
- *
- * If the folio's reference count reaches zero, the memory will be
- * released back to the page allocator and may be used by another
- * allocation immediately. Do not access the memory or the struct folio
- * after calling folio_put_refs() unless you can be sure that these weren't
- * the last references.
- *
- * Context: May be called in process or interrupt context, but not in NMI
- * context. May be called while holding a spinlock.
- */
-static inline void folio_put_refs(struct folio *folio, int refs)
-{
- if (folio_ref_sub_and_test(folio, refs))
- __folio_put(folio);
-}
-
-void folios_put_refs(struct folio_batch *folios, unsigned int *refs);
-
-/*
- * union release_pages_arg - an array of pages or folios
- *
- * release_pages() releases a simple array of multiple pages, and
- * accepts various different forms of said page array: either
- * a regular old boring array of pages, an array of folios, or
- * an array of encoded page pointers.
- *
- * The transparent union syntax for this kind of "any of these
- * argument types" is all kinds of ugly, so look away.
- */
-typedef union {
- struct page **pages;
- struct folio **folios;
- struct encoded_page **encoded_pages;
-} release_pages_arg __attribute__ ((__transparent_union__));
-
-void release_pages(release_pages_arg, int nr);
-
-/**
- * folios_put - Decrement the reference count on an array of folios.
- * @folios: The folios.
- *
- * Like folio_put(), but for a batch of folios. This is more efficient
- * than writing the loop yourself as it will optimise the locks which need
- * to be taken if the folios are freed. The folios batch is returned
- * empty and ready to be reused for another batch; there is no need to
- * reinitialise it.
- *
- * Context: May be called in process or interrupt context, but not in NMI
- * context. May be called while holding a spinlock.
- */
-static inline void folios_put(struct folio_batch *folios)
-{
- folios_put_refs(folios, NULL);
-}
-
-static inline void put_page(struct page *page)
-{
- struct folio *folio = page_folio(page);
-
- /*
- * For some devmap managed pages we need to catch refcount transition
- * from 2 to 1:
- */
- if (put_devmap_managed_folio_refs(folio, 1))
- return;
- folio_put(folio);
-}
-
/*
* GUP_PIN_COUNTING_BIAS, and the associated functions that use it, overload
* the page's refcount so that two separate items are tracked: the original page
diff --git a/include/linux/mm/folio_usage.h b/include/linux/mm/folio_usage.h
new file mode 100644
index 000000000000..1cf11ca1f5ab
--- /dev/null
+++ b/include/linux/mm/folio_usage.h
@@ -0,0 +1,182 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_FOLIO_USAGE_H
+#define _LINUX_MM_FOLIO_USAGE_H
+
+#include <linux/mm/devmap_managed.h> // for put_devmap_managed_page()
+#include <linux/mmdebug.h> // for VM_BUG_ON_PAGE()
+#include <linux/mm_types.h> // for struct folio
+#include <linux/page_ref.h>
+
+struct folio_batch;
+
+/*
+ * Methods to modify the page usage count.
+ *
+ * What counts for a page usage:
+ * - cache mapping (page->mapping)
+ * - private data (page->private)
+ * - page mapped in a task's page tables, each mapping
+ * is counted separately
+ *
+ * Also, many kernel routines increase the page count before a critical
+ * routine so they can be sure the page doesn't go away from under them.
+ */
+
+/*
+ * Drop a ref, return true if the refcount fell to zero (the page has no users)
+ */
+static inline int put_page_testzero(struct page *page)
+{
+ VM_BUG_ON_PAGE(page_ref_count(page) == 0, page);
+ return page_ref_dec_and_test(page);
+}
+
+static inline int folio_put_testzero(struct folio *folio)
+{
+ return put_page_testzero(&folio->page);
+}
+
+/*
+ * Try to grab a ref unless the page has a refcount of zero, return false if
+ * that is the case.
+ * This can be called when MMU is off so it must not access
+ * any of the virtual mappings.
+ */
+static inline bool get_page_unless_zero(struct page *page)
+{
+ return page_ref_add_unless(page, 1, 0);
+}
+
+static inline struct folio *folio_get_nontail_page(struct page *page)
+{
+ if (unlikely(!get_page_unless_zero(page)))
+ return NULL;
+ return (struct folio *)page;
+}
+
+void __folio_put(struct folio *folio);
+
+/* 127: arbitrary random number, small enough to assemble well */
+#define folio_ref_zero_or_close_to_overflow(folio) \
+ ((unsigned int) folio_ref_count(folio) + 127u <= 127u)
+
+/**
+ * folio_get - Increment the reference count on a folio.
+ * @folio: The folio.
+ *
+ * Context: May be called in any context, as long as you know that
+ * you have a refcount on the folio. If you do not already have one,
+ * folio_try_get() may be the right interface for you to use.
+ */
+static inline void folio_get(struct folio *folio)
+{
+ VM_BUG_ON_FOLIO(folio_ref_zero_or_close_to_overflow(folio), folio);
+ folio_ref_inc(folio);
+}
+
+static inline void get_page(struct page *page)
+{
+ folio_get(page_folio(page));
+}
+
+static inline __must_check bool try_get_page(struct page *page)
+{
+ page = compound_head(page);
+ if (WARN_ON_ONCE(page_ref_count(page) <= 0))
+ return false;
+ page_ref_inc(page);
+ return true;
+}
+
+/**
+ * folio_put - Decrement the reference count on a folio.
+ * @folio: The folio.
+ *
+ * If the folio's reference count reaches zero, the memory will be
+ * released back to the page allocator and may be used by another
+ * allocation immediately. Do not access the memory or the struct folio
+ * after calling folio_put() unless you can be sure that it wasn't the
+ * last reference.
+ *
+ * Context: May be called in process or interrupt context, but not in NMI
+ * context. May be called while holding a spinlock.
+ */
+static inline void folio_put(struct folio *folio)
+{
+ if (folio_put_testzero(folio))
+ __folio_put(folio);
+}
+
+/**
+ * folio_put_refs - Reduce the reference count on a folio.
+ * @folio: The folio.
+ * @refs: The amount to subtract from the folio's reference count.
+ *
+ * If the folio's reference count reaches zero, the memory will be
+ * released back to the page allocator and may be used by another
+ * allocation immediately. Do not access the memory or the struct folio
+ * after calling folio_put_refs() unless you can be sure that these weren't
+ * the last references.
+ *
+ * Context: May be called in process or interrupt context, but not in NMI
+ * context. May be called while holding a spinlock.
+ */
+static inline void folio_put_refs(struct folio *folio, int refs)
+{
+ if (folio_ref_sub_and_test(folio, refs))
+ __folio_put(folio);
+}
+
+void folios_put_refs(struct folio_batch *folios, unsigned int *refs);
+
+/*
+ * union release_pages_arg - an array of pages or folios
+ *
+ * release_pages() releases a simple array of multiple pages, and
+ * accepts various different forms of said page array: either
+ * a regular old boring array of pages, an array of folios, or
+ * an array of encoded page pointers.
+ *
+ * The transparent union syntax for this kind of "any of these
+ * argument types" is all kinds of ugly, so look away.
+ */
+typedef union {
+ struct page **pages;
+ struct folio **folios;
+ struct encoded_page **encoded_pages;
+} release_pages_arg __attribute__ ((__transparent_union__));
+
+void release_pages(release_pages_arg, int nr);
+
+/**
+ * folios_put - Decrement the reference count on an array of folios.
+ * @folios: The folios.
+ *
+ * Like folio_put(), but for a batch of folios. This is more efficient
+ * than writing the loop yourself as it will optimise the locks which need
+ * to be taken if the folios are freed. The folios batch is returned
+ * empty and ready to be reused for another batch; there is no need to
+ * reinitialise it.
+ *
+ * Context: May be called in process or interrupt context, but not in NMI
+ * context. May be called while holding a spinlock.
+ */
+static inline void folios_put(struct folio_batch *folios)
+{
+ folios_put_refs(folios, NULL);
+}
+
+static inline void put_page(struct page *page)
+{
+ struct folio *folio = page_folio(page);
+
+ /*
+ * For some devmap managed pages we need to catch refcount transition
+ * from 2 to 1:
+ */
+ if (put_devmap_managed_folio_refs(folio, 1))
+ return;
+ folio_put(folio);
+}
+
+#endif /* _LINUX_MM_FOLIO_USAGE_H */
--
2.39.2


2024-04-30 15:42:14

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 14/15] linux/mm.h: move high_memory to mm/high_memory.h

This variable is used by lots of arch/*/include/asm/ headers, but
these do not (and should not) include the huge linux/mm.h header.
Let's move this "extern" variable to a separate header and include
this one in arch/.

Signed-off-by: Max Kellermann <[email protected]>
---
arch/arm/include/asm/memory.h | 4 ++++
arch/arm/include/asm/pgtable.h | 2 ++
arch/csky/include/asm/page.h | 1 +
arch/hexagon/include/asm/mem-layout.h | 4 ++++
arch/m68k/include/asm/page_mm.h | 1 +
arch/m68k/include/asm/pgtable_mm.h | 1 +
arch/parisc/include/asm/floppy.h | 1 +
arch/powerpc/include/asm/book3s/32/pgtable.h | 4 ++++
arch/powerpc/include/asm/nohash/32/pgtable.h | 1 +
arch/powerpc/include/asm/page.h | 1 +
arch/x86/include/asm/floppy.h | 1 +
arch/x86/include/asm/pgtable_32_areas.h | 4 ++++
drivers/mtd/nand/onenand/onenand_samsung.c | 1 +
include/linux/mm.h | 2 +-
include/linux/mm/high_memory.h | 7 +++++++
15 files changed, 34 insertions(+), 1 deletion(-)
create mode 100644 include/linux/mm/high_memory.h

diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index ef2aa79ece5a..a67afb213e2e 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -387,6 +387,10 @@ static inline unsigned long __virt_to_idmap(unsigned long x)
*/
#define ARCH_PFN_OFFSET PHYS_PFN_OFFSET

+#ifndef __ASSEMBLY__
+#include <linux/mm/high_memory.h>
+#endif
+
#define virt_to_page(kaddr) pfn_to_page(virt_to_pfn(kaddr))
#define virt_addr_valid(kaddr) (((unsigned long)(kaddr) >= PAGE_OFFSET && (unsigned long)(kaddr) < (unsigned long)high_memory) \
&& pfn_valid(virt_to_pfn(kaddr)))
diff --git a/arch/arm/include/asm/pgtable.h b/arch/arm/include/asm/pgtable.h
index be91e376df79..eb80f6a65619 100644
--- a/arch/arm/include/asm/pgtable.h
+++ b/arch/arm/include/asm/pgtable.h
@@ -11,6 +11,8 @@
#include <asm/proc-fns.h>

#ifndef __ASSEMBLY__
+#include <linux/mm/high_memory.h>
+
/*
* ZERO_PAGE is a global shared page that is always zero: used
* for zero-mapped memory areas etc..
diff --git a/arch/csky/include/asm/page.h b/arch/csky/include/asm/page.h
index 0ca6c408c07f..17ccc91c3cd6 100644
--- a/arch/csky/include/asm/page.h
+++ b/arch/csky/include/asm/page.h
@@ -32,6 +32,7 @@

#ifndef __ASSEMBLY__

+#include <linux/mm/high_memory.h>
#include <linux/pfn.h>

#define virt_addr_valid(kaddr) ((void *)(kaddr) >= (void *)PAGE_OFFSET && \
diff --git a/arch/hexagon/include/asm/mem-layout.h b/arch/hexagon/include/asm/mem-layout.h
index e2f99413fe56..a09116c50043 100644
--- a/arch/hexagon/include/asm/mem-layout.h
+++ b/arch/hexagon/include/asm/mem-layout.h
@@ -10,6 +10,10 @@

#include <linux/const.h>

+#ifndef __ASSEMBLY__
+#include <linux/mm/high_memory.h>
+#endif
+
/*
* Have to do this for ginormous numbers, else they get printed as
* negative numbers, which the linker no likey when you try to
diff --git a/arch/m68k/include/asm/page_mm.h b/arch/m68k/include/asm/page_mm.h
index e0ae4d5fc985..f958655d1931 100644
--- a/arch/m68k/include/asm/page_mm.h
+++ b/arch/m68k/include/asm/page_mm.h
@@ -5,6 +5,7 @@
#ifndef __ASSEMBLY__

#include <linux/compiler.h>
+#include <linux/mm/high_memory.h>
#include <asm/module.h>

/*
diff --git a/arch/m68k/include/asm/pgtable_mm.h b/arch/m68k/include/asm/pgtable_mm.h
index dbdf1c2b2f66..ec593656bdc5 100644
--- a/arch/m68k/include/asm/pgtable_mm.h
+++ b/arch/m68k/include/asm/pgtable_mm.h
@@ -13,6 +13,7 @@

#ifndef __ASSEMBLY__
#include <asm/processor.h>
+#include <linux/mm/high_memory.h>
#include <linux/sched.h>
#include <linux/threads.h>

diff --git a/arch/parisc/include/asm/floppy.h b/arch/parisc/include/asm/floppy.h
index b318a7df52f6..98ed37c5dc59 100644
--- a/arch/parisc/include/asm/floppy.h
+++ b/arch/parisc/include/asm/floppy.h
@@ -8,6 +8,7 @@
#ifndef __ASM_PARISC_FLOPPY_H
#define __ASM_PARISC_FLOPPY_H

+#include <linux/mm/high_memory.h>
#include <linux/vmalloc.h>


diff --git a/arch/powerpc/include/asm/book3s/32/pgtable.h b/arch/powerpc/include/asm/book3s/32/pgtable.h
index 52971ee30717..03e0a32e1c2c 100644
--- a/arch/powerpc/include/asm/book3s/32/pgtable.h
+++ b/arch/powerpc/include/asm/book3s/32/pgtable.h
@@ -4,6 +4,10 @@

#include <asm-generic/pgtable-nopmd.h>

+#ifndef __ASSEMBLY__
+#include <linux/mm/high_memory.h>
+#endif
+
/*
* The "classic" 32-bit implementation of the PowerPC MMU uses a hash
* table containing PTEs, together with a set of 16 segment registers,
diff --git a/arch/powerpc/include/asm/nohash/32/pgtable.h b/arch/powerpc/include/asm/nohash/32/pgtable.h
index 9164a9e41b02..8a9f5b546e4a 100644
--- a/arch/powerpc/include/asm/nohash/32/pgtable.h
+++ b/arch/powerpc/include/asm/nohash/32/pgtable.h
@@ -5,6 +5,7 @@
#include <asm-generic/pgtable-nopmd.h>

#ifndef __ASSEMBLY__
+#include <linux/mm/high_memory.h>
#include <linux/sched.h>
#include <linux/threads.h>
#include <asm/mmu.h> /* For sub-arch specific PPC_PIN_SIZE */
diff --git a/arch/powerpc/include/asm/page.h b/arch/powerpc/include/asm/page.h
index e411e5a70ea3..9ae87fc2c648 100644
--- a/arch/powerpc/include/asm/page.h
+++ b/arch/powerpc/include/asm/page.h
@@ -7,6 +7,7 @@
*/

#ifndef __ASSEMBLY__
+#include <linux/mm/high_memory.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/bug.h>
diff --git a/arch/x86/include/asm/floppy.h b/arch/x86/include/asm/floppy.h
index 6ec3fc969ad5..7756e984f146 100644
--- a/arch/x86/include/asm/floppy.h
+++ b/arch/x86/include/asm/floppy.h
@@ -10,6 +10,7 @@
#ifndef _ASM_X86_FLOPPY_H
#define _ASM_X86_FLOPPY_H

+#include <linux/mm/high_memory.h>
#include <linux/vmalloc.h>

/*
diff --git a/arch/x86/include/asm/pgtable_32_areas.h b/arch/x86/include/asm/pgtable_32_areas.h
index b6355416a15a..b339137b4f4e 100644
--- a/arch/x86/include/asm/pgtable_32_areas.h
+++ b/arch/x86/include/asm/pgtable_32_areas.h
@@ -3,6 +3,10 @@

#include <asm/cpu_entry_area.h>

+#ifndef __ASSEMBLY__
+#include <linux/mm/high_memory.h>
+#endif
+
/*
* Just any arbitrary offset to the start of the vmalloc VM area: the
* current 8MB value just means that there will be a 8MB "hole" after the
diff --git a/drivers/mtd/nand/onenand/onenand_samsung.c b/drivers/mtd/nand/onenand/onenand_samsung.c
index fd6890a03d55..7c3cc270386d 100644
--- a/drivers/mtd/nand/onenand/onenand_samsung.c
+++ b/drivers/mtd/nand/onenand/onenand_samsung.c
@@ -15,6 +15,7 @@
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/mm/high_memory.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/onenand.h>
#include <linux/mtd/partitions.h>
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 5681fd5dbbbe..db6cc1e0900b 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -6,6 +6,7 @@
#include <linux/mm/folio_size.h>
#include <linux/mm/folio_usage.h>
#include <linux/mm/folio_zone.h>
+#include <linux/mm/high_memory.h>
#include <linux/mm/page_address.h>
#include <linux/mm/page_section.h>
#include <linux/mm/pfmemalloc.h>
@@ -83,7 +84,6 @@ static inline void totalram_pages_add(long count)
atomic_long_add(count, &_totalram_pages);
}

-extern void * high_memory;
extern int page_cluster;
extern const int page_cluster_max;

diff --git a/include/linux/mm/high_memory.h b/include/linux/mm/high_memory.h
new file mode 100644
index 000000000000..e504aafd0d48
--- /dev/null
+++ b/include/linux/mm/high_memory.h
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_HIGH_MEMORY_H
+#define _LINUX_MM_HIGH_MEMORY_H
+
+extern void * high_memory;
+
+#endif /* _LINUX_MM_HIGH_MEMORY_H */
--
2.39.2


2024-04-30 15:42:24

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 13/15] linux/mm.h: move is_vmalloc_addr() to mm/vmalloc_addr.h

This is needed to eliminate linux/dma-mapping.h's dependency on
linux/mm.h.

Signed-off-by: Max Kellermann <[email protected]>
---
include/linux/mm.h | 25 +------------------------
include/linux/mm/vmalloc_addr.h | 33 +++++++++++++++++++++++++++++++++
2 files changed, 34 insertions(+), 24 deletions(-)
create mode 100644 include/linux/mm/vmalloc_addr.h

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 046f960ef70e..5681fd5dbbbe 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -9,6 +9,7 @@
#include <linux/mm/page_address.h>
#include <linux/mm/page_section.h>
#include <linux/mm/pfmemalloc.h>
+#include <linux/mm/vmalloc_addr.h>
#include <linux/errno.h>
#include <linux/mmdebug.h>
#include <linux/gfp.h>
@@ -1087,30 +1088,6 @@ enum {
int region_intersects(resource_size_t offset, size_t size, unsigned long flags,
unsigned long desc);

-/* Support for virtually mapped pages */
-struct page *vmalloc_to_page(const void *addr);
-unsigned long vmalloc_to_pfn(const void *addr);
-
-/*
- * Determine if an address is within the vmalloc range
- *
- * On nommu, vmalloc/vfree wrap through kmalloc/kfree directly, so there
- * is no special casing required.
- */
-#ifdef CONFIG_MMU
-extern bool is_vmalloc_addr(const void *x);
-extern int is_vmalloc_or_module_addr(const void *x);
-#else
-static inline bool is_vmalloc_addr(const void *x)
-{
- return false;
-}
-static inline int is_vmalloc_or_module_addr(const void *x)
-{
- return 0;
-}
-#endif
-
/*
* How many times the entire folio is mapped as a single unit (eg by a
* PMD or PUD entry). This is probably not what you want, except for
diff --git a/include/linux/mm/vmalloc_addr.h b/include/linux/mm/vmalloc_addr.h
new file mode 100644
index 000000000000..86ad2dc94960
--- /dev/null
+++ b/include/linux/mm/vmalloc_addr.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_VMALLOC_ADDR_H
+#define _LINUX_MM_VMALLOC_ADDR_H
+
+#include <linux/types.h> // for bool
+
+struct page;
+
+/* Support for virtually mapped pages */
+struct page *vmalloc_to_page(const void *addr);
+unsigned long vmalloc_to_pfn(const void *addr);
+
+/*
+ * Determine if an address is within the vmalloc range
+ *
+ * On nommu, vmalloc/vfree wrap through kmalloc/kfree directly, so there
+ * is no special casing required.
+ */
+#ifdef CONFIG_MMU
+extern bool is_vmalloc_addr(const void *x);
+extern int is_vmalloc_or_module_addr(const void *x);
+#else
+static inline bool is_vmalloc_addr(const void *x)
+{
+ return false;
+}
+static inline int is_vmalloc_or_module_addr(const void *x)
+{
+ return 0;
+}
+#endif
+
+#endif /* _LINUX_MM_VMALLOC_ADDR_H */
--
2.39.2


2024-04-30 15:42:36

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 15/15] include: reduce dependencies on linux/mm.h

Replace <linux/mm.h> with the smaller pieces that were just splitted
out. This affects a few headers that are included by many, e.g. bio.h
and highmem.h, which now no longer depend on the fat <linux/mm.h>
header.

For this, several missing includes need to be added because they are
no longer indirectly included, e.g. <linux/fs.h>.

Signed-off-by: Max Kellermann <[email protected]>
---
include/linux/bio.h | 2 ++
include/linux/bpfptr.h | 1 -
include/linux/dma-mapping.h | 1 +
include/linux/highmem-internal.h | 2 ++
include/linux/highmem.h | 4 +++-
include/linux/net.h | 2 +-
include/linux/oom.h | 2 +-
include/linux/pagemap.h | 2 +-
include/linux/scatterlist.h | 2 +-
include/linux/skbuff.h | 4 ++++
include/linux/vmstat.h | 3 ++-
lib/scatterlist.c | 1 +
12 files changed, 19 insertions(+), 7 deletions(-)

diff --git a/include/linux/bio.h b/include/linux/bio.h
index 9b8a369f44bc..9b9b8b40f1e7 100644
--- a/include/linux/bio.h
+++ b/include/linux/bio.h
@@ -5,7 +5,9 @@
#ifndef __LINUX_BIO_H
#define __LINUX_BIO_H

+#include <linux/fs.h> // for struct kiocb, IOCB_NOWAIT
#include <linux/mempool.h>
+#include <linux/mm/folio_next.h>
/* struct bio, bio_vec and BIO_* flags are defined in blk_types.h */
#include <linux/blk_types.h>
#include <linux/uio.h>
diff --git a/include/linux/bpfptr.h b/include/linux/bpfptr.h
index 1af241525a17..19967a0e510c 100644
--- a/include/linux/bpfptr.h
+++ b/include/linux/bpfptr.h
@@ -3,7 +3,6 @@
#ifndef _LINUX_BPFPTR_H
#define _LINUX_BPFPTR_H

-#include <linux/mm.h>
#include <linux/sockptr.h>

typedef sockptr_t bpfptr_t;
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
index 4a658de44ee9..37d5591039c7 100644
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -11,6 +11,7 @@
#include <linux/scatterlist.h>
#include <linux/bug.h>
#include <linux/mem_encrypt.h>
+#include <linux/mm/vmalloc_addr.h>

/**
* List of possible attributes associated with a DMA mapping. The semantics
diff --git a/include/linux/highmem-internal.h b/include/linux/highmem-internal.h
index a3028e400a9c..a479e6b7c54c 100644
--- a/include/linux/highmem-internal.h
+++ b/include/linux/highmem-internal.h
@@ -2,6 +2,8 @@
#ifndef _LINUX_HIGHMEM_INTERNAL_H
#define _LINUX_HIGHMEM_INTERNAL_H

+#include <linux/mm/page_address.h>
+
/*
* Outside of CONFIG_HIGHMEM to support X86 32bit iomap_atomic() cruft.
*/
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 00341b56d291..10a165a913ad 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -7,7 +7,9 @@
#include <linux/bug.h>
#include <linux/cacheflush.h>
#include <linux/kmsan.h>
-#include <linux/mm.h>
+#include <linux/mm/folio_size.h> // for page_size()
+#include <linux/mm/folio_usage.h> // for folio_put()
+#include <linux/mm/page_address.h>
#include <linux/uaccess.h>
#include <linux/hardirq.h>

diff --git a/include/linux/net.h b/include/linux/net.h
index 15df6d5f27a7..7c04b3124366 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -21,7 +21,7 @@
#include <linux/rcupdate.h>
#include <linux/once.h>
#include <linux/fs.h>
-#include <linux/mm.h>
+#include <linux/page_ref.h> // for page_count()
#include <linux/sockptr.h>

#include <uapi/linux/net.h>
diff --git a/include/linux/oom.h b/include/linux/oom.h
index 7d0c9c48a0c5..518426e092d0 100644
--- a/include/linux/oom.h
+++ b/include/linux/oom.h
@@ -8,7 +8,7 @@
#include <linux/nodemask.h>
#include <uapi/linux/oom.h>
#include <linux/sched/coredump.h> /* MMF_* */
-#include <linux/mm.h> /* VM_FAULT* */
+#include <linux/mm_types.h> /* VM_FAULT* */

struct zonelist;
struct notifier_block;
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 850d32057939..70a99d7ebe10 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -5,7 +5,7 @@
/*
* Copyright 1995 Linus Torvalds
*/
-#include <linux/mm.h>
+#include <linux/mm_types.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/highmem.h>
diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h
index 0516e64dc03e..9221bba82b23 100644
--- a/include/linux/scatterlist.h
+++ b/include/linux/scatterlist.h
@@ -5,7 +5,7 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/bug.h>
-#include <linux/mm.h>
+#include <linux/mm/page_address.h>
#include <asm/io.h>

#ifdef CONFIG_UML
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index c43d6afebd50..4c8fe40fe1eb 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -16,6 +16,10 @@
#include <linux/bug.h>
#include <linux/bvec.h>
#include <linux/cache.h>
+#include <linux/gfp.h> // for alloc_pages_node()
+#include <linux/mm/folio_usage.h> // for get_page(), put_page()
+#include <linux/mm/folio_zone.h> // for page_to_nid()
+#include <linux/mm/pfmemalloc.h> // for page_is_pfmemalloc()
#include <linux/rbtree.h>
#include <linux/socket.h>
#include <linux/refcount.h>
diff --git a/include/linux/vmstat.h b/include/linux/vmstat.h
index 86bdcfe319ae..2cd9c921d516 100644
--- a/include/linux/vmstat.h
+++ b/include/linux/vmstat.h
@@ -4,7 +4,8 @@

#include <linux/types.h>
#include <linux/percpu.h>
-#include <linux/mm.h> // for folio_zone(), folio_nr_pages()
+#include <linux/mm/folio_size.h> // for folio_nr_pages()
+#include <linux/mm/folio_zone.h> // for folio_zone()
#include <linux/mmzone.h>
#include <linux/vm_event_item.h>
#include <linux/atomic.h>
diff --git a/lib/scatterlist.c b/lib/scatterlist.c
index 7bc2220fea80..775bad99fcd9 100644
--- a/lib/scatterlist.c
+++ b/lib/scatterlist.c
@@ -9,6 +9,7 @@
#include <linux/scatterlist.h>
#include <linux/highmem.h>
#include <linux/kmemleak.h>
+#include <linux/mm.h>
#include <linux/bvec.h>
#include <linux/uio.h>

--
2.39.2


2024-04-30 15:43:38

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 12/15] linux/mm.h: move pfmemalloc-related functions to pfmemalloc.h

This is needed to eliminate linux/skbuff.h's dependency on linux/mm.h.

Signed-off-by: Max Kellermann <[email protected]>
---
include/linux/mm.h | 45 +-----------------------------
include/linux/mm/pfmemalloc.h | 52 +++++++++++++++++++++++++++++++++++
2 files changed, 53 insertions(+), 44 deletions(-)
create mode 100644 include/linux/mm/pfmemalloc.h

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 7af85220711c..046f960ef70e 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -8,6 +8,7 @@
#include <linux/mm/folio_zone.h>
#include <linux/mm/page_address.h>
#include <linux/mm/page_section.h>
+#include <linux/mm/pfmemalloc.h>
#include <linux/errno.h>
#include <linux/mmdebug.h>
#include <linux/gfp.h>
@@ -1793,50 +1794,6 @@ static inline pgoff_t page_index(struct page *page)
return page->index;
}

-/*
- * Return true only if the page has been allocated with
- * ALLOC_NO_WATERMARKS and the low watermark was not
- * met implying that the system is under some pressure.
- */
-static inline bool page_is_pfmemalloc(const struct page *page)
-{
- /*
- * lru.next has bit 1 set if the page is allocated from the
- * pfmemalloc reserves. Callers may simply overwrite it if
- * they do not need to preserve that information.
- */
- return (uintptr_t)page->lru.next & BIT(1);
-}
-
-/*
- * Return true only if the folio has been allocated with
- * ALLOC_NO_WATERMARKS and the low watermark was not
- * met implying that the system is under some pressure.
- */
-static inline bool folio_is_pfmemalloc(const struct folio *folio)
-{
- /*
- * lru.next has bit 1 set if the page is allocated from the
- * pfmemalloc reserves. Callers may simply overwrite it if
- * they do not need to preserve that information.
- */
- return (uintptr_t)folio->lru.next & BIT(1);
-}
-
-/*
- * Only to be called by the page allocator on a freshly allocated
- * page.
- */
-static inline void set_page_pfmemalloc(struct page *page)
-{
- page->lru.next = (void *)BIT(1);
-}
-
-static inline void clear_page_pfmemalloc(struct page *page)
-{
- page->lru.next = NULL;
-}
-
/*
* Can be called by the pagefault handler when it gets a VM_FAULT_OOM.
*/
diff --git a/include/linux/mm/pfmemalloc.h b/include/linux/mm/pfmemalloc.h
new file mode 100644
index 000000000000..345b215a3566
--- /dev/null
+++ b/include/linux/mm/pfmemalloc.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_PFMEMALLOC_H
+#define _LINUX_MM_PFMEMALLOC_H
+
+#include <linux/bits.h> // for BIT()
+#include <linux/mm_types.h> // for struct page
+
+/*
+ * Return true only if the page has been allocated with
+ * ALLOC_NO_WATERMARKS and the low watermark was not
+ * met implying that the system is under some pressure.
+ */
+static inline bool page_is_pfmemalloc(const struct page *page)
+{
+ /*
+ * lru.next has bit 1 set if the page is allocated from the
+ * pfmemalloc reserves. Callers may simply overwrite it if
+ * they do not need to preserve that information.
+ */
+ return (uintptr_t)page->lru.next & BIT(1);
+}
+
+/*
+ * Return true only if the folio has been allocated with
+ * ALLOC_NO_WATERMARKS and the low watermark was not
+ * met implying that the system is under some pressure.
+ */
+static inline bool folio_is_pfmemalloc(const struct folio *folio)
+{
+ /*
+ * lru.next has bit 1 set if the page is allocated from the
+ * pfmemalloc reserves. Callers may simply overwrite it if
+ * they do not need to preserve that information.
+ */
+ return (uintptr_t)folio->lru.next & BIT(1);
+}
+
+/*
+ * Only to be called by the page allocator on a freshly allocated
+ * page.
+ */
+static inline void set_page_pfmemalloc(struct page *page)
+{
+ page->lru.next = (void *)BIT(1);
+}
+
+static inline void clear_page_pfmemalloc(struct page *page)
+{
+ page->lru.next = NULL;
+}
+
+#endif /* _LINUX_MM_PFMEMALLOC_H */
--
2.39.2


2024-04-30 15:53:21

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 08/15] linux/mm.h: move folio_next() to mm/folio_next.h

Prepare to reduce dependencies on linux/mm.h.

folio_next() is used by linux/bio.h. Moving it to a separate lean
header will allow us to avoid the dependency on linux/mm.h.

Having a one-function header may seem excessive, but there is hardly
another way if we want to distangle linux/mm.h from linux/bio.h. If
one day, say, folio_prev() gets added, we can still rename the header
to something like folio_iterator.h, but until that happens, this
folio_next.h header seems like the best trade-off to reduce
dependencies.

Signed-off-by: Max Kellermann <[email protected]>
---
include/linux/mm.h | 20 +-------------------
include/linux/mm/folio_next.h | 27 +++++++++++++++++++++++++++
2 files changed, 28 insertions(+), 19 deletions(-)
create mode 100644 include/linux/mm/folio_next.h

diff --git a/include/linux/mm.h b/include/linux/mm.h
index d5019aed8330..5b3d56454344 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2,6 +2,7 @@
#ifndef _LINUX_MM_H
#define _LINUX_MM_H

+#include <linux/mm/folio_next.h>
#include <linux/mm/folio_size.h>
#include <linux/mm/page_address.h>
#include <linux/mm/page_section.h>
@@ -1924,25 +1925,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
#define MAX_FOLIO_NR_PAGES MAX_ORDER_NR_PAGES
#endif

-/**
- * folio_next - Move to the next physical folio.
- * @folio: The folio we're currently operating on.
- *
- * If you have physically contiguous memory which may span more than
- * one folio (eg a &struct bio_vec), use this function to move from one
- * folio to the next. Do not use it if the memory is only virtually
- * contiguous as the folios are almost certainly not adjacent to each
- * other. This is the folio equivalent to writing ``page++``.
- *
- * Context: We assume that the folios are refcounted and/or locked at a
- * higher level and do not adjust the reference counts.
- * Return: The next struct folio.
- */
-static inline struct folio *folio_next(struct folio *folio)
-{
- return (struct folio *)folio_page(folio, folio_nr_pages(folio));
-}
-
/**
* folio_likely_mapped_shared - Estimate if the folio is mapped into the page
* tables of more than one MM
diff --git a/include/linux/mm/folio_next.h b/include/linux/mm/folio_next.h
new file mode 100644
index 000000000000..7016e303439c
--- /dev/null
+++ b/include/linux/mm/folio_next.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_FOLIO_NEXT_H
+#define _LINUX_MM_FOLIO_NEXT_H
+
+#include <linux/mm/folio_size.h> // for folio_nr_pages()
+#include <linux/mm/page_address.h> // for nth_page(), needed by folio_page()
+
+/**
+ * folio_next - Move to the next physical folio.
+ * @folio: The folio we're currently operating on.
+ *
+ * If you have physically contiguous memory which may span more than
+ * one folio (eg a &struct bio_vec), use this function to move from one
+ * folio to the next. Do not use it if the memory is only virtually
+ * contiguous as the folios are almost certainly not adjacent to each
+ * other. This is the folio equivalent to writing ``page++``.
+ *
+ * Context: We assume that the folios are refcounted and/or locked at a
+ * higher level and do not adjust the reference counts.
+ * Return: The next struct folio.
+ */
+static inline struct folio *folio_next(struct folio *folio)
+{
+ return (struct folio *)folio_page(folio, folio_nr_pages(folio));
+}
+
+#endif /* _LINUX_MM_FOLIO_NEXT_H */
--
2.39.2


2024-04-30 15:55:09

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 05/15] linux/mm.h: move section functions to mm/page_section.h

Prepare to reduce dependencies on linux/mm.h.

page_to_section() is used by __page_to_pfn() (but
asm-generic/memory_model.h does not include linux/mm.h). Thus, in
order to be able to use anything that calls page_to_pfn(), linux/mm.h
needs to be included.

This would prevent us from moving page_address() to a separate header,
because it calls lowmem_page_address() which in turn calls
page_to_virt() and then page_to_pfn(). To prepare for this move, we
move page_to_section() out of linux/mm.h into a separate lean header.

Signed-off-by: Max Kellermann <[email protected]>
---
include/linux/mm.h | 18 +-----------------
include/linux/mm/page_section.h | 23 +++++++++++++++++++++++
2 files changed, 24 insertions(+), 17 deletions(-)
create mode 100644 include/linux/mm/page_section.h

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 4a176690ab95..84013f24a6a7 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3,6 +3,7 @@
#define _LINUX_MM_H

#include <linux/mm/page_kasan_tag.h>
+#include <linux/mm/page_section.h>
#include <linux/errno.h>
#include <linux/mmdebug.h>
#include <linux/gfp.h>
@@ -1639,10 +1640,6 @@ static inline bool is_nommu_shared_mapping(vm_flags_t flags)
}
#endif

-#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
-#define SECTION_IN_PAGE_FLAGS
-#endif
-
/*
* The identification function is mainly used by the buddy allocator for
* determining if two pages could be buddies. We are not really identifying
@@ -1840,19 +1837,6 @@ static inline pg_data_t *folio_pgdat(const struct folio *folio)
return page_pgdat(&folio->page);
}

-#ifdef SECTION_IN_PAGE_FLAGS
-static inline void set_page_section(struct page *page, unsigned long section)
-{
- page->flags &= ~(SECTIONS_MASK << SECTIONS_PGSHIFT);
- page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
-}
-
-static inline unsigned long page_to_section(const struct page *page)
-{
- return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
-}
-#endif
-
/**
* folio_pfn - Return the Page Frame Number of a folio.
* @folio: The folio.
diff --git a/include/linux/mm/page_section.h b/include/linux/mm/page_section.h
new file mode 100644
index 000000000000..e4558c2691b8
--- /dev/null
+++ b/include/linux/mm/page_section.h
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_PAGE_SECTION_H
+#define _LINUX_MM_PAGE_SECTION_H
+
+#include <linux/mm_types.h> // for struct page
+#include <linux/mmzone.h> // for SECTIONS_*
+
+#if defined(CONFIG_SPARSEMEM) && !defined(CONFIG_SPARSEMEM_VMEMMAP)
+#define SECTION_IN_PAGE_FLAGS
+
+static inline void set_page_section(struct page *page, unsigned long section)
+{
+ page->flags &= ~(SECTIONS_MASK << SECTIONS_PGSHIFT);
+ page->flags |= (section & SECTIONS_MASK) << SECTIONS_PGSHIFT;
+}
+
+static inline unsigned long page_to_section(const struct page *page)
+{
+ return (page->flags >> SECTIONS_PGSHIFT) & SECTIONS_MASK;
+}
+#endif
+
+#endif /* _LINUX_MM_PAGE_SECTION_H */
--
2.39.2


2024-04-30 16:06:55

by Max Kellermann

[permalink] [raw]
Subject: [PATCH v5 07/15] linux/mm.h: move folio_size(), ... to mm/folio_size.h

Prepare to reduce dependencies on linux/mm.h.

folio_size()/page_size() are used by the following popular headers:

- linux/highmem.h
- linux/iov_iter.h
- linux/pagemap.h

Moving them to a separate lean header will allow us to avoid the
dependency on linux/mm.h. Additionally, it allows us to move
folio_next() to a separate header, because it needs folio_nr_pages()
which is also moved to folio_size.h.

Signed-off-by: Max Kellermann <[email protected]>
---
include/linux/mm.h | 140 +------------------------------
include/linux/mm/folio_size.h | 150 ++++++++++++++++++++++++++++++++++
2 files changed, 151 insertions(+), 139 deletions(-)
create mode 100644 include/linux/mm/folio_size.h

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 0dea734194aa..d5019aed8330 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -2,6 +2,7 @@
#ifndef _LINUX_MM_H
#define _LINUX_MM_H

+#include <linux/mm/folio_size.h>
#include <linux/mm/page_address.h>
#include <linux/mm/page_section.h>
#include <linux/errno.h>
@@ -1069,38 +1070,6 @@ int vma_is_stack_for_current(struct vm_area_struct *vma);
struct mmu_gather;
struct inode;

-/*
- * compound_order() can be called without holding a reference, which means
- * that niceties like page_folio() don't work. These callers should be
- * prepared to handle wild return values. For example, PG_head may be
- * set before the order is initialised, or this may be a tail page.
- * See compaction.c for some good examples.
- */
-static inline unsigned int compound_order(struct page *page)
-{
- struct folio *folio = (struct folio *)page;
-
- if (!test_bit(PG_head, &folio->flags))
- return 0;
- return folio->_flags_1 & 0xff;
-}
-
-/**
- * folio_order - The allocation order of a folio.
- * @folio: The folio.
- *
- * A folio is composed of 2^order pages. See get_order() for the definition
- * of order.
- *
- * Return: The order of the folio.
- */
-static inline unsigned int folio_order(struct folio *folio)
-{
- if (!folio_test_large(folio))
- return 0;
- return folio->_flags_1 & 0xff;
-}
-
#include <linux/huge_mm.h>

/*
@@ -1313,39 +1282,6 @@ void folio_copy(struct folio *dst, struct folio *src);

unsigned long nr_free_buffer_pages(void);

-/* Returns the number of bytes in this potentially compound page. */
-static inline unsigned long page_size(struct page *page)
-{
- return PAGE_SIZE << compound_order(page);
-}
-
-/* Returns the number of bits needed for the number of bytes in a page */
-static inline unsigned int page_shift(struct page *page)
-{
- return PAGE_SHIFT + compound_order(page);
-}
-
-/**
- * thp_order - Order of a transparent huge page.
- * @page: Head page of a transparent huge page.
- */
-static inline unsigned int thp_order(struct page *page)
-{
- VM_BUG_ON_PGFLAGS(PageTail(page), page);
- return compound_order(page);
-}
-
-/**
- * thp_size - Size of a transparent huge page.
- * @page: Head page of a transparent huge page.
- *
- * Return: Number of bytes in this page.
- */
-static inline unsigned long thp_size(struct page *page)
-{
- return PAGE_SIZE << thp_order(page);
-}
-
#ifdef CONFIG_MMU
/*
* Do pte_mkwrite, but only if the vma says VM_WRITE. We do this when
@@ -1981,23 +1917,6 @@ static inline void set_page_links(struct page *page, enum zone_type zone,
#endif
}

-/**
- * folio_nr_pages - The number of pages in the folio.
- * @folio: The folio.
- *
- * Return: A positive power of two.
- */
-static inline long folio_nr_pages(const struct folio *folio)
-{
- if (!folio_test_large(folio))
- return 1;
-#ifdef CONFIG_64BIT
- return folio->_folio_nr_pages;
-#else
- return 1L << (folio->_flags_1 & 0xff);
-#endif
-}
-
/* Only hugetlbfs can allocate folios larger than MAX_ORDER */
#ifdef CONFIG_ARCH_HAS_GIGANTIC_PAGE
#define MAX_FOLIO_NR_PAGES (1UL << PUD_ORDER)
@@ -2005,33 +1924,6 @@ static inline long folio_nr_pages(const struct folio *folio)
#define MAX_FOLIO_NR_PAGES MAX_ORDER_NR_PAGES
#endif

-/*
- * compound_nr() returns the number of pages in this potentially compound
- * page. compound_nr() can be called on a tail page, and is defined to
- * return 1 in that case.
- */
-static inline unsigned long compound_nr(struct page *page)
-{
- struct folio *folio = (struct folio *)page;
-
- if (!test_bit(PG_head, &folio->flags))
- return 1;
-#ifdef CONFIG_64BIT
- return folio->_folio_nr_pages;
-#else
- return 1L << (folio->_flags_1 & 0xff);
-#endif
-}
-
-/**
- * thp_nr_pages - The number of regular pages in this huge page.
- * @page: The head page of a huge page.
- */
-static inline int thp_nr_pages(struct page *page)
-{
- return folio_nr_pages((struct folio *)page);
-}
-
/**
* folio_next - Move to the next physical folio.
* @folio: The folio we're currently operating on.
@@ -2051,36 +1943,6 @@ static inline struct folio *folio_next(struct folio *folio)
return (struct folio *)folio_page(folio, folio_nr_pages(folio));
}

-/**
- * folio_shift - The size of the memory described by this folio.
- * @folio: The folio.
- *
- * A folio represents a number of bytes which is a power-of-two in size.
- * This function tells you which power-of-two the folio is. See also
- * folio_size() and folio_order().
- *
- * Context: The caller should have a reference on the folio to prevent
- * it from being split. It is not necessary for the folio to be locked.
- * Return: The base-2 logarithm of the size of this folio.
- */
-static inline unsigned int folio_shift(struct folio *folio)
-{
- return PAGE_SHIFT + folio_order(folio);
-}
-
-/**
- * folio_size - The number of bytes in a folio.
- * @folio: The folio.
- *
- * Context: The caller should have a reference on the folio to prevent
- * it from being split. It is not necessary for the folio to be locked.
- * Return: The number of bytes in this folio.
- */
-static inline size_t folio_size(struct folio *folio)
-{
- return PAGE_SIZE << folio_order(folio);
-}
-
/**
* folio_likely_mapped_shared - Estimate if the folio is mapped into the page
* tables of more than one MM
diff --git a/include/linux/mm/folio_size.h b/include/linux/mm/folio_size.h
new file mode 100644
index 000000000000..e7cd567cf069
--- /dev/null
+++ b/include/linux/mm/folio_size.h
@@ -0,0 +1,150 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MM_FOLIO_SIZE_H
+#define _LINUX_MM_FOLIO_SIZE_H
+
+#include <linux/bitops.h> // for test_bit()
+#include <linux/mmdebug.h> // for VM_BUG_ON_PGFLAGS()
+#include <linux/mm_types.h> // for struct page
+#include <linux/page-flags.h> // for folio_test_large()
+#include <asm/page.h> // for PAGE_SIZE, PAGE_SHIFT
+
+/*
+ * compound_order() can be called without holding a reference, which means
+ * that niceties like page_folio() don't work. These callers should be
+ * prepared to handle wild return values. For example, PG_head may be
+ * set before the order is initialised, or this may be a tail page.
+ * See compaction.c for some good examples.
+ */
+static inline unsigned int compound_order(struct page *page)
+{
+ struct folio *folio = (struct folio *)page;
+
+ if (!test_bit(PG_head, &folio->flags))
+ return 0;
+ return folio->_flags_1 & 0xff;
+}
+
+/**
+ * folio_order - The allocation order of a folio.
+ * @folio: The folio.
+ *
+ * A folio is composed of 2^order pages. See get_order() for the definition
+ * of order.
+ *
+ * Return: The order of the folio.
+ */
+static inline unsigned int folio_order(struct folio *folio)
+{
+ if (!folio_test_large(folio))
+ return 0;
+ return folio->_flags_1 & 0xff;
+}
+
+/* Returns the number of bytes in this potentially compound page. */
+static inline unsigned long page_size(struct page *page)
+{
+ return PAGE_SIZE << compound_order(page);
+}
+
+/* Returns the number of bits needed for the number of bytes in a page */
+static inline unsigned int page_shift(struct page *page)
+{
+ return PAGE_SHIFT + compound_order(page);
+}
+
+/**
+ * thp_order - Order of a transparent huge page.
+ * @page: Head page of a transparent huge page.
+ */
+static inline unsigned int thp_order(struct page *page)
+{
+ VM_BUG_ON_PGFLAGS(PageTail(page), page);
+ return compound_order(page);
+}
+
+/**
+ * thp_size - Size of a transparent huge page.
+ * @page: Head page of a transparent huge page.
+ *
+ * Return: Number of bytes in this page.
+ */
+static inline unsigned long thp_size(struct page *page)
+{
+ return PAGE_SIZE << thp_order(page);
+}
+
+/**
+ * folio_nr_pages - The number of pages in the folio.
+ * @folio: The folio.
+ *
+ * Return: A positive power of two.
+ */
+static inline long folio_nr_pages(const struct folio *folio)
+{
+ if (!folio_test_large(folio))
+ return 1;
+#ifdef CONFIG_64BIT
+ return folio->_folio_nr_pages;
+#else
+ return 1L << (folio->_flags_1 & 0xff);
+#endif
+}
+
+/*
+ * compound_nr() returns the number of pages in this potentially compound
+ * page. compound_nr() can be called on a tail page, and is defined to
+ * return 1 in that case.
+ */
+static inline unsigned long compound_nr(struct page *page)
+{
+ struct folio *folio = (struct folio *)page;
+
+ if (!test_bit(PG_head, &folio->flags))
+ return 1;
+#ifdef CONFIG_64BIT
+ return folio->_folio_nr_pages;
+#else
+ return 1L << (folio->_flags_1 & 0xff);
+#endif
+}
+
+/**
+ * thp_nr_pages - The number of regular pages in this huge page.
+ * @page: The head page of a huge page.
+ */
+static inline int thp_nr_pages(struct page *page)
+{
+ return folio_nr_pages((struct folio *)page);
+}
+
+/**
+ * folio_shift - The size of the memory described by this folio.
+ * @folio: The folio.
+ *
+ * A folio represents a number of bytes which is a power-of-two in size.
+ * This function tells you which power-of-two the folio is. See also
+ * folio_size() and folio_order().
+ *
+ * Context: The caller should have a reference on the folio to prevent
+ * it from being split. It is not necessary for the folio to be locked.
+ * Return: The base-2 logarithm of the size of this folio.
+ */
+static inline unsigned int folio_shift(struct folio *folio)
+{
+ return PAGE_SHIFT + folio_order(folio);
+}
+
+/**
+ * folio_size - The number of bytes in a folio.
+ * @folio: The folio.
+ *
+ * Context: The caller should have a reference on the folio to prevent
+ * it from being split. It is not necessary for the folio to be locked.
+ * Return: The number of bytes in this folio.
+ */
+static inline size_t folio_size(struct folio *folio)
+{
+ return PAGE_SIZE << folio_order(folio);
+}
+
+#endif /* _LINUX_MM_FOLIO_SIZE_H_H */
--
2.39.2