diff options
author | Jiri Kosina <jkosina@suse.cz> | 2010-12-10 09:19:18 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2010-12-10 09:19:18 -0500 |
commit | 2ade0c1d9d93b7642212657ef76f4a1e30233711 (patch) | |
tree | 63bc720c0ffe5f4760cac4ed617b9870b050175e /mm/filemap.c | |
parent | 504499f22c08a03e2e19dc88d31aa0ecd2ac815e (diff) | |
parent | 6313e3c21743cc88bb5bd8aa72948ee1e83937b6 (diff) |
Merge branch 'master' into upstream
Diffstat (limited to 'mm/filemap.c')
-rw-r--r-- | mm/filemap.c | 73 |
1 files changed, 44 insertions, 29 deletions
diff --git a/mm/filemap.c b/mm/filemap.c index 3d4df44e4221..ea89840fc65f 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 |
@@ -631,7 +644,9 @@ repeat: | |||
631 | pagep = radix_tree_lookup_slot(&mapping->page_tree, offset); | 644 | pagep = radix_tree_lookup_slot(&mapping->page_tree, offset); |
632 | if (pagep) { | 645 | if (pagep) { |
633 | page = radix_tree_deref_slot(pagep); | 646 | page = radix_tree_deref_slot(pagep); |
634 | if (unlikely(!page || page == RADIX_TREE_RETRY)) | 647 | if (unlikely(!page)) |
648 | goto out; | ||
649 | if (radix_tree_deref_retry(page)) | ||
635 | goto repeat; | 650 | goto repeat; |
636 | 651 | ||
637 | if (!page_cache_get_speculative(page)) | 652 | if (!page_cache_get_speculative(page)) |
@@ -647,6 +662,7 @@ repeat: | |||
647 | goto repeat; | 662 | goto repeat; |
648 | } | 663 | } |
649 | } | 664 | } |
665 | out: | ||
650 | rcu_read_unlock(); | 666 | rcu_read_unlock(); |
651 | 667 | ||
652 | return page; | 668 | return page; |
@@ -764,12 +780,11 @@ repeat: | |||
764 | page = radix_tree_deref_slot((void **)pages[i]); | 780 | page = radix_tree_deref_slot((void **)pages[i]); |
765 | if (unlikely(!page)) | 781 | if (unlikely(!page)) |
766 | continue; | 782 | continue; |
767 | /* | 783 | if (radix_tree_deref_retry(page)) { |
768 | * this can only trigger if nr_found == 1, making livelock | 784 | if (ret) |
769 | * a non issue. | 785 | start = pages[ret-1]->index; |
770 | */ | ||
771 | if (unlikely(page == RADIX_TREE_RETRY)) | ||
772 | goto restart; | 786 | goto restart; |
787 | } | ||
773 | 788 | ||
774 | if (!page_cache_get_speculative(page)) | 789 | if (!page_cache_get_speculative(page)) |
775 | goto repeat; | 790 | goto repeat; |
@@ -817,11 +832,7 @@ repeat: | |||
817 | page = radix_tree_deref_slot((void **)pages[i]); | 832 | page = radix_tree_deref_slot((void **)pages[i]); |
818 | if (unlikely(!page)) | 833 | if (unlikely(!page)) |
819 | continue; | 834 | continue; |
820 | /* | 835 | if (radix_tree_deref_retry(page)) |
821 | * this can only trigger if nr_found == 1, making livelock | ||
822 | * a non issue. | ||
823 | */ | ||
824 | if (unlikely(page == RADIX_TREE_RETRY)) | ||
825 | goto restart; | 836 | goto restart; |
826 | 837 | ||
827 | if (page->mapping == NULL || page->index != index) | 838 | if (page->mapping == NULL || page->index != index) |
@@ -874,11 +885,7 @@ repeat: | |||
874 | page = radix_tree_deref_slot((void **)pages[i]); | 885 | page = radix_tree_deref_slot((void **)pages[i]); |
875 | if (unlikely(!page)) | 886 | if (unlikely(!page)) |
876 | continue; | 887 | continue; |
877 | /* | 888 | if (radix_tree_deref_retry(page)) |
878 | * this can only trigger if nr_found == 1, making livelock | ||
879 | * a non issue. | ||
880 | */ | ||
881 | if (unlikely(page == RADIX_TREE_RETRY)) | ||
882 | goto restart; | 889 | goto restart; |
883 | 890 | ||
884 | if (!page_cache_get_speculative(page)) | 891 | if (!page_cache_get_speculative(page)) |
@@ -1016,6 +1023,9 @@ find_page: | |||
1016 | goto page_not_up_to_date; | 1023 | goto page_not_up_to_date; |
1017 | if (!trylock_page(page)) | 1024 | if (!trylock_page(page)) |
1018 | goto page_not_up_to_date; | 1025 | goto page_not_up_to_date; |
1026 | /* Did it get truncated before we got the lock? */ | ||
1027 | if (!page->mapping) | ||
1028 | goto page_not_up_to_date_locked; | ||
1019 | if (!mapping->a_ops->is_partially_uptodate(page, | 1029 | if (!mapping->a_ops->is_partially_uptodate(page, |
1020 | desc, offset)) | 1030 | desc, offset)) |
1021 | goto page_not_up_to_date_locked; | 1031 | goto page_not_up_to_date_locked; |
@@ -1539,25 +1549,30 @@ int filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1539 | * waiting for the lock. | 1549 | * waiting for the lock. |
1540 | */ | 1550 | */ |
1541 | do_async_mmap_readahead(vma, ra, file, page, offset); | 1551 | 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 { | 1552 | } else { |
1551 | /* No page in the page cache at all */ | 1553 | /* No page in the page cache at all */ |
1552 | do_sync_mmap_readahead(vma, ra, file, offset); | 1554 | do_sync_mmap_readahead(vma, ra, file, offset); |
1553 | count_vm_event(PGMAJFAULT); | 1555 | count_vm_event(PGMAJFAULT); |
1554 | ret = VM_FAULT_MAJOR; | 1556 | ret = VM_FAULT_MAJOR; |
1555 | retry_find: | 1557 | retry_find: |
1556 | page = find_lock_page(mapping, offset); | 1558 | page = find_get_page(mapping, offset); |
1557 | if (!page) | 1559 | if (!page) |
1558 | goto no_cached_page; | 1560 | goto no_cached_page; |
1559 | } | 1561 | } |
1560 | 1562 | ||
1563 | if (!lock_page_or_retry(page, vma->vm_mm, vmf->flags)) { | ||
1564 | page_cache_release(page); | ||
1565 | return ret | VM_FAULT_RETRY; | ||
1566 | } | ||
1567 | |||
1568 | /* Did it get truncated? */ | ||
1569 | if (unlikely(page->mapping != mapping)) { | ||
1570 | unlock_page(page); | ||
1571 | put_page(page); | ||
1572 | goto retry_find; | ||
1573 | } | ||
1574 | VM_BUG_ON(page->index != offset); | ||
1575 | |||
1561 | /* | 1576 | /* |
1562 | * We have a locked page in the page cache, now we need to check | 1577 | * 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. | 1578 | * that it's up-to-date. If not, it is going to be due to an error. |
@@ -2177,12 +2192,12 @@ generic_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
2177 | } | 2192 | } |
2178 | 2193 | ||
2179 | if (written > 0) { | 2194 | if (written > 0) { |
2180 | loff_t end = pos + written; | 2195 | pos += written; |
2181 | if (end > i_size_read(inode) && !S_ISBLK(inode->i_mode)) { | 2196 | if (pos > i_size_read(inode) && !S_ISBLK(inode->i_mode)) { |
2182 | i_size_write(inode, end); | 2197 | i_size_write(inode, pos); |
2183 | mark_inode_dirty(inode); | 2198 | mark_inode_dirty(inode); |
2184 | } | 2199 | } |
2185 | *ppos = end; | 2200 | *ppos = pos; |
2186 | } | 2201 | } |
2187 | out: | 2202 | out: |
2188 | return written; | 2203 | return written; |