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. Signed-off-by: Suraj Jitindar Singh <surajjs@xxxxxxxxxx> Cc: stable@xxxxxxxxxxxxxxx --- fs/ext4/balloc.c | 11 +++++------ fs/ext4/ext4.h | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/fs/ext4/balloc.c b/fs/ext4/balloc.c index 5368bf67300b..8fd0b3cdab4c 100644 --- a/fs/ext4/balloc.c +++ b/fs/ext4/balloc.c @@ -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", diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h index 149ee0ab6d64..236fc6500340 100644 --- a/fs/ext4/ext4.h +++ b/fs/ext4/ext4.h @@ -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 */ -- 2.17.1