diff options
Diffstat (limited to 'mm/filemap.c')
| -rw-r--r-- | mm/filemap.c | 42 |
1 files changed, 29 insertions, 13 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 3d4df44e4221..75572b5f2374 100644 --- a/mm/filemap.c +++ b/mm/filemap.c | |||
| @@ -612,6 +612,19 @@ void __lock_page_nosync(struct page *page) | |||
| 612 | TASK_UNINTERRUPTIBLE); | 612 | TASK_UNINTERRUPTIBLE); |
| 613 | } | 613 | } |
| 614 | 614 | ||
| 615 | int __lock_page_or_retry(struct page *page, struct mm_struct *mm, | ||
| 616 | unsigned int flags) | ||
| 617 | { | ||
| 618 | if (!(flags & FAULT_FLAG_ALLOW_RETRY)) { | ||
| 619 | __lock_page(page); | ||
| 620 | return 1; | ||
| 621 | } else { | ||
| 622 | up_read(&mm->mmap_sem); | ||
| 623 | wait_on_page_locked(page); | ||
| 624 | return 0; | ||
| 625 | } | ||
| 626 | } | ||
| 627 | |||
| 615 | /** | 628 | /** |
| 616 | * find_get_page - find and get a page reference | 629 | * find_get_page - find and get a page reference |
| 617 | * @mapping: the address_space to search | 630 | * @mapping: the address_space to search |
| @@ -1539,25 +1552,28 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
| 1539 | * waiting for the lock. | 1552 | * waiting for the lock. |
| 1540 | */ | 1553 | */ |
| 1541 | do_async_mmap_readahead(vma, ra, file, page, offset); | 1554 | do_async_mmap_readahead(vma, ra, file, page, offset); |
| 1542 | lock_page(page); | ||
| 1543 | |||
| 1544 | /* Did it get truncated? */ | ||
| 1545 | if (unlikely(page->mapping != mapping)) { | ||
| 1546 | unlock_page(page); | ||
| 1547 | put_page(page); | ||
| 1548 | goto no_cached_page; | ||
| 1549 | } | ||
| 1550 | } else { | 1555 | } else { |
| 1551 | /* No page in the page cache at all */ | 1556 | /* No page in the page cache at all */ |
| 1552 | do_sync_mmap_readahead(vma, ra, file, offset); | 1557 | do_sync_mmap_readahead(vma, ra, file, offset); |
| 1553 | count_vm_event(PGMAJFAULT); | 1558 | count_vm_event(PGMAJFAULT); |
| 1554 | ret = VM_FAULT_MAJOR; | 1559 | ret = VM_FAULT_MAJOR; |
| 1555 | retry_find: | 1560 | retry_find: |
| 1556 | page = find_lock_page(mapping, offset); | 1561 | page = find_get_page(mapping, offset); |
| 1557 | if (!page) | 1562 | if (!page) |
| 1558 | goto no_cached_page; | 1563 | goto no_cached_page; |
| 1559 | } | 1564 | } |
| 1560 | 1565 | ||
| 1566 | if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) | ||
| 1567 | return ret | VM_FAULT_RETRY; | ||
| 1568 | |||
| 1569 | /* Did it get truncated? */ | ||
| 1570 | if (unlikely(page->mapping != mapping)) { | ||
| 1571 | unlock_page(page); | ||
| 1572 | put_page(page); | ||
| 1573 | goto retry_find; | ||
| 1574 | } | ||
| 1575 | VM_BUG_ON(page->index != offset); | ||
| 1576 | |||
| 1561 | /* | 1577 | /* |
| 1562 | * We have a locked page in the page cache, now we need to check | 1578 | * We have a locked page in the page cache, now we need to check |
| 1563 | * that it's up-to-date. If not, it is going to be due to an error. | 1579 | * that it's up-to-date. If not, it is going to be due to an error. |
| @@ -2177,12 +2193,12 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
| 2177 | } | 2193 | } |
| 2178 | 2194 | ||
| 2179 | if (written > 0) { | 2195 | if (written > 0) { |
| 2180 | loff_t end = pos + written; | 2196 | pos += written; |
| 2181 | if (end > i_size_read(inode) && !S_ISBLK(inode->i_mode)) { | 2197 | if (pos > i_size_read(inode) && !S_ISBLK(inode->i_mode)) { |
| 2182 | i_size_write(inode, end); | 2198 | i_size_write(inode, pos); |
| 2183 | mark_inode_dirty(inode); | 2199 | mark_inode_dirty(inode); |
| 2184 | } | 2200 | } |
| 2185 | *ppos = end; | 2201 | *ppos = pos; |
| 2186 | } | 2202 | } |
| 2187 | out: | 2203 | out: |
| 2188 | return written; | 2204 | return written; |
