Skip to content

Commit

Permalink
btrfs: btrfs_issue_discard ensure offset/length are aligned to sector…
Browse files Browse the repository at this point in the history
… boundaries

It's possible, though unexpected, to pass unaligned offsets and lengths
to btrfs_issue_discard.  We then shift the offset/length values to sector
units.  If an unaligned offset has been passed, it will result in the
entire sector being discarded, possibly losing data.  An unaligned
length is safe but we'll end up returning an inaccurate number of
discarded bytes.

This patch aligns the offset to the 512B boundary, adjusts the length,
and warns, since we shouldn't be discarding on an offset that isn't
aligned with our sector size.

Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Reviewed-by: Filipe Manana <fdmanana@suse.com>
Tested-by: Filipe Manana <fdmanana@suse.com>
Signed-off-by: Chris Mason <clm@fb.com>
  • Loading branch information
Jeff Mahoney authored and Chris Mason committed Jul 29, 2015
1 parent d04c6b8 commit 4d89d37
Showing 1 changed file with 13 additions and 4 deletions.
17 changes: 13 additions & 4 deletions fs/btrfs/extent-tree.c
Original file line number Diff line number Diff line change
Expand Up @@ -1887,12 +1887,21 @@ static int btrfs_issue_discard(struct block_device *bdev, u64 start, u64 len,
u64 *discarded_bytes)
{
int ret = 0;
u64 aligned_start = ALIGN(start, 1 << 9);

*discarded_bytes = 0;
ret = blkdev_issue_discard(bdev, start >> 9, len >> 9, GFP_NOFS, 0);
if (!ret)
*discarded_bytes = len;
if (WARN_ON(start != aligned_start)) {
len -= aligned_start - start;
len = round_down(len, 1 << 9);
start = aligned_start;
}

*discarded_bytes = 0;
if (len) {
ret = blkdev_issue_discard(bdev, start >> 9, len >> 9,
GFP_NOFS, 0);
if (!ret)
*discarded_bytes = len;
}
return ret;
}

Expand Down

0 comments on commit 4d89d37

Please sign in to comment.