Skip to content

Commit b778cf9

Browse files
josefbacikkdave
authored andcommitted
btrfs: fix bytes_may_use underflow in prealloc error condtition
I hit the following warning while running my error injection stress testing: WARNING: CPU: 3 PID: 1453 at fs/btrfs/space-info.h:108 btrfs_free_reserved_data_space_noquota+0xfd/0x160 [btrfs] RIP: 0010:btrfs_free_reserved_data_space_noquota+0xfd/0x160 [btrfs] Call Trace: btrfs_free_reserved_data_space+0x4f/0x70 [btrfs] __btrfs_prealloc_file_range+0x378/0x470 [btrfs] elfcorehdr_read+0x40/0x40 ? elfcorehdr_read+0x40/0x40 ? btrfs_commit_transaction+0xca/0xa50 [btrfs] ? dput+0xb4/0x2a0 ? btrfs_log_dentry_safe+0x55/0x70 [btrfs] ? btrfs_sync_file+0x30e/0x420 [btrfs] ? do_fsync+0x38/0x70 ? __x64_sys_fdatasync+0x13/0x20 ? do_syscall_64+0x5b/0x1b0 ? entry_SYSCALL_64_after_hwframe+0x44/0xa9 This happens if we fail to insert our reserved file extent. At this point we've already converted our reservation from ->bytes_may_use to ->bytes_reserved. However once we break we will attempt to free everything from [cur_offset, end] from ->bytes_may_use, but our extent reservation will overlap part of this. Fix this problem by adding ins.offset (our extent allocation size) to cur_offset so we remove the actual remaining part from ->bytes_may_use. I validated this fix using my inject-error.py script python inject-error.py -o should_fail_bio -t cache_save_setup -t \ __btrfs_prealloc_file_range \ -t insert_reserved_file_extent.constprop.0 \ -r "-5" ./run-fsstress.sh where run-fsstress.sh simply mounts and runs fsstress on a disk. CC: [email protected] # 4.4+ Reviewed-by: Qu Wenruo <[email protected]> Signed-off-by: Josef Bacik <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent bd72717 commit b778cf9

File tree

1 file changed

+13
-3
lines changed

1 file changed

+13
-3
lines changed

fs/btrfs/inode.c

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9824,6 +9824,7 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
98249824
struct btrfs_root *root = BTRFS_I(inode)->root;
98259825
struct btrfs_key ins;
98269826
u64 cur_offset = start;
9827+
u64 clear_offset = start;
98279828
u64 i_size;
98289829
u64 cur_bytes;
98299830
u64 last_alloc = (u64)-1;
@@ -9858,6 +9859,15 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
98589859
btrfs_end_transaction(trans);
98599860
break;
98609861
}
9862+
9863+
/*
9864+
* We've reserved this space, and thus converted it from
9865+
* ->bytes_may_use to ->bytes_reserved. Any error that happens
9866+
* from here on out we will only need to clear our reservation
9867+
* for the remaining unreserved area, so advance our
9868+
* clear_offset by our extent size.
9869+
*/
9870+
clear_offset += ins.offset;
98619871
btrfs_dec_block_group_reservations(fs_info, ins.objectid);
98629872

98639873
last_alloc = ins.offset;
@@ -9937,9 +9947,9 @@ static int __btrfs_prealloc_file_range(struct inode *inode, int mode,
99379947
if (own_trans)
99389948
btrfs_end_transaction(trans);
99399949
}
9940-
if (cur_offset < end)
9941-
btrfs_free_reserved_data_space(inode, NULL, cur_offset,
9942-
end - cur_offset + 1);
9950+
if (clear_offset < end)
9951+
btrfs_free_reserved_data_space(inode, NULL, clear_offset,
9952+
end - clear_offset + 1);
99439953
return ret;
99449954
}
99459955

0 commit comments

Comments
 (0)