Fix corners in writepage and btrfs_truncate_page
authorChris Mason <chris.mason@oracle.com>
Thu, 15 May 2008 13:13:45 +0000 (09:13 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 25 Sep 2008 15:04:03 +0000 (11:04 -0400)
The extent_io writepage calls needed an extra check for discarding
pages that started on th last byte in the file.

btrfs_truncate_page needed checks to make sure the page was still part
of the file after reading it, and most importantly, needed to wait for
all IO to the page to finish before freeing the corresponding extents on
disk.

Signed-off-by: Chris Mason <chris.mason@oracle.com>
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/inode.c

index 2a3624adc0cfaaec555defb95ff642927ffb0c8c..17c508a941eb36de2e8d2471d40107ea16cf51f0 100644 (file)
@@ -1988,9 +1988,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
        u64 nr_delalloc;
        u64 delalloc_end;
 
+
        WARN_ON(!PageLocked(page));
-       if (page->index > end_index) {
-               clear_extent_dirty(tree, start, page_end, GFP_NOFS);
+       page_offset = i_size & (PAGE_CACHE_SIZE - 1);
+       if (page->index > end_index ||
+          (page->index == end_index && !page_offset)) {
+               page->mapping->a_ops->invalidatepage(page, 0);
                unlock_page(page);
                return 0;
        }
@@ -1998,13 +2001,13 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
        if (page->index == end_index) {
                char *userpage;
 
-               size_t offset = i_size & (PAGE_CACHE_SIZE - 1);
-
                userpage = kmap_atomic(page, KM_USER0);
-               memset(userpage + offset, 0, PAGE_CACHE_SIZE - offset);
-               flush_dcache_page(page);
+               memset(userpage + page_offset, 0,
+                      PAGE_CACHE_SIZE - page_offset);
                kunmap_atomic(userpage, KM_USER0);
+               flush_dcache_page(page);
        }
+       page_offset = 0;
 
        set_page_extent_mapped(page);
 
index df97d470812a31bdfee7efbf4e86fe7d1eb68eac..d968900c69739da5be852d92ce55d86178aec929 100644 (file)
@@ -305,7 +305,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
            (inline_size & (root->sectorsize -1)) == 0 ||
            inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
                u64 last_end;
-               u64 existing_delalloc = 0;
 
                for (i = 0; i < num_pages; i++) {
                        struct page *p = pages[i];
@@ -315,13 +314,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
                last_end = (u64)(pages[num_pages -1]->index) <<
                                PAGE_CACHE_SHIFT;
                last_end += PAGE_CACHE_SIZE - 1;
-               if (start_pos < isize) {
-                       u64 delalloc_start = start_pos;
-                       existing_delalloc = count_range_bits(io_tree,
-                                            &delalloc_start,
-                                            end_of_last_block, (u64)-1,
-                                            EXTENT_DELALLOC);
-               }
                set_extent_delalloc(io_tree, start_pos, end_of_last_block,
                                 GFP_NOFS);
                btrfs_add_ordered_inode(inode);
index 08760ff9bab757bb330c358a010823972099d6b5..40b4a8ec17fef7a56a1fa7b33f5373332125e8c4 100644 (file)
@@ -1180,19 +1180,26 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
                goto out;
 
        ret = -ENOMEM;
+again:
        page = grab_cache_page(mapping, index);
        if (!page)
                goto out;
        if (!PageUptodate(page)) {
                ret = btrfs_readpage(NULL, page);
                lock_page(page);
+               if (page->mapping != mapping) {
+                       unlock_page(page);
+                       page_cache_release(page);
+                       goto again;
+               }
                if (!PageUptodate(page)) {
                        ret = -EIO;
                        goto out;
                }
        }
-       page_start = (u64)page->index << PAGE_CACHE_SHIFT;
 
+       page_start = (u64)page->index << PAGE_CACHE_SHIFT;
+       wait_on_page_writeback(page);
        ret = btrfs_cow_one_page(inode, page, offset);
 
        unlock_page(page);