On Fri, Mar 25, 2016 at 01:25:49PM -0400, Josef Bacik wrote:
> There are a few races in the metadata reservation stuff.  First we add the 
> bytes
> to the block_rsv well after we've set the bit on the inode saying that we have
> space for it and after we've reserved the bytes.  So use the normal
> btrfs_block_rsv_add helper for this case.  Secondly we can flush delalloc
> extents when we try to reserve space for our write, which means that we could
> have used up the space for the inode and we wouldn't know because we only 
> check
> before the reservation.  So instead make sure we are always reserving space 
> for
> the inode update, and then if we don't need it release those bytes afterward.
> Thanks,

Looks fine.

Reviewed-by: Liu Bo <bo.li....@oracle.com>

> 
> Signed-off-by: Josef Bacik <jba...@fb.com>
> ---
>  fs/btrfs/extent-tree.c | 35 +++++++++++++----------------------
>  1 file changed, 13 insertions(+), 22 deletions(-)
> 
> diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
> index 06f4e7b..157a0b6 100644
> --- a/fs/btrfs/extent-tree.c
> +++ b/fs/btrfs/extent-tree.c
> @@ -5653,12 +5653,12 @@ int btrfs_delalloc_reserve_metadata(struct inode 
> *inode, u64 num_bytes)
>       u64 to_reserve = 0;
>       u64 csum_bytes;
>       unsigned nr_extents = 0;
> -     int extra_reserve = 0;
>       enum btrfs_reserve_flush_enum flush = BTRFS_RESERVE_FLUSH_ALL;
>       int ret = 0;
>       bool delalloc_lock = true;
>       u64 to_free = 0;
>       unsigned dropped;
> +     bool release_extra = false;
>  
>       /* If we are a free space inode we need to not flush since we will be in
>        * the middle of a transaction commit.  We also don't need the delalloc
> @@ -5684,24 +5684,15 @@ int btrfs_delalloc_reserve_metadata(struct inode 
> *inode, u64 num_bytes)
>                                        BTRFS_MAX_EXTENT_SIZE - 1,
>                                        BTRFS_MAX_EXTENT_SIZE);
>       BTRFS_I(inode)->outstanding_extents += nr_extents;
> -     nr_extents = 0;
>  
> +     nr_extents = 0;
>       if (BTRFS_I(inode)->outstanding_extents >
>           BTRFS_I(inode)->reserved_extents)
> -             nr_extents = BTRFS_I(inode)->outstanding_extents -
> +             nr_extents += BTRFS_I(inode)->outstanding_extents -
>                       BTRFS_I(inode)->reserved_extents;
>  
> -     /*
> -      * Add an item to reserve for updating the inode when we complete the
> -      * delalloc io.
> -      */
> -     if (!test_bit(BTRFS_INODE_DELALLOC_META_RESERVED,
> -                   &BTRFS_I(inode)->runtime_flags)) {
> -             nr_extents++;
> -             extra_reserve = 1;
> -     }
> -
> -     to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents);
> +     /* We always want to reserve a slot for updating the inode. */
> +     to_reserve = btrfs_calc_trans_metadata_size(root, nr_extents + 1);
>       to_reserve += calc_csum_metadata_size(inode, num_bytes, 1);
>       csum_bytes = BTRFS_I(inode)->csum_bytes;
>       spin_unlock(&BTRFS_I(inode)->lock);
> @@ -5713,18 +5704,16 @@ int btrfs_delalloc_reserve_metadata(struct inode 
> *inode, u64 num_bytes)
>                       goto out_fail;
>       }
>  
> -     ret = reserve_metadata_bytes(root, block_rsv, to_reserve, flush);
> +     ret = btrfs_block_rsv_add(root, block_rsv, to_reserve, flush);
>       if (unlikely(ret)) {
>               btrfs_qgroup_free_meta(root, nr_extents * root->nodesize);
>               goto out_fail;
>       }
>  
>       spin_lock(&BTRFS_I(inode)->lock);
> -     if (extra_reserve) {
> -             set_bit(BTRFS_INODE_DELALLOC_META_RESERVED,
> -                     &BTRFS_I(inode)->runtime_flags);
> -             nr_extents--;
> -     }
> +     if (test_and_set_bit(BTRFS_INODE_DELALLOC_META_RESERVED,
> +                          &BTRFS_I(inode)->runtime_flags))
> +             release_extra = true;
>       BTRFS_I(inode)->reserved_extents += nr_extents;
>       spin_unlock(&BTRFS_I(inode)->lock);
>  
> @@ -5734,8 +5723,10 @@ int btrfs_delalloc_reserve_metadata(struct inode 
> *inode, u64 num_bytes)
>       if (to_reserve)
>               trace_btrfs_space_reservation(root->fs_info, "delalloc",
>                                             btrfs_ino(inode), to_reserve, 1);
> -     block_rsv_add_bytes(block_rsv, to_reserve, 1);
> -
> +     if (release_extra)
> +             btrfs_block_rsv_release(root, block_rsv,
> +                                     btrfs_calc_trans_metadata_size(root,
> +                                                                    1));
>       return 0;
>  
>  out_fail:
> -- 
> 2.5.0
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to majord...@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to