diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-24 10:53:22 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-24 10:53:22 -0400 |
commit | db16826367fefcb0ddb93d76b66adc52eb4e6339 (patch) | |
tree | 626224c1eb1eb79c522714591f208b4fdbdcd9d4 /mm/rmap.c | |
parent | cd6045138ed1bb5d8773e940d51c34318eef3ef2 (diff) | |
parent | 465fdd97cbe16ef8727221857e96ef62dd352017 (diff) |
Merge branch 'hwpoison' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6
* 'hwpoison' of git://git.kernel.org/pub/scm/linux/kernel/git/ak/linux-mce-2.6: (21 commits)
HWPOISON: Enable error_remove_page on btrfs
HWPOISON: Add simple debugfs interface to inject hwpoison on arbitary PFNs
HWPOISON: Add madvise() based injector for hardware poisoned pages v4
HWPOISON: Enable error_remove_page for NFS
HWPOISON: Enable .remove_error_page for migration aware file systems
HWPOISON: The high level memory error handler in the VM v7
HWPOISON: Add PR_MCE_KILL prctl to control early kill behaviour per process
HWPOISON: shmem: call set_page_dirty() with locked page
HWPOISON: Define a new error_remove_page address space op for async truncation
HWPOISON: Add invalidate_inode_page
HWPOISON: Refactor truncate to allow direct truncating of page v2
HWPOISON: check and isolate corrupted free pages v2
HWPOISON: Handle hardware poisoned pages in try_to_unmap
HWPOISON: Use bitmask/action code for try_to_unmap behaviour
HWPOISON: x86: Add VM_FAULT_HWPOISON handling to x86 page fault handler v2
HWPOISON: Add poison check to page fault handling
HWPOISON: Add basic support for poisoned pages in fault handler v3
HWPOISON: Add new SIGBUS error codes for hardware poison signals
HWPOISON: Add support for poison swap entries v2
HWPOISON: Export some rmap vma locking to outside world
...
Diffstat (limited to 'mm/rmap.c')
-rw-r--r-- | mm/rmap.c | 60 |
1 files changed, 38 insertions, 22 deletions
@@ -36,6 +36,11 @@ | |||
36 | * mapping->tree_lock (widely used, in set_page_dirty, | 36 | * mapping->tree_lock (widely used, in set_page_dirty, |
37 | * in arch-dependent flush_dcache_mmap_lock, | 37 | * in arch-dependent flush_dcache_mmap_lock, |
38 | * within inode_lock in __sync_single_inode) | 38 | * within inode_lock in __sync_single_inode) |
39 | * | ||
40 | * (code doesn't rely on that order so it could be switched around) | ||
41 | * ->tasklist_lock | ||
42 | * anon_vma->lock (memory_failure, collect_procs_anon) | ||
43 | * pte map lock | ||
39 | */ | 44 | */ |
40 | 45 | ||
41 | #include <linux/mm.h> | 46 | #include <linux/mm.h> |
@@ -191,7 +196,7 @@ void __init anon_vma_init(void) | |||
191 | * Getting a lock on a stable anon_vma from a page off the LRU is | 196 | * Getting a lock on a stable anon_vma from a page off the LRU is |
192 | * tricky: page_lock_anon_vma rely on RCU to guard against the races. | 197 | * tricky: page_lock_anon_vma rely on RCU to guard against the races. |
193 | */ | 198 | */ |
194 | static struct anon_vma *page_lock_anon_vma(struct page *page) | 199 | struct anon_vma *page_lock_anon_vma(struct page *page) |
195 | { | 200 | { |
196 | struct anon_vma *anon_vma; | 201 | struct anon_vma *anon_vma; |
197 | unsigned long anon_mapping; | 202 | unsigned long anon_mapping; |
@@ -211,7 +216,7 @@ out: | |||
211 | return NULL; | 216 | return NULL; |
212 | } | 217 | } |
213 | 218 | ||
214 | static void page_unlock_anon_vma(struct anon_vma *anon_vma) | 219 | void page_unlock_anon_vma(struct anon_vma *anon_vma) |
215 | { | 220 | { |
216 | spin_unlock(&anon_vma->lock); | 221 | spin_unlock(&anon_vma->lock); |
217 | rcu_read_unlock(); | 222 | rcu_read_unlock(); |
@@ -311,7 +316,7 @@ pte_t *page_check_address(struct page *page, struct mm_struct *mm, | |||
311 | * if the page is not mapped into the page tables of this VMA. Only | 316 | * if the page is not mapped into the page tables of this VMA. Only |
312 | * valid for normal file or anonymous VMAs. | 317 | * valid for normal file or anonymous VMAs. |
313 | */ | 318 | */ |
314 | static int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma) | 319 | int page_mapped_in_vma(struct page *page, struct vm_area_struct *vma) |
315 | { | 320 | { |
316 | unsigned long address; | 321 | unsigned long address; |
317 | pte_t *pte; | 322 | pte_t *pte; |
@@ -756,7 +761,7 @@ void page_remove_rmap(struct page *page) | |||
756 | * repeatedly from either try_to_unmap_anon or try_to_unmap_file. | 761 | * repeatedly from either try_to_unmap_anon or try_to_unmap_file. |
757 | */ | 762 | */ |
758 | static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, | 763 | static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, |
759 | int migration) | 764 | enum ttu_flags flags) |
760 | { | 765 | { |
761 | struct mm_struct *mm = vma->vm_mm; | 766 | struct mm_struct *mm = vma->vm_mm; |
762 | unsigned long address; | 767 | unsigned long address; |
@@ -778,11 +783,13 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, | |||
778 | * If it's recently referenced (perhaps page_referenced | 783 | * If it's recently referenced (perhaps page_referenced |
779 | * skipped over this mm) then we should reactivate it. | 784 | * skipped over this mm) then we should reactivate it. |
780 | */ | 785 | */ |
781 | if (!migration) { | 786 | if (!(flags & TTU_IGNORE_MLOCK)) { |
782 | if (vma->vm_flags & VM_LOCKED) { | 787 | if (vma->vm_flags & VM_LOCKED) { |
783 | ret = SWAP_MLOCK; | 788 | ret = SWAP_MLOCK; |
784 | goto out_unmap; | 789 | goto out_unmap; |
785 | } | 790 | } |
791 | } | ||
792 | if (!(flags & TTU_IGNORE_ACCESS)) { | ||
786 | if (ptep_clear_flush_young_notify(vma, address, pte)) { | 793 | if (ptep_clear_flush_young_notify(vma, address, pte)) { |
787 | ret = SWAP_FAIL; | 794 | ret = SWAP_FAIL; |
788 | goto out_unmap; | 795 | goto out_unmap; |
@@ -800,7 +807,14 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, | |||
800 | /* Update high watermark before we lower rss */ | 807 | /* Update high watermark before we lower rss */ |
801 | update_hiwater_rss(mm); | 808 | update_hiwater_rss(mm); |
802 | 809 | ||
803 | if (PageAnon(page)) { | 810 | if (PageHWPoison(page) && !(flags & TTU_IGNORE_HWPOISON)) { |
811 | if (PageAnon(page)) | ||
812 | dec_mm_counter(mm, anon_rss); | ||
813 | else | ||
814 | dec_mm_counter(mm, file_rss); | ||
815 | set_pte_at(mm, address, pte, | ||
816 | swp_entry_to_pte(make_hwpoison_entry(page))); | ||
817 | } else if (PageAnon(page)) { | ||
804 | swp_entry_t entry = { .val = page_private(page) }; | 818 | swp_entry_t entry = { .val = page_private(page) }; |
805 | 819 | ||
806 | if (PageSwapCache(page)) { | 820 | if (PageSwapCache(page)) { |
@@ -822,12 +836,12 @@ static int try_to_unmap_one(struct page *page, struct vm_area_struct *vma, | |||
822 | * pte. do_swap_page() will wait until the migration | 836 | * pte. do_swap_page() will wait until the migration |
823 | * pte is removed and then restart fault handling. | 837 | * pte is removed and then restart fault handling. |
824 | */ | 838 | */ |
825 | BUG_ON(!migration); | 839 | BUG_ON(TTU_ACTION(flags) != TTU_MIGRATION); |
826 | entry = make_migration_entry(page, pte_write(pteval)); | 840 | entry = make_migration_entry(page, pte_write(pteval)); |
827 | } | 841 | } |
828 | set_pte_at(mm, address, pte, swp_entry_to_pte(entry)); | 842 | set_pte_at(mm, address, pte, swp_entry_to_pte(entry)); |
829 | BUG_ON(pte_file(*pte)); | 843 | BUG_ON(pte_file(*pte)); |
830 | } else if (PAGE_MIGRATION && migration) { | 844 | } else if (PAGE_MIGRATION && (TTU_ACTION(flags) == TTU_MIGRATION)) { |
831 | /* Establish migration entry for a file page */ | 845 | /* Establish migration entry for a file page */ |
832 | swp_entry_t entry; | 846 | swp_entry_t entry; |
833 | entry = make_migration_entry(page, pte_write(pteval)); | 847 | entry = make_migration_entry(page, pte_write(pteval)); |
@@ -996,12 +1010,13 @@ static int try_to_mlock_page(struct page *page, struct vm_area_struct *vma) | |||
996 | * vm_flags for that VMA. That should be OK, because that vma shouldn't be | 1010 | * vm_flags for that VMA. That should be OK, because that vma shouldn't be |
997 | * 'LOCKED. | 1011 | * 'LOCKED. |
998 | */ | 1012 | */ |
999 | static int try_to_unmap_anon(struct page *page, int unlock, int migration) | 1013 | static int try_to_unmap_anon(struct page *page, enum ttu_flags flags) |
1000 | { | 1014 | { |
1001 | struct anon_vma *anon_vma; | 1015 | struct anon_vma *anon_vma; |
1002 | struct vm_area_struct *vma; | 1016 | struct vm_area_struct *vma; |
1003 | unsigned int mlocked = 0; | 1017 | unsigned int mlocked = 0; |
1004 | int ret = SWAP_AGAIN; | 1018 | int ret = SWAP_AGAIN; |
1019 | int unlock = TTU_ACTION(flags) == TTU_MUNLOCK; | ||
1005 | 1020 | ||
1006 | if (MLOCK_PAGES && unlikely(unlock)) | 1021 | if (MLOCK_PAGES && unlikely(unlock)) |
1007 | ret = SWAP_SUCCESS; /* default for try_to_munlock() */ | 1022 | ret = SWAP_SUCCESS; /* default for try_to_munlock() */ |
@@ -1017,7 +1032,7 @@ static int try_to_unmap_anon(struct page *page, int unlock, int migration) | |||
1017 | continue; /* must visit all unlocked vmas */ | 1032 | continue; /* must visit all unlocked vmas */ |
1018 | ret = SWAP_MLOCK; /* saw at least one mlocked vma */ | 1033 | ret = SWAP_MLOCK; /* saw at least one mlocked vma */ |
1019 | } else { | 1034 | } else { |
1020 | ret = try_to_unmap_one(page, vma, migration); | 1035 | ret = try_to_unmap_one(page, vma, flags); |
1021 | if (ret == SWAP_FAIL || !page_mapped(page)) | 1036 | if (ret == SWAP_FAIL || !page_mapped(page)) |
1022 | break; | 1037 | break; |
1023 | } | 1038 | } |
@@ -1041,8 +1056,7 @@ static int try_to_unmap_anon(struct page *page, int unlock, int migration) | |||
1041 | /** | 1056 | /** |
1042 | * try_to_unmap_file - unmap/unlock file page using the object-based rmap method | 1057 | * try_to_unmap_file - unmap/unlock file page using the object-based rmap method |
1043 | * @page: the page to unmap/unlock | 1058 | * @page: the page to unmap/unlock |
1044 | * @unlock: request for unlock rather than unmap [unlikely] | 1059 | * @flags: action and flags |
1045 | * @migration: unmapping for migration - ignored if @unlock | ||
1046 | * | 1060 | * |
1047 | * Find all the mappings of a page using the mapping pointer and the vma chains | 1061 | * Find all the mappings of a page using the mapping pointer and the vma chains |
1048 | * contained in the address_space struct it points to. | 1062 | * contained in the address_space struct it points to. |
@@ -1054,7 +1068,7 @@ static int try_to_unmap_anon(struct page *page, int unlock, int migration) | |||
1054 | * vm_flags for that VMA. That should be OK, because that vma shouldn't be | 1068 | * vm_flags for that VMA. That should be OK, because that vma shouldn't be |
1055 | * 'LOCKED. | 1069 | * 'LOCKED. |
1056 | */ | 1070 | */ |
1057 | static int try_to_unmap_file(struct page *page, int unlock, int migration) | 1071 | static int try_to_unmap_file(struct page *page, enum ttu_flags flags) |
1058 | { | 1072 | { |
1059 | struct address_space *mapping = page->mapping; | 1073 | struct address_space *mapping = page->mapping; |
1060 | pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); | 1074 | pgoff_t pgoff = page->index << (PAGE_CACHE_SHIFT - PAGE_SHIFT); |
@@ -1066,6 +1080,7 @@ static int try_to_unmap_file(struct page *page, int unlock, int migration) | |||
1066 | unsigned long max_nl_size = 0; | 1080 | unsigned long max_nl_size = 0; |
1067 | unsigned int mapcount; | 1081 | unsigned int mapcount; |
1068 | unsigned int mlocked = 0; | 1082 | unsigned int mlocked = 0; |
1083 | int unlock = TTU_ACTION(flags) == TTU_MUNLOCK; | ||
1069 | 1084 | ||
1070 | if (MLOCK_PAGES && unlikely(unlock)) | 1085 | if (MLOCK_PAGES && unlikely(unlock)) |
1071 | ret = SWAP_SUCCESS; /* default for try_to_munlock() */ | 1086 | ret = SWAP_SUCCESS; /* default for try_to_munlock() */ |
@@ -1078,7 +1093,7 @@ static int try_to_unmap_file(struct page *page, int unlock, int migration) | |||
1078 | continue; /* must visit all vmas */ | 1093 | continue; /* must visit all vmas */ |
1079 | ret = SWAP_MLOCK; | 1094 | ret = SWAP_MLOCK; |
1080 | } else { | 1095 | } else { |
1081 | ret = try_to_unmap_one(page, vma, migration); | 1096 | ret = try_to_unmap_one(page, vma, flags); |
1082 | if (ret == SWAP_FAIL || !page_mapped(page)) | 1097 | if (ret == SWAP_FAIL || !page_mapped(page)) |
1083 | goto out; | 1098 | goto out; |
1084 | } | 1099 | } |
@@ -1103,7 +1118,8 @@ static int try_to_unmap_file(struct page *page, int unlock, int migration) | |||
1103 | ret = SWAP_MLOCK; /* leave mlocked == 0 */ | 1118 | ret = SWAP_MLOCK; /* leave mlocked == 0 */ |
1104 | goto out; /* no need to look further */ | 1119 | goto out; /* no need to look further */ |
1105 | } | 1120 | } |
1106 | if (!MLOCK_PAGES && !migration && (vma->vm_flags & VM_LOCKED)) | 1121 | if (!MLOCK_PAGES && !(flags & TTU_IGNORE_MLOCK) && |
1122 | (vma->vm_flags & VM_LOCKED)) | ||
1107 | continue; | 1123 | continue; |
1108 | cursor = (unsigned long) vma->vm_private_data; | 1124 | cursor = (unsigned long) vma->vm_private_data; |
1109 | if (cursor > max_nl_cursor) | 1125 | if (cursor > max_nl_cursor) |
@@ -1137,7 +1153,7 @@ static int try_to_unmap_file(struct page *page, int unlock, int migration) | |||
1137 | do { | 1153 | do { |
1138 | list_for_each_entry(vma, &mapping->i_mmap_nonlinear, | 1154 | list_for_each_entry(vma, &mapping->i_mmap_nonlinear, |
1139 | shared.vm_set.list) { | 1155 | shared.vm_set.list) { |
1140 | if (!MLOCK_PAGES && !migration && | 1156 | if (!MLOCK_PAGES && !(flags & TTU_IGNORE_MLOCK) && |
1141 | (vma->vm_flags & VM_LOCKED)) | 1157 | (vma->vm_flags & VM_LOCKED)) |
1142 | continue; | 1158 | continue; |
1143 | cursor = (unsigned long) vma->vm_private_data; | 1159 | cursor = (unsigned long) vma->vm_private_data; |
@@ -1177,7 +1193,7 @@ out: | |||
1177 | /** | 1193 | /** |
1178 | * try_to_unmap - try to remove all page table mappings to a page | 1194 | * try_to_unmap - try to remove all page table mappings to a page |
1179 | * @page: the page to get unmapped | 1195 | * @page: the page to get unmapped |
1180 | * @migration: migration flag | 1196 | * @flags: action and flags |
1181 | * | 1197 | * |
1182 | * Tries to remove all the page table entries which are mapping this | 1198 | * Tries to remove all the page table entries which are mapping this |
1183 | * page, used in the pageout path. Caller must hold the page lock. | 1199 | * page, used in the pageout path. Caller must hold the page lock. |
@@ -1188,16 +1204,16 @@ out: | |||
1188 | * SWAP_FAIL - the page is unswappable | 1204 | * SWAP_FAIL - the page is unswappable |
1189 | * SWAP_MLOCK - page is mlocked. | 1205 | * SWAP_MLOCK - page is mlocked. |
1190 | */ | 1206 | */ |
1191 | int try_to_unmap(struct page *page, int migration) | 1207 | int try_to_unmap(struct page *page, enum ttu_flags flags) |
1192 | { | 1208 | { |
1193 | int ret; | 1209 | int ret; |
1194 | 1210 | ||
1195 | BUG_ON(!PageLocked(page)); | 1211 | BUG_ON(!PageLocked(page)); |
1196 | 1212 | ||
1197 | if (PageAnon(page)) | 1213 | if (PageAnon(page)) |
1198 | ret = try_to_unmap_anon(page, 0, migration); | 1214 | ret = try_to_unmap_anon(page, flags); |
1199 | else | 1215 | else |
1200 | ret = try_to_unmap_file(page, 0, migration); | 1216 | ret = try_to_unmap_file(page, flags); |
1201 | if (ret != SWAP_MLOCK && !page_mapped(page)) | 1217 | if (ret != SWAP_MLOCK && !page_mapped(page)) |
1202 | ret = SWAP_SUCCESS; | 1218 | ret = SWAP_SUCCESS; |
1203 | return ret; | 1219 | return ret; |
@@ -1222,8 +1238,8 @@ int try_to_munlock(struct page *page) | |||
1222 | VM_BUG_ON(!PageLocked(page) || PageLRU(page)); | 1238 | VM_BUG_ON(!PageLocked(page) || PageLRU(page)); |
1223 | 1239 | ||
1224 | if (PageAnon(page)) | 1240 | if (PageAnon(page)) |
1225 | return try_to_unmap_anon(page, 1, 0); | 1241 | return try_to_unmap_anon(page, TTU_MUNLOCK); |
1226 | else | 1242 | else |
1227 | return try_to_unmap_file(page, 1, 0); | 1243 | return try_to_unmap_file(page, TTU_MUNLOCK); |
1228 | } | 1244 | } |
1229 | 1245 | ||