summaryrefslogtreecommitdiffstats
path: root/mm/rmap.c
diff options
context:
space:
mode:
authorOlof Johansson <olof@lixom.net>2012-11-06 07:51:06 -0800
committerOlof Johansson <olof@lixom.net>2012-11-06 07:51:06 -0800
commit66267ee58732bb4c21c7bbba004ee481b8ad2b30 (patch)
treebf7f72e623d7c1ca6472e0a1286e802cd3bff139 /mm/rmap.c
parent6ed68a6d83e4497dc33581ccc82b4fa3e7e8226d (diff)
parentf58007762f537ba13674a3138b3f4c20fff1cba9 (diff)
downloadlinux-66267ee58732bb4c21c7bbba004ee481b8ad2b30.tar.bz2
Merge branch 'arm-next' of git://git.xilinx.com/linux-xlnx into next/cleanup
From Michal Simek: * 'arm-next' of git://git.xilinx.com/linux-xlnx: zynq: move static peripheral mappings zynq: remove use of CLKDEV_LOOKUP zynq: use pl310 device tree bindings zynq: use GIC device tree bindings + Linux 3.7-rc3
Diffstat (limited to 'mm/rmap.c')
-rw-r--r--mm/rmap.c20
1 files changed, 15 insertions, 5 deletions
diff --git a/mm/rmap.c b/mm/rmap.c
index 7df7984d476c..2ee1ef0f317b 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -56,6 +56,7 @@
#include <linux/mmu_notifier.h>
#include <linux/migrate.h>
#include <linux/hugetlb.h>
+#include <linux/backing-dev.h>
#include <asm/tlbflush.h>
@@ -926,11 +927,8 @@ int page_mkclean(struct page *page)
if (page_mapped(page)) {
struct address_space *mapping = page_mapping(page);
- if (mapping) {
+ if (mapping)
ret = page_mkclean_file(mapping, page);
- if (page_test_and_clear_dirty(page_to_pfn(page), 1))
- ret = 1;
- }
}
return ret;
@@ -1116,6 +1114,7 @@ void page_add_file_rmap(struct page *page)
*/
void page_remove_rmap(struct page *page)
{
+ struct address_space *mapping = page_mapping(page);
bool anon = PageAnon(page);
bool locked;
unsigned long flags;
@@ -1138,8 +1137,19 @@ void page_remove_rmap(struct page *page)
* this if the page is anon, so about to be freed; but perhaps
* not if it's in swapcache - there might be another pte slot
* containing the swap entry, but page not yet written to swap.
+ *
+ * And we can skip it on file pages, so long as the filesystem
+ * participates in dirty tracking; but need to catch shm and tmpfs
+ * and ramfs pages which have been modified since creation by read
+ * fault.
+ *
+ * Note that mapping must be decided above, before decrementing
+ * mapcount (which luckily provides a barrier): once page is unmapped,
+ * it could be truncated and page->mapping reset to NULL at any moment.
+ * Note also that we are relying on page_mapping(page) to set mapping
+ * to &swapper_space when PageSwapCache(page).
*/
- if ((!anon || PageSwapCache(page)) &&
+ if (mapping && !mapping_cap_account_dirty(mapping) &&
page_test_and_clear_dirty(page_to_pfn(page), 1))
set_page_dirty(page);
/*