Re: [PATCH] Btrfs: reduce lock contention when create snapshot

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Thu, May 14, 2020 at 10:20 AM robbieko <robbieko@xxxxxxxxxxxx> wrote:
>
> From: Robbie Ko <robbieko@xxxxxxxxxxxx>
>
> When creating a snapshot, it takes a long time because
> flush dirty data is required.
>
> But we have taken two resources as shown below:
> 1. Destination directory inode lock
> 2. Global subvol semaphore
>
> This will cause subvol destroy/create/setflag blocked,
> until the snapshot is created.
>
> We fix by flush dirty data first to reduce the time of
> the critical section, and then lock the relevant resources.
>
> Signed-off-by: Robbie Ko <robbieko@xxxxxxxxxxxx>

Reviewed-by: Filipe Manana <fdmanana@xxxxxxxx>

Looks good, thanks.

> ---
>  fs/btrfs/ioctl.c | 70 ++++++++++++++++++++++++++++--------------------
>  1 file changed, 41 insertions(+), 29 deletions(-)
>
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 40b729dce91c..d0c1598dc51e 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -748,7 +748,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
>         struct btrfs_pending_snapshot *pending_snapshot;
>         struct btrfs_trans_handle *trans;
>         int ret;
> -       bool snapshot_force_cow = false;
>
>         if (!test_bit(BTRFS_ROOT_REF_COWS, &root->state))
>                 return -EINVAL;
> @@ -771,27 +770,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
>                 goto free_pending;
>         }
>
> -       /*
> -        * Force new buffered writes to reserve space even when NOCOW is
> -        * possible. This is to avoid later writeback (running dealloc) to
> -        * fallback to COW mode and unexpectedly fail with ENOSPC.
> -        */
> -       btrfs_drew_read_lock(&root->snapshot_lock);
> -
> -       ret = btrfs_start_delalloc_snapshot(root);
> -       if (ret)
> -               goto dec_and_free;
> -
> -       /*
> -        * All previous writes have started writeback in NOCOW mode, so now
> -        * we force future writes to fallback to COW mode during snapshot
> -        * creation.
> -        */
> -       atomic_inc(&root->snapshot_force_cow);
> -       snapshot_force_cow = true;
> -
> -       btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
> -
>         btrfs_init_block_rsv(&pending_snapshot->block_rsv,
>                              BTRFS_BLOCK_RSV_TEMP);
>         /*
> @@ -806,7 +784,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
>                                         &pending_snapshot->block_rsv, 8,
>                                         false);
>         if (ret)
> -               goto dec_and_free;
> +               goto free_pending;
>
>         pending_snapshot->dentry = dentry;
>         pending_snapshot->root = root;
> @@ -848,11 +826,6 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
>  fail:
>         btrfs_put_root(pending_snapshot->snap);
>         btrfs_subvolume_release_metadata(fs_info, &pending_snapshot->block_rsv);
> -dec_and_free:
> -       if (snapshot_force_cow)
> -               atomic_dec(&root->snapshot_force_cow);
> -       btrfs_drew_read_unlock(&root->snapshot_lock);
> -
>  free_pending:
>         kfree(pending_snapshot->root_item);
>         btrfs_free_path(pending_snapshot->path);
> @@ -983,6 +956,45 @@ static noinline int btrfs_mksubvol(const struct path *parent,
>         return error;
>  }
>
> +static noinline int btrfs_mksnapshot(const struct path *parent,
> +                                  const char *name, int namelen,
> +                                  struct btrfs_root *root,
> +                                  bool readonly,
> +                                  struct btrfs_qgroup_inherit *inherit)
> +{
> +       int ret;
> +       bool snapshot_force_cow = false;
> +
> +       /*
> +        * Force new buffered writes to reserve space even when NOCOW is
> +        * possible. This is to avoid later writeback (running dealloc) to
> +        * fallback to COW mode and unexpectedly fail with ENOSPC.
> +        */
> +       btrfs_drew_read_lock(&root->snapshot_lock);
> +
> +       ret = btrfs_start_delalloc_snapshot(root);
> +       if (ret)
> +               goto out;
> +
> +       /*
> +        * All previous writes have started writeback in NOCOW mode, so now
> +        * we force future writes to fallback to COW mode during snapshot
> +        * creation.
> +        */
> +       atomic_inc(&root->snapshot_force_cow);
> +       snapshot_force_cow = true;
> +
> +       btrfs_wait_ordered_extents(root, U64_MAX, 0, (u64)-1);
> +
> +       ret = btrfs_mksubvol(parent, name, namelen,
> +                            root, readonly, inherit);
> +out:
> +       if (snapshot_force_cow)
> +               atomic_dec(&root->snapshot_force_cow);
> +       btrfs_drew_read_unlock(&root->snapshot_lock);
> +       return ret;
> +}
> +
>  /*
>   * When we're defragging a range, we don't want to kick it off again
>   * 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,
>                          */
>                         ret = -EPERM;
>                 } else {
> -                       ret = btrfs_mksubvol(&file->f_path, name, namelen,
> +                       ret = btrfs_mksnapshot(&file->f_path, name, namelen,
>                                              BTRFS_I(src_inode)->root,
>                                              readonly, inherit);
>                 }
> --
> 2.17.1
>


-- 
Filipe David Manana,

“Whether you think you can, or you think you can't — you're right.”




[Index of Archives]     [Linux Filesystem Development]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux