Check in v2 version of "ext4: Punch hole and DAX fixes"
[ext4-patch-queue.git] / use-private-version-of-zero_new_buffers-for-data-journal-mode
blobae97626b51d44f385d34af205426601e29922de1
1 ext4: use private version of page_zero_new_buffers() for data=journal mode
3 If there is a error while copying data from userspace into the page
4 cache during a write(2) system call, in data=journal mode, in
5 ext4_journalled_write_end() were using page_zero_new_buffers() from
6 fs/buffer.c.  Unfortunately, this sets the buffer dirty flag, which is
7 no good if journalling is enabled.  This is a long-standing bug that
8 goes back for years and years in ext3, but a combination of (a)
9 data=journal not being very common, (b) in many case it only results
10 in a warning message. and (c) only very rarely causes the kernel hang,
11 means that we only really noticed this as a problem when commit
12 998ef75ddb caused this failure to happen frequently enough to cause
13 generic/208 to fail when run in data=journal mode.
15 The fix is to have our own version of this function that doesn't call
16 mark_dirty_buffer(), since we will end up calling
17 ext4_handle_dirty_metadata() on the buffer head(s) in questions very
18 shortly afterwards in ext4_journalled_write_end().
20 Thanks to Dave Hansen and Linus Torvalds for helping to identify the
21 root cause of the problem.
23 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
24 Reviewed-by: Jan Kara <jack@suse.com>
25 ---
26  fs/ext4/inode.c | 34 +++++++++++++++++++++++++++++++++-
27  1 file changed, 33 insertions(+), 1 deletion(-)
29 diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
30 index ae52e32..0a589bb 100644
31 --- a/fs/ext4/inode.c
32 +++ b/fs/ext4/inode.c
33 @@ -1181,6 +1181,38 @@ errout:
34         return ret ? ret : copied;
35  }
37 +/*
38 + * This is a private version of page_zero_new_buffers() which doesn't
39 + * set the buffer to be dirty, since in data=journalled mode we need
40 + * to call ext4_handle_dirty_metadata() instead.
41 + */
42 +static void zero_new_buffers(struct page *page, unsigned from, unsigned to)
44 +       unsigned int block_start = 0, block_end;
45 +       struct buffer_head *head, *bh;
47 +       bh = head = page_buffers(page);
48 +       do {
49 +               block_end = block_start + bh->b_size;
50 +               if (buffer_new(bh)) {
51 +                       if (block_end > from && block_start < to) {
52 +                               if (!PageUptodate(page)) {
53 +                                       unsigned start, size;
55 +                                       start = max(from, block_start);
56 +                                       size = min(to, block_end) - start;
58 +                                       zero_user(page, start, size);
59 +                                       set_buffer_uptodate(bh);
60 +                               }
61 +                               clear_buffer_new(bh);
62 +                       }
63 +               }
64 +               block_start = block_end;
65 +               bh = bh->b_this_page;
66 +       } while (bh != head);
69  static int ext4_journalled_write_end(struct file *file,
70                                      struct address_space *mapping,
71                                      loff_t pos, unsigned len, unsigned copied,
72 @@ -1207,7 +1239,7 @@ static int ext4_journalled_write_end(struct file *file,
73                 if (copied < len) {
74                         if (!PageUptodate(page))
75                                 copied = 0;
76 -                       page_zero_new_buffers(page, from+copied, to);
77 +                       zero_new_buffers(page, from+copied, to);
78                 }
80                 ret = ext4_walk_page_buffers(handle, page_buffers(page), from,