]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
s390/uv: Convert PG_arch_1 users to only work on small folios
authorDavid Hildenbrand <david@redhat.com>
Wed, 8 May 2024 18:29:49 +0000 (20:29 +0200)
committerAlexander Gordeev <agordeev@linux.ibm.com>
Wed, 5 Jun 2024 15:17:24 +0000 (17:17 +0200)
Now that make_folio_secure() may only set PG_arch_1 for small folios,
let's convert relevant remaining UV code to only work on (small) folios
and simply reject large folios early. This way, we'll never end up
touching PG_arch_1 on tail pages of a large folio in UV code.

The folio_get()/folio_put() for functions that are documented to already
hold a folio reference look weird; likely they are required to make
concurrent gmap_make_secure() back off because the caller might only hold
an implicit reference due to the page mapping. So leave that alone for now.

Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
Signed-off-by: David Hildenbrand <david@redhat.com>
Link: https://lore.kernel.org/r/20240508182955.358628-5-david@redhat.com
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Alexander Gordeev <agordeev@linux.ibm.com>
arch/s390/include/asm/page.h
arch/s390/kernel/uv.c

index 224ff9d433eadd58c4d4b904686096ffeb80602a..ecbf4b626f467c23caf80d5e5feed2b2a8562091 100644 (file)
@@ -247,7 +247,9 @@ static inline unsigned long __phys_addr(unsigned long x, bool is_31bit)
 #define pfn_to_phys(pfn)       ((pfn) << PAGE_SHIFT)
 
 #define phys_to_page(phys)     pfn_to_page(phys_to_pfn(phys))
+#define phys_to_folio(phys)    page_folio(phys_to_page(phys))
 #define page_to_phys(page)     pfn_to_phys(page_to_pfn(page))
+#define folio_to_phys(page)    pfn_to_phys(folio_pfn(folio))
 
 static inline void *pfn_to_virt(unsigned long pfn)
 {
index 3c6d86e3e8285b6c73c905872c2bc1c9d7b876f4..914dcec273294a3fd09cb23e5c2f49797d1fe340 100644 (file)
@@ -135,14 +135,18 @@ static int uv_destroy_page(unsigned long paddr)
  */
 int uv_destroy_owned_page(unsigned long paddr)
 {
-       struct page *page = phys_to_page(paddr);
+       struct folio *folio = phys_to_folio(paddr);
        int rc;
 
-       get_page(page);
+       /* See gmap_make_secure(): large folios cannot be secure */
+       if (unlikely(folio_test_large(folio)))
+               return 0;
+
+       folio_get(folio);
        rc = uv_destroy_page(paddr);
        if (!rc)
-               clear_bit(PG_arch_1, &page->flags);
-       put_page(page);
+               clear_bit(PG_arch_1, &folio->flags);
+       folio_put(folio);
        return rc;
 }
 
@@ -170,14 +174,18 @@ int uv_convert_from_secure(unsigned long paddr)
  */
 int uv_convert_owned_from_secure(unsigned long paddr)
 {
-       struct page *page = phys_to_page(paddr);
+       struct folio *folio = phys_to_folio(paddr);
        int rc;
 
-       get_page(page);
+       /* See gmap_make_secure(): large folios cannot be secure */
+       if (unlikely(folio_test_large(folio)))
+               return 0;
+
+       folio_get(folio);
        rc = uv_convert_from_secure(paddr);
        if (!rc)
-               clear_bit(PG_arch_1, &page->flags);
-       put_page(page);
+               clear_bit(PG_arch_1, &folio->flags);
+       folio_put(folio);
        return rc;
 }
 
@@ -479,33 +487,34 @@ EXPORT_SYMBOL_GPL(gmap_destroy_page);
  */
 int arch_make_page_accessible(struct page *page)
 {
+       struct folio *folio = page_folio(page);
        int rc = 0;
 
-       /* Hugepage cannot be protected, so nothing to do */
-       if (PageHuge(page))
+       /* See gmap_make_secure(): large folios cannot be secure */
+       if (unlikely(folio_test_large(folio)))
                return 0;
 
        /*
         * PG_arch_1 is used in 3 places:
         * 1. for kernel page tables during early boot
         * 2. for storage keys of huge pages and KVM
-        * 3. As an indication that this page might be secure. This can
+        * 3. As an indication that this small folio might be secure. This can
         *    overindicate, e.g. we set the bit before calling
         *    convert_to_secure.
         * As secure pages are never huge, all 3 variants can co-exists.
         */
-       if (!test_bit(PG_arch_1, &page->flags))
+       if (!test_bit(PG_arch_1, &folio->flags))
                return 0;
 
-       rc = uv_pin_shared(page_to_phys(page));
+       rc = uv_pin_shared(folio_to_phys(folio));
        if (!rc) {
-               clear_bit(PG_arch_1, &page->flags);
+               clear_bit(PG_arch_1, &folio->flags);
                return 0;
        }
 
-       rc = uv_convert_from_secure(page_to_phys(page));
+       rc = uv_convert_from_secure(folio_to_phys(folio));
        if (!rc) {
-               clear_bit(PG_arch_1, &page->flags);
+               clear_bit(PG_arch_1, &folio->flags);
                return 0;
        }