Add AS_NO_DIRECT_MAP for mappings where direct map entries of folios are
set to not present . Currently, mappings that match this description are
secretmem mappings (memfd_secret()). Later, some guest_memfd
configurations will also fall into this category.
Reject this new type of mappings in all locations that currently reject
secretmem mappings, on the assumption that if secretmem mappings are
rejected somewhere, it is precisely because of an inability to deal with
folios without direct map entries, and then make memfd_secret() use
AS_NO_DIRECT_MAP on its address_space to drop its special
vma_is_secretmem()/secretmem_mapping() checks.
This drops a optimization in gup_fast_folio_allowed() where
secretmem_mapping() was only called if CONFIG_SECRETMEM=y. secretmem is
enabled by default since commit b758fe6df50d ("mm/secretmem: make it on
by default"), so the secretmem check did not actually end up elided in
most cases anymore anyway.
Use a new flag instead of overloading AS_INACCESSIBLE (which is already
set by guest_memfd) because not all guest_memfd mappings will end up
being direct map removed (e.g. in pKVM setups, parts of guest_memfd that
can be mapped to userspace should also be GUP-able, and generally not
have restrictions on who can access it).
Signed-off-by: Patrick Roy <roypat@amazon.co.uk>
---
include/linux/pagemap.h | 16 ++++++++++++++++
include/linux/secretmem.h | 18 ------------------
lib/buildid.c | 4 ++--
mm/gup.c | 14 +++-----------
mm/mlock.c | 2 +-
mm/secretmem.c | 6 +-----
6 files changed, 23 insertions(+), 37 deletions(-)
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 12a12dae727d..b52b28ae4636 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -211,6 +211,7 @@ enum mapping_flags {
folio contents */
AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */
AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9,
+ AS_NO_DIRECT_MAP = 10, /* Folios in the mapping are not in the direct map */
/* Bits 16-25 are used for FOLIO_ORDER */
AS_FOLIO_ORDER_BITS = 5,
AS_FOLIO_ORDER_MIN = 16,
@@ -346,6 +347,21 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_spac
return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags);
}
+static inline void mapping_set_no_direct_map(struct address_space *mapping)
+{
+ set_bit(AS_NO_DIRECT_MAP, &mapping->flags);
+}
+
+static inline bool mapping_no_direct_map(struct address_space *mapping)
+{
+ return test_bit(AS_NO_DIRECT_MAP, &mapping->flags);
+}
+
+static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma)
+{
+ return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping);
+}
+
static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
{
return mapping->gfp_mask;
diff --git a/include/linux/secretmem.h b/include/linux/secretmem.h
index e918f96881f5..0ae1fb057b3d 100644
--- a/include/linux/secretmem.h
+++ b/include/linux/secretmem.h
@@ -4,28 +4,10 @@
#ifdef CONFIG_SECRETMEM
-extern const struct address_space_operations secretmem_aops;
-
-static inline bool secretmem_mapping(struct address_space *mapping)
-{
- return mapping->a_ops == &secretmem_aops;
-}
-
-bool vma_is_secretmem(struct vm_area_struct *vma);
bool secretmem_active(void);
#else
-static inline bool vma_is_secretmem(struct vm_area_struct *vma)
-{
- return false;
-}
-
-static inline bool secretmem_mapping(struct address_space *mapping)
-{
- return false;
-}
-
static inline bool secretmem_active(void)
{
return false;
diff --git a/lib/buildid.c b/lib/buildid.c
index c4b0f376fb34..33f173a607ad 100644
--- a/lib/buildid.c
+++ b/lib/buildid.c
@@ -65,8 +65,8 @@ static int freader_get_folio(struct freader *r, loff_t file_off)
freader_put_folio(r);
- /* reject secretmem folios created with memfd_secret() */
- if (secretmem_mapping(r->file->f_mapping))
+ /* reject secretmem folios created with memfd_secret() or guest_memfd() */
+ if (mapping_no_direct_map(r->file->f_mapping))
return -EFAULT;
r->folio = filemap_get_folio(r->file->f_mapping, file_off >> PAGE_SHIFT);
diff --git a/mm/gup.c b/mm/gup.c
index adffe663594d..8c988e076e5d 100644
--- a/mm/gup.c
+++ b/mm/gup.c
@@ -1234,7 +1234,7 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags)
if ((gup_flags & FOLL_SPLIT_PMD) && is_vm_hugetlb_page(vma))
return -EOPNOTSUPP;
- if (vma_is_secretmem(vma))
+ if (vma_is_no_direct_map(vma))
return -EFAULT;
if (write) {
@@ -2751,7 +2751,6 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags)
{
bool reject_file_backed = false;
struct address_space *mapping;
- bool check_secretmem = false;
unsigned long mapping_flags;
/*
@@ -2763,14 +2762,6 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags)
reject_file_backed = true;
/* We hold a folio reference, so we can safely access folio fields. */
-
- /* secretmem folios are always order-0 folios. */
- if (IS_ENABLED(CONFIG_SECRETMEM) && !folio_test_large(folio))
- check_secretmem = true;
-
- if (!reject_file_backed && !check_secretmem)
- return true;
-
if (WARN_ON_ONCE(folio_test_slab(folio)))
return false;
@@ -2812,8 +2803,9 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags)
* At this point, we know the mapping is non-null and points to an
* address_space object.
*/
- if (check_secretmem && secretmem_mapping(mapping))
+ if (mapping_no_direct_map(mapping))
return false;
+
/* The only remaining allowed file system is shmem. */
return !reject_file_backed || shmem_mapping(mapping);
}
diff --git a/mm/mlock.c b/mm/mlock.c
index a1d93ad33c6d..0def453fe881 100644
--- a/mm/mlock.c
+++ b/mm/mlock.c
@@ -474,7 +474,7 @@ static int mlock_fixup(struct vma_iterator *vmi, struct vm_area_struct *vma,
if (newflags == oldflags || (oldflags & VM_SPECIAL) ||
is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm) ||
- vma_is_dax(vma) || vma_is_secretmem(vma) || (oldflags & VM_DROPPABLE))
+ vma_is_dax(vma) || vma_is_no_direct_map(vma) || (oldflags & VM_DROPPABLE))
/* don't set VM_LOCKED or VM_LOCKONFAULT and don't count */
goto out;
diff --git a/mm/secretmem.c b/mm/secretmem.c
index 422dcaa32506..a2daee0e63a5 100644
--- a/mm/secretmem.c
+++ b/mm/secretmem.c
@@ -134,11 +134,6 @@ static int secretmem_mmap_prepare(struct vm_area_desc *desc)
return 0;
}
-bool vma_is_secretmem(struct vm_area_struct *vma)
-{
- return vma->vm_ops == &secretmem_vm_ops;
-}
-
static const struct file_operations secretmem_fops = {
.release = secretmem_release,
.mmap_prepare = secretmem_mmap_prepare,
@@ -206,6 +201,7 @@ static struct file *secretmem_file_create(unsigned long flags)
mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER);
mapping_set_unevictable(inode->i_mapping);
+ mapping_set_no_direct_map(inode->i_mapping);
inode->i_op = &secretmem_iops;
inode->i_mapping->a_ops = &secretmem_aops;
--
2.50.1
Hi Patrick, kernel test robot noticed the following build warnings: [auto build test WARNING on a6ad54137af92535cfe32e19e5f3bc1bb7dbd383] url: https://github.com/intel-lab-lkp/linux/commits/Roy-Patrick/filemap-Pass-address_space-mapping-to-free_folio/20250828-174202 base: a6ad54137af92535cfe32e19e5f3bc1bb7dbd383 patch link: https://lore.kernel.org/r/20250828093902.2719-4-roypat%40amazon.co.uk patch subject: [PATCH v5 03/12] mm: introduce AS_NO_DIRECT_MAP config: loongarch-randconfig-r133-20250831 (https://download.01.org/0day-ci/archive/20250831/202508311805.yfcdeaFC-lkp@intel.com/config) compiler: loongarch64-linux-gcc (GCC) 14.3.0 reproduce: (https://download.01.org/0day-ci/archive/20250831/202508311805.yfcdeaFC-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202508311805.yfcdeaFC-lkp@intel.com/ sparse warnings: (new ones prefixed by >>) >> mm/secretmem.c:155:39: sparse: sparse: symbol 'secretmem_aops' was not declared. Should it be static? vim +/secretmem_aops +155 mm/secretmem.c 1507f51255c9ff Mike Rapoport 2021-07-07 154 1507f51255c9ff Mike Rapoport 2021-07-07 @155 const struct address_space_operations secretmem_aops = { 46de8b979492e1 Matthew Wilcox (Oracle 2022-02-09 156) .dirty_folio = noop_dirty_folio, 6612ed24a24273 Matthew Wilcox (Oracle 2022-05-02 157) .free_folio = secretmem_free_folio, 5409548df3876a Matthew Wilcox (Oracle 2022-06-06 158) .migrate_folio = secretmem_migrate_folio, 1507f51255c9ff Mike Rapoport 2021-07-07 159 }; 1507f51255c9ff Mike Rapoport 2021-07-07 160 -- 0-DAY CI Kernel Test Service https://github.com/intel/lkp-tests/wiki
On Sun, 2025-08-31 at 11:26 +0100, kernel test robot wrote: > Hi Patrick, > > kernel test robot noticed the following build warnings: > > [auto build test WARNING on a6ad54137af92535cfe32e19e5f3bc1bb7dbd383] > > url: https://github.com/intel-lab-lkp/linux/commits/Roy-Patrick/filemap-Pass-address_space-mapping-to-free_folio/20250828-174202 > base: a6ad54137af92535cfe32e19e5f3bc1bb7dbd383 > patch link: https://lore.kernel.org/r/20250828093902.2719-4-roypat%40amazon.co.uk > patch subject: [PATCH v5 03/12] mm: introduce AS_NO_DIRECT_MAP > config: loongarch-randconfig-r133-20250831 (https://download.01.org/0day-ci/archive/20250831/202508311805.yfcdeaFC-lkp@intel.com/config) > compiler: loongarch64-linux-gcc (GCC) 14.3.0 > reproduce: (https://download.01.org/0day-ci/archive/20250831/202508311805.yfcdeaFC-lkp@intel.com/reproduce) > > If you fix the issue in a separate patch/commit (i.e. not just a new version of > the same patch/commit), kindly add following tags > | Reported-by: kernel test robot <lkp@intel.com> > | Closes: https://lore.kernel.org/oe-kbuild-all/202508311805.yfcdeaFC-lkp@intel.com/ > > sparse warnings: (new ones prefixed by >>) >>> mm/secretmem.c:155:39: sparse: sparse: symbol 'secretmem_aops' was not declared. Should it be static? > > vim +/secretmem_aops +155 mm/secretmem.c > > 1507f51255c9ff Mike Rapoport 2021-07-07 154 > 1507f51255c9ff Mike Rapoport 2021-07-07 @155 const struct address_space_operations secretmem_aops = { > 46de8b979492e1 Matthew Wilcox (Oracle 2022-02-09 156) .dirty_folio = noop_dirty_folio, > 6612ed24a24273 Matthew Wilcox (Oracle 2022-05-02 157) .free_folio = secretmem_free_folio, > 5409548df3876a Matthew Wilcox (Oracle 2022-06-06 158) .migrate_folio = secretmem_migrate_folio, > 1507f51255c9ff Mike Rapoport 2021-07-07 159 }; > 1507f51255c9ff Mike Rapoport 2021-07-07 160 > > -- > 0-DAY CI Kernel Test Service > https://github.com/intel/lkp-tests/wiki This is the same thing Mike already pointed out (making `secretmem_aops` static)
On 28.08.25 11:39, Roy, Patrick wrote: > Add AS_NO_DIRECT_MAP for mappings where direct map entries of folios are > set to not present . Currently, mappings that match this description are > secretmem mappings (memfd_secret()). Later, some guest_memfd > configurations will also fall into this category. > > Reject this new type of mappings in all locations that currently reject > secretmem mappings, on the assumption that if secretmem mappings are > rejected somewhere, it is precisely because of an inability to deal with > folios without direct map entries, and then make memfd_secret() use > AS_NO_DIRECT_MAP on its address_space to drop its special > vma_is_secretmem()/secretmem_mapping() checks. > > This drops a optimization in gup_fast_folio_allowed() where > secretmem_mapping() was only called if CONFIG_SECRETMEM=y. secretmem is > enabled by default since commit b758fe6df50d ("mm/secretmem: make it on > by default"), so the secretmem check did not actually end up elided in > most cases anymore anyway. > > Use a new flag instead of overloading AS_INACCESSIBLE (which is already > set by guest_memfd) because not all guest_memfd mappings will end up > being direct map removed (e.g. in pKVM setups, parts of guest_memfd that > can be mapped to userspace should also be GUP-able, and generally not > have restrictions on who can access it). > > Signed-off-by: Patrick Roy <roypat@amazon.co.uk> > --- [...] > +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) > +{ > + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); > +} > + "vma_is_no_direct_map" reads a bit weird. "vma_has_no_direct_map" or "vma_no_direct_mapping" might be better. With the comment Mike and Fuad raised, this LGTM. -- Cheers David / dhildenb
On Thu, 2025-08-28 at 22:00 +0100, David Hildenbrand wrote: > On 28.08.25 11:39, Roy, Patrick wrote: >> Add AS_NO_DIRECT_MAP for mappings where direct map entries of folios are >> set to not present . Currently, mappings that match this description are >> secretmem mappings (memfd_secret()). Later, some guest_memfd >> configurations will also fall into this category. >> >> Reject this new type of mappings in all locations that currently reject >> secretmem mappings, on the assumption that if secretmem mappings are >> rejected somewhere, it is precisely because of an inability to deal with >> folios without direct map entries, and then make memfd_secret() use >> AS_NO_DIRECT_MAP on its address_space to drop its special >> vma_is_secretmem()/secretmem_mapping() checks. >> >> This drops a optimization in gup_fast_folio_allowed() where >> secretmem_mapping() was only called if CONFIG_SECRETMEM=y. secretmem is >> enabled by default since commit b758fe6df50d ("mm/secretmem: make it on >> by default"), so the secretmem check did not actually end up elided in >> most cases anymore anyway. >> >> Use a new flag instead of overloading AS_INACCESSIBLE (which is already >> set by guest_memfd) because not all guest_memfd mappings will end up >> being direct map removed (e.g. in pKVM setups, parts of guest_memfd that >> can be mapped to userspace should also be GUP-able, and generally not >> have restrictions on who can access it). >> >> Signed-off-by: Patrick Roy <roypat@amazon.co.uk> >> --- > [...] > >> +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) >> +{ >> + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); >> +} >> + > > "vma_is_no_direct_map" reads a bit weird. > > "vma_has_no_direct_map" or "vma_no_direct_mapping" might be better. I went with "vma_has_no_direct_map" for now, because vma_no_direct_mapping would imply (to me at least) changing "mapping_no_direct_map" to "mapping_no_direct_mapping", which also reads a bit weird imo. > With the comment Mike and Fuad raised, this LGTM. > > > -- > Cheers > > David / dhildenb Best, Patrick
On Thu, Aug 28, 2025 at 09:39:19AM +0000, Roy, Patrick wrote: > Add AS_NO_DIRECT_MAP for mappings where direct map entries of folios are > set to not present . Currently, mappings that match this description are > secretmem mappings (memfd_secret()). Later, some guest_memfd > configurations will also fall into this category. > > Reject this new type of mappings in all locations that currently reject > secretmem mappings, on the assumption that if secretmem mappings are > rejected somewhere, it is precisely because of an inability to deal with > folios without direct map entries, and then make memfd_secret() use > AS_NO_DIRECT_MAP on its address_space to drop its special > vma_is_secretmem()/secretmem_mapping() checks. > > This drops a optimization in gup_fast_folio_allowed() where > secretmem_mapping() was only called if CONFIG_SECRETMEM=y. secretmem is > enabled by default since commit b758fe6df50d ("mm/secretmem: make it on > by default"), so the secretmem check did not actually end up elided in > most cases anymore anyway. > > Use a new flag instead of overloading AS_INACCESSIBLE (which is already > set by guest_memfd) because not all guest_memfd mappings will end up > being direct map removed (e.g. in pKVM setups, parts of guest_memfd that > can be mapped to userspace should also be GUP-able, and generally not > have restrictions on who can access it). > > Signed-off-by: Patrick Roy <roypat@amazon.co.uk> > --- > include/linux/pagemap.h | 16 ++++++++++++++++ > include/linux/secretmem.h | 18 ------------------ > lib/buildid.c | 4 ++-- > mm/gup.c | 14 +++----------- > mm/mlock.c | 2 +- > mm/secretmem.c | 6 +----- > 6 files changed, 23 insertions(+), 37 deletions(-) > > diff --git a/include/linux/secretmem.h b/include/linux/secretmem.h > index e918f96881f5..0ae1fb057b3d 100644 > --- a/include/linux/secretmem.h > +++ b/include/linux/secretmem.h > @@ -4,28 +4,10 @@ > > #ifdef CONFIG_SECRETMEM > > -extern const struct address_space_operations secretmem_aops; Please also make secretmem_aops static in mm/secretmem.c > -static inline bool secretmem_mapping(struct address_space *mapping) > -{ > - return mapping->a_ops == &secretmem_aops; > -} > - ... > diff --git a/mm/gup.c b/mm/gup.c > index adffe663594d..8c988e076e5d 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -1234,7 +1234,7 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags) > if ((gup_flags & FOLL_SPLIT_PMD) && is_vm_hugetlb_page(vma)) > return -EOPNOTSUPP; > > - if (vma_is_secretmem(vma)) > + if (vma_is_no_direct_map(vma)) > return -EFAULT; > > if (write) { > @@ -2751,7 +2751,6 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags) > { > bool reject_file_backed = false; > struct address_space *mapping; > - bool check_secretmem = false; > unsigned long mapping_flags; > > /* > @@ -2763,14 +2762,6 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags) > reject_file_backed = true; > > /* We hold a folio reference, so we can safely access folio fields. */ > - > - /* secretmem folios are always order-0 folios. */ > - if (IS_ENABLED(CONFIG_SECRETMEM) && !folio_test_large(folio)) > - check_secretmem = true; > - > - if (!reject_file_backed && !check_secretmem) > - return true; > - > if (WARN_ON_ONCE(folio_test_slab(folio))) > return false; There's a check for hugetlb after this and a comment there mentions secretmem, please update that to "mapping with no direct map" or something like that. -- Sincerely yours, Mike.
Hi Mike, On Thu, 2025-08-28 at 15:26 +0100, Mike Rapoport wrote: > On Thu, Aug 28, 2025 at 09:39:19AM +0000, Roy, Patrick wrote: >> Add AS_NO_DIRECT_MAP for mappings where direct map entries of folios are >> set to not present . Currently, mappings that match this description are >> secretmem mappings (memfd_secret()). Later, some guest_memfd >> configurations will also fall into this category. >> >> Reject this new type of mappings in all locations that currently reject >> secretmem mappings, on the assumption that if secretmem mappings are >> rejected somewhere, it is precisely because of an inability to deal with >> folios without direct map entries, and then make memfd_secret() use >> AS_NO_DIRECT_MAP on its address_space to drop its special >> vma_is_secretmem()/secretmem_mapping() checks. >> >> This drops a optimization in gup_fast_folio_allowed() where >> secretmem_mapping() was only called if CONFIG_SECRETMEM=y. secretmem is >> enabled by default since commit b758fe6df50d ("mm/secretmem: make it on >> by default"), so the secretmem check did not actually end up elided in >> most cases anymore anyway. >> >> Use a new flag instead of overloading AS_INACCESSIBLE (which is already >> set by guest_memfd) because not all guest_memfd mappings will end up >> being direct map removed (e.g. in pKVM setups, parts of guest_memfd that >> can be mapped to userspace should also be GUP-able, and generally not >> have restrictions on who can access it). >> >> Signed-off-by: Patrick Roy <roypat@amazon.co.uk> >> --- >> include/linux/pagemap.h | 16 ++++++++++++++++ >> include/linux/secretmem.h | 18 ------------------ >> lib/buildid.c | 4 ++-- >> mm/gup.c | 14 +++----------- >> mm/mlock.c | 2 +- >> mm/secretmem.c | 6 +----- >> 6 files changed, 23 insertions(+), 37 deletions(-) >> >> diff --git a/include/linux/secretmem.h b/include/linux/secretmem.h >> index e918f96881f5..0ae1fb057b3d 100644 >> --- a/include/linux/secretmem.h >> +++ b/include/linux/secretmem.h >> @@ -4,28 +4,10 @@ >> >> #ifdef CONFIG_SECRETMEM >> >> -extern const struct address_space_operations secretmem_aops; > > Please also make secretmem_aops static in mm/secretmem.c Ack. >> -static inline bool secretmem_mapping(struct address_space *mapping) >> -{ >> - return mapping->a_ops == &secretmem_aops; >> -} >> - > > ... > >> diff --git a/mm/gup.c b/mm/gup.c >> index adffe663594d..8c988e076e5d 100644 >> --- a/mm/gup.c >> +++ b/mm/gup.c >> @@ -1234,7 +1234,7 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags) >> if ((gup_flags & FOLL_SPLIT_PMD) && is_vm_hugetlb_page(vma)) >> return -EOPNOTSUPP; >> >> - if (vma_is_secretmem(vma)) >> + if (vma_is_no_direct_map(vma)) >> return -EFAULT; >> >> if (write) { >> @@ -2751,7 +2751,6 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags) >> { >> bool reject_file_backed = false; >> struct address_space *mapping; >> - bool check_secretmem = false; >> unsigned long mapping_flags; >> >> /* >> @@ -2763,14 +2762,6 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags) >> reject_file_backed = true; >> >> /* We hold a folio reference, so we can safely access folio fields. */ >> - >> - /* secretmem folios are always order-0 folios. */ >> - if (IS_ENABLED(CONFIG_SECRETMEM) && !folio_test_large(folio)) >> - check_secretmem = true; >> - >> - if (!reject_file_backed && !check_secretmem) >> - return true; >> - >> if (WARN_ON_ONCE(folio_test_slab(folio))) >> return false; > > There's a check for hugetlb after this and a comment there mentions > secretmem, please update that to "mapping with no direct map" or something > like that. Ack. > -- > Sincerely yours, > Mike. Thanks, Patrick
Hi Patrick, On Thu, 28 Aug 2025 at 10:39, Roy, Patrick <roypat@amazon.co.uk> wrote: > > Add AS_NO_DIRECT_MAP for mappings where direct map entries of folios are > set to not present . Currently, mappings that match this description are > secretmem mappings (memfd_secret()). Later, some guest_memfd > configurations will also fall into this category. > > Reject this new type of mappings in all locations that currently reject > secretmem mappings, on the assumption that if secretmem mappings are > rejected somewhere, it is precisely because of an inability to deal with > folios without direct map entries, and then make memfd_secret() use > AS_NO_DIRECT_MAP on its address_space to drop its special > vma_is_secretmem()/secretmem_mapping() checks. > > This drops a optimization in gup_fast_folio_allowed() where > secretmem_mapping() was only called if CONFIG_SECRETMEM=y. secretmem is > enabled by default since commit b758fe6df50d ("mm/secretmem: make it on > by default"), so the secretmem check did not actually end up elided in > most cases anymore anyway. > > Use a new flag instead of overloading AS_INACCESSIBLE (which is already > set by guest_memfd) because not all guest_memfd mappings will end up > being direct map removed (e.g. in pKVM setups, parts of guest_memfd that > can be mapped to userspace should also be GUP-able, and generally not > have restrictions on who can access it). > > Signed-off-by: Patrick Roy <roypat@amazon.co.uk> > --- > include/linux/pagemap.h | 16 ++++++++++++++++ > include/linux/secretmem.h | 18 ------------------ > lib/buildid.c | 4 ++-- > mm/gup.c | 14 +++----------- > mm/mlock.c | 2 +- > mm/secretmem.c | 6 +----- > 6 files changed, 23 insertions(+), 37 deletions(-) > > diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h > index 12a12dae727d..b52b28ae4636 100644 > --- a/include/linux/pagemap.h > +++ b/include/linux/pagemap.h > @@ -211,6 +211,7 @@ enum mapping_flags { > folio contents */ > AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */ > AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, > + AS_NO_DIRECT_MAP = 10, /* Folios in the mapping are not in the direct map */ > /* Bits 16-25 are used for FOLIO_ORDER */ > AS_FOLIO_ORDER_BITS = 5, > AS_FOLIO_ORDER_MIN = 16, > @@ -346,6 +347,21 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_spac > return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); > } > > +static inline void mapping_set_no_direct_map(struct address_space *mapping) > +{ > + set_bit(AS_NO_DIRECT_MAP, &mapping->flags); > +} > + > +static inline bool mapping_no_direct_map(struct address_space *mapping) > +{ > + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); > +} > + > +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) > +{ > + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); > +} > + Any reason vma is const whereas mapping in the function that it calls (defined above it) isn't? Cheers, /fuad > static inline gfp_t mapping_gfp_mask(struct address_space * mapping) > { > return mapping->gfp_mask; > diff --git a/include/linux/secretmem.h b/include/linux/secretmem.h > index e918f96881f5..0ae1fb057b3d 100644 > --- a/include/linux/secretmem.h > +++ b/include/linux/secretmem.h > @@ -4,28 +4,10 @@ > > #ifdef CONFIG_SECRETMEM > > -extern const struct address_space_operations secretmem_aops; > - > -static inline bool secretmem_mapping(struct address_space *mapping) > -{ > - return mapping->a_ops == &secretmem_aops; > -} > - > -bool vma_is_secretmem(struct vm_area_struct *vma); > bool secretmem_active(void); > > #else > > -static inline bool vma_is_secretmem(struct vm_area_struct *vma) > -{ > - return false; > -} > - > -static inline bool secretmem_mapping(struct address_space *mapping) > -{ > - return false; > -} > - > static inline bool secretmem_active(void) > { > return false; > diff --git a/lib/buildid.c b/lib/buildid.c > index c4b0f376fb34..33f173a607ad 100644 > --- a/lib/buildid.c > +++ b/lib/buildid.c > @@ -65,8 +65,8 @@ static int freader_get_folio(struct freader *r, loff_t file_off) > > freader_put_folio(r); > > - /* reject secretmem folios created with memfd_secret() */ > - if (secretmem_mapping(r->file->f_mapping)) > + /* reject secretmem folios created with memfd_secret() or guest_memfd() */ > + if (mapping_no_direct_map(r->file->f_mapping)) > return -EFAULT; > > r->folio = filemap_get_folio(r->file->f_mapping, file_off >> PAGE_SHIFT); > diff --git a/mm/gup.c b/mm/gup.c > index adffe663594d..8c988e076e5d 100644 > --- a/mm/gup.c > +++ b/mm/gup.c > @@ -1234,7 +1234,7 @@ static int check_vma_flags(struct vm_area_struct *vma, unsigned long gup_flags) > if ((gup_flags & FOLL_SPLIT_PMD) && is_vm_hugetlb_page(vma)) > return -EOPNOTSUPP; > > - if (vma_is_secretmem(vma)) > + if (vma_is_no_direct_map(vma)) > return -EFAULT; > > if (write) { > @@ -2751,7 +2751,6 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags) > { > bool reject_file_backed = false; > struct address_space *mapping; > - bool check_secretmem = false; > unsigned long mapping_flags; > > /* > @@ -2763,14 +2762,6 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags) > reject_file_backed = true; > > /* We hold a folio reference, so we can safely access folio fields. */ > - > - /* secretmem folios are always order-0 folios. */ > - if (IS_ENABLED(CONFIG_SECRETMEM) && !folio_test_large(folio)) > - check_secretmem = true; > - > - if (!reject_file_backed && !check_secretmem) > - return true; > - > if (WARN_ON_ONCE(folio_test_slab(folio))) > return false; > > @@ -2812,8 +2803,9 @@ static bool gup_fast_folio_allowed(struct folio *folio, unsigned int flags) > * At this point, we know the mapping is non-null and points to an > * address_space object. > */ > - if (check_secretmem && secretmem_mapping(mapping)) > + if (mapping_no_direct_map(mapping)) > return false; > + > /* The only remaining allowed file system is shmem. */ > return !reject_file_backed || shmem_mapping(mapping); > } > diff --git a/mm/mlock.c b/mm/mlock.c > index a1d93ad33c6d..0def453fe881 100644 > --- a/mm/mlock.c > +++ b/mm/mlock.c > @@ -474,7 +474,7 @@ static int mlock_fixup(struct vma_iterator *vmi, struct vm_area_struct *vma, > > if (newflags == oldflags || (oldflags & VM_SPECIAL) || > is_vm_hugetlb_page(vma) || vma == get_gate_vma(current->mm) || > - vma_is_dax(vma) || vma_is_secretmem(vma) || (oldflags & VM_DROPPABLE)) > + vma_is_dax(vma) || vma_is_no_direct_map(vma) || (oldflags & VM_DROPPABLE)) > /* don't set VM_LOCKED or VM_LOCKONFAULT and don't count */ > goto out; > > diff --git a/mm/secretmem.c b/mm/secretmem.c > index 422dcaa32506..a2daee0e63a5 100644 > --- a/mm/secretmem.c > +++ b/mm/secretmem.c > @@ -134,11 +134,6 @@ static int secretmem_mmap_prepare(struct vm_area_desc *desc) > return 0; > } > > -bool vma_is_secretmem(struct vm_area_struct *vma) > -{ > - return vma->vm_ops == &secretmem_vm_ops; > -} > - > static const struct file_operations secretmem_fops = { > .release = secretmem_release, > .mmap_prepare = secretmem_mmap_prepare, > @@ -206,6 +201,7 @@ static struct file *secretmem_file_create(unsigned long flags) > > mapping_set_gfp_mask(inode->i_mapping, GFP_HIGHUSER); > mapping_set_unevictable(inode->i_mapping); > + mapping_set_no_direct_map(inode->i_mapping); > > inode->i_op = &secretmem_iops; > inode->i_mapping->a_ops = &secretmem_aops; > -- > 2.50.1 >
Hi Fuad! On Thu, 2025-08-28 at 11:21 +0100, Fuad Tabba wrote: > Hi Patrick, > > On Thu, 28 Aug 2025 at 10:39, Roy, Patrick <roypat@amazon.co.uk> wrote: >> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h >> index 12a12dae727d..b52b28ae4636 100644 >> --- a/include/linux/pagemap.h >> +++ b/include/linux/pagemap.h >> @@ -211,6 +211,7 @@ enum mapping_flags { >> folio contents */ >> AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */ >> AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, >> + AS_NO_DIRECT_MAP = 10, /* Folios in the mapping are not in the direct map */ >> /* Bits 16-25 are used for FOLIO_ORDER */ >> AS_FOLIO_ORDER_BITS = 5, >> AS_FOLIO_ORDER_MIN = 16, >> @@ -346,6 +347,21 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_spac >> return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); >> } >> >> +static inline void mapping_set_no_direct_map(struct address_space *mapping) >> +{ >> + set_bit(AS_NO_DIRECT_MAP, &mapping->flags); >> +} >> + >> +static inline bool mapping_no_direct_map(struct address_space *mapping) >> +{ >> + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); >> +} >> + >> +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) >> +{ >> + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); >> +} >> + > Any reason vma is const whereas mapping in the function that it calls > (defined above it) isn't? Ah, I cannot say that that was a conscious decision, but rather an artifact of the code that I looked at for reference when writing these two simply did it this way. Are you saying both should be const, or neither (in my mind, both could be const, but the mapping_*() family of functions further up in this file dont take const arguments, so I'm a bit unsure now)? > Cheers, > /fuad Best, Patrick
On Mon, 2025-09-01 at 14:54 +0100, "Roy, Patrick" wrote: > > Hi Fuad! > > On Thu, 2025-08-28 at 11:21 +0100, Fuad Tabba wrote: >> Hi Patrick, >> >> On Thu, 28 Aug 2025 at 10:39, Roy, Patrick <roypat@amazon.co.uk> wrote: >>> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h >>> index 12a12dae727d..b52b28ae4636 100644 >>> --- a/include/linux/pagemap.h >>> +++ b/include/linux/pagemap.h >>> @@ -211,6 +211,7 @@ enum mapping_flags { >>> folio contents */ >>> AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */ >>> AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, >>> + AS_NO_DIRECT_MAP = 10, /* Folios in the mapping are not in the direct map */ >>> /* Bits 16-25 are used for FOLIO_ORDER */ >>> AS_FOLIO_ORDER_BITS = 5, >>> AS_FOLIO_ORDER_MIN = 16, >>> @@ -346,6 +347,21 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_spac >>> return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); >>> } >>> >>> +static inline void mapping_set_no_direct_map(struct address_space *mapping) >>> +{ >>> + set_bit(AS_NO_DIRECT_MAP, &mapping->flags); >>> +} >>> + >>> +static inline bool mapping_no_direct_map(struct address_space *mapping) >>> +{ >>> + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); >>> +} >>> + >>> +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) >>> +{ >>> + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); >>> +} >>> + >> Any reason vma is const whereas mapping in the function that it calls >> (defined above it) isn't? > > Ah, I cannot say that that was a conscious decision, but rather an artifact of > the code that I looked at for reference when writing these two simply did it > this way. Are you saying both should be const, or neither (in my mind, both > could be const, but the mapping_*() family of functions further up in this file > dont take const arguments, so I'm a bit unsure now)? Hah, just saw https://lore.kernel.org/linux-mm/20250901123028.3383461-3-max.kellermann@ionos.com/. Guess that means "both should be const" then :D >> Cheers, >> /fuad > > Best, > Patrick
Hi Patrick, On Mon, 1 Sept 2025 at 15:56, Roy, Patrick <roypat@amazon.co.uk> wrote: > > On Mon, 2025-09-01 at 14:54 +0100, "Roy, Patrick" wrote: > > > > Hi Fuad! > > > > On Thu, 2025-08-28 at 11:21 +0100, Fuad Tabba wrote: > >> Hi Patrick, > >> > >> On Thu, 28 Aug 2025 at 10:39, Roy, Patrick <roypat@amazon.co.uk> wrote: > >>> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h > >>> index 12a12dae727d..b52b28ae4636 100644 > >>> --- a/include/linux/pagemap.h > >>> +++ b/include/linux/pagemap.h > >>> @@ -211,6 +211,7 @@ enum mapping_flags { > >>> folio contents */ > >>> AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */ > >>> AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, > >>> + AS_NO_DIRECT_MAP = 10, /* Folios in the mapping are not in the direct map */ > >>> /* Bits 16-25 are used for FOLIO_ORDER */ > >>> AS_FOLIO_ORDER_BITS = 5, > >>> AS_FOLIO_ORDER_MIN = 16, > >>> @@ -346,6 +347,21 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_spac > >>> return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); > >>> } > >>> > >>> +static inline void mapping_set_no_direct_map(struct address_space *mapping) > >>> +{ > >>> + set_bit(AS_NO_DIRECT_MAP, &mapping->flags); > >>> +} > >>> + > >>> +static inline bool mapping_no_direct_map(struct address_space *mapping) > >>> +{ > >>> + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); > >>> +} > >>> + > >>> +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) > >>> +{ > >>> + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); > >>> +} > >>> + > >> Any reason vma is const whereas mapping in the function that it calls > >> (defined above it) isn't? > > > > Ah, I cannot say that that was a conscious decision, but rather an artifact of > > the code that I looked at for reference when writing these two simply did it > > this way. Are you saying both should be const, or neither (in my mind, both > > could be const, but the mapping_*() family of functions further up in this file > > dont take const arguments, so I'm a bit unsure now)? > > Hah, just saw > https://lore.kernel.org/linux-mm/20250901123028.3383461-3-max.kellermann@ionos.com/. > Guess that means "both should be const" then :D I don't have any strong preference regarding which way, as long as it's consistent. The thing that should be avoided is having one function with a parameter marked as const, pass that parameter (or something derived from it), to a non-const function. Instead of helping, this could cause a lot of headaches when trying to debug things in the future, and figuring out what something that's supposed to be "const" is being "corrupted". Cheers, /fuad > > >> Cheers, > >> /fuad > > > > Best, > > Patrick >
On 02.09.25 09:59, Fuad Tabba wrote: > Hi Patrick, > > On Mon, 1 Sept 2025 at 15:56, Roy, Patrick <roypat@amazon.co.uk> wrote: >> >> On Mon, 2025-09-01 at 14:54 +0100, "Roy, Patrick" wrote: >>> >>> Hi Fuad! >>> >>> On Thu, 2025-08-28 at 11:21 +0100, Fuad Tabba wrote: >>>> Hi Patrick, >>>> >>>> On Thu, 28 Aug 2025 at 10:39, Roy, Patrick <roypat@amazon.co.uk> wrote: >>>>> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h >>>>> index 12a12dae727d..b52b28ae4636 100644 >>>>> --- a/include/linux/pagemap.h >>>>> +++ b/include/linux/pagemap.h >>>>> @@ -211,6 +211,7 @@ enum mapping_flags { >>>>> folio contents */ >>>>> AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */ >>>>> AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, >>>>> + AS_NO_DIRECT_MAP = 10, /* Folios in the mapping are not in the direct map */ >>>>> /* Bits 16-25 are used for FOLIO_ORDER */ >>>>> AS_FOLIO_ORDER_BITS = 5, >>>>> AS_FOLIO_ORDER_MIN = 16, >>>>> @@ -346,6 +347,21 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_spac >>>>> return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); >>>>> } >>>>> >>>>> +static inline void mapping_set_no_direct_map(struct address_space *mapping) >>>>> +{ >>>>> + set_bit(AS_NO_DIRECT_MAP, &mapping->flags); >>>>> +} >>>>> + >>>>> +static inline bool mapping_no_direct_map(struct address_space *mapping) >>>>> +{ >>>>> + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); >>>>> +} >>>>> + >>>>> +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) >>>>> +{ >>>>> + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); >>>>> +} >>>>> + >>>> Any reason vma is const whereas mapping in the function that it calls >>>> (defined above it) isn't? >>> >>> Ah, I cannot say that that was a conscious decision, but rather an artifact of >>> the code that I looked at for reference when writing these two simply did it >>> this way. Are you saying both should be const, or neither (in my mind, both >>> could be const, but the mapping_*() family of functions further up in this file >>> dont take const arguments, so I'm a bit unsure now)? >> >> Hah, just saw >> https://lore.kernel.org/linux-mm/20250901123028.3383461-3-max.kellermann@ionos.com/. >> Guess that means "both should be const" then :D > > I don't have any strong preference regarding which way, as long as > it's consistent. The thing that should be avoided is having one > function with a parameter marked as const, pass that parameter (or > something derived from it), to a non-const function. I think the compiler will tell you that that is not ok (and you'd have to force-cast the const it away). Agreed that we should be using const * for these simple getter/test functions. -- Cheers David / dhildenb
On Tue, 2 Sept 2025 at 09:46, David Hildenbrand <david@redhat.com> wrote: > > On 02.09.25 09:59, Fuad Tabba wrote: > > Hi Patrick, > > > > On Mon, 1 Sept 2025 at 15:56, Roy, Patrick <roypat@amazon.co.uk> wrote: > >> > >> On Mon, 2025-09-01 at 14:54 +0100, "Roy, Patrick" wrote: > >>> > >>> Hi Fuad! > >>> > >>> On Thu, 2025-08-28 at 11:21 +0100, Fuad Tabba wrote: > >>>> Hi Patrick, > >>>> > >>>> On Thu, 28 Aug 2025 at 10:39, Roy, Patrick <roypat@amazon.co.uk> wrote: > >>>>> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h > >>>>> index 12a12dae727d..b52b28ae4636 100644 > >>>>> --- a/include/linux/pagemap.h > >>>>> +++ b/include/linux/pagemap.h > >>>>> @@ -211,6 +211,7 @@ enum mapping_flags { > >>>>> folio contents */ > >>>>> AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */ > >>>>> AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, > >>>>> + AS_NO_DIRECT_MAP = 10, /* Folios in the mapping are not in the direct map */ > >>>>> /* Bits 16-25 are used for FOLIO_ORDER */ > >>>>> AS_FOLIO_ORDER_BITS = 5, > >>>>> AS_FOLIO_ORDER_MIN = 16, > >>>>> @@ -346,6 +347,21 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_spac > >>>>> return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); > >>>>> } > >>>>> > >>>>> +static inline void mapping_set_no_direct_map(struct address_space *mapping) > >>>>> +{ > >>>>> + set_bit(AS_NO_DIRECT_MAP, &mapping->flags); > >>>>> +} > >>>>> + > >>>>> +static inline bool mapping_no_direct_map(struct address_space *mapping) > >>>>> +{ > >>>>> + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); > >>>>> +} > >>>>> + > >>>>> +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) > >>>>> +{ > >>>>> + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); > >>>>> +} > >>>>> + > >>>> Any reason vma is const whereas mapping in the function that it calls > >>>> (defined above it) isn't? > >>> > >>> Ah, I cannot say that that was a conscious decision, but rather an artifact of > >>> the code that I looked at for reference when writing these two simply did it > >>> this way. Are you saying both should be const, or neither (in my mind, both > >>> could be const, but the mapping_*() family of functions further up in this file > >>> dont take const arguments, so I'm a bit unsure now)? > >> > >> Hah, just saw > >> https://lore.kernel.org/linux-mm/20250901123028.3383461-3-max.kellermann@ionos.com/. > >> Guess that means "both should be const" then :D > > > > I don't have any strong preference regarding which way, as long as > > it's consistent. The thing that should be avoided is having one > > function with a parameter marked as const, pass that parameter (or > > something derived from it), to a non-const function. > > I think the compiler will tell you that that is not ok (and you'd have > to force-cast the const it away). Not for the scenario I'm worried about. The compiler didn't complain about this (from this patch): +static inline bool mapping_no_direct_map(struct address_space *mapping) +{ + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); +} + +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) +{ + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); +} vma_is_no_direct_map() takes a const, but mapping_no_direct_map() doesn't. For now, mapping_no_direct_map() doesn't modify anything. But it could, and the compiler wouldn't complain. Cheers, /fuad > Agreed that we should be using const * for these simple getter/test > functions. > > -- > Cheers > > David / dhildenb >
On Tue, 2025-09-02 at 09:50 +0100, Fuad Tabba wrote: > On Tue, 2 Sept 2025 at 09:46, David Hildenbrand <david@redhat.com> wrote: >> >> On 02.09.25 09:59, Fuad Tabba wrote: >>> Hi Patrick, >>> >>> On Mon, 1 Sept 2025 at 15:56, Roy, Patrick <roypat@amazon.co.uk> wrote: >>>> >>>> On Mon, 2025-09-01 at 14:54 +0100, "Roy, Patrick" wrote: >>>>> >>>>> Hi Fuad! >>>>> >>>>> On Thu, 2025-08-28 at 11:21 +0100, Fuad Tabba wrote: >>>>>> Hi Patrick, >>>>>> >>>>>> On Thu, 28 Aug 2025 at 10:39, Roy, Patrick <roypat@amazon.co.uk> wrote: >>>>>>> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h >>>>>>> index 12a12dae727d..b52b28ae4636 100644 >>>>>>> --- a/include/linux/pagemap.h >>>>>>> +++ b/include/linux/pagemap.h >>>>>>> @@ -211,6 +211,7 @@ enum mapping_flags { >>>>>>> folio contents */ >>>>>>> AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */ >>>>>>> AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, >>>>>>> + AS_NO_DIRECT_MAP = 10, /* Folios in the mapping are not in the direct map */ >>>>>>> /* Bits 16-25 are used for FOLIO_ORDER */ >>>>>>> AS_FOLIO_ORDER_BITS = 5, >>>>>>> AS_FOLIO_ORDER_MIN = 16, >>>>>>> @@ -346,6 +347,21 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_spac >>>>>>> return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); >>>>>>> } >>>>>>> >>>>>>> +static inline void mapping_set_no_direct_map(struct address_space *mapping) >>>>>>> +{ >>>>>>> + set_bit(AS_NO_DIRECT_MAP, &mapping->flags); >>>>>>> +} >>>>>>> + >>>>>>> +static inline bool mapping_no_direct_map(struct address_space *mapping) >>>>>>> +{ >>>>>>> + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); >>>>>>> +} >>>>>>> + >>>>>>> +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) >>>>>>> +{ >>>>>>> + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); >>>>>>> +} >>>>>>> + >>>>>> Any reason vma is const whereas mapping in the function that it calls >>>>>> (defined above it) isn't? >>>>> >>>>> Ah, I cannot say that that was a conscious decision, but rather an artifact of >>>>> the code that I looked at for reference when writing these two simply did it >>>>> this way. Are you saying both should be const, or neither (in my mind, both >>>>> could be const, but the mapping_*() family of functions further up in this file >>>>> dont take const arguments, so I'm a bit unsure now)? >>>> >>>> Hah, just saw >>>> https://lore.kernel.org/linux-mm/20250901123028.3383461-3-max.kellermann@ionos.com/. >>>> Guess that means "both should be const" then :D >>> >>> I don't have any strong preference regarding which way, as long as >>> it's consistent. The thing that should be avoided is having one >>> function with a parameter marked as const, pass that parameter (or >>> something derived from it), to a non-const function. >> >> I think the compiler will tell you that that is not ok (and you'd have >> to force-cast the const it away). > > Not for the scenario I'm worried about. The compiler didn't complain > about this (from this patch): > > +static inline bool mapping_no_direct_map(struct address_space *mapping) > +{ > + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); > +} > + > +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) > +{ > + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); > +} > > vma_is_no_direct_map() takes a const, but mapping_no_direct_map() > doesn't. For now, mapping_no_direct_map() doesn't modify anything. But > it could, and the compiler wouldn't complain. Wouldn't this only be a problem if vma->vm_file->f_mapping was a 'const struct address_space *const'? I thought const-ness doesn't leak into pointers (e.g. even above, vma_is_no_direct_map isn't allowed to make vma point at something else, but it could modify the pointed-to vm_area_struct). > Cheers, > /fuad > > >> Agreed that we should be using const * for these simple getter/test >> functions. >> >> -- >> Cheers >> >> David / dhildenb >>
On Tue, 2 Sept 2025 at 10:18, Roy, Patrick <roypat@amazon.co.uk> wrote: > > On Tue, 2025-09-02 at 09:50 +0100, Fuad Tabba wrote: > > On Tue, 2 Sept 2025 at 09:46, David Hildenbrand <david@redhat.com> wrote: > >> > >> On 02.09.25 09:59, Fuad Tabba wrote: > >>> Hi Patrick, > >>> > >>> On Mon, 1 Sept 2025 at 15:56, Roy, Patrick <roypat@amazon.co.uk> wrote: > >>>> > >>>> On Mon, 2025-09-01 at 14:54 +0100, "Roy, Patrick" wrote: > >>>>> > >>>>> Hi Fuad! > >>>>> > >>>>> On Thu, 2025-08-28 at 11:21 +0100, Fuad Tabba wrote: > >>>>>> Hi Patrick, > >>>>>> > >>>>>> On Thu, 28 Aug 2025 at 10:39, Roy, Patrick <roypat@amazon.co.uk> wrote: > >>>>>>> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h > >>>>>>> index 12a12dae727d..b52b28ae4636 100644 > >>>>>>> --- a/include/linux/pagemap.h > >>>>>>> +++ b/include/linux/pagemap.h > >>>>>>> @@ -211,6 +211,7 @@ enum mapping_flags { > >>>>>>> folio contents */ > >>>>>>> AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */ > >>>>>>> AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, > >>>>>>> + AS_NO_DIRECT_MAP = 10, /* Folios in the mapping are not in the direct map */ > >>>>>>> /* Bits 16-25 are used for FOLIO_ORDER */ > >>>>>>> AS_FOLIO_ORDER_BITS = 5, > >>>>>>> AS_FOLIO_ORDER_MIN = 16, > >>>>>>> @@ -346,6 +347,21 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_spac > >>>>>>> return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); > >>>>>>> } > >>>>>>> > >>>>>>> +static inline void mapping_set_no_direct_map(struct address_space *mapping) > >>>>>>> +{ > >>>>>>> + set_bit(AS_NO_DIRECT_MAP, &mapping->flags); > >>>>>>> +} > >>>>>>> + > >>>>>>> +static inline bool mapping_no_direct_map(struct address_space *mapping) > >>>>>>> +{ > >>>>>>> + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); > >>>>>>> +} > >>>>>>> + > >>>>>>> +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) > >>>>>>> +{ > >>>>>>> + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); > >>>>>>> +} > >>>>>>> + > >>>>>> Any reason vma is const whereas mapping in the function that it calls > >>>>>> (defined above it) isn't? > >>>>> > >>>>> Ah, I cannot say that that was a conscious decision, but rather an artifact of > >>>>> the code that I looked at for reference when writing these two simply did it > >>>>> this way. Are you saying both should be const, or neither (in my mind, both > >>>>> could be const, but the mapping_*() family of functions further up in this file > >>>>> dont take const arguments, so I'm a bit unsure now)? > >>>> > >>>> Hah, just saw > >>>> https://lore.kernel.org/linux-mm/20250901123028.3383461-3-max.kellermann@ionos.com/. > >>>> Guess that means "both should be const" then :D > >>> > >>> I don't have any strong preference regarding which way, as long as > >>> it's consistent. The thing that should be avoided is having one > >>> function with a parameter marked as const, pass that parameter (or > >>> something derived from it), to a non-const function. > >> > >> I think the compiler will tell you that that is not ok (and you'd have > >> to force-cast the const it away). > > > > Not for the scenario I'm worried about. The compiler didn't complain > > about this (from this patch): > > > > +static inline bool mapping_no_direct_map(struct address_space *mapping) > > +{ > > + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); > > +} > > + > > +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) > > +{ > > + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); > > +} > > > > vma_is_no_direct_map() takes a const, but mapping_no_direct_map() > > doesn't. For now, mapping_no_direct_map() doesn't modify anything. But > > it could, and the compiler wouldn't complain. > > Wouldn't this only be a problem if vma->vm_file->f_mapping was a 'const struct > address_space *const'? I thought const-ness doesn't leak into pointers (e.g. > even above, vma_is_no_direct_map isn't allowed to make vma point at something > else, but it could modify the pointed-to vm_area_struct). That's the thing, constness checks don't carry over to pointers within a struct, but a person reading the code would assume that a function with a parameter marked as const wouldn't modify anything related to that parameter. Cheers, /fuad > > Cheers, > > /fuad > > > > > >> Agreed that we should be using const * for these simple getter/test > >> functions. > >> > >> -- > >> Cheers > >> > >> David / dhildenb > >> >
On 02.09.25 11:21, Fuad Tabba wrote: > On Tue, 2 Sept 2025 at 10:18, Roy, Patrick <roypat@amazon.co.uk> wrote: >> >> On Tue, 2025-09-02 at 09:50 +0100, Fuad Tabba wrote: >>> On Tue, 2 Sept 2025 at 09:46, David Hildenbrand <david@redhat.com> wrote: >>>> >>>> On 02.09.25 09:59, Fuad Tabba wrote: >>>>> Hi Patrick, >>>>> >>>>> On Mon, 1 Sept 2025 at 15:56, Roy, Patrick <roypat@amazon.co.uk> wrote: >>>>>> >>>>>> On Mon, 2025-09-01 at 14:54 +0100, "Roy, Patrick" wrote: >>>>>>> >>>>>>> Hi Fuad! >>>>>>> >>>>>>> On Thu, 2025-08-28 at 11:21 +0100, Fuad Tabba wrote: >>>>>>>> Hi Patrick, >>>>>>>> >>>>>>>> On Thu, 28 Aug 2025 at 10:39, Roy, Patrick <roypat@amazon.co.uk> wrote: >>>>>>>>> diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h >>>>>>>>> index 12a12dae727d..b52b28ae4636 100644 >>>>>>>>> --- a/include/linux/pagemap.h >>>>>>>>> +++ b/include/linux/pagemap.h >>>>>>>>> @@ -211,6 +211,7 @@ enum mapping_flags { >>>>>>>>> folio contents */ >>>>>>>>> AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */ >>>>>>>>> AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9, >>>>>>>>> + AS_NO_DIRECT_MAP = 10, /* Folios in the mapping are not in the direct map */ >>>>>>>>> /* Bits 16-25 are used for FOLIO_ORDER */ >>>>>>>>> AS_FOLIO_ORDER_BITS = 5, >>>>>>>>> AS_FOLIO_ORDER_MIN = 16, >>>>>>>>> @@ -346,6 +347,21 @@ static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_spac >>>>>>>>> return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags); >>>>>>>>> } >>>>>>>>> >>>>>>>>> +static inline void mapping_set_no_direct_map(struct address_space *mapping) >>>>>>>>> +{ >>>>>>>>> + set_bit(AS_NO_DIRECT_MAP, &mapping->flags); >>>>>>>>> +} >>>>>>>>> + >>>>>>>>> +static inline bool mapping_no_direct_map(struct address_space *mapping) >>>>>>>>> +{ >>>>>>>>> + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); >>>>>>>>> +} >>>>>>>>> + >>>>>>>>> +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) >>>>>>>>> +{ >>>>>>>>> + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); >>>>>>>>> +} >>>>>>>>> + >>>>>>>> Any reason vma is const whereas mapping in the function that it calls >>>>>>>> (defined above it) isn't? >>>>>>> >>>>>>> Ah, I cannot say that that was a conscious decision, but rather an artifact of >>>>>>> the code that I looked at for reference when writing these two simply did it >>>>>>> this way. Are you saying both should be const, or neither (in my mind, both >>>>>>> could be const, but the mapping_*() family of functions further up in this file >>>>>>> dont take const arguments, so I'm a bit unsure now)? >>>>>> >>>>>> Hah, just saw >>>>>> https://lore.kernel.org/linux-mm/20250901123028.3383461-3-max.kellermann@ionos.com/. >>>>>> Guess that means "both should be const" then :D >>>>> >>>>> I don't have any strong preference regarding which way, as long as >>>>> it's consistent. The thing that should be avoided is having one >>>>> function with a parameter marked as const, pass that parameter (or >>>>> something derived from it), to a non-const function. >>>> >>>> I think the compiler will tell you that that is not ok (and you'd have >>>> to force-cast the const it away). >>> >>> Not for the scenario I'm worried about. The compiler didn't complain >>> about this (from this patch): >>> >>> +static inline bool mapping_no_direct_map(struct address_space *mapping) >>> +{ >>> + return test_bit(AS_NO_DIRECT_MAP, &mapping->flags); >>> +} >>> + >>> +static inline bool vma_is_no_direct_map(const struct vm_area_struct *vma) >>> +{ >>> + return vma->vm_file && mapping_no_direct_map(vma->vm_file->f_mapping); >>> +} >>> >>> vma_is_no_direct_map() takes a const, but mapping_no_direct_map() >>> doesn't. For now, mapping_no_direct_map() doesn't modify anything. But >>> it could, and the compiler wouldn't complain. >> >> Wouldn't this only be a problem if vma->vm_file->f_mapping was a 'const struct >> address_space *const'? I thought const-ness doesn't leak into pointers (e.g. >> even above, vma_is_no_direct_map isn't allowed to make vma point at something >> else, but it could modify the pointed-to vm_area_struct). > > That's the thing, constness checks don't carry over to pointers within > a struct, but a person reading the code would assume that a function > with a parameter marked as const wouldn't modify anything related to > that parameter. Ah, thanks, I forgot that detail, it's only for embedded structs but not pointers. I wonder if something (sparse?) could detect such cases. -- Cheers David / dhildenb
© 2016 - 2025 Red Hat, Inc.