FAILED: patch "[PATCH] ext4: fix potential race between s_flex_groups online" failed to apply to 4.9-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 4.9-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 7c990728b99ed6fbe9c75fc202fce1172d9916da Mon Sep 17 00:00:00 2001
From: Suraj Jitindar Singh <[email protected]>
Date: Tue, 18 Feb 2020 19:08:51 -0800
Subject: [PATCH] ext4: fix potential race between s_flex_groups online
resizing and access
During an online resize an array of s_flex_groups structures gets replaced so it can get enlarged. If there is a concurrent access to the array and this memory has been reused then this can lead to an invalid memory access.
The s_flex_group array has been converted into an array of pointers rather than an array of structures. This is to ensure that the information contained in the structures cannot get out of sync during a resize due to an accessor updating the value in the old structure after it has been copied but before the array pointer is updated. Since the structures them- selves are no longer copied but only the pointers to them this case is mitigated.
fs/ext4/ext4.h +1 -1
@@ -1512,7 +1512,7 @@ struct ext4_sb_info {unsigned int s_extent_max_zeroout_kb;unsigned int s_log_groups_per_flex; -struct flex_groups *s_flex_groups; +struct flex_groups *__rcu *s_flex_groups;ext4_group_t s_flex_groups_allocated;/* workqueue for reserved extent conversions (buffered io) */
fs/ext4/ialloc.c +14 -9
@@ -328,11 +328,13 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)percpu_counter_inc (&sbi->s_freeinodes_counter);if (sbi->s_log_groups_per_flex) { -ext4_group_t f =ext4_flex_group (sbi, block_group); +struct flex_groups *fg; -atomic_inc (&sbi->s_flex_groups[f].free_inodes); + fg =sbi_array_rcu_deref (sbi, s_flex_groups, +ext4_flex_group (sbi, block_group)); +atomic_inc (&fg->free_inodes);if (is_directory) -atomic_dec (&sbi->s_flex_groups[f].used_dirs); +atomic_dec (&fg->used_dirs); }BUFFER_TRACE (bh2,"call ext4_handle_dirty_metadata" ); fatal =ext4_handle_dirty_metadata (handle,NULL , bh2);
@@ -368,12 +370,13 @@ static void get_orlov_stats(struct super_block *sb, ext4_group_t g, int flex_size, struct orlov_stats *stats) { struct ext4_group_desc *desc; -struct flex_groups *flex_group =EXT4_SB (sb)->s_flex_groups;if (flex_size >1 ) { - stats->free_inodes =atomic_read (&flex_group[g].free_inodes); - stats->free_clusters =atomic64_read (&flex_group[g].free_clusters); - stats->used_dirs =atomic_read (&flex_group[g].used_dirs); +struct flex_groups *fg =sbi_array_rcu_deref (EXT4_SB (sb), + s_flex_groups, g); + stats->free_inodes =atomic_read (&fg->free_inodes); + stats->free_clusters =atomic64_read (&fg->free_clusters); + stats->used_dirs =atomic_read (&fg->used_dirs);return ; }
@@ -1054,7 +1057,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,if (sbi->s_log_groups_per_flex) {ext4_group_t f =ext4_flex_group (sbi, group); -atomic_inc (&sbi->s_flex_groups[f].used_dirs); +atomic_inc (&sbi_array_rcu_deref (sbi, s_flex_groups, + f)->used_dirs); } }if (ext4_has_group_desc_csum (sb)) {
@@ -1077,7 +1081,8 @@ struct inode *__ext4_new_inode(handle_t *handle, struct inode *dir,if (sbi->s_log_groups_per_flex) { flex_group =ext4_flex_group (sbi, group); -atomic_dec (&sbi->s_flex_groups[flex_group].free_inodes); +atomic_dec (&sbi_array_rcu_deref (sbi, s_flex_groups, + flex_group)->free_inodes); } inode->i_ino = ino + group *EXT4_INODES_PER_GROUP (sb);
fs/ext4/mballoc.c +6 -3
@@ -3038,7 +3038,8 @@ ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac,ext4_group_t flex_group =ext4_flex_group (sbi, ac->ac_b_ex.fe_group);atomic64_sub (ac->ac_b_ex.fe_len, - &sbi->s_flex_groups[flex_group].free_clusters); + &sbi_array_rcu_deref (sbi, s_flex_groups, + flex_group)->free_clusters); } err =ext4_handle_dirty_metadata (handle,NULL , bitmap_bh);
@@ -4936,7 +4937,8 @@ void ext4_free_blocks(handle_t *handle, struct inode *inode,if (sbi->s_log_groups_per_flex) {ext4_group_t flex_group =ext4_flex_group (sbi, block_group);atomic64_add (count_clusters, - &sbi->s_flex_groups[flex_group].free_clusters); + &sbi_array_rcu_deref (sbi, s_flex_groups, + flex_group)->free_clusters); }/*
@@ -5093,7 +5095,8 @@ int ext4_group_add_blocks(handle_t *handle, struct super_block *sb,if (sbi->s_log_groups_per_flex) {ext4_group_t flex_group =ext4_flex_group (sbi, block_group);atomic64_add (clusters_freed, - &sbi->s_flex_groups[flex_group].free_clusters); + &sbi_array_rcu_deref (sbi, s_flex_groups, + flex_group)->free_clusters); }ext4_mb_unload_buddy (&e4b);
fs/ext4/resize.c +5 -2
@@ -1430,11 +1430,14 @@ static void ext4_update_super(struct super_block *sb, percpu_counter_read(&sbi->s_freeclusters_counter));if (ext4_has_feature_flex_bg (sb) && sbi->s_log_groups_per_flex) {ext4_group_t flex_group; +struct flex_groups *fg; + flex_group =ext4_flex_group (sbi, group_data[0 ].group); + fg =sbi_array_rcu_deref (sbi, s_flex_groups, flex_group);atomic64_add (EXT4_NUM_B2C (sbi, free_blocks), - &sbi->s_flex_groups[flex_group].free_clusters); + &fg->free_clusters);atomic_add (EXT4_INODES_PER_GROUP (sb) * flex_gd->count, - &sbi->s_flex_groups[flex_group].free_inodes); + &fg->free_inodes); }/*
fs/ext4/super.c +50 -22
126 lines not on this page · raw message