• F
    btrfs: fix race between swap file activation and snapshot creation · cfc71a1b
    Filipe Manana 提交于
    stable inclusion
    from stable-5.10.22
    commit 6fc9e5866cb9d66bf3e9d05ff6831132733c098a
    bugzilla: 50796
    
    --------------------------------
    
    commit dd0734f2 upstream.
    
    When creating a snapshot we check if the current number of swap files, in
    the root, is non-zero, and if it is, we error out and warn that we can not
    create the snapshot because there are active swap files.
    
    However this is racy because when a task started activation of a swap
    file, another task might have started already snapshot creation and might
    have seen the counter for the number of swap files as zero. This means
    that after the swap file is activated we may end up with a snapshot of the
    same root successfully created, and therefore when the first write to the
    swap file happens it has to fall back into COW mode, which should never
    happen for active swap files.
    
    Basically what can happen is:
    
    1) Task A starts snapshot creation and enters ioctl.c:create_snapshot().
       There it sees that root->nr_swapfiles has a value of 0 so it continues;
    
    2) Task B enters btrfs_swap_activate(). It is not aware that another task
       started snapshot creation but it did not finish yet. It increments
       root->nr_swapfiles from 0 to 1;
    
    3) Task B checks that the file meets all requirements to be an active
       swap file - it has NOCOW set, there are no snapshots for the inode's
       root at the moment, no file holes, no reflinked extents, etc;
    
    4) Task B returns success and now the file is an active swap file;
    
    5) Task A commits the transaction to create the snapshot and finishes.
       The swap file's extents are now shared between the original root and
       the snapshot;
    
    6) A write into an extent of the swap file is attempted - there is a
       snapshot of the file's root, so we fall back to COW mode and therefore
       the physical location of the extent changes on disk.
    
    So fix this by taking the snapshot lock during swap file activation before
    locking the extent range, as that is the order in which we lock these
    during buffered writes.
    
    Fixes: ed46ff3d ("Btrfs: support swap files")
    CC: stable@vger.kernel.org # 5.4+
    Reviewed-by: NAnand Jain <anand.jain@oracle.com>
    Reviewed-by: NJosef Bacik <josef@toxicpanda.com>
    Signed-off-by: NFilipe Manana <fdmanana@suse.com>
    Signed-off-by: NDavid Sterba <dsterba@suse.com>
    Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    Signed-off-by: NChen Jun <chenjun102@huawei.com>
    Acked-by: N  Weilong Chen <chenweilong@huawei.com>
    Signed-off-by: NZheng Zengkai <zhengzengkai@huawei.com>
    cfc71a1b
inode.c 288.7 KB