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/truncate.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/truncate.c')
-rw-r--r-- | mm/truncate.c | 72 |
1 files changed, 52 insertions, 20 deletions
diff --git a/mm/truncate.c b/mm/truncate.c index ccc3ecf7cb98..a17b3977cfdf 100644 --- a/mm/truncate.c +++ b/mm/truncate.c | |||
@@ -93,11 +93,11 @@ EXPORT_SYMBOL(cancel_dirty_page); | |||
93 | * its lock, b) when a concurrent invalidate_mapping_pages got there first and | 93 | * its lock, b) when a concurrent invalidate_mapping_pages got there first and |
94 | * c) when tmpfs swizzles a page between a tmpfs inode and swapper_space. | 94 | * c) when tmpfs swizzles a page between a tmpfs inode and swapper_space. |
95 | */ | 95 | */ |
96 | static void | 96 | static int |
97 | truncate_complete_page(struct address_space *mapping, struct page *page) | 97 | truncate_complete_page(struct address_space *mapping, struct page *page) |
98 | { | 98 | { |
99 | if (page->mapping != mapping) | 99 | if (page->mapping != mapping) |
100 | return; | 100 | return -EIO; |
101 | 101 | ||
102 | if (page_has_private(page)) | 102 | if (page_has_private(page)) |
103 | do_invalidatepage(page, 0); | 103 | do_invalidatepage(page, 0); |
@@ -108,6 +108,7 @@ truncate_complete_page(struct address_space *mapping, struct page *page) | |||
108 | remove_from_page_cache(page); | 108 | remove_from_page_cache(page); |
109 | ClearPageMappedToDisk(page); | 109 | ClearPageMappedToDisk(page); |
110 | page_cache_release(page); /* pagecache ref */ | 110 | page_cache_release(page); /* pagecache ref */ |
111 | return 0; | ||
111 | } | 112 | } |
112 | 113 | ||
113 | /* | 114 | /* |
@@ -135,6 +136,51 @@ invalidate_complete_page(struct address_space *mapping, struct page *page) | |||
135 | return ret; | 136 | return ret; |
136 | } | 137 | } |
137 | 138 | ||
139 | int truncate_inode_page(struct address_space *mapping, struct page *page) | ||
140 | { | ||
141 | if (page_mapped(page)) { | ||
142 | unmap_mapping_range(mapping, | ||
143 | (loff_t)page->index << PAGE_CACHE_SHIFT, | ||
144 | PAGE_CACHE_SIZE, 0); | ||
145 | } | ||
146 | return truncate_complete_page(mapping, page); | ||
147 | } | ||
148 | |||
149 | /* | ||
150 | * Used to get rid of pages on hardware memory corruption. | ||
151 | */ | ||
152 | int generic_error_remove_page(struct address_space *mapping, struct page *page) | ||
153 | { | ||
154 | if (!mapping) | ||
155 | return -EINVAL; | ||
156 | /* | ||
157 | * Only punch for normal data pages for now. | ||
158 | * Handling other types like directories would need more auditing. | ||
159 | */ | ||
160 | if (!S_ISREG(mapping->host->i_mode)) | ||
161 | return -EIO; | ||
162 | return truncate_inode_page(mapping, page); | ||
163 | } | ||
164 | EXPORT_SYMBOL(generic_error_remove_page); | ||
165 | |||
166 | /* | ||
167 | * Safely invalidate one page from its pagecache mapping. | ||
168 | * It only drops clean, unused pages. The page must be locked. | ||
169 | * | ||
170 | * Returns 1 if the page is successfully invalidated, otherwise 0. | ||
171 | */ | ||
172 | int invalidate_inode_page(struct page *page) | ||
173 | { | ||
174 | struct address_space *mapping = page_mapping(page); | ||
175 | if (!mapping) | ||
176 | return 0; | ||
177 | if (PageDirty(page) || PageWriteback(page)) | ||
178 | return 0; | ||
179 | if (page_mapped(page)) | ||
180 | return 0; | ||
181 | return invalidate_complete_page(mapping, page); | ||
182 | } | ||
183 | |||
138 | /** | 184 | /** |
139 | * truncate_inode_pages - truncate range of pages specified by start & end byte offsets | 185 | * truncate_inode_pages - truncate range of pages specified by start & end byte offsets |
140 | * @mapping: mapping to truncate | 186 | * @mapping: mapping to truncate |
@@ -196,12 +242,7 @@ void truncate_inode_pages_range(struct address_space *mapping, | |||
196 | unlock_page(page); | 242 | unlock_page(page); |
197 | continue; | 243 | continue; |
198 | } | 244 | } |
199 | if (page_mapped(page)) { | 245 | truncate_inode_page(mapping, page); |
200 | unmap_mapping_range(mapping, | ||
201 | (loff_t)page_index<<PAGE_CACHE_SHIFT, | ||
202 | PAGE_CACHE_SIZE, 0); | ||
203 | } | ||
204 | truncate_complete_page(mapping, page); | ||
205 | unlock_page(page); | 246 | unlock_page(page); |
206 | } | 247 | } |
207 | pagevec_release(&pvec); | 248 | pagevec_release(&pvec); |
@@ -238,15 +279,10 @@ void truncate_inode_pages_range(struct address_space *mapping, | |||
238 | break; | 279 | break; |
239 | lock_page(page); | 280 | lock_page(page); |
240 | wait_on_page_writeback(page); | 281 | wait_on_page_writeback(page); |
241 | if (page_mapped(page)) { | 282 | truncate_inode_page(mapping, page); |
242 | unmap_mapping_range(mapping, | ||
243 | (loff_t)page->index<<PAGE_CACHE_SHIFT, | ||
244 | PAGE_CACHE_SIZE, 0); | ||
245 | } | ||
246 | if (page->index > next) | 283 | if (page->index > next) |
247 | next = page->index; | 284 | next = page->index; |
248 | next++; | 285 | next++; |
249 | truncate_complete_page(mapping, page); | ||
250 | unlock_page(page); | 286 | unlock_page(page); |
251 | } | 287 | } |
252 | pagevec_release(&pvec); | 288 | pagevec_release(&pvec); |
@@ -311,12 +347,8 @@ unsigned long invalidate_mapping_pages(struct address_space *mapping, | |||
311 | if (lock_failed) | 347 | if (lock_failed) |
312 | continue; | 348 | continue; |
313 | 349 | ||
314 | if (PageDirty(page) || PageWriteback(page)) | 350 | ret += invalidate_inode_page(page); |
315 | goto unlock; | 351 | |
316 | if (page_mapped(page)) | ||
317 | goto unlock; | ||
318 | ret += invalidate_complete_page(mapping, page); | ||
319 | unlock: | ||
320 | unlock_page(page); | 352 | unlock_page(page); |
321 | if (next > end) | 353 | if (next > end) |
322 | break; | 354 | break; |