diff options
Diffstat (limited to 'mm/filemap_xip.c')
-rw-r--r-- | mm/filemap_xip.c | 478 |
1 files changed, 0 insertions, 478 deletions
diff --git a/mm/filemap_xip.c b/mm/filemap_xip.c deleted file mode 100644 index c175f9f25210..000000000000 --- a/mm/filemap_xip.c +++ /dev/null | |||
@@ -1,478 +0,0 @@ | |||
1 | /* | ||
2 | * linux/mm/filemap_xip.c | ||
3 | * | ||
4 | * Copyright (C) 2005 IBM Corporation | ||
5 | * Author: Carsten Otte <cotte@de.ibm.com> | ||
6 | * | ||
7 | * derived from linux/mm/filemap.c - Copyright (C) Linus Torvalds | ||
8 | * | ||
9 | */ | ||
10 | |||
11 | #include <linux/fs.h> | ||
12 | #include <linux/backing-dev.h> | ||
13 | #include <linux/pagemap.h> | ||
14 | #include <linux/export.h> | ||
15 | #include <linux/uio.h> | ||
16 | #include <linux/rmap.h> | ||
17 | #include <linux/mmu_notifier.h> | ||
18 | #include <linux/sched.h> | ||
19 | #include <linux/seqlock.h> | ||
20 | #include <linux/mutex.h> | ||
21 | #include <linux/gfp.h> | ||
22 | #include <asm/tlbflush.h> | ||
23 | #include <asm/io.h> | ||
24 | |||
25 | /* | ||
26 | * We do use our own empty page to avoid interference with other users | ||
27 | * of ZERO_PAGE(), such as /dev/zero | ||
28 | */ | ||
29 | static DEFINE_MUTEX(xip_sparse_mutex); | ||
30 | static seqcount_t xip_sparse_seq = SEQCNT_ZERO(xip_sparse_seq); | ||
31 | static struct page *__xip_sparse_page; | ||
32 | |||
33 | /* called under xip_sparse_mutex */ | ||
34 | static struct page *xip_sparse_page(void) | ||
35 | { | ||
36 | if (!__xip_sparse_page) { | ||
37 | struct page *page = alloc_page(GFP_HIGHUSER | __GFP_ZERO); | ||
38 | |||
39 | if (page) | ||
40 | __xip_sparse_page = page; | ||
41 | } | ||
42 | return __xip_sparse_page; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * This is a file read routine for execute in place files, and uses | ||
47 | * the mapping->a_ops->get_xip_mem() function for the actual low-level | ||
48 | * stuff. | ||
49 | * | ||
50 | * Note the struct file* is not used at all. It may be NULL. | ||
51 | */ | ||
52 | static ssize_t | ||
53 | do_xip_mapping_read(struct address_space *mapping, | ||
54 | struct file_ra_state *_ra, | ||
55 | struct file *filp, | ||
56 | char __user *buf, | ||
57 | size_t len, | ||
58 | loff_t *ppos) | ||
59 | { | ||
60 | struct inode *inode = mapping->host; | ||
61 | pgoff_t index, end_index; | ||
62 | unsigned long offset; | ||
63 | loff_t isize, pos; | ||
64 | size_t copied = 0, error = 0; | ||
65 | |||
66 | BUG_ON(!mapping->a_ops->get_xip_mem); | ||
67 | |||
68 | pos = *ppos; | ||
69 | index = pos >> PAGE_CACHE_SHIFT; | ||
70 | offset = pos & ~PAGE_CACHE_MASK; | ||
71 | |||
72 | isize = i_size_read(inode); | ||
73 | if (!isize) | ||
74 | goto out; | ||
75 | |||
76 | end_index = (isize - 1) >> PAGE_CACHE_SHIFT; | ||
77 | do { | ||
78 | unsigned long nr, left; | ||
79 | void *xip_mem; | ||
80 | unsigned long xip_pfn; | ||
81 | int zero = 0; | ||
82 | |||
83 | /* nr is the maximum number of bytes to copy from this page */ | ||
84 | nr = PAGE_CACHE_SIZE; | ||
85 | if (index >= end_index) { | ||
86 | if (index > end_index) | ||
87 | goto out; | ||
88 | nr = ((isize - 1) & ~PAGE_CACHE_MASK) + 1; | ||
89 | if (nr <= offset) { | ||
90 | goto out; | ||
91 | } | ||
92 | } | ||
93 | nr = nr - offset; | ||
94 | if (nr > len - copied) | ||
95 | nr = len - copied; | ||
96 | |||
97 | error = mapping->a_ops->get_xip_mem(mapping, index, 0, | ||
98 | &xip_mem, &xip_pfn); | ||
99 | if (unlikely(error)) { | ||
100 | if (error == -ENODATA) { | ||
101 | /* sparse */ | ||
102 | zero = 1; | ||
103 | } else | ||
104 | goto out; | ||
105 | } | ||
106 | |||
107 | /* If users can be writing to this page using arbitrary | ||
108 | * virtual addresses, take care about potential aliasing | ||
109 | * before reading the page on the kernel side. | ||
110 | */ | ||
111 | if (mapping_writably_mapped(mapping)) | ||
112 | /* address based flush */ ; | ||
113 | |||
114 | /* | ||
115 | * Ok, we have the mem, so now we can copy it to user space... | ||
116 | * | ||
117 | * The actor routine returns how many bytes were actually used.. | ||
118 | * NOTE! This may not be the same as how much of a user buffer | ||
119 | * we filled up (we may be padding etc), so we can only update | ||
120 | * "pos" here (the actor routine has to update the user buffer | ||
121 | * pointers and the remaining count). | ||
122 | */ | ||
123 | if (!zero) | ||
124 | left = __copy_to_user(buf+copied, xip_mem+offset, nr); | ||
125 | else | ||
126 | left = __clear_user(buf + copied, nr); | ||
127 | |||
128 | if (left) { | ||
129 | error = -EFAULT; | ||
130 | goto out; | ||
131 | } | ||
132 | |||
133 | copied += (nr - left); | ||
134 | offset += (nr - left); | ||
135 | index += offset >> PAGE_CACHE_SHIFT; | ||
136 | offset &= ~PAGE_CACHE_MASK; | ||
137 | } while (copied < len); | ||
138 | |||
139 | out: | ||
140 | *ppos = pos + copied; | ||
141 | if (filp) | ||
142 | file_accessed(filp); | ||
143 | |||
144 | return (copied ? copied : error); | ||
145 | } | ||
146 | |||
147 | ssize_t | ||
148 | xip_file_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos) | ||
149 | { | ||
150 | if (!access_ok(VERIFY_WRITE, buf, len)) | ||
151 | return -EFAULT; | ||
152 | |||
153 | return do_xip_mapping_read(filp->f_mapping, &filp->f_ra, filp, | ||
154 | buf, len, ppos); | ||
155 | } | ||
156 | EXPORT_SYMBOL_GPL(xip_file_read); | ||
157 | |||
158 | /* | ||
159 | * __xip_unmap is invoked from xip_unmap and xip_write | ||
160 | * | ||
161 | * This function walks all vmas of the address_space and unmaps the | ||
162 | * __xip_sparse_page when found at pgoff. | ||
163 | */ | ||
164 | static void __xip_unmap(struct address_space * mapping, unsigned long pgoff) | ||
165 | { | ||
166 | struct vm_area_struct *vma; | ||
167 | struct page *page; | ||
168 | unsigned count; | ||
169 | int locked = 0; | ||
170 | |||
171 | count = read_seqcount_begin(&xip_sparse_seq); | ||
172 | |||
173 | page = __xip_sparse_page; | ||
174 | if (!page) | ||
175 | return; | ||
176 | |||
177 | retry: | ||
178 | i_mmap_lock_read(mapping); | ||
179 | vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff) { | ||
180 | pte_t *pte, pteval; | ||
181 | spinlock_t *ptl; | ||
182 | struct mm_struct *mm = vma->vm_mm; | ||
183 | unsigned long address = vma->vm_start + | ||
184 | ((pgoff - vma->vm_pgoff) << PAGE_SHIFT); | ||
185 | |||
186 | BUG_ON(address < vma->vm_start || address >= vma->vm_end); | ||
187 | pte = page_check_address(page, mm, address, &ptl, 1); | ||
188 | if (pte) { | ||
189 | /* Nuke the page table entry. */ | ||
190 | flush_cache_page(vma, address, pte_pfn(*pte)); | ||
191 | pteval = ptep_clear_flush(vma, address, pte); | ||
192 | page_remove_rmap(page); | ||
193 | dec_mm_counter(mm, MM_FILEPAGES); | ||
194 | BUG_ON(pte_dirty(pteval)); | ||
195 | pte_unmap_unlock(pte, ptl); | ||
196 | /* must invalidate_page _before_ freeing the page */ | ||
197 | mmu_notifier_invalidate_page(mm, address); | ||
198 | page_cache_release(page); | ||
199 | } | ||
200 | } | ||
201 | i_mmap_unlock_read(mapping); | ||
202 | |||
203 | if (locked) { | ||
204 | mutex_unlock(&xip_sparse_mutex); | ||
205 | } else if (read_seqcount_retry(&xip_sparse_seq, count)) { | ||
206 | mutex_lock(&xip_sparse_mutex); | ||
207 | locked = 1; | ||
208 | goto retry; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | /* | ||
213 | * xip_fault() is invoked via the vma operations vector for a | ||
214 | * mapped memory region to read in file data during a page fault. | ||
215 | * | ||
216 | * This function is derived from filemap_fault, but used for execute in place | ||
217 | */ | ||
218 | static int xip_file_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | ||
219 | { | ||
220 | struct file *file = vma->vm_file; | ||
221 | struct address_space *mapping = file->f_mapping; | ||
222 | struct inode *inode = mapping->host; | ||
223 | pgoff_t size; | ||
224 | void *xip_mem; | ||
225 | unsigned long xip_pfn; | ||
226 | struct page *page; | ||
227 | int error; | ||
228 | |||
229 | /* XXX: are VM_FAULT_ codes OK? */ | ||
230 | again: | ||
231 | size = (i_size_read(inode) + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | ||
232 | if (vmf->pgoff >= size) | ||
233 | return VM_FAULT_SIGBUS; | ||
234 | |||
235 | error = mapping->a_ops->get_xip_mem(mapping, vmf->pgoff, 0, | ||
236 | &xip_mem, &xip_pfn); | ||
237 | if (likely(!error)) | ||
238 | goto found; | ||
239 | if (error != -ENODATA) | ||
240 | return VM_FAULT_OOM; | ||
241 | |||
242 | /* sparse block */ | ||
243 | if ((vma->vm_flags & (VM_WRITE | VM_MAYWRITE)) && | ||
244 | (vma->vm_flags & (VM_SHARED | VM_MAYSHARE)) && | ||
245 | (!(mapping->host->i_sb->s_flags & MS_RDONLY))) { | ||
246 | int err; | ||
247 | |||
248 | /* maybe shared writable, allocate new block */ | ||
249 | mutex_lock(&xip_sparse_mutex); | ||
250 | error = mapping->a_ops->get_xip_mem(mapping, vmf->pgoff, 1, | ||
251 | &xip_mem, &xip_pfn); | ||
252 | mutex_unlock(&xip_sparse_mutex); | ||
253 | if (error) | ||
254 | return VM_FAULT_SIGBUS; | ||
255 | /* unmap sparse mappings at pgoff from all other vmas */ | ||
256 | __xip_unmap(mapping, vmf->pgoff); | ||
257 | |||
258 | found: | ||
259 | err = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, | ||
260 | xip_pfn); | ||
261 | if (err == -ENOMEM) | ||
262 | return VM_FAULT_OOM; | ||
263 | /* | ||
264 | * err == -EBUSY is fine, we've raced against another thread | ||
265 | * that faulted-in the same page | ||
266 | */ | ||
267 | if (err != -EBUSY) | ||
268 | BUG_ON(err); | ||
269 | return VM_FAULT_NOPAGE; | ||
270 | } else { | ||
271 | int err, ret = VM_FAULT_OOM; | ||
272 | |||
273 | mutex_lock(&xip_sparse_mutex); | ||
274 | write_seqcount_begin(&xip_sparse_seq); | ||
275 | error = mapping->a_ops->get_xip_mem(mapping, vmf->pgoff, 0, | ||
276 | &xip_mem, &xip_pfn); | ||
277 | if (unlikely(!error)) { | ||
278 | write_seqcount_end(&xip_sparse_seq); | ||
279 | mutex_unlock(&xip_sparse_mutex); | ||
280 | goto again; | ||
281 | } | ||
282 | if (error != -ENODATA) | ||
283 | goto out; | ||
284 | /* not shared and writable, use xip_sparse_page() */ | ||
285 | page = xip_sparse_page(); | ||
286 | if (!page) | ||
287 | goto out; | ||
288 | err = vm_insert_page(vma, (unsigned long)vmf->virtual_address, | ||
289 | page); | ||
290 | if (err == -ENOMEM) | ||
291 | goto out; | ||
292 | |||
293 | ret = VM_FAULT_NOPAGE; | ||
294 | out: | ||
295 | write_seqcount_end(&xip_sparse_seq); | ||
296 | mutex_unlock(&xip_sparse_mutex); | ||
297 | |||
298 | return ret; | ||
299 | } | ||
300 | } | ||
301 | |||
302 | static const struct vm_operations_struct xip_file_vm_ops = { | ||
303 | .fault = xip_file_fault, | ||
304 | .page_mkwrite = filemap_page_mkwrite, | ||
305 | }; | ||
306 | |||
307 | int xip_file_mmap(struct file * file, struct vm_area_struct * vma) | ||
308 | { | ||
309 | BUG_ON(!file->f_mapping->a_ops->get_xip_mem); | ||
310 | |||
311 | file_accessed(file); | ||
312 | vma->vm_ops = &xip_file_vm_ops; | ||
313 | vma->vm_flags |= VM_MIXEDMAP; | ||
314 | return 0; | ||
315 | } | ||
316 | EXPORT_SYMBOL_GPL(xip_file_mmap); | ||
317 | |||
318 | static ssize_t | ||
319 | __xip_file_write(struct file *filp, const char __user *buf, | ||
320 | size_t count, loff_t pos, loff_t *ppos) | ||
321 | { | ||
322 | struct address_space * mapping = filp->f_mapping; | ||
323 | const struct address_space_operations *a_ops = mapping->a_ops; | ||
324 | struct inode *inode = mapping->host; | ||
325 | long status = 0; | ||
326 | size_t bytes; | ||
327 | ssize_t written = 0; | ||
328 | |||
329 | BUG_ON(!mapping->a_ops->get_xip_mem); | ||
330 | |||
331 | do { | ||
332 | unsigned long index; | ||
333 | unsigned long offset; | ||
334 | size_t copied; | ||
335 | void *xip_mem; | ||
336 | unsigned long xip_pfn; | ||
337 | |||
338 | offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ | ||
339 | index = pos >> PAGE_CACHE_SHIFT; | ||
340 | bytes = PAGE_CACHE_SIZE - offset; | ||
341 | if (bytes > count) | ||
342 | bytes = count; | ||
343 | |||
344 | status = a_ops->get_xip_mem(mapping, index, 0, | ||
345 | &xip_mem, &xip_pfn); | ||
346 | if (status == -ENODATA) { | ||
347 | /* we allocate a new page unmap it */ | ||
348 | mutex_lock(&xip_sparse_mutex); | ||
349 | status = a_ops->get_xip_mem(mapping, index, 1, | ||
350 | &xip_mem, &xip_pfn); | ||
351 | mutex_unlock(&xip_sparse_mutex); | ||
352 | if (!status) | ||
353 | /* unmap page at pgoff from all other vmas */ | ||
354 | __xip_unmap(mapping, index); | ||
355 | } | ||
356 | |||
357 | if (status) | ||
358 | break; | ||
359 | |||
360 | copied = bytes - | ||
361 | __copy_from_user_nocache(xip_mem + offset, buf, bytes); | ||
362 | |||
363 | if (likely(copied > 0)) { | ||
364 | status = copied; | ||
365 | |||
366 | if (status >= 0) { | ||
367 | written += status; | ||
368 | count -= status; | ||
369 | pos += status; | ||
370 | buf += status; | ||
371 | } | ||
372 | } | ||
373 | if (unlikely(copied != bytes)) | ||
374 | if (status >= 0) | ||
375 | status = -EFAULT; | ||
376 | if (status < 0) | ||
377 | break; | ||
378 | } while (count); | ||
379 | *ppos = pos; | ||
380 | /* | ||
381 | * No need to use i_size_read() here, the i_size | ||
382 | * cannot change under us because we hold i_mutex. | ||
383 | */ | ||
384 | if (pos > inode->i_size) { | ||
385 | i_size_write(inode, pos); | ||
386 | mark_inode_dirty(inode); | ||
387 | } | ||
388 | |||
389 | return written ? written : status; | ||
390 | } | ||
391 | |||
392 | ssize_t | ||
393 | xip_file_write(struct file *filp, const char __user *buf, size_t len, | ||
394 | loff_t *ppos) | ||
395 | { | ||
396 | struct address_space *mapping = filp->f_mapping; | ||
397 | struct inode *inode = mapping->host; | ||
398 | size_t count; | ||
399 | loff_t pos; | ||
400 | ssize_t ret; | ||
401 | |||
402 | mutex_lock(&inode->i_mutex); | ||
403 | |||
404 | if (!access_ok(VERIFY_READ, buf, len)) { | ||
405 | ret=-EFAULT; | ||
406 | goto out_up; | ||
407 | } | ||
408 | |||
409 | pos = *ppos; | ||
410 | count = len; | ||
411 | |||
412 | /* We can write back this queue in page reclaim */ | ||
413 | current->backing_dev_info = inode_to_bdi(inode); | ||
414 | |||
415 | ret = generic_write_checks(filp, &pos, &count, S_ISBLK(inode->i_mode)); | ||
416 | if (ret) | ||
417 | goto out_backing; | ||
418 | if (count == 0) | ||
419 | goto out_backing; | ||
420 | |||
421 | ret = file_remove_suid(filp); | ||
422 | if (ret) | ||
423 | goto out_backing; | ||
424 | |||
425 | ret = file_update_time(filp); | ||
426 | if (ret) | ||
427 | goto out_backing; | ||
428 | |||
429 | ret = __xip_file_write (filp, buf, count, pos, ppos); | ||
430 | |||
431 | out_backing: | ||
432 | current->backing_dev_info = NULL; | ||
433 | out_up: | ||
434 | mutex_unlock(&inode->i_mutex); | ||
435 | return ret; | ||
436 | } | ||
437 | EXPORT_SYMBOL_GPL(xip_file_write); | ||
438 | |||
439 | /* | ||
440 | * truncate a page used for execute in place | ||
441 | * functionality is analog to block_truncate_page but does use get_xip_mem | ||
442 | * to get the page instead of page cache | ||
443 | */ | ||
444 | int | ||
445 | xip_truncate_page(struct address_space *mapping, loff_t from) | ||
446 | { | ||
447 | pgoff_t index = from >> PAGE_CACHE_SHIFT; | ||
448 | unsigned offset = from & (PAGE_CACHE_SIZE-1); | ||
449 | unsigned blocksize; | ||
450 | unsigned length; | ||
451 | void *xip_mem; | ||
452 | unsigned long xip_pfn; | ||
453 | int err; | ||
454 | |||
455 | BUG_ON(!mapping->a_ops->get_xip_mem); | ||
456 | |||
457 | blocksize = 1 << mapping->host->i_blkbits; | ||
458 | length = offset & (blocksize - 1); | ||
459 | |||
460 | /* Block boundary? Nothing to do */ | ||
461 | if (!length) | ||
462 | return 0; | ||
463 | |||
464 | length = blocksize - length; | ||
465 | |||
466 | err = mapping->a_ops->get_xip_mem(mapping, index, 0, | ||
467 | &xip_mem, &xip_pfn); | ||
468 | if (unlikely(err)) { | ||
469 | if (err == -ENODATA) | ||
470 | /* Hole? No need to truncate */ | ||
471 | return 0; | ||
472 | else | ||
473 | return err; | ||
474 | } | ||
475 | memset(xip_mem + offset, 0, length); | ||
476 | return 0; | ||
477 | } | ||
478 | EXPORT_SYMBOL_GPL(xip_truncate_page); | ||