aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Mason <clm@fb.com>2017-06-23 12:48:21 -0400
committerDavid Sterba <dsterba@suse.com>2017-06-29 14:17:02 -0400
commit6374e57ad8091b9c2db2eecc536c7f0166ce099e (patch)
treef4a5c584983c110e0b2ddc9e3b51c25e11801353
parentded56184a562b925a588b6e78688e2e60757b425 (diff)
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 70e7af244 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>
-rw-r--r--fs/btrfs/dev-replace.c4
-rw-r--r--fs/btrfs/extent-tree.c12
-rw-r--r--fs/btrfs/ioctl.c2
-rw-r--r--fs/btrfs/ordered-data.c17
-rw-r--r--fs/btrfs/ordered-data.h4
-rw-r--r--fs/btrfs/qgroup.c2
-rw-r--r--fs/btrfs/relocation.c2
-rw-r--r--fs/btrfs/scrub.c2
-rw-r--r--fs/btrfs/super.c2
-rw-r--r--fs/btrfs/transaction.c2
10 files changed, 24 insertions, 25 deletions
diff --git a/fs/btrfs/dev-replace.c b/fs/btrfs/dev-replace.c
index 5fe1ca8abc70..bee3edeea7a3 100644
--- a/fs/btrfs/dev-replace.c
+++ b/fs/btrfs/dev-replace.c
@@ -388,7 +388,7 @@ int btrfs_dev_replace_start(struct btrfs_fs_info *fs_info,
388 if (ret) 388 if (ret)
389 btrfs_err(fs_info, "kobj add dev failed %d", ret); 389 btrfs_err(fs_info, "kobj add dev failed %d", ret);
390 390
391 btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1); 391 btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
392 392
393 /* force writing the updated state information to disk */ 393 /* force writing the updated state information to disk */
394 trans = btrfs_start_transaction(root, 0); 394 trans = btrfs_start_transaction(root, 0);
@@ -507,7 +507,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
507 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount); 507 mutex_unlock(&dev_replace->lock_finishing_cancel_unmount);
508 return ret; 508 return ret;
509 } 509 }
510 btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1); 510 btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
511 511
512 trans = btrfs_start_transaction(root, 0); 512 trans = btrfs_start_transaction(root, 0);
513 if (IS_ERR(trans)) { 513 if (IS_ERR(trans)) {
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index a3339acec28c..375f8c728d91 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -4288,7 +4288,7 @@ commit_trans:
4288 4288
4289 if (need_commit > 0) { 4289 if (need_commit > 0) {
4290 btrfs_start_delalloc_roots(fs_info, 0, -1); 4290 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,
4292 (u64)-1); 4292 (u64)-1);
4293 } 4293 }
4294 4294
@@ -4748,14 +4748,14 @@ static void btrfs_writeback_inodes_sb_nr(struct btrfs_fs_info *fs_info,
4748 } 4748 }
4749} 4749}
4750 4750
4751static inline int calc_reclaim_items_nr(struct btrfs_fs_info *fs_info, 4751static inline u64 calc_reclaim_items_nr(struct btrfs_fs_info *fs_info,
4752 u64 to_reclaim) 4752 u64 to_reclaim)
4753{ 4753{
4754 u64 bytes; 4754 u64 bytes;
4755 int nr; 4755 u64 nr;
4756 4756
4757 bytes = btrfs_calc_trans_metadata_size(fs_info, 1); 4757 bytes = btrfs_calc_trans_metadata_size(fs_info, 1);
4758 nr = (int)div64_u64(to_reclaim, bytes); 4758 nr = div64_u64(to_reclaim, bytes);
4759 if (!nr) 4759 if (!nr)
4760 nr = 1; 4760 nr = 1;
4761 return nr; 4761 return nr;
@@ -4774,15 +4774,15 @@ static void shrink_delalloc(struct btrfs_fs_info *fs_info, u64 to_reclaim,
4774 struct btrfs_trans_handle *trans; 4774 struct btrfs_trans_handle *trans;
4775 u64 delalloc_bytes; 4775 u64 delalloc_bytes;
4776 u64 max_reclaim; 4776 u64 max_reclaim;
4777 u64 items;
4777 long time_left; 4778 long time_left;
4778 unsigned long nr_pages; 4779 unsigned long nr_pages;
4779 int loops; 4780 int loops;
4780 int items;
4781 enum btrfs_reserve_flush_enum flush; 4781 enum btrfs_reserve_flush_enum flush;
4782 4782
4783 /* Calc the number of the pages we need flush for space reservation */ 4783 /* Calc the number of the pages we need flush for space reservation */
4784 items = calc_reclaim_items_nr(fs_info, to_reclaim); 4784 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;
4786 4786
4787 trans = (struct btrfs_trans_handle *)current->journal_info; 4787 trans = (struct btrfs_trans_handle *)current->journal_info;
4788 block_rsv = &fs_info->delalloc_block_rsv; 4788 block_rsv = &fs_info->delalloc_block_rsv;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index b4e9941efb60..fa1b78cf25f6 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -689,7 +689,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
689 if (ret) 689 if (ret)
690 goto dec_and_free; 690 goto dec_and_free;
691 691
692 btrfs_wait_ordered_extents(root, -1, 0, (u64)-1); 692 btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
693 693
694 btrfs_init_block_rsv(&pending_snapshot->block_rsv, 694 btrfs_init_block_rsv(&pending_snapshot->block_rsv,
695 BTRFS_BLOCK_RSV_TEMP); 695 BTRFS_BLOCK_RSV_TEMP);
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c
index 7b40e2e7292a..a3aca495e33e 100644
--- a/fs/btrfs/ordered-data.c
+++ b/fs/btrfs/ordered-data.c
@@ -663,7 +663,7 @@ static void btrfs_run_ordered_extent_work(struct btrfs_work *work)
663 * wait for all the ordered extents in a root. This is done when balancing 663 * wait for all the ordered extents in a root. This is done when balancing
664 * space between drives. 664 * space between drives.
665 */ 665 */
666int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr, 666u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
667 const u64 range_start, const u64 range_len) 667 const u64 range_start, const u64 range_len)
668{ 668{
669 struct btrfs_fs_info *fs_info = root->fs_info; 669 struct btrfs_fs_info *fs_info = root->fs_info;
@@ -671,7 +671,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
671 LIST_HEAD(skipped); 671 LIST_HEAD(skipped);
672 LIST_HEAD(works); 672 LIST_HEAD(works);
673 struct btrfs_ordered_extent *ordered, *next; 673 struct btrfs_ordered_extent *ordered, *next;
674 int count = 0; 674 u64 count = 0;
675 const u64 range_end = range_start + range_len; 675 const u64 range_end = range_start + range_len;
676 676
677 mutex_lock(&root->ordered_extent_mutex); 677 mutex_lock(&root->ordered_extent_mutex);
@@ -701,7 +701,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
701 701
702 cond_resched(); 702 cond_resched();
703 spin_lock(&root->ordered_extent_lock); 703 spin_lock(&root->ordered_extent_lock);
704 if (nr != -1) 704 if (nr != U64_MAX)
705 nr--; 705 nr--;
706 count++; 706 count++;
707 } 707 }
@@ -720,13 +720,13 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr,
720 return count; 720 return count;
721} 721}
722 722
723int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr, 723u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
724 const u64 range_start, const u64 range_len) 724 const u64 range_start, const u64 range_len)
725{ 725{
726 struct btrfs_root *root; 726 struct btrfs_root *root;
727 struct list_head splice; 727 struct list_head splice;
728 int done; 728 u64 total_done = 0;
729 int total_done = 0; 729 u64 done;
730 730
731 INIT_LIST_HEAD(&splice); 731 INIT_LIST_HEAD(&splice);
732 732
@@ -748,9 +748,8 @@ int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr,
748 total_done += done; 748 total_done += done;
749 749
750 spin_lock(&fs_info->ordered_root_lock); 750 spin_lock(&fs_info->ordered_root_lock);
751 if (nr != -1) { 751 if (nr != U64_MAX) {
752 nr -= done; 752 nr -= done;
753 WARN_ON(nr < 0);
754 } 753 }
755 } 754 }
756 list_splice_tail(&splice, &fs_info->ordered_roots); 755 list_splice_tail(&splice, &fs_info->ordered_roots);
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h
index e0c1d5b8d859..56c4c0ee6381 100644
--- a/fs/btrfs/ordered-data.h
+++ b/fs/btrfs/ordered-data.h
@@ -200,9 +200,9 @@ int btrfs_ordered_update_i_size(struct inode *inode, u64 offset,
200 struct btrfs_ordered_extent *ordered); 200 struct btrfs_ordered_extent *ordered);
201int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr, 201int btrfs_find_ordered_sum(struct inode *inode, u64 offset, u64 disk_bytenr,
202 u32 *sum, int len); 202 u32 *sum, int len);
203int btrfs_wait_ordered_extents(struct btrfs_root *root, int nr, 203u64 btrfs_wait_ordered_extents(struct btrfs_root *root, u64 nr,
204 const u64 range_start, const u64 range_len); 204 const u64 range_start, const u64 range_len);
205int btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, int nr, 205u64 btrfs_wait_ordered_roots(struct btrfs_fs_info *fs_info, u64 nr,
206 const u64 range_start, const u64 range_len); 206 const u64 range_start, const u64 range_len);
207void btrfs_get_logged_extents(struct btrfs_inode *inode, 207void btrfs_get_logged_extents(struct btrfs_inode *inode,
208 struct list_head *logged_list, 208 struct list_head *logged_list,
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index fc9dffaa9524..4ce351efe281 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -2405,7 +2405,7 @@ retry:
2405 ret = btrfs_start_delalloc_inodes(root, 0); 2405 ret = btrfs_start_delalloc_inodes(root, 0);
2406 if (ret) 2406 if (ret)
2407 return ret; 2407 return ret;
2408 btrfs_wait_ordered_extents(root, -1, 0, (u64)-1); 2408 btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
2409 trans = btrfs_join_transaction(root); 2409 trans = btrfs_join_transaction(root);
2410 if (IS_ERR(trans)) 2410 if (IS_ERR(trans))
2411 return PTR_ERR(trans); 2411 return PTR_ERR(trans);
diff --git a/fs/btrfs/relocation.c b/fs/btrfs/relocation.c
index dc69b6ba29af..65661d1aae4e 100644
--- a/fs/btrfs/relocation.c
+++ b/fs/btrfs/relocation.c
@@ -4373,7 +4373,7 @@ int btrfs_relocate_block_group(struct btrfs_fs_info *fs_info, u64 group_start)
4373 4373
4374 btrfs_wait_block_group_reservations(rc->block_group); 4374 btrfs_wait_block_group_reservations(rc->block_group);
4375 btrfs_wait_nocow_writers(rc->block_group); 4375 btrfs_wait_nocow_writers(rc->block_group);
4376 btrfs_wait_ordered_roots(fs_info, -1, 4376 btrfs_wait_ordered_roots(fs_info, U64_MAX,
4377 rc->block_group->key.objectid, 4377 rc->block_group->key.objectid,
4378 rc->block_group->key.offset); 4378 rc->block_group->key.offset);
4379 4379
diff --git a/fs/btrfs/scrub.c b/fs/btrfs/scrub.c
index 738e784ba20d..0cebeb5eb5d0 100644
--- a/fs/btrfs/scrub.c
+++ b/fs/btrfs/scrub.c
@@ -3836,7 +3836,7 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
3836 */ 3836 */
3837 btrfs_wait_block_group_reservations(cache); 3837 btrfs_wait_block_group_reservations(cache);
3838 btrfs_wait_nocow_writers(cache); 3838 btrfs_wait_nocow_writers(cache);
3839 ret = btrfs_wait_ordered_roots(fs_info, -1, 3839 ret = btrfs_wait_ordered_roots(fs_info, U64_MAX,
3840 cache->key.objectid, 3840 cache->key.objectid,
3841 cache->key.offset); 3841 cache->key.offset);
3842 if (ret > 0) { 3842 if (ret > 0) {
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index ba2cb7f96986..74e47794e63f 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1177,7 +1177,7 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
1177 return 0; 1177 return 0;
1178 } 1178 }
1179 1179
1180 btrfs_wait_ordered_roots(fs_info, -1, 0, (u64)-1); 1180 btrfs_wait_ordered_roots(fs_info, U64_MAX, 0, (u64)-1);
1181 1181
1182 trans = btrfs_attach_transaction_barrier(root); 1182 trans = btrfs_attach_transaction_barrier(root);
1183 if (IS_ERR(trans)) { 1183 if (IS_ERR(trans)) {
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
index 309b73da756b..f615d59b0489 100644
--- a/fs/btrfs/transaction.c
+++ b/fs/btrfs/transaction.c
@@ -1923,7 +1923,7 @@ static inline int btrfs_start_delalloc_flush(struct btrfs_fs_info *fs_info)
1923static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info) 1923static inline void btrfs_wait_delalloc_flush(struct btrfs_fs_info *fs_info)
1924{ 1924{
1925 if (btrfs_test_opt(fs_info, FLUSHONCOMMIT)) 1925 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);
1927} 1927}
1928 1928
1929static inline void 1929static inline void