Re: [PATCH 2/2] Btrfs: fix fiemap extent SHARED flag error with range clone.
On 2018年03月07日 20:17, Nikolay Borisov wrote: > > > On 7.03.2018 14:14, Qu Wenruo wrote: >> >> > > > SHARED flag is determined after extent map merge, so here we can't rely on em here. >>> >>> Shouldn't extent maps correspond to 1:1 disk-state. I.e. they are just >>> the memory cache of the extent state. So if we merge them, shouldn't we >>> also merge the on-disk extents as well ? >> >> Not 1:1. >> >> In memory one is merged maybe to save memory. >> >> But on-disk file extents has size limit. >> For compressed one it's 128K and 128M for uncompressed one. > > Fair enough, however 4 extents, 16k each should warrant merging on-disk > as well, no ? dd oflag=dsync That ensures we won't merge on-disk extents. Thanks, Qu > > > -- > 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 > signature.asc Description: OpenPGP digital signature
Re: [PATCH 2/2] Btrfs: fix fiemap extent SHARED flag error with range clone.
On 7.03.2018 14:14, Qu Wenruo wrote: > > >>> >>> SHARED flag is determined after extent map merge, so here we can't rely >>> on em here. >> >> Shouldn't extent maps correspond to 1:1 disk-state. I.e. they are just >> the memory cache of the extent state. So if we merge them, shouldn't we >> also merge the on-disk extents as well ? > > Not 1:1. > > In memory one is merged maybe to save memory. > > But on-disk file extents has size limit. > For compressed one it's 128K and 128M for uncompressed one. Fair enough, however 4 extents, 16k each should warrant merging on-disk as well, no ? -- 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
Re: [PATCH 2/2] Btrfs: fix fiemap extent SHARED flag error with range clone.
On 2018年03月07日 19:27, Nikolay Borisov wrote: > > > On 7.03.2018 13:18, Qu Wenruo wrote: >> >> >> On 2018年03月07日 19:01, robbieko wrote: >>> Qu Wenruo 於 2018-03-07 18:42 寫到: On 2018年03月07日 18:33, Qu Wenruo wrote: > > > On 2018年03月07日 16:20, robbieko wrote: >> From: Robbie Ko >> >> [BUG] >> Range clone can cause fiemap to return error result. >> Like: >> # mount /dev/vdb5 /mnt/btrfs >> # dd if=ev/zero bsK count=2 oflag=dsync of=/mnt/btrfs/file >> # xfs_io -c "fiemap -v" /mnt/btrfs/file >> /mnt/btrfs/file: >> EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS >> 0: [0..63]: 4241424..4241487 64 0x1 >> >> # cloner -s $((16*1024)) /mnt/btrfs/file /mnt/btrfs/file_clone >> # xfs_io -c "fiemap -v" /mnt/btrfs/file >> /mnt/btrfs/file: >> EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS >> 0: [0..63]: 4241424..4241487 64 0x1 >> If we clone second file extent, we will get error FLAGS, >> SHARED bit is not set. >> >> [REASON] >> Btrfs only checks if the first extent in extent map is shared, >> but extent may merge. >> >> [FIX] >> Here we will check each extent with extent map range, >> if one of them is shared, extent map is shared. >> >> [PATCH RESULT] >> # xfs_io -c "fiemap -v" /mnt/btrfs/file >> /mnt/btrfs/file: >> EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS >> 0: [0..63]: 4241424..4241487 64 0x2001 >> >> Signed-off-by: Robbie Ko >> --- >> fs/btrfs/extent_io.c | 146 >> +-- >> 1 file changed, 131 insertions(+), 15 deletions(-) >> >> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c >> index 066b6df..5c6dca9 100644 >> --- a/fs/btrfs/extent_io.c >> +++ b/fs/btrfs/extent_io.c >> @@ -4394,8 +4394,8 @@ static int emit_fiemap_extent(struct >> fiemap_extent_info *fieinfo, >> */ >> if (cache->offset + cache->len =offset && >> cache->phys + cache->len =phys && >> - (cache->flags & ~FIEMAP_EXTENT_LAST) => - (flags >> & ~FIEMAP_EXTENT_LAST)) { >> + (cache->flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED)) >> => + (flags & >> ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED))) { >> cache->len +=en; >> cache->flags |=lags; >> goto try_submit_last; >> @@ -4450,6 +4450,134 @@ static int emit_last_fiemap_cache(struct >> btrfs_fs_info *fs_info, >> return ret; >> } >> >> +/* >> + * Helper to check the file range is shared. >> + * >> + * Fiemap extent will be combined with many extents, so we need to >> examine >> + * each extent, and if shared, the results are shared. >> + * >> + * Return: 0 if file range is not shared, 1 if it is shared, < 0 on >> error. >> + */ >> +static int extent_map_check_shared(struct inode *inode, u64 start, >> u64 end) >> +{ >> + struct btrfs_fs_info *fs_info =trfs_sb(inode->i_sb); >> + struct btrfs_root *root =TRFS_I(inode)->root; >> + int ret =; >> + struct extent_buffer *leaf; >> + struct btrfs_path *path; >> + struct btrfs_file_extent_item *fi; >> + struct btrfs_key found_key; >> + int check_prev =; >> + int extent_type; >> + int shared =; >> + u64 cur_offset; >> + u64 extent_end; >> + u64 ino =trfs_ino(BTRFS_I(inode)); >> + u64 disk_bytenr; >> + >> + path =trfs_alloc_path(); >> + if (!path) { >> + return -ENOMEM; >> + } >> + >> + cur_offset =tart; >> + while (1) { >> + ret =trfs_lookup_file_extent(NULL, root, path, ino, >> + cur_offset, 0); >> + if (ret < 0) >> + goto error; >> + if (ret > 0 && path->slots[0] > 0 && check_prev) { >> + leaf =ath->nodes[0]; >> + btrfs_item_key_to_cpu(leaf, &found_key, >> + path->slots[0] - 1); >> + if (found_key.objectid =ino && >> + found_key.type =BTRFS_EXTENT_DATA_KEY) >> + path->slots[0]--; >> + } >> + check_prev =; >> +next_slot: >> + leaf =ath->nodes[0]; >> + if (path->slots[0] >=trfs_header_nritems(leaf)) { >> + ret =trfs_next_leaf(root, path); >> + if (ret < 0) >> + goto error; >> + if (ret > 0) >> + break; >> + leaf =ath->nodes[0]; >> + } >> + >> + disk_bytenr =; >> + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); >> + >> + if (found_key.objectid > ino) >> + break; >> +
Re: [PATCH 2/2] Btrfs: fix fiemap extent SHARED flag error with range clone.
On 7.03.2018 13:18, Qu Wenruo wrote: > > > On 2018年03月07日 19:01, robbieko wrote: >> Qu Wenruo 於 2018-03-07 18:42 寫到: >>> On 2018年03月07日 18:33, Qu Wenruo wrote: On 2018年03月07日 16:20, robbieko wrote: > From: Robbie Ko > > [BUG] > Range clone can cause fiemap to return error result. > Like: > # mount /dev/vdb5 /mnt/btrfs > # dd if=/dev/zero bs=16K count=2 oflag=dsync of=/mnt/btrfs/file > # xfs_io -c "fiemap -v" /mnt/btrfs/file > /mnt/btrfs/file: > EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS > 0: [0..63]: 4241424..4241487 64 0x1 > > # cloner -s $((16*1024)) /mnt/btrfs/file /mnt/btrfs/file_clone > # xfs_io -c "fiemap -v" /mnt/btrfs/file > /mnt/btrfs/file: > EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS > 0: [0..63]: 4241424..4241487 64 0x1 > If we clone second file extent, we will get error FLAGS, > SHARED bit is not set. > > [REASON] > Btrfs only checks if the first extent in extent map is shared, > but extent may merge. > > [FIX] > Here we will check each extent with extent map range, > if one of them is shared, extent map is shared. > > [PATCH RESULT] > # xfs_io -c "fiemap -v" /mnt/btrfs/file > /mnt/btrfs/file: > EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS > 0: [0..63]: 4241424..4241487 64 0x2001 > > Signed-off-by: Robbie Ko > --- > fs/btrfs/extent_io.c | 146 > +-- > 1 file changed, 131 insertions(+), 15 deletions(-) > > diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c > index 066b6df..5c6dca9 100644 > --- a/fs/btrfs/extent_io.c > +++ b/fs/btrfs/extent_io.c > @@ -4394,8 +4394,8 @@ static int emit_fiemap_extent(struct > fiemap_extent_info *fieinfo, > */ > if (cache->offset + cache->len == offset && > cache->phys + cache->len == phys && > - (cache->flags & ~FIEMAP_EXTENT_LAST) == > - (flags & ~FIEMAP_EXTENT_LAST)) { > + (cache->flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED)) == > + (flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED))) { > cache->len += len; > cache->flags |= flags; > goto try_submit_last; > @@ -4450,6 +4450,134 @@ static int emit_last_fiemap_cache(struct > btrfs_fs_info *fs_info, > return ret; > } > > +/* > + * Helper to check the file range is shared. > + * > + * Fiemap extent will be combined with many extents, so we need to > examine > + * each extent, and if shared, the results are shared. > + * > + * Return: 0 if file range is not shared, 1 if it is shared, < 0 on > error. > + */ > +static int extent_map_check_shared(struct inode *inode, u64 start, > u64 end) > +{ > + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); > + struct btrfs_root *root = BTRFS_I(inode)->root; > + int ret = 0; > + struct extent_buffer *leaf; > + struct btrfs_path *path; > + struct btrfs_file_extent_item *fi; > + struct btrfs_key found_key; > + int check_prev = 1; > + int extent_type; > + int shared = 0; > + u64 cur_offset; > + u64 extent_end; > + u64 ino = btrfs_ino(BTRFS_I(inode)); > + u64 disk_bytenr; > + > + path = btrfs_alloc_path(); > + if (!path) { > + return -ENOMEM; > + } > + > + cur_offset = start; > + while (1) { > + ret = btrfs_lookup_file_extent(NULL, root, path, ino, > + cur_offset, 0); > + if (ret < 0) > + goto error; > + if (ret > 0 && path->slots[0] > 0 && check_prev) { > + leaf = path->nodes[0]; > + btrfs_item_key_to_cpu(leaf, &found_key, > + path->slots[0] - 1); > + if (found_key.objectid == ino && > + found_key.type == BTRFS_EXTENT_DATA_KEY) > + path->slots[0]--; > + } > + check_prev = 0; > +next_slot: > + leaf = path->nodes[0]; > + if (path->slots[0] >= btrfs_header_nritems(leaf)) { > + ret = btrfs_next_leaf(root, path); > + if (ret < 0) > + goto error; > + if (ret > 0) > + break; > + leaf = path->nodes[0]; > + } > + > + disk_bytenr = 0; > + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); > + > + if (found_key.objectid > ino) > + break; > + if (WARN_ON_ONCE(found_key.objectid < ino) || > + found_key.type < BTRFS_EXTENT_DATA_KEY) { > + path->slots[0]++;
Re: [PATCH 2/2] Btrfs: fix fiemap extent SHARED flag error with range clone.
On 2018年03月07日 19:01, robbieko wrote: > Qu Wenruo 於 2018-03-07 18:42 寫到: >> On 2018年03月07日 18:33, Qu Wenruo wrote: >>> >>> >>> On 2018年03月07日 16:20, robbieko wrote: From: Robbie Ko [BUG] Range clone can cause fiemap to return error result. Like: # mount /dev/vdb5 /mnt/btrfs # dd if=/dev/zero bs=16K count=2 oflag=dsync of=/mnt/btrfs/file # xfs_io -c "fiemap -v" /mnt/btrfs/file /mnt/btrfs/file: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..63]: 4241424..4241487 64 0x1 # cloner -s $((16*1024)) /mnt/btrfs/file /mnt/btrfs/file_clone # xfs_io -c "fiemap -v" /mnt/btrfs/file /mnt/btrfs/file: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..63]: 4241424..4241487 64 0x1 If we clone second file extent, we will get error FLAGS, SHARED bit is not set. [REASON] Btrfs only checks if the first extent in extent map is shared, but extent may merge. [FIX] Here we will check each extent with extent map range, if one of them is shared, extent map is shared. [PATCH RESULT] # xfs_io -c "fiemap -v" /mnt/btrfs/file /mnt/btrfs/file: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..63]: 4241424..4241487 64 0x2001 Signed-off-by: Robbie Ko --- fs/btrfs/extent_io.c | 146 +-- 1 file changed, 131 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 066b6df..5c6dca9 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4394,8 +4394,8 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo, */ if (cache->offset + cache->len == offset && cache->phys + cache->len == phys && - (cache->flags & ~FIEMAP_EXTENT_LAST) == - (flags & ~FIEMAP_EXTENT_LAST)) { + (cache->flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED)) == + (flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED))) { cache->len += len; cache->flags |= flags; goto try_submit_last; @@ -4450,6 +4450,134 @@ static int emit_last_fiemap_cache(struct btrfs_fs_info *fs_info, return ret; } +/* + * Helper to check the file range is shared. + * + * Fiemap extent will be combined with many extents, so we need to examine + * each extent, and if shared, the results are shared. + * + * Return: 0 if file range is not shared, 1 if it is shared, < 0 on error. + */ +static int extent_map_check_shared(struct inode *inode, u64 start, u64 end) +{ + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + struct btrfs_root *root = BTRFS_I(inode)->root; + int ret = 0; + struct extent_buffer *leaf; + struct btrfs_path *path; + struct btrfs_file_extent_item *fi; + struct btrfs_key found_key; + int check_prev = 1; + int extent_type; + int shared = 0; + u64 cur_offset; + u64 extent_end; + u64 ino = btrfs_ino(BTRFS_I(inode)); + u64 disk_bytenr; + + path = btrfs_alloc_path(); + if (!path) { + return -ENOMEM; + } + + cur_offset = start; + while (1) { + ret = btrfs_lookup_file_extent(NULL, root, path, ino, + cur_offset, 0); + if (ret < 0) + goto error; + if (ret > 0 && path->slots[0] > 0 && check_prev) { + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, + path->slots[0] - 1); + if (found_key.objectid == ino && + found_key.type == BTRFS_EXTENT_DATA_KEY) + path->slots[0]--; + } + check_prev = 0; +next_slot: + leaf = path->nodes[0]; + if (path->slots[0] >= btrfs_header_nritems(leaf)) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto error; + if (ret > 0) + break; + leaf = path->nodes[0]; + } + + disk_bytenr = 0; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + + if (found_key.objectid > ino) + break; + if (WARN_ON_ONCE(found_key.objectid < ino) || + found_key.type < BTRFS_EXTENT_DATA_KEY) { + path->slots[0]++; + goto next_slot; + } + if (found_key.type > BTRFS_EXTENT_DATA_KEY || + found_key.offset > end) + break; +
Re: [PATCH 2/2] Btrfs: fix fiemap extent SHARED flag error with range clone.
Qu Wenruo 於 2018-03-07 18:42 寫到: On 2018年03月07日 18:33, Qu Wenruo wrote: On 2018年03月07日 16:20, robbieko wrote: From: Robbie Ko [BUG] Range clone can cause fiemap to return error result. Like: # mount /dev/vdb5 /mnt/btrfs # dd if=/dev/zero bs=16K count=2 oflag=dsync of=/mnt/btrfs/file # xfs_io -c "fiemap -v" /mnt/btrfs/file /mnt/btrfs/file: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..63]: 4241424..424148764 0x1 # cloner -s $((16*1024)) /mnt/btrfs/file /mnt/btrfs/file_clone # xfs_io -c "fiemap -v" /mnt/btrfs/file /mnt/btrfs/file: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..63]: 4241424..424148764 0x1 If we clone second file extent, we will get error FLAGS, SHARED bit is not set. [REASON] Btrfs only checks if the first extent in extent map is shared, but extent may merge. [FIX] Here we will check each extent with extent map range, if one of them is shared, extent map is shared. [PATCH RESULT] # xfs_io -c "fiemap -v" /mnt/btrfs/file /mnt/btrfs/file: EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS 0: [0..63]: 4241424..424148764 0x2001 Signed-off-by: Robbie Ko --- fs/btrfs/extent_io.c | 146 +-- 1 file changed, 131 insertions(+), 15 deletions(-) diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index 066b6df..5c6dca9 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c @@ -4394,8 +4394,8 @@ static int emit_fiemap_extent(struct fiemap_extent_info *fieinfo, */ if (cache->offset + cache->len == offset && cache->phys + cache->len == phys && - (cache->flags & ~FIEMAP_EXTENT_LAST) == - (flags & ~FIEMAP_EXTENT_LAST)) { + (cache->flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED)) == + (flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED))) { cache->len += len; cache->flags |= flags; goto try_submit_last; @@ -4450,6 +4450,134 @@ static int emit_last_fiemap_cache(struct btrfs_fs_info *fs_info, return ret; } +/* + * Helper to check the file range is shared. + * + * Fiemap extent will be combined with many extents, so we need to examine + * each extent, and if shared, the results are shared. + * + * Return: 0 if file range is not shared, 1 if it is shared, < 0 on error. + */ +static int extent_map_check_shared(struct inode *inode, u64 start, u64 end) +{ + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); + struct btrfs_root *root = BTRFS_I(inode)->root; + int ret = 0; + struct extent_buffer *leaf; + struct btrfs_path *path; + struct btrfs_file_extent_item *fi; + struct btrfs_key found_key; + int check_prev = 1; + int extent_type; + int shared = 0; + u64 cur_offset; + u64 extent_end; + u64 ino = btrfs_ino(BTRFS_I(inode)); + u64 disk_bytenr; + + path = btrfs_alloc_path(); + if (!path) { + return -ENOMEM; + } + + cur_offset = start; + while (1) { + ret = btrfs_lookup_file_extent(NULL, root, path, ino, + cur_offset, 0); + if (ret < 0) + goto error; + if (ret > 0 && path->slots[0] > 0 && check_prev) { + leaf = path->nodes[0]; + btrfs_item_key_to_cpu(leaf, &found_key, + path->slots[0] - 1); + if (found_key.objectid == ino && + found_key.type == BTRFS_EXTENT_DATA_KEY) + path->slots[0]--; + } + check_prev = 0; +next_slot: + leaf = path->nodes[0]; + if (path->slots[0] >= btrfs_header_nritems(leaf)) { + ret = btrfs_next_leaf(root, path); + if (ret < 0) + goto error; + if (ret > 0) + break; + leaf = path->nodes[0]; + } + + disk_bytenr = 0; + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); + + if (found_key.objectid > ino) + break; + if (WARN_ON_ONCE(found_key.objectid < ino) || + found_key.type < BTRFS_EXTENT_DATA_KEY) { + path->slots[0]++; + goto next_slot; + } + if (found_key.type > BTRFS_EXTENT_DATA_KEY || + found_key.offset > end) + break; + + fi = btrfs_item_ptr(leaf, path->slots[0], + struct btrfs_file_extent_item); + extent_type = btrfs_file_extent_type(leaf, fi); + + if (extent_type == BTRFS_
Re: [PATCH 2/2] Btrfs: fix fiemap extent SHARED flag error with range clone.
On 2018年03月07日 18:33, Qu Wenruo wrote: > > > On 2018年03月07日 16:20, robbieko wrote: >> From: Robbie Ko >> >> [BUG] >> Range clone can cause fiemap to return error result. >> Like: >> # mount /dev/vdb5 /mnt/btrfs >> # dd if=/dev/zero bs=16K count=2 oflag=dsync of=/mnt/btrfs/file >> # xfs_io -c "fiemap -v" /mnt/btrfs/file >> /mnt/btrfs/file: >> EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS >>0: [0..63]: 4241424..424148764 0x1 >> >> # cloner -s $((16*1024)) /mnt/btrfs/file /mnt/btrfs/file_clone >> # xfs_io -c "fiemap -v" /mnt/btrfs/file >> /mnt/btrfs/file: >> EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS >>0: [0..63]: 4241424..424148764 0x1 >> If we clone second file extent, we will get error FLAGS, >> SHARED bit is not set. >> >> [REASON] >> Btrfs only checks if the first extent in extent map is shared, >> but extent may merge. >> >> [FIX] >> Here we will check each extent with extent map range, >> if one of them is shared, extent map is shared. >> >> [PATCH RESULT] >> # xfs_io -c "fiemap -v" /mnt/btrfs/file >> /mnt/btrfs/file: >> EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS >>0: [0..63]: 4241424..424148764 0x2001 >> >> Signed-off-by: Robbie Ko >> --- >> fs/btrfs/extent_io.c | 146 >> +-- >> 1 file changed, 131 insertions(+), 15 deletions(-) >> >> diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c >> index 066b6df..5c6dca9 100644 >> --- a/fs/btrfs/extent_io.c >> +++ b/fs/btrfs/extent_io.c >> @@ -4394,8 +4394,8 @@ static int emit_fiemap_extent(struct >> fiemap_extent_info *fieinfo, >> */ >> if (cache->offset + cache->len == offset && >> cache->phys + cache->len == phys && >> -(cache->flags & ~FIEMAP_EXTENT_LAST) == >> -(flags & ~FIEMAP_EXTENT_LAST)) { >> +(cache->flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED)) == >> +(flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED))) { >> cache->len += len; >> cache->flags |= flags; >> goto try_submit_last; >> @@ -4450,6 +4450,134 @@ static int emit_last_fiemap_cache(struct >> btrfs_fs_info *fs_info, >> return ret; >> } >> >> +/* >> + * Helper to check the file range is shared. >> + * >> + * Fiemap extent will be combined with many extents, so we need to examine >> + * each extent, and if shared, the results are shared. >> + * >> + * Return: 0 if file range is not shared, 1 if it is shared, < 0 on error. >> + */ >> +static int extent_map_check_shared(struct inode *inode, u64 start, u64 end) >> +{ >> +struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); >> +struct btrfs_root *root = BTRFS_I(inode)->root; >> +int ret = 0; >> +struct extent_buffer *leaf; >> +struct btrfs_path *path; >> +struct btrfs_file_extent_item *fi; >> +struct btrfs_key found_key; >> +int check_prev = 1; >> +int extent_type; >> +int shared = 0; >> +u64 cur_offset; >> +u64 extent_end; >> +u64 ino = btrfs_ino(BTRFS_I(inode)); >> +u64 disk_bytenr; >> + >> +path = btrfs_alloc_path(); >> +if (!path) { >> +return -ENOMEM; >> +} >> + >> +cur_offset = start; >> +while (1) { >> +ret = btrfs_lookup_file_extent(NULL, root, path, ino, >> + cur_offset, 0); >> +if (ret < 0) >> +goto error; >> +if (ret > 0 && path->slots[0] > 0 && check_prev) { >> +leaf = path->nodes[0]; >> +btrfs_item_key_to_cpu(leaf, &found_key, >> + path->slots[0] - 1); >> +if (found_key.objectid == ino && >> +found_key.type == BTRFS_EXTENT_DATA_KEY) >> +path->slots[0]--; >> +} >> +check_prev = 0; >> +next_slot: >> +leaf = path->nodes[0]; >> +if (path->slots[0] >= btrfs_header_nritems(leaf)) { >> +ret = btrfs_next_leaf(root, path); >> +if (ret < 0) >> +goto error; >> +if (ret > 0) >> +break; >> +leaf = path->nodes[0]; >> +} >> + >> +disk_bytenr = 0; >> +btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); >> + >> +if (found_key.objectid > ino) >> +break; >> +if (WARN_ON_ONCE(found_key.objectid < ino) || >> +found_key.type < BTRFS_EXTENT_DATA_KEY) { >> +path->slots[0]++; >> +goto next_slot; >> +} >> +if (found_key.type > BTRFS_EXTENT_DATA_KEY || >> +found_key.offset > end) >> +break; >> + >> +fi = btrfs_item_ptr(leaf, path->slots[0], >> +
Re: [PATCH 2/2] Btrfs: fix fiemap extent SHARED flag error with range clone.
On 2018年03月07日 16:20, robbieko wrote: > From: Robbie Ko > > [BUG] > Range clone can cause fiemap to return error result. > Like: > # mount /dev/vdb5 /mnt/btrfs > # dd if=/dev/zero bs=16K count=2 oflag=dsync of=/mnt/btrfs/file > # xfs_io -c "fiemap -v" /mnt/btrfs/file > /mnt/btrfs/file: > EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS >0: [0..63]: 4241424..424148764 0x1 > > # cloner -s $((16*1024)) /mnt/btrfs/file /mnt/btrfs/file_clone > # xfs_io -c "fiemap -v" /mnt/btrfs/file > /mnt/btrfs/file: > EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS >0: [0..63]: 4241424..424148764 0x1 > If we clone second file extent, we will get error FLAGS, > SHARED bit is not set. > > [REASON] > Btrfs only checks if the first extent in extent map is shared, > but extent may merge. > > [FIX] > Here we will check each extent with extent map range, > if one of them is shared, extent map is shared. > > [PATCH RESULT] > # xfs_io -c "fiemap -v" /mnt/btrfs/file > /mnt/btrfs/file: > EXT: FILE-OFFSET BLOCK-RANGE TOTAL FLAGS >0: [0..63]: 4241424..424148764 0x2001 > > Signed-off-by: Robbie Ko > --- > fs/btrfs/extent_io.c | 146 > +-- > 1 file changed, 131 insertions(+), 15 deletions(-) > > diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c > index 066b6df..5c6dca9 100644 > --- a/fs/btrfs/extent_io.c > +++ b/fs/btrfs/extent_io.c > @@ -4394,8 +4394,8 @@ static int emit_fiemap_extent(struct fiemap_extent_info > *fieinfo, >*/ > if (cache->offset + cache->len == offset && > cache->phys + cache->len == phys && > - (cache->flags & ~FIEMAP_EXTENT_LAST) == > - (flags & ~FIEMAP_EXTENT_LAST)) { > + (cache->flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED)) == > + (flags & ~(FIEMAP_EXTENT_LAST|FIEMAP_EXTENT_SHARED))) { > cache->len += len; > cache->flags |= flags; > goto try_submit_last; > @@ -4450,6 +4450,134 @@ static int emit_last_fiemap_cache(struct > btrfs_fs_info *fs_info, > return ret; > } > > +/* > + * Helper to check the file range is shared. > + * > + * Fiemap extent will be combined with many extents, so we need to examine > + * each extent, and if shared, the results are shared. > + * > + * Return: 0 if file range is not shared, 1 if it is shared, < 0 on error. > + */ > +static int extent_map_check_shared(struct inode *inode, u64 start, u64 end) > +{ > + struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb); > + struct btrfs_root *root = BTRFS_I(inode)->root; > + int ret = 0; > + struct extent_buffer *leaf; > + struct btrfs_path *path; > + struct btrfs_file_extent_item *fi; > + struct btrfs_key found_key; > + int check_prev = 1; > + int extent_type; > + int shared = 0; > + u64 cur_offset; > + u64 extent_end; > + u64 ino = btrfs_ino(BTRFS_I(inode)); > + u64 disk_bytenr; > + > + path = btrfs_alloc_path(); > + if (!path) { > + return -ENOMEM; > + } > + > + cur_offset = start; > + while (1) { > + ret = btrfs_lookup_file_extent(NULL, root, path, ino, > +cur_offset, 0); > + if (ret < 0) > + goto error; > + if (ret > 0 && path->slots[0] > 0 && check_prev) { > + leaf = path->nodes[0]; > + btrfs_item_key_to_cpu(leaf, &found_key, > + path->slots[0] - 1); > + if (found_key.objectid == ino && > + found_key.type == BTRFS_EXTENT_DATA_KEY) > + path->slots[0]--; > + } > + check_prev = 0; > +next_slot: > + leaf = path->nodes[0]; > + if (path->slots[0] >= btrfs_header_nritems(leaf)) { > + ret = btrfs_next_leaf(root, path); > + if (ret < 0) > + goto error; > + if (ret > 0) > + break; > + leaf = path->nodes[0]; > + } > + > + disk_bytenr = 0; > + btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); > + > + if (found_key.objectid > ino) > + break; > + if (WARN_ON_ONCE(found_key.objectid < ino) || > + found_key.type < BTRFS_EXTENT_DATA_KEY) { > + path->slots[0]++; > + goto next_slot; > + } > + if (found_key.type > BTRFS_EXTENT_DATA_KEY || > + found_key.offset > end) > + break; > + > + fi = btrfs_item_ptr(leaf, path->slots[0], > + struct btrfs_file_extent_item); > + extent_type = btrfs_file_extent_type(leaf, f