diff mbox

[2/2] vrange: Try to add sigbus semantics.

Message ID 1393363729-8459-3-git-send-email-john.stultz@linaro.org
State New
Headers show

Commit Message

John Stultz Feb. 25, 2014, 9:28 p.m. UTC
This patch tries to add sigbus semantics when applications
access volatile pages that have been purged.

XXX: this breaks the pages_purged reporting.

This patch is based on earlier work of Minchan's, so credit to
him for his original work.

Cc: Minchan Kim <minchan@kernel.org>
Signed-off-by: John Stultz <john.stultz@linaro.org>
---
 include/linux/swap.h   |  6 +++++-
 include/linux/vrange.h | 14 +++++++++++++-
 mm/memory.c            | 24 ++++++++++++++++++++++++
 mm/vrange.c            |  2 +-
 4 files changed, 43 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/include/linux/swap.h b/include/linux/swap.h
index 46ba0c6..d90d245 100644
--- a/include/linux/swap.h
+++ b/include/linux/swap.h
@@ -49,6 +49,9 @@  static inline int current_is_kswapd(void)
  * actions on faults.
  */
 
+#define SWP_VRANGE_NUM 1
+#define SWP_VRANGE (MAX_SWAPFILES + SWP_HWPOISON_NUM + SWP_MIGRATION_NUM)
+
 /*
  * NUMA node memory migration support
  */
@@ -71,7 +74,8 @@  static inline int current_is_kswapd(void)
 #endif
 
 #define MAX_SWAPFILES \
-	((1 << MAX_SWAPFILES_SHIFT) - SWP_MIGRATION_NUM - SWP_HWPOISON_NUM)
+	((1 << MAX_SWAPFILES_SHIFT) - SWP_MIGRATION_NUM - SWP_HWPOISON_NUM \
+			-SWP_VRANGE_NUM)
 
 /*
  * Magic header for a swap area. The first part of the union is
diff --git a/include/linux/vrange.h b/include/linux/vrange.h
index 696e001..d51d822 100644
--- a/include/linux/vrange.h
+++ b/include/linux/vrange.h
@@ -2,11 +2,23 @@ 
 #define _LINUX_VRANGE_H
 
 #include <linux/mm.h>
-
+#include <linux/swap.h>
+#include <linux/swapops.h>
 
 #define VRANGE_NONVOLATILE 0
 #define VRANGE_VOLATILE 1
 
 extern int discard_vpage(struct page *page);
 
+static inline swp_entry_t make_vrange_entry(void)
+{
+	return swp_entry(SWP_VRANGE, 0);
+}
+
+static inline int is_vrange_entry(swp_entry_t entry)
+{
+	return swp_type(entry) == SWP_VRANGE;
+}
+
+
 #endif /* _LINUX_VRANGE_H */
diff --git a/mm/memory.c b/mm/memory.c
index be6a0c0..2e8dc62 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -60,6 +60,7 @@ 
 #include <linux/migrate.h>
 #include <linux/string.h>
 #include <linux/dma-debug.h>
+#include <linux/vrange.h>
 
 #include <asm/io.h>
 #include <asm/pgalloc.h>
@@ -807,6 +808,8 @@  copy_one_pte(struct mm_struct *dst_mm, struct mm_struct *src_mm,
 	if (unlikely(!pte_present(pte))) {
 		if (!pte_file(pte)) {
 			swp_entry_t entry = pte_to_swp_entry(pte);
+			if (is_vrange_entry(entry))
+				goto out_set_pte;
 
 			if (swap_duplicate(entry) < 0)
 				return entry.val;
@@ -1152,6 +1155,8 @@  again:
 				print_bad_pte(vma, addr, ptent, NULL);
 		} else {
 			swp_entry_t entry = pte_to_swp_entry(ptent);
+			if (is_vrange_entry(entry))
+				goto out;
 
 			if (!non_swap_entry(entry))
 				rss[MM_SWAPENTS]--;
@@ -1168,6 +1173,7 @@  again:
 			if (unlikely(!free_swap_and_cache(entry)))
 				print_bad_pte(vma, addr, ptent, NULL);
 		}
+out:
 		pte_clear_not_present_full(mm, addr, pte, tlb->fullmm);
 	} while (pte++, addr += PAGE_SIZE, addr != end);
 
@@ -3642,6 +3648,8 @@  static int handle_pte_fault(struct mm_struct *mm,
 
 	entry = *pte;
 	if (!pte_present(entry)) {
+		swp_entry_t vrange_entry;
+retry:
 		if (pte_none(entry)) {
 			if (vma->vm_ops) {
 				if (likely(vma->vm_ops->fault))
@@ -3651,6 +3659,22 @@  static int handle_pte_fault(struct mm_struct *mm,
 			return do_anonymous_page(mm, vma, address,
 						 pte, pmd, flags);
 		}
+
+		vrange_entry = pte_to_swp_entry(entry);
+		if (unlikely(is_vrange_entry(vrange_entry))) {
+			if (vma->vm_flags & VM_VOLATILE)
+				return VM_FAULT_SIGBUS;
+			/* zap pte */
+			ptl = pte_lockptr(mm, pmd);
+			spin_lock(ptl);
+			if (unlikely(!pte_same(*pte, entry)))
+				goto unlock;
+			flush_cache_page(vma, address, pte_pfn(*pte));
+			ptep_clear_flush(vma, address, pte);
+			pte_unmap_unlock(pte, ptl);
+			goto retry;
+		}
+
 		if (pte_file(entry))
 			return do_nonlinear_fault(mm, vma, address,
 					pte, pmd, flags, entry);
diff --git a/mm/vrange.c b/mm/vrange.c
index b80f611..69b58d0 100644
--- a/mm/vrange.c
+++ b/mm/vrange.c
@@ -209,7 +209,7 @@  static void try_to_discard_one(struct page *page, struct vm_area_struct *vma)
 	page_remove_rmap(page);
 	page_cache_release(page);
 
-//	set_pte_at(mm, addr, pte, swp_entry_to_pte(make_vrange_entry()));
+	set_pte_at(mm, addr, pte, swp_entry_to_pte(make_vrange_entry()));
 	pte_unmap_unlock(pte, ptl);
 	mmu_notifier_invalidate_page(mm, addr);