summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-04-17 20:55:18 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-04-17 20:55:18 -0700
commitdd9fd0e03de648c6cc189adfc21d349f2a6b69b8 (patch)
tree0854dc562d133303a0e2748d9bcd6b23e8213768 /include/linux
parent3df9aaf34e68c9256b08d02ca65ced12bf9e8d9e (diff)
[PATCH] rmap: nonlinear truncation
From: Hugh Dickins <hugh@veritas.com> The earlier changes introducing PageAnon left truncated pages mapped into nonlinear vmas unswappable. Once we go to object-based rmap, it's impossible to find where file page is mapped once page->mapping cleared: switching them to anonymous is odd, and breaks strict commit accounting. So now handle truncation of nonlinear vmas correctly. And factor in Daniel's cluster filesystem needs while we're there: when invalidating local cache, we do want to unmap shared pages from all mms, but we do not want to discard private COWed modifications of those pages (which truncation discards to satisfy the SIGBUS semantics demanded by specs). Drew from Daniel's patch (LKML 2 Mar 04), but didn't always follow it; fewer name changes, but still some - "unmap" rather than "invalidate". zap_page_range is not exported, safe to give it and all the too-many layers an extra zap_details arg, in normal cases just NULL. Given details, zap_pte_range checks page mapping or index to skip anon or untruncated pages. I didn't realize before implementing, that in nonlinear case, it should set a file pte when truncating - otherwise linear pages might appear in place of SIGBUS. I suspect this implies that ->populate functions ought to set file ptes beyond EOF instead of failing, but haven't changed them as yet. To avoid making yet another copy of that ugly linear pgidx test, added inline function linear_page_index (to pagemap.h to get PAGE_CACHE_SIZE, though as usual things don't really work if it differs from PAGE_SIZE). Ooh, I thought I'd removed ___add_to_page_cache last time, do so now. unmap_page_range static, shift its hugepage check up into sole caller unmap_vmas. Killed "killme" debug from unmap_vmas, not seen it trigger. unmap_mapping_range is exported without restriction: I'm one of those who believe it should be generally available. But I'm wrongly placed to decide that, probably just sob quietly to myself if _GPL added later.
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/mm.h19
-rw-r--r--include/linux/pagemap.h12
2 files changed, 17 insertions, 14 deletions
diff --git a/include/linux/mm.h b/include/linux/mm.h
index 4fd3c76ac05f..d664c4ffbcc7 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -439,22 +439,27 @@ struct file *shmem_file_setup(char * name, loff_t size, unsigned long flags);
void shmem_lock(struct file * file, int lock);
int shmem_zero_setup(struct vm_area_struct *);
+struct zap_details;
void zap_page_range(struct vm_area_struct *vma, unsigned long address,
- unsigned long size);
+ unsigned long size, struct zap_details *);
int unmap_vmas(struct mmu_gather **tlbp, struct mm_struct *mm,
struct vm_area_struct *start_vma, unsigned long start_addr,
- unsigned long end_addr, unsigned long *nr_accounted);
-void unmap_page_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
- unsigned long address, unsigned long size);
+ unsigned long end_addr, unsigned long *nr_accounted,
+ struct zap_details *);
void clear_page_tables(struct mmu_gather *tlb, unsigned long first, int nr);
int copy_page_range(struct mm_struct *dst, struct mm_struct *src,
struct vm_area_struct *vma);
int zeromap_page_range(struct vm_area_struct *vma, unsigned long from,
unsigned long size, pgprot_t prot);
+void unmap_mapping_range(struct address_space *mapping,
+ loff_t const holebegin, loff_t const holelen, int even_cows);
+
+static inline void unmap_shared_mapping_range(struct address_space *mapping,
+ loff_t const holebegin, loff_t const holelen)
+{
+ unmap_mapping_range(mapping, holebegin, holelen, 0);
+}
-extern void invalidate_mmap_range(struct address_space *mapping,
- loff_t const holebegin,
- loff_t const holelen);
extern int vmtruncate(struct inode * inode, loff_t offset);
extern pmd_t *FASTCALL(__pmd_alloc(struct mm_struct *mm, pgd_t *pgd, unsigned long address));
extern pte_t *FASTCALL(pte_alloc_kernel(struct mm_struct *mm, pmd_t *pmd, unsigned long address));
diff --git a/include/linux/pagemap.h b/include/linux/pagemap.h
index 5585675ab842..e5acf35963a2 100644
--- a/include/linux/pagemap.h
+++ b/include/linux/pagemap.h
@@ -139,14 +139,12 @@ static inline unsigned long get_page_cache_size(void)
return atomic_read(&nr_pagecache);
}
-static inline void ___add_to_page_cache(struct page *page,
- struct address_space *mapping, unsigned long index)
+static inline pgoff_t linear_page_index(struct vm_area_struct *vma,
+ unsigned long address)
{
- page->mapping = mapping;
- page->index = index;
-
- mapping->nrpages++;
- pagecache_acct(1);
+ pgoff_t pgoff = (address - vma->vm_start) >> PAGE_SHIFT;
+ pgoff += vma->vm_pgoff;
+ return pgoff >> (PAGE_CACHE_SHIFT - PAGE_SHIFT);
}
extern void FASTCALL(__lock_page(struct page *page));