Commit 9c02ac97 authored by Daeho Jeong's avatar Daeho Jeong Committed by Theodore Ts'o

ext4: fix xfstest generic/269 double revoked buffer bug with bigalloc

When you repeatly execute xfstest generic/269 with bigalloc_1k option
enabled using the below command:

"./kvm-xfstests -c bigalloc_1k -m nodelalloc -C 1000 generic/269"

you can easily see the below bug message.

"JBD2 unexpected failure: jbd2_journal_revoke: !buffer_revoked(bh);"

This means that an already revoked buffer is erroneously revoked again
and it is caused by doing revoke for the buffer at the wrong position
in ext4_free_blocks(). We need to re-position the buffer revoke
procedure for an unspecified buffer after checking the cluster boundary
for bigalloc option. If not, some part of the cluster can be doubly
revoked.
Signed-off-by: default avatarDaeho Jeong <daeho.jeong@samsung.com>
parent 9008a58e
...@@ -4687,22 +4687,11 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, ...@@ -4687,22 +4687,11 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
ext4_debug("freeing block %llu\n", block); ext4_debug("freeing block %llu\n", block);
trace_ext4_free_blocks(inode, block, count, flags); trace_ext4_free_blocks(inode, block, count, flags);
if (flags & EXT4_FREE_BLOCKS_FORGET) { if (bh && (flags & EXT4_FREE_BLOCKS_FORGET)) {
struct buffer_head *tbh = bh; BUG_ON(count > 1);
int i;
BUG_ON(bh && (count > 1));
for (i = 0; i < count; i++) {
cond_resched();
if (!bh)
tbh = sb_find_get_block(inode->i_sb,
block + i);
if (!tbh)
continue;
ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA, ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
inode, tbh, block + i); inode, bh, block);
}
} }
/* /*
...@@ -4747,6 +4736,19 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode, ...@@ -4747,6 +4736,19 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,
count += sbi->s_cluster_ratio - overflow; count += sbi->s_cluster_ratio - overflow;
} }
if (!bh && (flags & EXT4_FREE_BLOCKS_FORGET)) {
int i;
for (i = 0; i < count; i++) {
cond_resched();
bh = sb_find_get_block(inode->i_sb, block + i);
if (!bh)
continue;
ext4_forget(handle, flags & EXT4_FREE_BLOCKS_METADATA,
inode, bh, block + i);
}
}
do_more: do_more:
overflow = 0; overflow = 0;
ext4_get_group_no_and_offset(sb, block, &block_group, &bit); ext4_get_group_no_and_offset(sb, block, &block_group, &bit);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment