@@ -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
@@ -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 */
@@ -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);
@@ -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);
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(-)