ext4: fix data corruption in data=journal mode
[pandora-kernel.git] / fs / ext4 / inode.c
index 7e22e76..f881e34 100644 (file)
@@ -1073,7 +1073,9 @@ static int ext4_writeback_write_end(struct file *file,
  * set the buffer to be dirty, since in data=journalled mode we need
  * to call ext4_handle_dirty_metadata() instead.
  */
-static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
+static void ext4_journalled_zero_new_buffers(handle_t *handle,
+                                           struct page *page,
+                                           unsigned from, unsigned to)
 {
        unsigned int block_start = 0, block_end;
        struct buffer_head *head, *bh;
@@ -1090,7 +1092,7 @@ static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
                                        size = min(to, block_end) - start;
 
                                        zero_user(page, start, size);
-                                       set_buffer_uptodate(bh);
+                                       write_end_fn(handle, bh);
                                }
                                clear_buffer_new(bh);
                        }
@@ -1118,16 +1120,19 @@ static int ext4_journalled_write_end(struct file *file,
 
        BUG_ON(!ext4_handle_valid(handle));
 
-       if (copied < len) {
-               if (!PageUptodate(page))
-                       copied = 0;
-               zero_new_buffers(page, from+copied, to);
+       if (unlikely(copied < len) && !PageUptodate(page)) {
+               copied = 0;
+               ext4_journalled_zero_new_buffers(handle, page, from, to);
+       } else {
+               if (unlikely(copied < len))
+                       ext4_journalled_zero_new_buffers(handle, page,
+                                                        from + copied, to);
+               ret = walk_page_buffers(handle, page_buffers(page), from,
+                                       from + copied, &partial,
+                                       write_end_fn);
+               if (!partial)
+                       SetPageUptodate(page);
        }
-
-       ret = walk_page_buffers(handle, page_buffers(page), from,
-                               to, &partial, write_end_fn);
-       if (!partial)
-               SetPageUptodate(page);
        new_i_size = pos + copied;
        if (new_i_size > inode->i_size)
                i_size_write(inode, pos+copied);