mm/memory.c | 5 +---- mm/swap.c | 8 +++++++- mm/swap_state.c | 14 ++++++++++++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/mm/memory.c b/mm/memory.c index 62fdcd1995f4..174542ab2b90 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -283,11 +283,8 @@ int __tlb_remove_page(struct mmu_gather *tlb, struct page *page, bool dirty) VM_BUG_ON(!tlb->need_flush); - /* FIXME! This needs to be batched too */ - if (dirty) - set_page_dirty(page); batch = tlb->active; - batch->pages[batch->nr++] = page; + batch->pages[batch->nr++] = (void *) (dirty + (unsigned long)page); if (batch->nr == batch->max) { if (!tlb_next_batch(tlb)) return 0; diff --git a/mm/swap.c b/mm/swap.c index 9ce43ba4498b..1a58c58c7f41 100644 --- a/mm/swap.c +++ b/mm/swap.c @@ -821,8 +821,14 @@ void release_pages(struct page **pages, int nr, int cold) struct lruvec *lruvec; unsigned long uninitialized_var(flags); + /* + * NOTE! The low bit of the struct page pointer in + * the "pages[]" array is used as a dirty bit, so + * we ignore it + */ for (i = 0; i < nr; i++) { - struct page *page = pages[i]; + unsigned long pageval = (unsigned long)pages[i]; + struct page *page = (void *)(~1ul & pageval); if (unlikely(PageCompound(page))) { if (zone) { diff --git a/mm/swap_state.c b/mm/swap_state.c index e76ace30d436..bb0b2d675a82 100644 --- a/mm/swap_state.c +++ b/mm/swap_state.c @@ -258,6 +258,11 @@ void free_page_and_swap_cache(struct page *page) /* * Passed an array of pages, drop them all from swapcache and then release * them. They are removed from the LRU and freed if this is their last use. + * + * NOTE! The low bit of the "struct page" pointers passed in is a dirty + * indicator, saying that the page needs to be marked dirty before freeing. + * + * release_pages() itself ignores that bit. */ void free_pages_and_swap_cache(struct page **pages, int nr) { @@ -268,8 +273,13 @@ void free_pages_and_swap_cache(struct page **pages, int nr) int todo = min(nr, PAGEVEC_SIZE); int i; - for (i = 0; i < todo; i++) - free_swap_cache(pagep[i]); + for (i = 0; i < todo; i++) { + unsigned long pageval = (unsigned long) pagep[i]; + struct page *page = (void *)(~1ul & pageval); + if (pageval & 1) + set_page_dirty(page); + free_swap_cache(page); + } release_pages(pagep, todo, 0); pagep += todo; nr -= todo;