|
31 | 31 | #include <linux/vmstat.h>
|
32 | 32 | #include <linux/pfn_t.h>
|
33 | 33 | #include <linux/sizes.h>
|
| 34 | +#include <linux/mmu_notifier.h> |
34 | 35 | #include <linux/iomap.h>
|
35 | 36 | #include "internal.h"
|
36 | 37 |
|
@@ -614,6 +615,59 @@ static void *dax_insert_mapping_entry(struct address_space *mapping,
|
614 | 615 | return new_entry;
|
615 | 616 | }
|
616 | 617 |
|
| 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 | + |
617 | 671 | static int dax_writeback_one(struct block_device *bdev,
|
618 | 672 | struct address_space *mapping, pgoff_t index, void *entry)
|
619 | 673 | {
|
@@ -687,7 +741,17 @@ static int dax_writeback_one(struct block_device *bdev,
|
687 | 741 | goto unmap;
|
688 | 742 | }
|
689 | 743 |
|
| 744 | + dax_mapping_entry_mkclean(mapping, index, pfn_t_to_pfn(dax.pfn)); |
690 | 745 | 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); |
691 | 755 | unmap:
|
692 | 756 | dax_unmap_atomic(bdev, &dax);
|
693 | 757 | put_locked_mapping_entry(mapping, index, entry);
|
|
0 commit comments