[2/2] btrfs: use btrfs_block_group_cache_done in update_block_group
diff mbox series

Message ID 20190924205044.31830-2-josef@toxicpanda.com
State New
Headers show
Series
  • [1/2] btrfs: check page->mapping when loading free space cache
Related show

Commit Message

Josef Bacik Sept. 24, 2019, 8:50 p.m. UTC
When free'ing extents in a block group we check to see if the block
group is not cached, and then cache it if we need to.  However we'll
just carry on as long as we're loading the cache.  This is problematic
because we are dirtying the block group here.  If we are fast enough we
could do a transaction commit and clear the free space cache while we're
still loading the space cache in another thread.  This truncates the
free space inode, which will keep it from loading the space cache.

Fix this by using the btrfs_block_group_cache_done helper so that we try
to load the space cache unconditionally here, which will result in the
caller waiting for the fast caching to complete and keep us from
truncating the free space inode.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
---
 fs/btrfs/block-group.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Comments

Nikolay Borisov Oct. 1, 2019, 2:08 p.m. UTC | #1
On 24.09.19 г. 23:50 ч., Josef Bacik wrote:
> When free'ing extents in a block group we check to see if the block
> group is not cached, and then cache it if we need to.  However we'll
> just carry on as long as we're loading the cache.  This is problematic
> because we are dirtying the block group here.  If we are fast enough we
> could do a transaction commit and clear the free space cache while we're

This would imply a race condition between loading the space cache and
running delayed refs - because there where
__btrfs_free_extent->btrfs_update_blockgroup(alloc=0) is called from, no ?

> still loading the space cache in another thread.  This truncates the
> free space inode, which will keep it from loading the space cache.
> 
> Fix this by using the btrfs_block_group_cache_done helper so that we try
> to load the space cache unconditionally here, which will result in the
> caller waiting for the fast caching to complete and keep us from
> truncating the free space inode.

So the problem was that cache->cached == BTRFS_CACHE_NO misses other
interim states e.g. CACHE_STARTED/CACHE_FAST. Which leads to the
aforementioned race, correct?


> 
> Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Based on our offlist discussion:

Reviewed-by: Nikolay Borisov <nborisov@suse.com>

> ---
>  fs/btrfs/block-group.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
> index bf7e3f23bba7..d7b3a516f27a 100644
> --- a/fs/btrfs/block-group.c
> +++ b/fs/btrfs/block-group.c
> @@ -2661,7 +2661,7 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
>  		 * is because we need the unpinning stage to actually add the
>  		 * space back to the block group, otherwise we will leak space.
>  		 */
> -		if (!alloc && cache->cached == BTRFS_CACHE_NO)
> +		if (!alloc && !btrfs_block_group_cache_done(cache))
>  			btrfs_cache_block_group(cache, 1);
>  
>  		byte_in_group = bytenr - cache->key.objectid;
>

Patch
diff mbox series

diff --git a/fs/btrfs/block-group.c b/fs/btrfs/block-group.c
index bf7e3f23bba7..d7b3a516f27a 100644
--- a/fs/btrfs/block-group.c
+++ b/fs/btrfs/block-group.c
@@ -2661,7 +2661,7 @@  int btrfs_update_block_group(struct btrfs_trans_handle *trans,
 		 * is because we need the unpinning stage to actually add the
 		 * space back to the block group, otherwise we will leak space.
 		 */
-		if (!alloc && cache->cached == BTRFS_CACHE_NO)
+		if (!alloc && !btrfs_block_group_cache_done(cache))
 			btrfs_cache_block_group(cache, 1);
 
 		byte_in_group = bytenr - cache->key.objectid;