Skip to contentSkip to conversation

ext4: Fix potential races when performing online resizing

PATCH Applied Suraj Jitindar Singh 3 participants 11 messages Feb 19, 2020 – Feb 21, 2020

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover ext4: Fix potential races when performing online resizing

This patch series fixes 2 additional races between array resizing and array element access when performing online resizing of the arrays s_group_info and s_flex_groups.

These patches apply on top of the patch:
[PATCH RFC] ext4: fix potential race between online resizing and write operations

The macro sbi_array_rcu_deref() is introduced for simplicity but can be removed if undesired.

Tested by performing the following:
truncate -s 100G /tmp/foo
sudo bash -c 'while true; do dd if=/dev/zero of=/mnt/xxx bs=1M count=1; sync; \
rm /mnt/xxx; done' &
while true; do mkfs.ext4 -b 1024 -E resize=26213883 /tmp/foo 2096635 -F; \
sudo mount -o loop /tmp/foo /mnt; sudo resize2fs /dev/loop0 26213883; \
sudo umount /mnt; done

Suraj Jitindar Singh (3):
ext4: introduce macro sbi_array_rcu_deref() to access rcu protected
fields
ext4: fix potential race between s_group_info online resizing and
access
ext4: fix potential race between s_flex_groups online resizing and
access

 fs/ext4/balloc.c  | 11 +++++-----
 fs/ext4/ext4.h    | 25 +++++++++++++++++----
 fs/ext4/ialloc.c  | 21 +++++++++++-------
 fs/ext4/mballoc.c | 19 ++++++++++------
 fs/ext4/resize.c  |  4 ++--
 fs/ext4/super.c   | 56 ++++++++++++++++++++++++++++++++---------------
 6 files changed, 91 insertions(+), 45 deletions(-)
Signature · 1 line
2.17.1
#1 lore raw

PATCH 1/3 ext4: introduce macro sbi_array_rcu_deref() to access rcu protected fields

The s_group_desc field in the super block info (sbi) is protected by rcu to prevent access to an invalid pointer during online resize operations. There are 2 other arrays in sbi, s_group_info and s_flex_groups, which require similar rcu protection which is introduced in the subsequent patches. Introduce a helper macro sbi_array_rcu_deref() to be used to provide rcu protected access to such fields.

Also update the current s_group_desc access site to use the macro.

---
 fs/ext4/balloc.c | 11 +++++------
 fs/ext4/ext4.h   | 17 +++++++++++++++++
 2 files changed, 22 insertions(+), 6 deletions(-)
fs/ext4/balloc.c +5 -6
index 5368bf67300b..8fd0b3cdab4c 100644
@@ -281,14 +281,13 @@ struct ext4_group_desc * ext4_get_group_desc(struct super_block *sb,
 
 	group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
 	offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
-	rcu_read_lock();
-	bh_p = rcu_dereference(sbi->s_group_desc)[group_desc];
+	bh_p = sbi_array_rcu_deref(sbi, s_group_desc, group_desc);
 	/*
-	 * We can unlock here since the pointer being dereferenced won't be
-	 * dereferenced again. By looking at the usage in add_new_gdb() the
-	 * value isn't modified, just the pointer, and so it remains valid.
+	 * sbi_array_rcu_deref returns with rcu unlocked, this is ok since
+	 * the pointer being dereferenced won't be dereferenced again. By
+	 * looking at the usage in add_new_gdb() the value isn't modified,
+	 * just the pointer, and so it remains valid.
 	 */
-	rcu_read_unlock();
 	if (!bh_p) {
 		ext4_error(sb, "Group descriptor not loaded - "
 			   "block_group = %u, group_desc = %u, desc = %u",
fs/ext4/ext4.h +17 -0
index 149ee0ab6d64..236fc6500340 100644
@@ -1576,6 +1576,23 @@ static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino)
 		 ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
 }
 
+/*
+ * Returns: sbi->field[index]
+ * Used to access an array element from the following sbi fields which require
+ * rcu protection to avoid dereferencing an invalid pointer due to reassignment
+ * - s_group_desc
+ * - s_group_info
+ * - s_flex_group
+ */
+#define sbi_array_rcu_deref(sbi, field, index)				   \
+({									   \
+	typeof(*((sbi)->field)) _v;					   \
+	rcu_read_lock();						   \
+	_v = ((typeof((sbi)->field))rcu_dereference((sbi)->field))[index]; \
+	rcu_read_unlock();						   \
+	_v;								   \
+})
+
 /*
  * Simulate_fail codes
  */
Signature · 1 line
2.17.1
#2 lore raw

Re: [PATCH 1/3] ext4: introduce macro sbi_array_rcu_deref() to access rcu protected fields

+Cc stable
(correctly this time)

Quoted 9 lines · Suraj Jitindar Singh

The s_group_desc field in the super block info (sbi) is protected by rcu to
prevent access to an invalid pointer during online resize operations. There are 2 other arrays in sbi, s_group_info and s_flex_groups, which
require similar rcu protection which is introduced in the subsequent patches. Introduce a helper macro sbi_array_rcu_deref() to be used to provide rcu protected access to such fields.

Quoted 3 lines

Also update the current s_group_desc access site to use the macro.

Quoted 76 lines
---
 fs/ext4/balloc.c | 11 +++++------
 fs/ext4/ext4.h   | 17 +++++++++++++++++
 2 files changed, 22 insertions(+), 6 deletions(-)
fs/ext4/balloc.c +1 -3
index 5368bf67300b..8fd0b3cdab4c 100644
@@ -281,14 +281,13 @@ struct ext4_group_desc *
 ext4_get_group_desc(struct super_block *sb,
 
 	group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
 	offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
-	rcu_read_lock();
-	bh_p = rcu_dereference(sbi->s_group_desc)[group_desc];
+	bh_p = sbi_array_rcu_deref(sbi, s_group_desc, group_desc);
 	/*
-	 * We can unlock here since the pointer being dereferenced

won't be

fs/ext4/balloc.c +0 -1
-	 * dereferenced again. By looking at the usage in add_new_gdb()

the

fs/ext4/balloc.c +0 -1
-	 * value isn't modified, just the pointer, and so it remains

valid.

fs/ext4/balloc.c +1 -0
+	 * sbi_array_rcu_deref returns with rcu unlocked, this is ok

since

fs/ext4/balloc.c +1 -0
+	 * the pointer being dereferenced won't be dereferenced again.

By

fs/ext4/balloc.c +1 -0
+	 * looking at the usage in add_new_gdb() the value isn't

modified,

fs/ext4/balloc.c +1 -1
+	 * just the pointer, and so it remains valid.
 	 */
-	rcu_read_unlock();
 	if (!bh_p) {
 		ext4_error(sb, "Group descriptor not loaded - "
 			   "block_group = %u, group_desc = %u, desc =

%u",

fs/ext4/ext4.h +3 -0
index 149ee0ab6d64..236fc6500340 100644
@@ -1576,6 +1576,23 @@ static inline int ext4_valid_inum(struct
 super_block *sb, unsigned long ino)
 		 ino <= le32_to_cpu(EXT4_SB(sb)->s_es-
 >s_inodes_count));
 }
 
+/*
+ * Returns: sbi->field[index]
+ * Used to access an array element from the following sbi fields

which require
+ * rcu protection to avoid dereferencing an invalid pointer due to reassignment
+ * - s_group_desc
+ * - s_group_info
+ * - s_flex_group
+ */
+#define sbi_array_rcu_deref(sbi, field, index)

	   \
fs/ext4/ext4.h +4 -0
+({									
   \
+	typeof(*((sbi)->field)) _v;					
   \
+	rcu_read_lock();						   \
+	_v = ((typeof((sbi)->field))rcu_dereference((sbi)-
Quoted 1 line

field))[index]; \

fs/ext4/ext4.h +4 -0
+	rcu_read_unlock();						
   \
+	_v;								
   \
+})
+
 /*
  * Simulate_fail codes
  */
Reviewed-by on v1 1/3
#3 lore raw

Re: [PATCH 1/3] ext4: introduce macro sbi_array_rcu_deref() to access rcu protected fields

In reply to Suraj Jitindar Singh
Quoted 60 lines · Suraj Jitindar Singh

The s_group_desc field in the super block info (sbi) is protected by rcu to prevent access to an invalid pointer during online resize operations. There are 2 other arrays in sbi, s_group_info and s_flex_groups, which require similar rcu protection which is introduced in the subsequent patches. Introduce a helper macro sbi_array_rcu_deref() to be used to provide rcu protected access to such fields.

Also update the current s_group_desc access site to use the macro.

---
 fs/ext4/balloc.c | 11 +++++------
 fs/ext4/ext4.h   | 17 +++++++++++++++++
 2 files changed, 22 insertions(+), 6 deletions(-)
fs/ext4/balloc.c +5 -6
index 5368bf67300b..8fd0b3cdab4c 100644
@@ -281,14 +281,13 @@ struct ext4_group_desc * ext4_get_group_desc(struct
 super_block *sb,
 
 	group_desc = block_group >> EXT4_DESC_PER_BLOCK_BITS(sb);
 	offset = block_group & (EXT4_DESC_PER_BLOCK(sb) - 1);
-	rcu_read_lock();
-	bh_p = rcu_dereference(sbi->s_group_desc)[group_desc];
+	bh_p = sbi_array_rcu_deref(sbi, s_group_desc, group_desc);
 	/*
-	 * We can unlock here since the pointer being dereferenced won't be
-	 * dereferenced again. By looking at the usage in add_new_gdb() the
-	 * value isn't modified, just the pointer, and so it remains valid.
+	 * sbi_array_rcu_deref returns with rcu unlocked, this is ok since
+	 * the pointer being dereferenced won't be dereferenced again. By
+	 * looking at the usage in add_new_gdb() the value isn't modified,
+	 * just the pointer, and so it remains valid.
 	 */
-	rcu_read_unlock();
 	if (!bh_p) {
 		ext4_error(sb, "Group descriptor not loaded - "
fs/ext4/balloc.c +0 -0
 			   "block_group = %u, group_desc = %u, desc = %u",
fs/ext4/ext4.h +3 -0
index 149ee0ab6d64..236fc6500340 100644
@@ -1576,6 +1576,23 @@ static inline int ext4_valid_inum(struct super_block
 *sb, unsigned long ino)
 		 ino <= le32_to_cpu(EXT4_SB(sb)->s_es->s_inodes_count));
 }
 
+/*
+ * Returns: sbi->field[index]
+ * Used to access an array element from the following sbi fields which

require
+ * rcu protection to avoid dereferencing an invalid pointer due to reassignment
+ * - s_group_desc
+ * - s_group_info
+ * - s_flex_group
+ */

fs/ext4/ext4.h static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) · line 1591

Quoted 6 lines
fs/ext4/ext4.h +5 -0
+#define sbi_array_rcu_deref(sbi, field, index)				
   \
+({									   \
+	typeof(*((sbi)->field)) _v;					   \
+	rcu_read_lock();						   \
+	_v = ((typeof((sbi)->field))rcu_dereference((sbi)->field))[index]; \

Minor nit, this can be

_v = ((typeof(_v)*)rcu_dereference((sbi)->field))[index];

fs/ext4/ext4.h static inline int ext4_valid_inum(struct super_block *sb, unsigned long ino) · line 1595

Quoted 4 lines
fs/ext4/ext4.h +4 -0
+	rcu_read_unlock();						   \
+	_v;								   \
+})
+

Looks good to me

maintainer
#4 lore raw

Re: [PATCH 1/3] ext4: introduce macro sbi_array_rcu_deref() to access rcu protected fields

In reply to Suraj Jitindar Singh
Quoted 11 lines · Suraj Jitindar Singh

The s_group_desc field in the super block info (sbi) is protected by rcu to prevent access to an invalid pointer during online resize operations. There are 2 other arrays in sbi, s_group_info and s_flex_groups, which require similar rcu protection which is introduced in the subsequent patches. Introduce a helper macro sbi_array_rcu_deref() to be used to provide rcu protected access to such fields.

Also update the current s_group_desc access site to use the macro.

Thanks, applied with the simplification suggested by Balbir. Also note that I generally use [email protected] instead of [email protected], since that avoids sending excess mail to [email protected] mailing list. (The stable kernel scripts look for [email protected] as well as [email protected].) I've made that change in the version of the patch that I applied.

- Ted

#5 lore raw

PATCH 2/3 ext4: fix potential race between s_group_info online resizing and access

In reply to Suraj Jitindar Singh

During an online resize an array of pointers to s_group_info gets replaced so it can get enlarged. If there is a concurrent access to the array in ext4_get_group_info() and this memory has been reused then this can lead to an invalid memory access.

---
 fs/ext4/ext4.h    |  6 +++---
 fs/ext4/mballoc.c | 10 ++++++----
 2 files changed, 9 insertions(+), 7 deletions(-)
fs/ext4/ext4.h +3 -3
index 236fc6500340..3f4aaaae7da6 100644
@@ -2994,13 +2994,13 @@ static inline
 struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
 					    ext4_group_t group)
 {
-	 struct ext4_group_info ***grp_info;
+	 struct ext4_group_info **grp_info;
 	 long indexv, indexh;
 	 BUG_ON(group >= EXT4_SB(sb)->s_groups_count);
-	 grp_info = EXT4_SB(sb)->s_group_info;
 	 indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb));
 	 indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1);
-	 return grp_info[indexv][indexh];
+	 grp_info = sbi_array_rcu_deref(EXT4_SB(sb), s_group_info, indexv);
+	 return grp_info[indexh];
 }
 
 /*
fs/ext4/mballoc.c +6 -4
index f64838187559..0d9b17afc85f 100644
@@ -2356,7 +2356,7 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	unsigned size;
-	struct ext4_group_info ***new_groupinfo;
+	struct ext4_group_info ***old_groupinfo, ***new_groupinfo;
 
 	size = (ngroups + EXT4_DESC_PER_BLOCK(sb) - 1) >>
 		EXT4_DESC_PER_BLOCK_BITS(sb);
@@ -2369,13 +2369,15 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb, ext4_group_t ngroups)
 		ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group");
 		return -ENOMEM;
 	}
-	if (sbi->s_group_info) {
+	old_groupinfo = sbi->s_group_info;
+	if (sbi->s_group_info)
 		memcpy(new_groupinfo, sbi->s_group_info,
 		       sbi->s_group_info_size * sizeof(*sbi->s_group_info));
-		kvfree(sbi->s_group_info);
-	}
 	sbi->s_group_info = new_groupinfo;
+	rcu_assign_pointer(sbi->s_group_info, new_groupinfo);
 	sbi->s_group_info_size = size / sizeof(*sbi->s_group_info);
+	if (old_groupinfo)
+		ext4_kvfree_array_rcu(old_groupinfo);
 	ext4_debug("allocated s_groupinfo array for %d meta_bg's\n", 
 		   sbi->s_group_info_size);
 	return 0;
Signature · 1 line
2.17.1
Reviewed-by on v1 2/3
#6 lore raw

Re: [PATCH 2/3] ext4: fix potential race between s_group_info online resizing and access

Quoted 67 lines · Suraj Jitindar Singh

During an online resize an array of pointers to s_group_info gets replaced so it can get enlarged. If there is a concurrent access to the array in ext4_get_group_info() and this memory has been reused then this can lead to an invalid memory access.

---
 fs/ext4/ext4.h    |  6 +++---
 fs/ext4/mballoc.c | 10 ++++++----
 2 files changed, 9 insertions(+), 7 deletions(-)
fs/ext4/ext4.h +3 -3
index 236fc6500340..3f4aaaae7da6 100644
@@ -2994,13 +2994,13 @@ static inline
 struct ext4_group_info *ext4_get_group_info(struct super_block *sb,
 					    ext4_group_t group)
 {
-	 struct ext4_group_info ***grp_info;
+	 struct ext4_group_info **grp_info;
 	 long indexv, indexh;
 	 BUG_ON(group >= EXT4_SB(sb)->s_groups_count);
-	 grp_info = EXT4_SB(sb)->s_group_info;
 	 indexv = group >> (EXT4_DESC_PER_BLOCK_BITS(sb));
 	 indexh = group & ((EXT4_DESC_PER_BLOCK(sb)) - 1);
-	 return grp_info[indexv][indexh];
+	 grp_info = sbi_array_rcu_deref(EXT4_SB(sb), s_group_info, indexv);
+	 return grp_info[indexh];
 }
 
 /*
fs/ext4/mballoc.c +1 -1
index f64838187559..0d9b17afc85f 100644
@@ -2356,7 +2356,7 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb,
 ext4_group_t ngroups)
 {
 	struct ext4_sb_info *sbi = EXT4_SB(sb);
 	unsigned size;
-	struct ext4_group_info ***new_groupinfo;
+	struct ext4_group_info ***old_groupinfo, ***new_groupinfo;
 
 	size = (ngroups + EXT4_DESC_PER_BLOCK(sb) - 1) >>
fs/ext4/mballoc.c +5 -3
 		EXT4_DESC_PER_BLOCK_BITS(sb);
@@ -2369,13 +2369,15 @@ int ext4_mb_alloc_groupinfo(struct super_block *sb,
 ext4_group_t ngroups)
 		ext4_msg(sb, KERN_ERR, "can't allocate buddy meta group");
 		return -ENOMEM;
 	}
-	if (sbi->s_group_info) {
+	old_groupinfo = sbi->s_group_info;
+	if (sbi->s_group_info)
 		memcpy(new_groupinfo, sbi->s_group_info,
 		       sbi->s_group_info_size * sizeof(*sbi->s_group_info));
-		kvfree(sbi->s_group_info);
-	}
 	sbi->s_group_info = new_groupinfo;
+	rcu_assign_pointer(sbi->s_group_info, new_groupinfo);
 	sbi->s_group_info_size = size / sizeof(*sbi->s_group_info);
+	if (old_groupinfo)
+		ext4_kvfree_array_rcu(old_groupinfo);
 	ext4_debug("allocated s_groupinfo array for %d meta_bg's\n", 
 		   sbi->s_group_info_size);
Quoted 1 line

return 0;

maintainer Applied
#7 lore raw

Re: [PATCH 2/3] ext4: fix potential race between s_group_info online resizing and access

In reply to Suraj Jitindar Singh
Quoted 8 lines · Suraj Jitindar Singh

During an online resize an array of pointers to s_group_info gets replaced so it can get enlarged. If there is a concurrent access to the array in ext4_get_group_info() and this memory has been reused then this can lead to an invalid memory access.

Thanks, applied.

- Ted

#8 lore raw

PATCH 3/3 ext4: fix potential race between s_flex_groups online resizing and access

In reply to Suraj Jitindar Singh

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    |  2 +-
 fs/ext4/ialloc.c  | 21 +++++++++++-------
 fs/ext4/mballoc.c |  9 +++++---
 fs/ext4/resize.c  |  4 ++--
 fs/ext4/super.c   | 56 ++++++++++++++++++++++++++++++++---------------
 5 files changed, 60 insertions(+), 32 deletions(-)
fs/ext4/ext4.h +1 -1
index 3f4aaaae7da6..e8157ce5988b 100644
@@ -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 **s_flex_groups;
 	ext4_group_t s_flex_groups_allocated;
 
 	/* workqueue for reserved extent conversions (buffered io) */
fs/ext4/ialloc.c +13 -8
index c66e8f9451a2..9324552a2ac2 100644
@@ -330,9 +330,11 @@ void ext4_free_inode(handle_t *handle, struct inode *inode)
 	if (sbi->s_log_groups_per_flex) {
 		ext4_group_t f = ext4_flex_group(sbi, block_group);
 
-		atomic_inc(&sbi->s_flex_groups[f].free_inodes);
+		atomic_inc(&sbi_array_rcu_deref(sbi, s_flex_groups,
+						f)->free_inodes);
 		if (is_directory)
-			atomic_dec(&sbi->s_flex_groups[f].used_dirs);
+			atomic_dec(&sbi_array_rcu_deref(sbi, s_flex_groups,
+							f)->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;
+	struct flex_groups *flex_group = sbi_array_rcu_deref(EXT4_SB(sb),
+							     s_flex_groups, g);
 
 	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);
+		stats->free_inodes = atomic_read(&flex_group->free_inodes);
+		stats->free_clusters = atomic64_read(&flex_group->free_clusters);
+		stats->used_dirs = atomic_read(&flex_group->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
index 0d9b17afc85f..0de1191e12a8 100644
@@ -3022,7 +3022,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);
@@ -4920,7 +4921,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);
 	}
 
 	/*
@@ -5077,7 +5079,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 +2 -2
index 6fbe8607095f..941941a629a3 100644
@@ -1427,9 +1427,9 @@ static void ext4_update_super(struct super_block *sb,
 		ext4_group_t flex_group;
 		flex_group = ext4_flex_group(sbi, group_data[0].group);
 		atomic64_add(EXT4_NUM_B2C(sbi, free_blocks),
-			     &sbi->s_flex_groups[flex_group].free_clusters);
+			     &sbi->s_flex_groups[flex_group]->free_clusters);
 		atomic_add(EXT4_INODES_PER_GROUP(sb) * flex_gd->count,
-			   &sbi->s_flex_groups[flex_group].free_inodes);
+			   &sbi->s_flex_groups[flex_group]->free_inodes);
 	}
 
 	/*
fs/ext4/super.c +38 -18

94 lines not on this page · raw message

Signature · 1 line
2.17.1
maintainer
#9 lore raw
In reply to Suraj Jitindar Singh

Hi Suraj,

All of the patches to fix BZ 206443 are now on the ext4 git tree:

https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git/log/?h=dev

I'm currently giving them a full regression test set using xfstests. Could you run your tests to make sure it looks good for you?

I'm hoping to issue a pull request to Linus in time for 5.6-rc3 by this weekend.

Also, if you can figure out a way to package up the repro as an xfstests test case, that would be really excellent. I think the challenge is that some of them took a *huge* amount of pounding before they repro'ed, correct? I wasn't actually able to trigger the repro using kvm, but I was only using a 2 CPU configuration.

Thanks,

- Ted

#10 lore raw
Quoted 5 lines · Theodore Y. Ts'o

Hi Suraj,

All of the patches to fix BZ 206443 are now on the ext4 git tree:

https://git.kernel.org/pub/scm/linux/kernel/git/tytso/ext4.git/log/?h=dev

Quoted 3 lines

I'm currently giving them a full regression test set using xfstests. Could you run your tests to make sure it looks good for you?

Hi,

Have run my repo case for 6 hours without issue. Previously this reproduced 100% of the time within <30 mins.

Quoted 10 lines

I'm hoping to issue a pull request to Linus in time for 5.6-rc3 by this weekend.

Also, if you can figure out a way to package up the repro as an xfstests test case, that would be really excellent. I think the challenge is that some of them took a *huge* amount of pounding before
they repro'ed, correct? I wasn't actually able to trigger the repro using kvm, but I was only using a 2 CPU configuration.

I will look into this.

Thanks,
Suraj

Quoted 5 lines

Thanks,

- Ted