All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Matthew Wilcox (Oracle)" <willy@infradead.org>
To: akpm@linux-foundation.org
Cc: "Matthew Wilcox (Oracle)" <willy@infradead.org>,
	linux-fsdevel@vger.kernel.org, linux-mm@kvack.org,
	linux-kernel@vger.kernel.org, Jeff Layton <jlayton@kernel.org>,
	"Kirill A . Shutemov" <kirill.shutemov@linux.intel.com>,
	Vlastimil Babka <vbabka@suse.cz>,
	William Kucharski <william.kucharski@oracle.com>
Subject: [PATCH v11 02/33] mm: Introduce struct folio
Date: Mon, 14 Jun 2021 21:14:04 +0100	[thread overview]
Message-ID: <20210614201435.1379188-3-willy@infradead.org> (raw)
In-Reply-To: <20210614201435.1379188-1-willy@infradead.org>

A struct folio is a new abstraction to replace the venerable struct page.
A function which takes a struct folio argument declares that it will
operate on the entire (possibly compound) page, not just PAGE_SIZE bytes.
In return, the caller guarantees that the pointer it is passing does
not point to a tail page.  No change to generated code.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Acked-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
Acked-by: Vlastimil Babka <vbabka@suse.cz>
Reviewed-by: William Kucharski <william.kucharski@oracle.com>
---
 Documentation/core-api/mm-api.rst |  1 +
 include/linux/mm.h                | 74 +++++++++++++++++++++++++++++++
 include/linux/mm_types.h          | 60 +++++++++++++++++++++++++
 include/linux/page-flags.h        | 28 ++++++++++++
 4 files changed, 163 insertions(+)

diff --git a/Documentation/core-api/mm-api.rst b/Documentation/core-api/mm-api.rst
index a42f9baddfbf..2a94e6164f80 100644
--- a/Documentation/core-api/mm-api.rst
+++ b/Documentation/core-api/mm-api.rst
@@ -95,6 +95,7 @@ More Memory Management Functions
 .. kernel-doc:: mm/mempolicy.c
 .. kernel-doc:: include/linux/mm_types.h
    :internal:
+.. kernel-doc:: include/linux/page-flags.h
 .. kernel-doc:: include/linux/mm.h
    :internal:
 .. kernel-doc:: include/linux/mmzone.h
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 877eb8730eea..19f2ec1a2221 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -950,6 +950,20 @@ static inline unsigned int compound_order(struct page *page)
 	return page[1].compound_order;
 }
 
+/**
+ * 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)
+{
+	return compound_order(&folio->page);
+}
+
 static inline bool hpage_pincount_available(struct page *page)
 {
 	/*
@@ -1595,6 +1609,65 @@ 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 number which is a power of two.
+ */
+static inline unsigned long folio_nr_pages(struct folio *folio)
+{
+	return compound_nr(&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));
+}
+
+/**
+ * folio_shift - The number of bits covered by this folio.
+ * @folio: The folio.
+ *
+ * A folio contains a number of bytes which is a power-of-two in size.
+ * This function tells you which power-of-two the folio is.
+ *
+ * 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);
+}
+
 /*
  * Some inline functions in vmstat.h depend on page_zone()
  */
@@ -1699,6 +1772,7 @@ 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))
 
 /*
  * Flags passed to show_mem() and show_free_areas() to suppress output in
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 5aacc1c10a45..3118ba8b5a4e 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -224,6 +224,66 @@ struct page {
 #endif
 } _struct_page_alignment;
 
+/**
+ * struct folio - Represents a contiguous set of bytes.
+ * @flags: Identical to the page flags.
+ * @lru: Least Recently Used list; tracks how recently this folio was used.
+ * @mapping: The file this page belongs to, or refers to the anon_vma for
+ *    anonymous pages.
+ * @index: Offset within the file, in units of pages.  For anonymous pages,
+ *    this is the index from the beginning of the mmap.
+ * @private: Filesystem per-folio data (see folio_attach_private()).
+ *    Used for swp_entry_t if folio_swapcache().
+ * @_mapcount: Do not access this member directly.  Use folio_mapcount() to
+ *    find out how many times this folio is mapped by userspace.
+ * @_refcount: Do not access this member directly.  Use folio_ref_count()
+ *    to find how many references there are to this folio.
+ * @memcg_data: Memory Control Group data.
+ *
+ * A folio is a physically, virtually and logically contiguous set
+ * of bytes.  It is a power-of-two in size, and it is aligned to that
+ * same power-of-two.  It is at least as large as %PAGE_SIZE.  If it is
+ * in the page cache, it is at a file offset which is a multiple of that
+ * power-of-two.  It may be mapped into userspace at an address which is
+ * at an arbitrary page offset, but its kernel virtual address is aligned
+ * to its size.
+ */
+struct folio {
+	/* private: don't document the anon union */
+	union {
+		struct {
+	/* public: */
+			unsigned long flags;
+			struct list_head lru;
+			struct address_space *mapping;
+			pgoff_t index;
+			void *private;
+			atomic_t _mapcount;
+			atomic_t _refcount;
+#ifdef CONFIG_MEMCG
+			unsigned long memcg_data;
+#endif
+	/* private: the union with struct page is transitional */
+		};
+		struct page page;
+	};
+};
+
+static_assert(sizeof(struct page) == sizeof(struct folio));
+#define FOLIO_MATCH(pg, fl)						\
+	static_assert(offsetof(struct page, pg) == offsetof(struct folio, fl))
+FOLIO_MATCH(flags, flags);
+FOLIO_MATCH(lru, lru);
+FOLIO_MATCH(compound_head, lru);
+FOLIO_MATCH(index, index);
+FOLIO_MATCH(private, private);
+FOLIO_MATCH(_mapcount, _mapcount);
+FOLIO_MATCH(_refcount, _refcount);
+#ifdef CONFIG_MEMCG
+FOLIO_MATCH(memcg_data, memcg_data);
+#endif
+#undef FOLIO_MATCH
+
 static inline atomic_t *compound_mapcount_ptr(struct page *page)
 {
 	return &page[1].compound_mapcount;
diff --git a/include/linux/page-flags.h b/include/linux/page-flags.h
index d8e26243db25..df48da56cfba 100644
--- a/include/linux/page-flags.h
+++ b/include/linux/page-flags.h
@@ -188,6 +188,34 @@ static inline unsigned long _compound_head(const struct page *page)
 
 #define compound_head(page)	((typeof(page))_compound_head(page))
 
+/**
+ * page_folio - Converts from page to folio.
+ * @p: The page.
+ *
+ * Every page is part of a folio.  This function cannot be called on a
+ * NULL pointer.
+ *
+ * Context: No reference, nor lock is required on @page.  If the caller
+ * does not hold a reference, this call may race with a folio split, so
+ * it should re-check the folio still contains this page after gaining
+ * a reference on the folio.
+ * Return: The folio which contains this page.
+ */
+#define page_folio(p)		(_Generic((p),				\
+	const struct page *:	(const struct folio *)_compound_head(p), \
+	struct page *:		(struct folio *)_compound_head(p)))
+
+/**
+ * folio_page - Return a page from a folio.
+ * @folio: The folio.
+ * @n: The page number to return.
+ *
+ * @n is relative to the start of the folio.  This function does not
+ * check that the page number lies within @folio; the caller is presumed
+ * to have a reference to the page.
+ */
+#define folio_page(folio, n)	nth_page(&(folio)->page, n)
+
 static __always_inline int PageTail(struct page *page)
 {
 	return READ_ONCE(page->compound_head) & 1;
-- 
2.30.2


  parent reply	other threads:[~2021-06-14 20:16 UTC|newest]

Thread overview: 68+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-06-14 20:14 [PATCH v11 00/33] Memory folios Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 01/33] mm: Convert get_page_unless_zero() to return bool Matthew Wilcox (Oracle)
2021-06-15  6:24   ` Christoph Hellwig
2021-06-14 20:14 ` Matthew Wilcox (Oracle) [this message]
2021-06-14 20:14 ` [PATCH v11 03/33] mm: Add folio_pgdat(), folio_zone() and folio_zonenum() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 04/33] mm/vmstat: Add functions to account folio statistics Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 05/33] mm/debug: Add VM_BUG_ON_FOLIO() and VM_WARN_ON_ONCE_FOLIO() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 06/33] mm: Add folio reference count functions Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 07/33] mm: Add folio_put() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 08/33] mm: Add folio_get() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 09/33] mm: Add folio_try_get_rcu() Matthew Wilcox (Oracle)
2021-06-15  6:25   ` Christoph Hellwig
2021-06-14 20:14 ` [PATCH v11 10/33] mm: Add folio flag manipulation functions Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 11/33] mm/lru: Add folio LRU functions Matthew Wilcox (Oracle)
2021-06-15  6:27   ` Christoph Hellwig
2021-06-14 20:14 ` [PATCH v11 12/33] mm: Handle per-folio private data Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 13/33] mm/filemap: Add folio_index(), folio_file_page() and folio_contains() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 14/33] mm/filemap: Add folio_next_index() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 15/33] mm/filemap: Add folio_offset() and folio_file_offset() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 16/33] mm/util: Add folio_mapping() and folio_file_mapping() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 17/33] mm/memcg: Add folio wrappers for various functions Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 18/33] mm/filemap: Add folio_unlock() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 19/33] mm/filemap: Add folio_lock() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 20/33] mm/filemap: Add folio_lock_killable() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 21/33] mm/filemap: Add __folio_lock_async() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 22/33] mm/filemap: Add folio_wait_locked() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 23/33] mm/filemap: Add __folio_lock_or_retry() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 24/33] mm/swap: Add folio_rotate_reclaimable() Matthew Wilcox (Oracle)
2021-06-15  6:29   ` Christoph Hellwig
2021-06-14 20:14 ` [PATCH v11 25/33] mm/filemap: Add folio_end_writeback() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 26/33] mm/writeback: Add folio_wait_writeback() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 27/33] mm/writeback: Add folio_wait_stable() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 28/33] mm/filemap: Add folio_wait_bit() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 29/33] mm/filemap: Add folio_wake_bit() Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 30/33] mm/filemap: Convert page wait queues to be folios Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 31/33] mm/filemap: Add folio private_2 functions Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 32/33] fs/netfs: Add folio fscache functions Matthew Wilcox (Oracle)
2021-06-14 20:14 ` [PATCH v11 33/33] mm: Add folio_mapped() Matthew Wilcox (Oracle)
2021-06-15  6:31   ` Christoph Hellwig
2021-06-16  9:16 ` [PATCH v11 32/33] fs/netfs: Add folio fscache functions David Howells
2021-06-16  9:19 ` [PATCH v11 01/33] mm: Convert get_page_unless_zero() to return bool David Howells
2021-06-16  9:31 ` [PATCH v11 02/33] mm: Introduce struct folio David Howells
2021-06-16  9:36 ` [PATCH v11 04/33] mm/vmstat: Add functions to account folio statistics David Howells
2021-06-16  9:54 ` [PATCH v11 05/33] mm/debug: Add VM_BUG_ON_FOLIO() and VM_WARN_ON_ONCE_FOLIO() David Howells
2021-06-16  9:55 ` [PATCH v11 06/33] mm: Add folio reference count functions David Howells
2021-06-16  9:55 ` [PATCH v11 07/33] mm: Add folio_put() David Howells
2021-06-16  9:56 ` [PATCH v11 08/33] mm: Add folio_get() David Howells
2021-06-16  9:58 ` [PATCH v11 10/33] mm: Add folio flag manipulation functions David Howells
2021-06-16 10:00 ` [PATCH v11 11/33] mm/lru: Add folio LRU functions David Howells
2021-06-16 10:03 ` [PATCH v11 13/33] mm/filemap: Add folio_index(), folio_file_page() and folio_contains() David Howells
2021-06-16 11:38   ` Matthew Wilcox
2021-06-16 10:04 ` [PATCH v11 14/33] mm/filemap: Add folio_next_index() David Howells
2021-06-16 10:05 ` [PATCH v11 15/33] mm/filemap: Add folio_offset() and folio_file_offset() David Howells
2021-06-16 10:10 ` [PATCH v11 16/33] mm/util: Add folio_mapping() and folio_file_mapping() David Howells
2021-06-16 10:13 ` [PATCH v11 18/33] mm/filemap: Add folio_unlock() David Howells
2021-06-16 10:17 ` [PATCH v11 19/33] mm/filemap: Add folio_lock() David Howells
2021-06-16 10:22 ` [PATCH v11 21/33] mm/filemap: Add __folio_lock_async() David Howells
2021-06-16 10:23 ` [PATCH v11 22/33] mm/filemap: Add folio_wait_locked() David Howells
2021-06-16 10:27 ` [PATCH v11 24/33] mm/swap: Add folio_rotate_reclaimable() David Howells
2021-06-16 11:46   ` Matthew Wilcox
2021-06-16 10:30 ` [PATCH v11 26/33] mm/writeback: Add folio_wait_writeback() David Howells
2021-06-16 11:55   ` Matthew Wilcox
2021-06-16 10:32 ` [PATCH v11 27/33] mm/writeback: Add folio_wait_stable() David Howells
2021-06-16 10:33 ` [PATCH v11 28/33] mm/filemap: Add folio_wait_bit() David Howells
2021-06-16 10:35 ` [PATCH v11 30/33] mm/filemap: Convert page wait queues to be folios David Howells
2021-06-16 10:37 ` [PATCH v11 33/33] mm: Add folio_mapped() David Howells
2021-06-16 10:41 ` [PATCH v11 02/33] mm: Introduce struct folio David Howells
2021-06-16 10:54 ` [PATCH v11 00/33] Memory folios David Howells

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210614201435.1379188-3-willy@infradead.org \
    --to=willy@infradead.org \
    --cc=akpm@linux-foundation.org \
    --cc=jlayton@kernel.org \
    --cc=kirill.shutemov@linux.intel.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=vbabka@suse.cz \
    --cc=william.kucharski@oracle.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.