add patch remove-unused-mode-parameter
[ext4-patch-queue.git] / fix-SEEK_HOLE_DATA-for-blocksize-lt-pagesize
blobefb3943a87ca97b53006610d21dd60f305ec3a2e
1 ext4: fix SEEK_HOLE/SEEK_DATA for blocksize < pagesize
3 From: Jan Kara <jack@suse.cz>
5 ext4_find_unwritten_pgoff() does not properly handle a situation when
6 starting index is in the middle of a page and blocksize < pagesize. The
7 following command shows the bug on filesystem with 1k blocksize:
9   xfs_io -f -c "falloc 0 4k" \
10             -c "pwrite 1k 1k" \
11             -c "pwrite 3k 1k" \
12             -c "seek -a -r 0" foo
14 In this example, neither lseek(fd, 1024, SEEK_HOLE) nor lseek(fd, 2048,
15 SEEK_DATA) will return the correct result.
17 Fix the problem by neglecting buffers in a page before starting offset.
19 Reported-by: Andreas Gruenbacher <agruenba@redhat.com>
20 Signed-off-by: Theodore Ts'o <tytso@mit.edu>
21 Signed-off-by: Jan Kara <jack@suse.cz>
22 CC: stable@vger.kernel.org # 3.8+
23 ---
24  fs/ext4/file.c | 3 +++
25  1 file changed, 3 insertions(+)
27 This is an easy fix for the SEEK_HOLE/SEEK_DATA bug Andreas found. Longer
28 term we want to move ext4 to use page_cache_seek_hole_data() however for
29 stable backporting this is more suitable.
31 diff --git a/fs/ext4/file.c b/fs/ext4/file.c
32 index b221d0b546b0..8ba34cbe8fe7 100644
33 --- a/fs/ext4/file.c
34 +++ b/fs/ext4/file.c
35 @@ -530,6 +530,8 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
36                                 lastoff = page_offset(page);
37                                 bh = head = page_buffers(page);
38                                 do {
39 +                                       if (lastoff + bh->b_size <= startoff)
40 +                                               goto next;
41                                         if (buffer_uptodate(bh) ||
42                                             buffer_unwritten(bh)) {
43                                                 if (whence == SEEK_DATA)
44 @@ -544,6 +546,7 @@ static int ext4_find_unwritten_pgoff(struct inode *inode,
45                                                 unlock_page(page);
46                                                 goto out;
47                                         }
48 +next:
49                                         lastoff += bh->b_size;
50                                         bh = bh->b_this_page;
51                                 } while (bh != head);
52 -- 
53 2.12.3