Skip to content

Commit c11fbb6

Browse files
Robbie Kokdave
authored andcommitted
btrfs: reduce lock contention when creating snapshot
When creating a snapshot, ordered extents need to be flushed and this can take a long time. In create_snapshot there are two locks held when this happens: 1. Destination directory inode lock 2. Global subvolume semaphore This will unnecessarily block other operations like subvolume destroy, create, or setflag until the snapshot is created. We can fix that by moving the flush outside the locked section as this does not depend on the aforementioned locks. The code factors out the snapshot related work from create_snapshot to btrfs_mksnapshot. __btrfs_ioctl_snap_create btrfs_mksubvol create_subvol btrfs_mksnapshot <flush> btrfs_mksubvol create_snapshot Reviewed-by: Filipe Manana <[email protected]> Signed-off-by: Robbie Ko <[email protected]> Reviewed-by: David Sterba <[email protected]> Signed-off-by: David Sterba <[email protected]>
1 parent aeb935a commit c11fbb6

File tree

1 file changed

+41
-29
lines changed

1 file changed

+41
-29
lines changed

fs/btrfs/ioctl.c

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -748,7 +748,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
748748
struct btrfs_pending_snapshot *pending_snapshot;
749749
struct btrfs_trans_handle *trans;
750750
int ret;
751-
bool snapshot_force_cow = false;
752751

753752
if (!test_bit(BTRFS_ROOT_SHAREABLE, &root->state))
754753
return -EINVAL;
@@ -771,27 +770,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
771770
goto free_pending;
772771
}
773772

774-
/*
775-
* Force new buffered writes to reserve space even when NOCOW is
776-
* possible. This is to avoid later writeback (running dealloc) to
777-
* fallback to COW mode and unexpectedly fail with ENOSPC.
778-
*/
779-
btrfs_drew_read_lock(&root->snapshot_lock);
780-
781-
ret = btrfs_start_delalloc_snapshot(root);
782-
if (ret)
783-
goto dec_and_free;
784-
785-
/*
786-
* All previous writes have started writeback in NOCOW mode, so now
787-
* we force future writes to fallback to COW mode during snapshot
788-
* creation.
789-
*/
790-
atomic_inc(&root->snapshot_force_cow);
791-
snapshot_force_cow = true;
792-
793-
btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
794-
795773
btrfs_init_block_rsv(&pending_snapshot->block_rsv,
796774
BTRFS_BLOCK_RSV_TEMP);
797775
/*
@@ -806,7 +784,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
806784
&pending_snapshot->block_rsv, 8,
807785
false);
808786
if (ret)
809-
goto dec_and_free;
787+
goto free_pending;
810788

811789
pending_snapshot->dentry = dentry;
812790
pending_snapshot->root = root;
@@ -848,11 +826,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
848826
fail:
849827
btrfs_put_root(pending_snapshot->snap);
850828
btrfs_subvolume_release_metadata(fs_info, &pending_snapshot->block_rsv);
851-
dec_and_free:
852-
if (snapshot_force_cow)
853-
atomic_dec(&root->snapshot_force_cow);
854-
btrfs_drew_read_unlock(&root->snapshot_lock);
855-
856829
free_pending:
857830
kfree(pending_snapshot->root_item);
858831
btrfs_free_path(pending_snapshot->path);
@@ -983,6 +956,45 @@ static noinline int btrfs_mksubvol(const struct path *parent,
983956
return error;
984957
}
985958

959+
static noinline int btrfs_mksnapshot(const struct path *parent,
960+
const char *name, int namelen,
961+
struct btrfs_root *root,
962+
bool readonly,
963+
struct btrfs_qgroup_inherit *inherit)
964+
{
965+
int ret;
966+
bool snapshot_force_cow = false;
967+
968+
/*
969+
* Force new buffered writes to reserve space even when NOCOW is
970+
* possible. This is to avoid later writeback (running dealloc) to
971+
* fallback to COW mode and unexpectedly fail with ENOSPC.
972+
*/
973+
btrfs_drew_read_lock(&root->snapshot_lock);
974+
975+
ret = btrfs_start_delalloc_snapshot(root);
976+
if (ret)
977+
goto out;
978+
979+
/*
980+
* All previous writes have started writeback in NOCOW mode, so now
981+
* we force future writes to fallback to COW mode during snapshot
982+
* creation.
983+
*/
984+
atomic_inc(&root->snapshot_force_cow);
985+
snapshot_force_cow = true;
986+
987+
btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
988+
989+
ret = btrfs_mksubvol(parent, name, namelen,
990+
root, readonly, inherit);
991+
out:
992+
if (snapshot_force_cow)
993+
atomic_dec(&root->snapshot_force_cow);
994+
btrfs_drew_read_unlock(&root->snapshot_lock);
995+
return ret;
996+
}
997+
986998
/*
987999
* When we're defragging a range, we don't want to kick it off again
9881000
* if it is really just waiting for delalloc to send it down.
@@ -1762,7 +1774,7 @@ static noinline int __btrfs_ioctl_snap_create(struct file *file,
17621774
*/
17631775
ret = -EPERM;
17641776
} else {
1765-
ret = btrfs_mksubvol(&file->f_path, name, namelen,
1777+
ret = btrfs_mksnapshot(&file->f_path, name, namelen,
17661778
BTRFS_I(src_inode)->root,
17671779
readonly, inherit);
17681780
}

0 commit comments

Comments
 (0)