Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ext4: use atomic64_t for the per-flexbg free_clusters count

A user who was using a 8TB+ file system and with a very large flexbg
size (> 65536) could cause the atomic_t used in the struct flex_groups
to overflow. This was detected by PaX security patchset:

http://forums.grsecurity.net/viewtopic.php?f=3&t=3289&p=12551#p12551

This bug was introduced in commit 9f24e4208f7e, so it's been around
since 2.6.30. :-(

Fix this by using an atomic64_t for struct orlav_stats's
free_clusters.

Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Reviewed-by: Lukas Czerner <lczerner@redhat.com>
Cc: stable@vger.kernel.org

+15 -15
+3 -3
fs/ext4/ext4.h
··· 335 335 */ 336 336 337 337 struct flex_groups { 338 - atomic_t free_inodes; 339 - atomic_t free_clusters; 340 - atomic_t used_dirs; 338 + atomic64_t free_clusters; 339 + atomic_t free_inodes; 340 + atomic_t used_dirs; 341 341 }; 342 342 343 343 #define EXT4_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not in use */
+2 -2
fs/ext4/ialloc.c
··· 324 324 } 325 325 326 326 struct orlov_stats { 327 + __u64 free_clusters; 327 328 __u32 free_inodes; 328 - __u32 free_clusters; 329 329 __u32 used_dirs; 330 330 }; 331 331 ··· 342 342 343 343 if (flex_size > 1) { 344 344 stats->free_inodes = atomic_read(&flex_group[g].free_inodes); 345 - stats->free_clusters = atomic_read(&flex_group[g].free_clusters); 345 + stats->free_clusters = atomic64_read(&flex_group[g].free_clusters); 346 346 stats->used_dirs = atomic_read(&flex_group[g].used_dirs); 347 347 return; 348 348 }
+6 -6
fs/ext4/mballoc.c
··· 2804 2804 if (sbi->s_log_groups_per_flex) { 2805 2805 ext4_group_t flex_group = ext4_flex_group(sbi, 2806 2806 ac->ac_b_ex.fe_group); 2807 - atomic_sub(ac->ac_b_ex.fe_len, 2808 - &sbi->s_flex_groups[flex_group].free_clusters); 2807 + atomic64_sub(ac->ac_b_ex.fe_len, 2808 + &sbi->s_flex_groups[flex_group].free_clusters); 2809 2809 } 2810 2810 2811 2811 err = ext4_handle_dirty_metadata(handle, NULL, bitmap_bh); ··· 4661 4661 4662 4662 if (sbi->s_log_groups_per_flex) { 4663 4663 ext4_group_t flex_group = ext4_flex_group(sbi, block_group); 4664 - atomic_add(count_clusters, 4665 - &sbi->s_flex_groups[flex_group].free_clusters); 4664 + atomic64_add(count_clusters, 4665 + &sbi->s_flex_groups[flex_group].free_clusters); 4666 4666 } 4667 4667 4668 4668 ext4_mb_unload_buddy(&e4b); ··· 4804 4804 4805 4805 if (sbi->s_log_groups_per_flex) { 4806 4806 ext4_group_t flex_group = ext4_flex_group(sbi, block_group); 4807 - atomic_add(EXT4_NUM_B2C(sbi, blocks_freed), 4808 - &sbi->s_flex_groups[flex_group].free_clusters); 4807 + atomic64_add(EXT4_NUM_B2C(sbi, blocks_freed), 4808 + &sbi->s_flex_groups[flex_group].free_clusters); 4809 4809 } 4810 4810 4811 4811 ext4_mb_unload_buddy(&e4b);
+2 -2
fs/ext4/resize.c
··· 1360 1360 sbi->s_log_groups_per_flex) { 1361 1361 ext4_group_t flex_group; 1362 1362 flex_group = ext4_flex_group(sbi, group_data[0].group); 1363 - atomic_add(EXT4_NUM_B2C(sbi, free_blocks), 1364 - &sbi->s_flex_groups[flex_group].free_clusters); 1363 + atomic64_add(EXT4_NUM_B2C(sbi, free_blocks), 1364 + &sbi->s_flex_groups[flex_group].free_clusters); 1365 1365 atomic_add(EXT4_INODES_PER_GROUP(sb) * flex_gd->count, 1366 1366 &sbi->s_flex_groups[flex_group].free_inodes); 1367 1367 }
+2 -2
fs/ext4/super.c
··· 1923 1923 flex_group = ext4_flex_group(sbi, i); 1924 1924 atomic_add(ext4_free_inodes_count(sb, gdp), 1925 1925 &sbi->s_flex_groups[flex_group].free_inodes); 1926 - atomic_add(ext4_free_group_clusters(sb, gdp), 1927 - &sbi->s_flex_groups[flex_group].free_clusters); 1926 + atomic64_add(ext4_free_group_clusters(sb, gdp), 1927 + &sbi->s_flex_groups[flex_group].free_clusters); 1928 1928 atomic_add(ext4_used_dirs_count(sb, gdp), 1929 1929 &sbi->s_flex_groups[flex_group].used_dirs); 1930 1930 }