add patch fix-xfstest-generic-269-double-revoked-buffer-bug
[ext4-patch-queue.git] / fix-xfstest-generic-269-double-revoked-buffer-bug
blob8a341394e13a6b76d67279485ca4bf2c9945b5a0
1 ext4: fix xfstest generic/269 double revoked buffer bug with bigalloc
3 From: Daeho Jeong <daeho.jeong@samsung.com>
5 When you repeatly execute xfstest generic/269 with bigalloc_1k option
6 enabled using the below command:
8 "./kvm-xfstests -c bigalloc_1k -m nodelalloc -C 1000 generic/269"
10 you can easily see the below bug message.
12 "JBD2 unexpected failure: jbd2_journal_revoke: !buffer_revoked(bh);"
14 This means that an already revoked buffer is erroneously revoked again
15 and it is caused by doing revoke for the buffer at the wrong position
16 in ext4_free_blocks(). We need to re-position the buffer revoke
17 procedure for an unspecified buffer after checking the cluster boundary
18 for bigalloc option. If not, some part of the cluster can be doubly
19 revoked.
21 Signed-off-by: Daeho Jeong <daeho.jeong@samsung.com>
22 ---
23  fs/ext4/mballoc.c | 32 +++++++++++++++++---------------
24  1 file changed, 17 insertions(+), 15 deletions(-)
26 diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
27 index cf48581..b4da7f2 100644
28 --- a/fs/ext4/mballoc.c
29 +++ b/fs/ext4/mballoc.c
30 @@ -4686,22 +4686,11 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
31         ext4_debug("freeing block %llu\n", block);
32         trace_ext4_free_blocks(inode, block, count, flags);
34 -       if (flags & EXT4_FREE_BLOCKS_FORGET) {
35 -               struct buffer_head *tbh = bh;
36 -               int i;
38 -               BUG_ON(bh && (count > 1));
39 +       if (bh && (flags & EXT4_FREE_BLOCKS_FORGET)) {
40 +               BUG_ON(count > 1);
42 -               for (i = 0; i < count; i++) {
43 -                       cond_resched();
44 -                       if (!bh)
45 -                               tbh = sb_find_get_block(inode->i_sb,
46 -                                                       block + i);
47 -                       if (!tbh)
48 -                               continue;
49 -                       ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
50 -                                   inode, tbh, block + i);
51 -               }
52 +               ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
53 +                           inode, bh, block);
54         }
56         /*
57 @@ -4746,6 +4735,19 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
58                         count += sbi->s_cluster_ratio - overflow;
59         }
61 +       if (!bh && (flags & EXT4_FREE_BLOCKS_FORGET)) {
62 +               int i;
64 +               for (i = 0; i < count; i++) {
65 +                       cond_resched();
66 +                       bh = sb_find_get_block(inode->i_sb, block + i);
67 +                       if (!bh)
68 +                               continue;
69 +                       ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
70 +                                   inode, bh, block + i);
71 +               }
72 +       }
74  do_more:
75         overflow = 0;
76         ext4_get_group_no_and_offset(sb, block, &block_group, &bit);