btrfs: fix integer overflow in calc_reclaim_items_nr
Dave Jones hit a WARN_ON(nr < 0) in btrfs_wait_ordered_roots() with v4.12-rc6. This was because commit70e7af244
made it possible for calc_reclaim_items_nr() to return a negative number. It's not really a bug in that commit, it just didn't go far enough down the stack to find all the possible 64->32 bit overflows. This switches calc_reclaim_items_nr() to return a u64 and changes everyone that uses the results of that math to u64 as well. Reported-by: Dave Jones <davej@codemonkey.org.uk> Fixes:70e7af2
("Btrfs: fix delalloc accounting leak caused by u32 overflow") Signed-off-by: Chris Mason <clm@fb.com> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
ded56184a5
commit
6374e57ad8
|
@ -388,7 +388,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
|
|||
if (ret)
|
||||
btrfs_err(fs_info, "kobj add dev failed %d", ret);
|
||||
|
||||
btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1);
|
||||
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
|
||||
|
||||
/* force writing the updated state information to disk */
|
||||
trans = btrfs_start_transaction(root, 0);
|
||||
|
@ -507,7 +507,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
|
|||
mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
|
||||
return ret;
|
||||
}
|
||||
btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1);
|
||||
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
|
||||
|
||||
trans = btrfs_start_transaction(root, 0);
|
||||
if (IS_ERR(trans)) {
|
||||
|
|
|
@ -4288,7 +4288,7 @@ commit_trans:
|
|||
|
||||
if (need_commit > 0) {
|
||||
btrfs_start_delalloc_roots(fs_info, 0, -1);
|
||||
btrfs_wait_ordered_roots(fs_info, -1, 0,
|
||||
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0,
|
||||
(u64)-1);
|
||||
}
|
||||
|
||||
|
@ -4748,14 +4748,14 @@ static void btrfs_writeback_inodes_sb_nr(struct btrfs_fs_info *fs_info,
|
|||
}
|
||||
}
|
||||
|
||||
static inline int calc_reclaim_items_nr(struct btrfs_fs_info *fs_info,
|
||||
static inline u64 calc_reclaim_items_nr(struct btrfs_fs_info *fs_info,
|
||||
u64 to_reclaim)
|
||||
{
|
||||
u64 bytes;
|
||||
int nr;
|
||||
u64 nr;
|
||||
|
||||
bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
|
||||
nr = (int)div64_u64(to_reclaim, bytes);
|
||||
nr = div64_u64(to_reclaim, bytes);
|
||||
if (!nr)
|
||||
nr = 1;
|
||||
return nr;
|
||||
|
@ -4774,15 +4774,15 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info, u64 to_reclaim,
|
|||
struct btrfs_trans_handle *trans;
|
||||
u64 delalloc_bytes;
|
||||
u64 max_reclaim;
|
||||
u64 items;
|
||||
long time_left;
|
||||
unsigned long nr_pages;
|
||||
int loops;
|
||||
int items;
|
||||
enum btrfs_reserve_flush_enum flush;
|
||||
|
||||
/* Calc the number of the pages we need flush for space reservation */
|
||||
items = calc_reclaim_items_nr(fs_info, to_reclaim);
|
||||
to_reclaim = (u64)items * EXTENT_SIZE_PER_ITEM;
|
||||
to_reclaim = items * EXTENT_SIZE_PER_ITEM;
|
||||
|
||||
trans = (struct btrfs_trans_handle *)current->journal_info;
|
||||
block_rsv = &fs_info->delalloc_block_rsv;
|
||||
|
|
|
@ -689,7 +689,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
|
|||
if (ret)
|
||||
goto dec_and_free;
|
||||
|
||||
btrfs_wait_ordered_extents(root, -1, 0, (u64)-1);
|
||||
btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
|
||||
|
||||
btrfs_init_block_rsv(&pending_snapshot->block_rsv,
|
||||
BTRFS_BLOCK_RSV_TEMP);
|
||||
|
|
|
@ -663,7 +663,7 @@ static void btrfs_run_ordered_extent_work(struct btrfs_work *work)
|
|||
* wait for all the ordered extents in a root. This is done when balancing
|
||||
* space between drives.
|
||||
*/
|
||||
int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
|
||||
u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
|
||||
const u64 range_start, const u64 range_len)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = root->fs_info;
|
||||
|
@ -671,7 +671,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
|
|||
LIST_HEAD(skipped);
|
||||
LIST_HEAD(works);
|
||||
struct btrfs_ordered_extent *ordered, *next;
|
||||
int count = 0;
|
||||
u64 count = 0;
|
||||
const u64 range_end = range_start + range_len;
|
||||
|
||||
mutex_lock(&root->ordered_extent_mutex);
|
||||
|
@ -701,7 +701,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
|
|||
|
||||
cond_resched();
|
||||
spin_lock(&root->ordered_extent_lock);
|
||||
if (nr != -1)
|
||||
if (nr != U64_MAX)
|
||||
nr--;
|
||||
count++;
|
||||
}
|
||||
|
@ -720,13 +720,13 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
|
|||
return count;
|
||||
}
|
||||
|
||||
int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr,
|
||||
u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
||||
const u64 range_start, const u64 range_len)
|
||||
{
|
||||
struct btrfs_root *root;
|
||||
struct list_head splice;
|
||||
int done;
|
||||
int total_done = 0;
|
||||
u64 total_done = 0;
|
||||
u64 done;
|
||||
|
||||
INIT_LIST_HEAD(&splice);
|
||||
|
||||
|
@ -748,9 +748,8 @@ int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr,
|
|||
total_done += done;
|
||||
|
||||
spin_lock(&fs_info->ordered_root_lock);
|
||||
if (nr != -1) {
|
||||
if (nr != U64_MAX) {
|
||||
nr -= done;
|
||||
WARN_ON(nr < 0);
|
||||
}
|
||||
}
|
||||
list_splice_tail(&splice, &fs_info->ordered_roots);
|
||||
|
|
|
@ -200,9 +200,9 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
|
|||
struct btrfs_ordered_extent *ordered);
|
||||
int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
|
||||
u32 *sum, int len);
|
||||
int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
|
||||
u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
|
||||
const u64 range_start, const u64 range_len);
|
||||
int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr,
|
||||
u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
|
||||
const u64 range_start, const u64 range_len);
|
||||
void btrfs_get_logged_extents(struct btrfs_inode *inode,
|
||||
struct list_head *logged_list,
|
||||
|
|
|
@ -2405,7 +2405,7 @@ retry:
|
|||
ret = btrfs_start_delalloc_inodes(root, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
btrfs_wait_ordered_extents(root, -1, 0, (u64)-1);
|
||||
btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
|
||||
trans = btrfs_join_transaction(root);
|
||||
if (IS_ERR(trans))
|
||||
return PTR_ERR(trans);
|
||||
|
|
|
@ -4373,7 +4373,7 @@ int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start)
|
|||
|
||||
btrfs_wait_block_group_reservations(rc->block_group);
|
||||
btrfs_wait_nocow_writers(rc->block_group);
|
||||
btrfs_wait_ordered_roots(fs_info, -1,
|
||||
btrfs_wait_ordered_roots(fs_info, U64_MAX,
|
||||
rc->block_group->key.objectid,
|
||||
rc->block_group->key.offset);
|
||||
|
||||
|
|
|
@ -3836,7 +3836,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
|
|||
*/
|
||||
btrfs_wait_block_group_reservations(cache);
|
||||
btrfs_wait_nocow_writers(cache);
|
||||
ret = btrfs_wait_ordered_roots(fs_info, -1,
|
||||
ret = btrfs_wait_ordered_roots(fs_info, U64_MAX,
|
||||
cache->key.objectid,
|
||||
cache->key.offset);
|
||||
if (ret > 0) {
|
||||
|
|
|
@ -1177,7 +1177,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
|
|||
return 0;
|
||||
}
|
||||
|
||||
btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1);
|
||||
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
|
||||
|
||||
trans = btrfs_attach_transaction_barrier(root);
|
||||
if (IS_ERR(trans)) {
|
||||
|
|
|
@ -1923,7 +1923,7 @@ static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
|
|||
static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
|
||||
{
|
||||
if (btrfs_test_opt(fs_info, FLUSHONCOMMIT))
|
||||
btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1);
|
||||
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
Loading…
Reference in New Issue