]> git.itanic.dy.fi Git - linux-stable/commitdiff
parisc: Fix flush_dcache_page() for usage from irq context
authorHelge Deller <deller@gmx.de>
Wed, 24 May 2023 15:07:07 +0000 (17:07 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 30 May 2023 11:44:09 +0000 (12:44 +0100)
commit 61e150fb310729c98227a5edf6e4a3619edc3702 upstream.

Since at least kernel 6.1, flush_dcache_page() is called with IRQs
disabled, e.g. from aio_complete().

But the current implementation for flush_dcache_page() on parisc
unintentionally re-enables IRQs, which may lead to deadlocks.

Fix it by using xa_lock_irqsave() and xa_unlock_irqrestore()
for the flush_dcache_mmap_*lock() macros instead.

Cc: linux-parisc@vger.kernel.org
Cc: stable@kernel.org # 5.18+
Signed-off-by: Helge Deller <deller@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
arch/parisc/include/asm/cacheflush.h
arch/parisc/kernel/cache.c

index 0c83644bfa5cbb3624b7d33b3fc70cf5d78f4a00..b4076ac51005e58b1509fc168d05e5504417cca9 100644 (file)
@@ -57,6 +57,11 @@ extern void flush_dcache_page(struct page *page);
 
 #define flush_dcache_mmap_lock(mapping)                xa_lock_irq(&mapping->i_pages)
 #define flush_dcache_mmap_unlock(mapping)      xa_unlock_irq(&mapping->i_pages)
+#define flush_dcache_mmap_lock_irqsave(mapping, flags)         \
+               xa_lock_irqsave(&mapping->i_pages, flags)
+#define flush_dcache_mmap_unlock_irqrestore(mapping, flags)    \
+               xa_unlock_irqrestore(&mapping->i_pages, flags)
+
 
 #define flush_icache_page(vma,page)    do {            \
        flush_kernel_dcache_page(page);                 \
index a82b3eaa539896b986010f63622c7c8321848625..fd84789b5ca4bebeecf7cca5cf8c755cb8949bb7 100644 (file)
@@ -328,6 +328,7 @@ void flush_dcache_page(struct page *page)
        struct vm_area_struct *mpnt;
        unsigned long offset;
        unsigned long addr, old_addr = 0;
+       unsigned long flags;
        pgoff_t pgoff;
 
        if (mapping && !mapping_mapped(mapping)) {
@@ -347,7 +348,7 @@ void flush_dcache_page(struct page *page)
         * declared as MAP_PRIVATE or MAP_SHARED), so we only need
         * to flush one address here for them all to become coherent */
 
-       flush_dcache_mmap_lock(mapping);
+       flush_dcache_mmap_lock_irqsave(mapping, flags);
        vma_interval_tree_foreach(mpnt, &mapping->i_mmap, pgoff, pgoff) {
                offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
                addr = mpnt->vm_start + offset;
@@ -370,7 +371,7 @@ void flush_dcache_page(struct page *page)
                        old_addr = addr;
                }
        }
-       flush_dcache_mmap_unlock(mapping);
+       flush_dcache_mmap_unlock_irqrestore(mapping, flags);
 }
 EXPORT_SYMBOL(flush_dcache_page);