Skip to content

Commit 4b4bb46

Browse files
jankaratorvalds
authored andcommitted
dax: clear dirty entry tags on cache flush
Currently we never clear dirty tags in DAX mappings and thus address ranges to flush accumulate. Now that we have locking of radix tree entries, we have all the locking necessary to reliably clear the radix tree dirty tag when flushing caches for corresponding address range. Similarly to page_mkclean() we also have to write-protect pages to get a page fault when the page is next written to so that we can mark the entry dirty again. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Jan Kara <[email protected]> Reviewed-by: Ross Zwisler <[email protected]> Cc: Kirill A. Shutemov <[email protected]> Cc: Dan Williams <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 2f89dc1 commit 4b4bb46

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

fs/dax.c

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include <linux/vmstat.h>
3232
#include <linux/pfn_t.h>
3333
#include <linux/sizes.h>
34+
#include <linux/mmu_notifier.h>
3435
#include <linux/iomap.h>
3536
#include "internal.h"
3637

@@ -614,6 +615,59 @@ static void *dax_insert_mapping_entry(struct address_space *mapping,
614615
return new_entry;
615616
}
616617

618+
static inline unsigned long
619+
pgoff_address(pgoff_t pgoff, struct vm_area_struct *vma)
620+
{
621+
unsigned long address;
622+
623+
address = vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT);
624+
VM_BUG_ON_VMA(address < vma->vm_start || address >= vma->vm_end, vma);
625+
return address;
626+
}
627+
628+
/* Walk all mappings of a given index of a file and writeprotect them */
629+
static void dax_mapping_entry_mkclean(struct address_space *mapping,
630+
pgoff_t index, unsigned long pfn)
631+
{
632+
struct vm_area_struct *vma;
633+
pte_t *ptep;
634+
pte_t pte;
635+
spinlock_t *ptl;
636+
bool changed;
637+
638+
i_mmap_lock_read(mapping);
639+
vma_interval_tree_foreach(vma, &mapping->i_mmap, index, index) {
640+
unsigned long address;
641+
642+
cond_resched();
643+
644+
if (!(vma->vm_flags & VM_SHARED))
645+
continue;
646+
647+
address = pgoff_address(index, vma);
648+
changed = false;
649+
if (follow_pte(vma->vm_mm, address, &ptep, &ptl))
650+
continue;
651+
if (pfn != pte_pfn(*ptep))
652+
goto unlock;
653+
if (!pte_dirty(*ptep) && !pte_write(*ptep))
654+
goto unlock;
655+
656+
flush_cache_page(vma, address, pfn);
657+
pte = ptep_clear_flush(vma, address, ptep);
658+
pte = pte_wrprotect(pte);
659+
pte = pte_mkclean(pte);
660+
set_pte_at(vma->vm_mm, address, ptep, pte);
661+
changed = true;
662+
unlock:
663+
pte_unmap_unlock(ptep, ptl);
664+
665+
if (changed)
666+
mmu_notifier_invalidate_page(vma->vm_mm, address);
667+
}
668+
i_mmap_unlock_read(mapping);
669+
}
670+
617671
static int dax_writeback_one(struct block_device *bdev,
618672
struct address_space *mapping, pgoff_t index, void *entry)
619673
{
@@ -687,7 +741,17 @@ static int dax_writeback_one(struct block_device *bdev,
687741
goto unmap;
688742
}
689743

744+
dax_mapping_entry_mkclean(mapping, index, pfn_t_to_pfn(dax.pfn));
690745
wb_cache_pmem(dax.addr, dax.size);
746+
/*
747+
* After we have flushed the cache, we can clear the dirty tag. There
748+
* cannot be new dirty data in the pfn after the flush has completed as
749+
* the pfn mappings are writeprotected and fault waits for mapping
750+
* entry lock.
751+
*/
752+
spin_lock_irq(&mapping->tree_lock);
753+
radix_tree_tag_clear(page_tree, index, PAGECACHE_TAG_DIRTY);
754+
spin_unlock_irq(&mapping->tree_lock);
691755
unmap:
692756
dax_unmap_atomic(bdev, &dax);
693757
put_locked_mapping_entry(mapping, index, entry);

0 commit comments

Comments
 (0)