Skip to content

Commit 6374e57

Browse files
masonclkdave
authored andcommitted
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 commit 70e7af2 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>
1 parent ded5618 commit 6374e57

File tree

10 files changed

+24
-25
lines changed

10 files changed

+24
-25
lines changed

fs/btrfs/dev-replace.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
388388
if (ret)
389389
btrfs_err(fs_info, "kobj add dev failed %d", ret);
390390

391-
btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1);
391+
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
392392

393393
/* force writing the updated state information to disk */
394394
trans = btrfs_start_transaction(root, 0);
@@ -507,7 +507,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
507507
mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
508508
return ret;
509509
}
510-
btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1);
510+
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
511511

512512
trans = btrfs_start_transaction(root, 0);
513513
if (IS_ERR(trans)) {

fs/btrfs/extent-tree.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4288,7 +4288,7 @@ int btrfs_alloc_data_chunk_ondemand(struct btrfs_inode *inode, u64 bytes)
42884288

42894289
if (need_commit > 0) {
42904290
btrfs_start_delalloc_roots(fs_info, 0, -1);
4291-
btrfs_wait_ordered_roots(fs_info, -1, 0,
4291+
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0,
42924292
(u64)-1);
42934293
}
42944294

@@ -4748,14 +4748,14 @@ static void btrfs_writeback_inodes_sb_nr(struct btrfs_fs_info *fs_info,
47484748
}
47494749
}
47504750

4751-
static inline int calc_reclaim_items_nr(struct btrfs_fs_info *fs_info,
4751+
static inline u64 calc_reclaim_items_nr(struct btrfs_fs_info *fs_info,
47524752
u64 to_reclaim)
47534753
{
47544754
u64 bytes;
4755-
int nr;
4755+
u64 nr;
47564756

47574757
bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
4758-
nr = (int)div64_u64(to_reclaim, bytes);
4758+
nr = div64_u64(to_reclaim, bytes);
47594759
if (!nr)
47604760
nr = 1;
47614761
return nr;
@@ -4774,15 +4774,15 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info, u64 to_reclaim,
47744774
struct btrfs_trans_handle *trans;
47754775
u64 delalloc_bytes;
47764776
u64 max_reclaim;
4777+
u64 items;
47774778
long time_left;
47784779
unsigned long nr_pages;
47794780
int loops;
4780-
int items;
47814781
enum btrfs_reserve_flush_enum flush;
47824782

47834783
/* Calc the number of the pages we need flush for space reservation */
47844784
items = calc_reclaim_items_nr(fs_info, to_reclaim);
4785-
to_reclaim = (u64)items * EXTENT_SIZE_PER_ITEM;
4785+
to_reclaim = items * EXTENT_SIZE_PER_ITEM;
47864786

47874787
trans = (struct btrfs_trans_handle *)current->journal_info;
47884788
block_rsv = &fs_info->delalloc_block_rsv;

fs/btrfs/ioctl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,7 +689,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
689689
if (ret)
690690
goto dec_and_free;
691691

692-
btrfs_wait_ordered_extents(root, -1, 0, (u64)-1);
692+
btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
693693

694694
btrfs_init_block_rsv(&pending_snapshot->block_rsv,
695695
BTRFS_BLOCK_RSV_TEMP);

fs/btrfs/ordered-data.c

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -663,15 +663,15 @@ static void btrfs_run_ordered_extent_work(struct btrfs_work *work)
663663
* wait for all the ordered extents in a root. This is done when balancing
664664
* space between drives.
665665
*/
666-
int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
666+
u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
667667
const u64 range_start, const u64 range_len)
668668
{
669669
struct btrfs_fs_info *fs_info = root->fs_info;
670670
LIST_HEAD(splice);
671671
LIST_HEAD(skipped);
672672
LIST_HEAD(works);
673673
struct btrfs_ordered_extent *ordered, *next;
674-
int count = 0;
674+
u64 count = 0;
675675
const u64 range_end = range_start + range_len;
676676

677677
mutex_lock(&root->ordered_extent_mutex);
@@ -701,7 +701,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
701701

702702
cond_resched();
703703
spin_lock(&root->ordered_extent_lock);
704-
if (nr != -1)
704+
if (nr != U64_MAX)
705705
nr--;
706706
count++;
707707
}
@@ -720,13 +720,13 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
720720
return count;
721721
}
722722

723-
int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr,
724-
const u64 range_start, const u64 range_len)
723+
u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
724+
const u64 range_start, const u64 range_len)
725725
{
726726
struct btrfs_root *root;
727727
struct list_head splice;
728-
int done;
729-
int total_done = 0;
728+
u64 total_done = 0;
729+
u64 done;
730730

731731
INIT_LIST_HEAD(&splice);
732732

@@ -748,9 +748,8 @@ int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr,
748748
total_done += done;
749749

750750
spin_lock(&fs_info->ordered_root_lock);
751-
if (nr != -1) {
751+
if (nr != U64_MAX) {
752752
nr -= done;
753-
WARN_ON(nr < 0);
754753
}
755754
}
756755
list_splice_tail(&splice, &fs_info->ordered_roots);

fs/btrfs/ordered-data.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,9 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
200200
struct btrfs_ordered_extent *ordered);
201201
int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
202202
u32 *sum, int len);
203-
int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
203+
u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
204204
const u64 range_start, const u64 range_len);
205-
int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr,
205+
u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
206206
const u64 range_start, const u64 range_len);
207207
void btrfs_get_logged_extents(struct btrfs_inode *inode,
208208
struct list_head *logged_list,

fs/btrfs/qgroup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2405,7 +2405,7 @@ static int qgroup_reserve(struct btrfs_root *root, u64 num_bytes, bool enforce)
24052405
ret = btrfs_start_delalloc_inodes(root, 0);
24062406
if (ret)
24072407
return ret;
2408-
btrfs_wait_ordered_extents(root, -1, 0, (u64)-1);
2408+
btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
24092409
trans = btrfs_join_transaction(root);
24102410
if (IS_ERR(trans))
24112411
return PTR_ERR(trans);

fs/btrfs/relocation.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4373,7 +4373,7 @@ int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start)
43734373

43744374
btrfs_wait_block_group_reservations(rc->block_group);
43754375
btrfs_wait_nocow_writers(rc->block_group);
4376-
btrfs_wait_ordered_roots(fs_info, -1,
4376+
btrfs_wait_ordered_roots(fs_info, U64_MAX,
43774377
rc->block_group->key.objectid,
43784378
rc->block_group->key.offset);
43794379

fs/btrfs/scrub.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3836,7 +3836,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
38363836
*/
38373837
btrfs_wait_block_group_reservations(cache);
38383838
btrfs_wait_nocow_writers(cache);
3839-
ret = btrfs_wait_ordered_roots(fs_info, -1,
3839+
ret = btrfs_wait_ordered_roots(fs_info, U64_MAX,
38403840
cache->key.objectid,
38413841
cache->key.offset);
38423842
if (ret > 0) {

fs/btrfs/super.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1177,7 +1177,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
11771177
return 0;
11781178
}
11791179

1180-
btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1);
1180+
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
11811181

11821182
trans = btrfs_attach_transaction_barrier(root);
11831183
if (IS_ERR(trans)) {

fs/btrfs/transaction.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1923,7 +1923,7 @@ static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
19231923
static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
19241924
{
19251925
if (btrfs_test_opt(fs_info, FLUSHONCOMMIT))
1926-
btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1);
1926+
btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
19271927
}
19281928

19291929
static inline void

0 commit comments

Comments
 (0)