diff mbox series

[v6,04/23] mm/uffd: PTE_MARKER_UFFD_WP

Message ID 20211115075522.73795-5-peterx@redhat.com (mailing list archive)
State New
Headers show
Series userfaultfd-wp: Support shmem and hugetlbfs | expand

Commit Message

Peter Xu Nov. 15, 2021, 7:55 a.m. UTC
This patch introduces the 1st user of pte marker: the uffd-wp marker.

When the pte marker is installed with the uffd-wp bit set, it means this pte
was wr-protected by uffd.

We will use this special pte to arm the ptes that got either unmapped or
swapped out for a file-backed region that was previously wr-protected.  This
special pte could trigger a page fault just like swap entries.

This idea is greatly inspired by Hugh and Andrea in the discussion, which is
referenced in the links below.

Some helpers are introduced to detect whether a swap pte is uffd wr-protected.
After the pte marker introduced, one swap pte can be wr-protected in two forms:
either it is a normal swap pte and it has _PAGE_SWP_UFFD_WP set, or it's a pte
marker that has PTE_MARKER_UFFD_WP set.

Link: https://lore.kernel.org/lkml/20201126222359.8120-1-peterx@redhat.com/
Link: https://lore.kernel.org/lkml/20201130230603.46187-1-peterx@redhat.com/
Suggested-by: Andrea Arcangeli <aarcange@redhat.com>
Suggested-by: Hugh Dickins <hughd@google.com>
Signed-off-by: Peter Xu <peterx@redhat.com>
---
 include/linux/swapops.h       |  3 ++-
 include/linux/userfaultfd_k.h | 38 +++++++++++++++++++++++++++++++++++
 mm/Kconfig                    |  9 +++++++++
 3 files changed, 49 insertions(+), 1 deletion(-)

Comments

Alistair Popple Dec. 16, 2021, 5:18 a.m. UTC | #1
On Monday, 15 November 2021 6:55:03 PM AEDT Peter Xu wrote:

[...]

> +/*
> + * Returns true if this is a swap pte and was uffd-wp wr-protected in either
> + * forms (pte marker or a normal swap pte), false otherwise.
> + */
> +static inline bool pte_swp_uffd_wp_any(pte_t pte)
> +{
> +#ifdef CONFIG_PTE_MARKER_UFFD_WP
> +	if (!is_swap_pte(pte))
> +		return false;
> +
> +	if (pte_swp_uffd_wp(pte))
> +		return true;

If I'm not mistaken normal swap uffd-wp ptes can still exist when
CONFIG_PTE_MARKER_UFFD_WP=n so shouldn't this be outside the #ifdef protection?

In fact we could drop the #ifdef entirely here as it is safe to call
is_pte_marker_uffd_wp() without CONFIG_PTE_MARKER_UFFD_WP.

> +
> +	if (is_pte_marker_uffd_wp(pte))
> +		return true;
> +#endif
> +	return false;
> +}
> +
>  #endif /* _LINUX_USERFAULTFD_K_H */
> diff --git a/mm/Kconfig b/mm/Kconfig
> index 66f23c6c2032..f01c8e0afadf 100644
> --- a/mm/Kconfig
> +++ b/mm/Kconfig
> @@ -904,6 +904,15 @@ config PTE_MARKER
>  	help
>  	  Allows to create marker PTEs for file-backed memory.
>  
> +config PTE_MARKER_UFFD_WP
> +	bool "Marker PTEs support for userfaultfd write protection"
> +	depends on PTE_MARKER && HAVE_ARCH_USERFAULTFD_WP
> +
> +	help
> +	  Allows to create marker PTEs for userfaultfd write protection
> +	  purposes.  It is required to enable userfaultfd write protection on
> +	  file-backed memory types like shmem and hugetlbfs.
> +
>  source "mm/damon/Kconfig"
>  
>  endmenu
>
Peter Xu Dec. 16, 2021, 5:45 a.m. UTC | #2
On Thu, Dec 16, 2021 at 04:18:50PM +1100, Alistair Popple wrote:
> On Monday, 15 November 2021 6:55:03 PM AEDT Peter Xu wrote:
> 
> [...]
> 
> > +/*
> > + * Returns true if this is a swap pte and was uffd-wp wr-protected in either
> > + * forms (pte marker or a normal swap pte), false otherwise.
> > + */
> > +static inline bool pte_swp_uffd_wp_any(pte_t pte)
> > +{
> > +#ifdef CONFIG_PTE_MARKER_UFFD_WP
> > +	if (!is_swap_pte(pte))
> > +		return false;
> > +
> > +	if (pte_swp_uffd_wp(pte))
> > +		return true;
> 
> If I'm not mistaken normal swap uffd-wp ptes can still exist when
> CONFIG_PTE_MARKER_UFFD_WP=n so shouldn't this be outside the #ifdef protection?
> 
> In fact we could drop the #ifdef entirely here as it is safe to call
> is_pte_marker_uffd_wp() without CONFIG_PTE_MARKER_UFFD_WP.

But if CONFIG_PTE_MARKER_UFFD_WP=n then it means we don't support file-backed
uffd-wp.  The thing is pte_swp_uffd_wp_any() is only needed for file-backed..
Anonymous uffd-wp code never uses it.

In other words, pte_swp_uffd_wp() is indeed still a valid helper, however this
specific function (pte_swp_uffd_wp_any) may not really be necessary anymore.

Keeping the "#ifdef" could still help, imho, to generate clean code for direct
calls to pte_swp_uffd_wp_any() if someone wants to turn pte markers off,
e.g. we could still have chance to optimize below:

        if (pte_swp_uffd_wp_any(pte) &&
                !(zap_flags & ZAP_FLAG_DROP_MARKER))
                set_huge_pte_at(mm, address, ptep,
                                make_pte_marker(PTE_MARKER_UFFD_WP));
        else
                huge_pte_clear(mm, address, ptep, sz);

Into:

        huge_pte_clear(mm, address, ptep, sz);

with any decent compiler.

That's majorly why I still slightly prefer to keep it, and that's also one of
the major reason to have the config knob, imho.

Thanks,
diff mbox series

Patch

diff --git a/include/linux/swapops.h b/include/linux/swapops.h
index 5103d2a4ae38..2cec3ef355a7 100644
--- a/include/linux/swapops.h
+++ b/include/linux/swapops.h
@@ -249,7 +249,8 @@  static inline int is_writable_migration_entry(swp_entry_t entry)
 
 typedef unsigned long pte_marker;
 
-#define  PTE_MARKER_MASK     (0)
+#define  PTE_MARKER_UFFD_WP  BIT(0)
+#define  PTE_MARKER_MASK     (PTE_MARKER_UFFD_WP)
 
 #ifdef CONFIG_PTE_MARKER
 
diff --git a/include/linux/userfaultfd_k.h b/include/linux/userfaultfd_k.h
index 33cea484d1ad..7d7ffec53ddb 100644
--- a/include/linux/userfaultfd_k.h
+++ b/include/linux/userfaultfd_k.h
@@ -15,6 +15,8 @@ 
 
 #include <linux/fcntl.h>
 #include <linux/mm.h>
+#include <linux/swap.h>
+#include <linux/swapops.h>
 #include <asm-generic/pgtable_uffd.h>
 
 /* The set of all possible UFFD-related VM flags. */
@@ -236,4 +238,40 @@  static inline void userfaultfd_unmap_complete(struct mm_struct *mm,
 
 #endif /* CONFIG_USERFAULTFD */
 
+static inline bool is_pte_marker_uffd_wp(pte_t pte)
+{
+#ifdef CONFIG_PTE_MARKER_UFFD_WP
+	swp_entry_t entry;
+
+	if (!is_swap_pte(pte))
+		return false;
+
+	entry = pte_to_swp_entry(pte);
+
+	return is_pte_marker_entry(entry) &&
+	    (pte_marker_get(entry) & PTE_MARKER_UFFD_WP);
+#else
+	return false;
+#endif
+}
+
+/*
+ * Returns true if this is a swap pte and was uffd-wp wr-protected in either
+ * forms (pte marker or a normal swap pte), false otherwise.
+ */
+static inline bool pte_swp_uffd_wp_any(pte_t pte)
+{
+#ifdef CONFIG_PTE_MARKER_UFFD_WP
+	if (!is_swap_pte(pte))
+		return false;
+
+	if (pte_swp_uffd_wp(pte))
+		return true;
+
+	if (is_pte_marker_uffd_wp(pte))
+		return true;
+#endif
+	return false;
+}
+
 #endif /* _LINUX_USERFAULTFD_K_H */
diff --git a/mm/Kconfig b/mm/Kconfig
index 66f23c6c2032..f01c8e0afadf 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -904,6 +904,15 @@  config PTE_MARKER
 	help
 	  Allows to create marker PTEs for file-backed memory.
 
+config PTE_MARKER_UFFD_WP
+	bool "Marker PTEs support for userfaultfd write protection"
+	depends on PTE_MARKER && HAVE_ARCH_USERFAULTFD_WP
+
+	help
+	  Allows to create marker PTEs for userfaultfd write protection
+	  purposes.  It is required to enable userfaultfd write protection on
+	  file-backed memory types like shmem and hugetlbfs.
+
 source "mm/damon/Kconfig"
 
 endmenu