This commit was manufactured by cvs2svn to create tag 'before-xenU'.
[linux-2.6.git] / mm / fremap.c
1 /*
2  *   linux/mm/fremap.c
3  * 
4  * Explicit pagetable population and nonlinear (random) mappings support.
5  *
6  * started by Ingo Molnar, Copyright (C) 2002, 2003
7  */
8
9 #include <linux/mm.h>
10 #include <linux/swap.h>
11 #include <linux/file.h>
12 #include <linux/mman.h>
13 #include <linux/pagemap.h>
14 #include <linux/swapops.h>
15 #include <linux/rmap.h>
16 #include <linux/module.h>
17 #include <linux/vs_memory.h>
18 #include <linux/syscalls.h>
19 #include <linux/vs_memory.h>
20
21 #include <asm/mmu_context.h>
22 #include <asm/cacheflush.h>
23 #include <asm/tlbflush.h>
24
25 static inline void zap_pte(struct mm_struct *mm, struct vm_area_struct *vma,
26                         unsigned long addr, pte_t *ptep)
27 {
28         pte_t pte = *ptep;
29
30         if (pte_none(pte))
31                 return;
32         if (pte_present(pte)) {
33                 unsigned long pfn = pte_pfn(pte);
34
35                 flush_cache_page(vma, addr, pfn);
36                 pte = ptep_clear_flush(vma, addr, ptep);
37                 if (pfn_valid(pfn)) {
38                         struct page *page = pfn_to_page(pfn);
39                         if (!PageReserved(page)) {
40                                 if (pte_dirty(pte))
41                                         set_page_dirty(page);
42                                 page_remove_rmap(page);
43                                 page_cache_release(page);
44                                 dec_mm_counter(mm, rss);
45                         }
46                 }
47         } else {
48                 if (!pte_file(pte))
49                         free_swap_and_cache(pte_to_swp_entry(pte));
50                 pte_clear(mm, addr, ptep);
51         }
52 }
53
54 /*
55  * Install a file page to a given virtual memory address, release any
56  * previously existing mapping.
57  */
58 int install_page(struct mm_struct *mm, struct vm_area_struct *vma,
59                 unsigned long addr, struct page *page, pgprot_t prot)
60 {
61         struct inode *inode;
62         pgoff_t size;
63         int err = -ENOMEM;
64         pte_t *pte;
65         pmd_t *pmd;
66         pud_t *pud;
67         pgd_t *pgd;
68         pte_t pte_val;
69
70         pgd = pgd_offset(mm, addr);
71         spin_lock(&mm->page_table_lock);
72
73         if (!vx_rsspages_avail(mm, 1))
74                 goto err_unlock;
75         
76         if (!vx_rsspages_avail(mm, 1))
77                 goto err_unlock;
78
79         pud = pud_alloc(mm, pgd, addr);
80         if (!pud)
81                 goto err_unlock;
82
83         pmd = pmd_alloc(mm, pud, addr);
84         if (!pmd)
85                 goto err_unlock;
86
87         pte = pte_alloc_map(mm, pmd, addr);
88         if (!pte)
89                 goto err_unlock;
90
91         /*
92          * This page may have been truncated. Tell the
93          * caller about it.
94          */
95         err = -EINVAL;
96         if (vma->vm_file) {
97                 inode = vma->vm_file->f_mapping->host;
98                 size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
99                 if (!page->mapping || page->index >= size)
100                         goto err_unlock;
101         }
102
103         zap_pte(mm, vma, addr, pte);
104
105         inc_mm_counter(mm,rss);
106         flush_icache_page(vma, page);
107         set_pte_at(mm, addr, pte, mk_pte(page, prot));
108         page_add_file_rmap(page);
109         pte_val = *pte;
110         pte_unmap(pte);
111         update_mmu_cache(vma, addr, pte_val);
112
113         err = 0;
114 err_unlock:
115         spin_unlock(&mm->page_table_lock);
116         return err;
117 }
118 EXPORT_SYMBOL(install_page);
119
120
121 /*
122  * Install a file pte to a given virtual memory address, release any
123  * previously existing mapping.
124  */
125 int install_file_pte(struct mm_struct *mm, struct vm_area_struct *vma,
126                 unsigned long addr, unsigned long pgoff, pgprot_t prot)
127 {
128         int err = -ENOMEM;
129         pte_t *pte;
130         pmd_t *pmd;
131         pud_t *pud;
132         pgd_t *pgd;
133         pte_t pte_val;
134
135         pgd = pgd_offset(mm, addr);
136         spin_lock(&mm->page_table_lock);
137         
138         pud = pud_alloc(mm, pgd, addr);
139         if (!pud)
140                 goto err_unlock;
141
142         pmd = pmd_alloc(mm, pud, addr);
143         if (!pmd)
144                 goto err_unlock;
145
146         pte = pte_alloc_map(mm, pmd, addr);
147         if (!pte)
148                 goto err_unlock;
149
150         zap_pte(mm, vma, addr, pte);
151
152         set_pte_at(mm, addr, pte, pgoff_to_pte(pgoff));
153         pte_val = *pte;
154         pte_unmap(pte);
155         update_mmu_cache(vma, addr, pte_val);
156         spin_unlock(&mm->page_table_lock);
157         return 0;
158
159 err_unlock:
160         spin_unlock(&mm->page_table_lock);
161         return err;
162 }
163
164
165 /***
166  * sys_remap_file_pages - remap arbitrary pages of a shared backing store
167  *                        file within an existing vma.
168  * @start: start of the remapped virtual memory range
169  * @size: size of the remapped virtual memory range
170  * @prot: new protection bits of the range
171  * @pgoff: to be mapped page of the backing store file
172  * @flags: 0 or MAP_NONBLOCKED - the later will cause no IO.
173  *
174  * this syscall works purely via pagetables, so it's the most efficient
175  * way to map the same (large) file into a given virtual window. Unlike
176  * mmap()/mremap() it does not create any new vmas. The new mappings are
177  * also safe across swapout.
178  *
179  * NOTE: the 'prot' parameter right now is ignored, and the vma's default
180  * protection is used. Arbitrary protections might be implemented in the
181  * future.
182  */
183 asmlinkage long sys_remap_file_pages(unsigned long start, unsigned long size,
184         unsigned long __prot, unsigned long pgoff, unsigned long flags)
185 {
186         struct mm_struct *mm = current->mm;
187         struct address_space *mapping;
188         unsigned long end = start + size;
189         struct vm_area_struct *vma;
190         int err = -EINVAL;
191         int has_write_lock = 0;
192
193         if (__prot)
194                 return err;
195         /*
196          * Sanitize the syscall parameters:
197          */
198         start = start & PAGE_MASK;
199         size = size & PAGE_MASK;
200
201         /* Does the address range wrap, or is the span zero-sized? */
202         if (start + size <= start)
203                 return err;
204
205         /* Can we represent this offset inside this architecture's pte's? */
206 #if PTE_FILE_MAX_BITS < BITS_PER_LONG
207         if (pgoff + (size >> PAGE_SHIFT) >= (1UL << PTE_FILE_MAX_BITS))
208                 return err;
209 #endif
210
211         /* We need down_write() to change vma->vm_flags. */
212         down_read(&mm->mmap_sem);
213  retry:
214         vma = find_vma(mm, start);
215
216         /*
217          * Make sure the vma is shared, that it supports prefaulting,
218          * and that the remapped range is valid and fully within
219          * the single existing vma.  vm_private_data is used as a
220          * swapout cursor in a VM_NONLINEAR vma (unless VM_RESERVED
221          * or VM_LOCKED, but VM_LOCKED could be revoked later on).
222          */
223         if (vma && (vma->vm_flags & VM_SHARED) &&
224                 (!vma->vm_private_data ||
225                         (vma->vm_flags & (VM_NONLINEAR|VM_RESERVED))) &&
226                 vma->vm_ops && vma->vm_ops->populate &&
227                         end > start && start >= vma->vm_start &&
228                                 end <= vma->vm_end) {
229
230                 /* Must set VM_NONLINEAR before any pages are populated. */
231                 if (pgoff != linear_page_index(vma, start) &&
232                     !(vma->vm_flags & VM_NONLINEAR)) {
233                         if (!has_write_lock) {
234                                 up_read(&mm->mmap_sem);
235                                 down_write(&mm->mmap_sem);
236                                 has_write_lock = 1;
237                                 goto retry;
238                         }
239                         mapping = vma->vm_file->f_mapping;
240                         spin_lock(&mapping->i_mmap_lock);
241                         flush_dcache_mmap_lock(mapping);
242                         vma->vm_flags |= VM_NONLINEAR;
243                         vma_prio_tree_remove(vma, &mapping->i_mmap);
244                         vma_nonlinear_insert(vma, &mapping->i_mmap_nonlinear);
245                         flush_dcache_mmap_unlock(mapping);
246                         spin_unlock(&mapping->i_mmap_lock);
247                 }
248
249                 err = vma->vm_ops->populate(vma, start, size,
250                                             vma->vm_page_prot,
251                                             pgoff, flags & MAP_NONBLOCK);
252
253                 /*
254                  * We can't clear VM_NONLINEAR because we'd have to do
255                  * it after ->populate completes, and that would prevent
256                  * downgrading the lock.  (Locks can't be upgraded).
257                  */
258         }
259         if (likely(!has_write_lock))
260                 up_read(&mm->mmap_sem);
261         else
262                 up_write(&mm->mmap_sem);
263
264         return err;
265 }
266