• Hugh Dickins's avatar
    shmem: move spinlock into shmem_recalc_inode() to fix quota support · 3c1b7528
    Hugh Dickins authored
    Commit "shmem: fix quota lock nesting in huge hole handling" was not so
    good: Smatch caught shmem_recalc_inode()'s shmem_inode_unacct_blocks()
    descending into quota_send_warning(): where blocking GFP_NOFS is used,
    yet shmem_recalc_inode() is called holding the shmem inode's info->lock.
    
    Yes, both __dquot_alloc_space() and __dquot_free_space() are commented
    "This operation can block, but only after everything is updated" - when
    calling flush_warnings() at the end - both its print_warning() and its
    quota_send_warning() may block.
    
    Rework shmem_recalc_inode() to take the shmem inode's info->lock inside,
    and drop it before calling shmem_inode_unacct_blocks().
    
    And why were the spin_locks disabling interrupts?  That was just a relic
    from when shmem_charge() and shmem_uncharge() were called while holding
    i_pages xa_lock: stop disabling interrupts for info->lock now.
    
    To help stop me from making the same mistake again, add a might_sleep()
    into shmem_inode_acct_block() and shmem_inode_unacct_blocks(); and those
    functions have grown, so let the compiler decide whether to inline them.
    Reported-by: default avatarDan Carpenter <dan.carpenter@linaro.org>
    Closes: https://lore.kernel.org/linux-fsdevel/ffd7ca34-7f2a-44ee-b05d-b54d920ce076@moroto.mountain/Signed-off-by: default avatarHugh Dickins <hughd@google.com>
    Reviewed-by: default avatarJan Kara <jack@suse.cz>
    Message-Id: <29f48045-2cb5-7db-ecf1-72462f1bef5@google.com>
    Signed-off-by: default avatarChristian Brauner <brauner@kernel.org>
    3c1b7528
shmem.c 125 KB