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