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