lkml.org 
[lkml]   [2022]   [Oct]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH AUTOSEL 5.10 15/17] btrfs: add KCSAN annotations for unlocked access to block_rsv->full
    Date
    From: David Sterba <dsterba@suse.com>

    [ Upstream commit 748f553c3c4c4f175c6c834358632aff802d72cf ]

    KCSAN reports that there's unlocked access mixed with locked access,
    which is technically correct but is not a bug. To avoid false alerts at
    least from KCSAN, add annotation and use a wrapper whenever ->full is
    accessed for read outside of lock.

    It is used as a fast check and only advisory. In the worst case the
    block reserve is found !full and becomes full in the meantime, but
    properly handled.

    Depending on the value of ->full, btrfs_block_rsv_release decides
    where to return the reservation, and block_rsv_release_bytes handles a
    NULL pointer for block_rsv and if it's not NULL then it double checks
    the full status under a lock.

    Link: https://lore.kernel.org/linux-btrfs/CAAwBoOJDjei5Hnem155N_cJwiEkVwJYvgN-tQrwWbZQGhFU=cA@mail.gmail.com/
    Link: https://lore.kernel.org/linux-btrfs/YvHU/vsXd7uz5V6j@hungrycats.org
    Reported-by: Zygo Blaxell <ce3g8jdj@umail.furryterror.org>
    Signed-off-by: David Sterba <dsterba@suse.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/btrfs/block-rsv.c | 2 +-
    fs/btrfs/block-rsv.h | 9 +++++++++
    fs/btrfs/transaction.c | 4 ++--
    3 files changed, 12 insertions(+), 3 deletions(-)

    diff --git a/fs/btrfs/block-rsv.c b/fs/btrfs/block-rsv.c
    index bc920afe23bf..692a1739bef6 100644
    --- a/fs/btrfs/block-rsv.c
    +++ b/fs/btrfs/block-rsv.c
    @@ -285,7 +285,7 @@ u64 btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
    */
    if (block_rsv == delayed_rsv)
    target = global_rsv;
    - else if (block_rsv != global_rsv && !delayed_rsv->full)
    + else if (block_rsv != global_rsv && !btrfs_block_rsv_full(delayed_rsv))
    target = delayed_rsv;

    if (target && block_rsv->space_info != target->space_info)
    diff --git a/fs/btrfs/block-rsv.h b/fs/btrfs/block-rsv.h
    index 0b6ae5302837..f0431547acf2 100644
    --- a/fs/btrfs/block-rsv.h
    +++ b/fs/btrfs/block-rsv.h
    @@ -90,4 +90,13 @@ static inline void btrfs_unuse_block_rsv(struct btrfs_fs_info *fs_info,
    btrfs_block_rsv_release(fs_info, block_rsv, 0, NULL);
    }

    +/*
    + * Fast path to check if the reserve is full, may be carefully used outside of
    + * locks.
    + */
    +static inline bool btrfs_block_rsv_full(const struct btrfs_block_rsv *rsv)
    +{
    + return data_race(rsv->full);
    +}
    +
    #endif /* BTRFS_BLOCK_RSV_H */
    diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c
    index 8daa9e4eb1d2..3cfa7cce266e 100644
    --- a/fs/btrfs/transaction.c
    +++ b/fs/btrfs/transaction.c
    @@ -608,7 +608,7 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
    */
    num_bytes = btrfs_calc_insert_metadata_size(fs_info, num_items);
    if (flush == BTRFS_RESERVE_FLUSH_ALL &&
    - delayed_refs_rsv->full == 0) {
    + btrfs_block_rsv_full(delayed_refs_rsv) == 0) {
    delayed_refs_bytes = num_bytes;
    num_bytes <<= 1;
    }
    @@ -633,7 +633,7 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
    if (rsv->space_info->force_alloc)
    do_chunk_alloc = true;
    } else if (num_items == 0 && flush == BTRFS_RESERVE_FLUSH_ALL &&
    - !delayed_refs_rsv->full) {
    + !btrfs_block_rsv_full(delayed_refs_rsv)) {
    /*
    * Some people call with btrfs_start_transaction(root, 0)
    * because they can be throttled, but have some other mechanism
    --
    2.35.1
    \
     
     \ /
      Last update: 2022-10-11 17:33    [W:7.746 / U:0.004 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site