On Mon, Jun 15, 2015 at 2:41 PM,  <[email protected]> wrote:
> From: Jeff Mahoney <[email protected]>
>
> Btrfs doesn't track superblocks with extent records so there is nothing
> persistent on-disk to indicate that those blocks are in use.  We track
> the superblocks in memory to ensure they don't get used by removing them
> from the free space cache when we load a block group from disk.  Prior
> to 47ab2a6c6a (Btrfs: remove empty block groups automatically), that
> was fine since the block group would never be reclaimed so the superblock
> was always safe.  Once we started removing the empty block groups, we
> were protected by the fact that discards weren't being properly issued
> for unused space either via FITRIM or -odiscard.  The block groups were
> still being released, but the blocks remained on disk.
>
> In order to properly discard unused block groups, we need to filter out
> the superblocks from the discard range.  Superblocks are located at fixed
> locations on each device, so it makes sense to filter them out in
> btrfs_issue_discard, which is used by both -odiscard and FITRIM.
>
> Signed-off-by: Jeff Mahoney <[email protected]>
Reviewed-by: Filipe Manana <[email protected]>
Tested-by: Filipe Manana <[email protected]>

> ---
>  fs/btrfs/extent-tree.c | 59 
> ++++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 55 insertions(+), 4 deletions(-)
>
> diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
> index cf9cefd..1e44b93 100644
> --- a/fs/btrfs/extent-tree.c
> +++ b/fs/btrfs/extent-tree.c
> @@ -1884,10 +1884,12 @@ static int remove_extent_backref(struct 
> btrfs_trans_handle *trans,
>         return ret;
>  }
>
> +#define in_range(b, first, len)        ((b) >= (first) && (b) < (first) + 
> (len))
>  static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
>                                u64 *discarded_bytes)
>  {
> -       int ret = 0;
> +       int j, ret = 0;
> +       u64 bytes_left, end;
>         u64 aligned_start = ALIGN(start, 1 << 9);
>
>         if (WARN_ON(start != aligned_start)) {
> @@ -1897,11 +1899,60 @@ static int btrfs_issue_discard(struct block_device 
> *bdev, u64 start, u64 len,
>         }
>
>         *discarded_bytes = 0;
> -       if (len) {
> -               ret = blkdev_issue_discard(bdev, start >> 9, len >> 9,
> +
> +       if (!len)
> +               return 0;
> +
> +       end = start + len;
> +       bytes_left = len;
> +
> +       /* Skip any superblocks on this device. */
> +       for (j = 0; j < BTRFS_SUPER_MIRROR_MAX; j++) {
> +               u64 sb_start = btrfs_sb_offset(j);
> +               u64 sb_end = sb_start + BTRFS_SUPER_INFO_SIZE;
> +               u64 size = sb_start - start;
> +
> +               if (!in_range(sb_start, start, bytes_left) &&
> +                   !in_range(sb_end, start, bytes_left) &&
> +                   !in_range(start, sb_start, BTRFS_SUPER_INFO_SIZE))
> +                       continue;
> +
> +               /*
> +                * Superblock spans beginning of range.  Adjust start and
> +                * try again.
> +                */
> +               if (sb_start <= start) {
> +                       start += sb_end - start;
> +                       if (start > end) {
> +                               bytes_left = 0;
> +                               break;
> +                       }
> +                       bytes_left = end - start;
> +                       continue;
> +               }
> +
> +               if (size) {
> +                       ret = blkdev_issue_discard(bdev, start >> 9, size >> 
> 9,
> +                                                  GFP_NOFS, 0);
> +                       if (!ret)
> +                               *discarded_bytes += size;
> +                       else if (ret != -EOPNOTSUPP)
> +                               return ret;
> +               }
> +
> +               start = sb_end;
> +               if (start > end) {
> +                       bytes_left = 0;
> +                       break;
> +               }
> +               bytes_left = end - start;
> +       }
> +
> +       if (bytes_left) {
> +               ret = blkdev_issue_discard(bdev, start >> 9, bytes_left >> 9,
>                                            GFP_NOFS, 0);
>                 if (!ret)
> -                       *discarded_bytes = len;
> +                       *discarded_bytes += bytes_left;
>         }
>         return ret;
>  }
> --
> 2.4.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
> the body of a message to [email protected]
> More majordomo info at  http://vger.kernel.org/majordomo-info.html



-- 
Filipe David Manana,

"Reasonable men adapt themselves to the world.
 Unreasonable men adapt the world to themselves.
 That's why all progress depends on unreasonable men."
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to