The per-filesystem reservation window rb-tree (s_rsv_window_root) is protected by s_rsv_window_lock. Mark the s_rsv_window_root field with __guarded_by() for Clang's context analysis. The helpers (ext2_rsv_window_add, rsv_window_remove, and find_next_reservable_window) that mutate or walk the tree are all called with the s_rsv_window_lock held. Annotate these helpers with __must_hold(). The accesses in ext2_fill_super() are before the superblock is live. Since no concurrent access should be possible, s_rsv_window_lock is not taken. Convert the spinlock initialization to use scoped_guard(spinlock_init, ...) and place the writes under the guard to prevent warnings. Signed-off-by: Timothy Day --- fs/ext2/balloc.c | 3 +++ fs/ext2/ext2.h | 5 +++-- fs/ext2/super.c | 27 ++++++++++++++------------- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/fs/ext2/balloc.c b/fs/ext2/balloc.c index 53c91cb38bde..80acc1e19387 100644 --- a/fs/ext2/balloc.c +++ b/fs/ext2/balloc.c @@ -334,6 +334,7 @@ search_reserve_window(struct rb_root *root, ext2_fsblk_t goal) */ void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_window_node *rsv) + __must_hold(&EXT2_SB(sb)->s_rsv_window_lock) { struct rb_root *root = &EXT2_SB(sb)->s_rsv_window_root; struct rb_node *node = &rsv->rsv_node; @@ -373,6 +374,7 @@ void ext2_rsv_window_add(struct super_block *sb, */ static void rsv_window_remove(struct super_block *sb, struct ext2_reserve_window_node *rsv) + __must_hold(&EXT2_SB(sb)->s_rsv_window_lock) { rsv->rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; rsv->rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; @@ -759,6 +761,7 @@ static int find_next_reservable_window( struct super_block * sb, ext2_fsblk_t start_block, ext2_fsblk_t last_block) + __must_hold(&EXT2_SB(sb)->s_rsv_window_lock) { struct rb_node *next; struct ext2_reserve_window_node *rsv, *prev; diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index b6ae29b2e6ec..404f4223a6bd 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -102,7 +102,7 @@ struct ext2_sb_info { struct blockgroup_lock *s_blockgroup_lock; /* root of the per fs reservation window tree */ spinlock_t s_rsv_window_lock; - struct rb_root s_rsv_window_root; + struct rb_root s_rsv_window_root __guarded_by(&s_rsv_window_lock); struct ext2_reserve_window_node s_rsv_window_head; /* * s_lock protects against concurrent modifications of s_mount_state, @@ -712,7 +712,8 @@ extern void ext2_discard_reservation (struct inode *); extern int ext2_should_retry_alloc(struct super_block *sb, int *retries); extern void ext2_init_block_alloc_info(struct inode *inode) __must_hold(&EXT2_I(inode)->truncate_mutex); -extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_window_node *rsv); +extern void ext2_rsv_window_add(struct super_block *sb, struct ext2_reserve_window_node *rsv) + __must_hold(&EXT2_SB(sb)->s_rsv_window_lock); /* dir.c */ int ext2_add_link(struct dentry *, struct inode *); diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 0fa7914e5f04..b7f042e42009 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -1131,19 +1131,20 @@ static int ext2_fill_super(struct super_block *sb, struct fs_context *fc) sbi->s_next_generation = get_random_u32(); /* per filesystem reservation list head & lock */ - spin_lock_init(&sbi->s_rsv_window_lock); - sbi->s_rsv_window_root = RB_ROOT; - /* - * Add a single, static dummy reservation to the start of the - * reservation window list --- it gives us a placeholder for - * append-at-start-of-list which makes the allocation logic - * _much_ simpler. - */ - sbi->s_rsv_window_head.rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; - sbi->s_rsv_window_head.rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; - sbi->s_rsv_window_head.rsv_alloc_hit = 0; - sbi->s_rsv_window_head.rsv_goal_size = 0; - ext2_rsv_window_add(sb, &sbi->s_rsv_window_head); + scoped_guard(spinlock_init, &EXT2_SB(sb)->s_rsv_window_lock) { + sbi->s_rsv_window_root = RB_ROOT; + /* + * Add a single, static dummy reservation to the start of the + * reservation window list --- it gives us a placeholder for + * append-at-start-of-list which makes the allocation logic + * _much_ simpler. + */ + sbi->s_rsv_window_head.rsv_start = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; + sbi->s_rsv_window_head.rsv_end = EXT2_RESERVE_WINDOW_NOT_ALLOCATED; + sbi->s_rsv_window_head.rsv_alloc_hit = 0; + sbi->s_rsv_window_head.rsv_goal_size = 0; + ext2_rsv_window_add(sb, &sbi->s_rsv_window_head); + } err = percpu_counter_init(&sbi->s_freeblocks_counter, ext2_count_free_blocks(sb), GFP_KERNEL); -- 2.43.0