aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLiu Bo <bo.li.liu@oracle.com>2013-07-01 10:13:26 -0400
committerChris Mason <chris.mason@fusionio.com>2013-08-09 19:29:17 -0400
commite68afa49aec5f0851e550ee1de48fcc3a9bf5ef7 (patch)
tree7588f986736b53f7d6e3117a5c3afdff1f638e13 /fs
parent7cddc193924ef6ce679ef0977e01e96d0aedfd1d (diff)
Btrfs: fix a bug of snapshot-aware defrag to make it work on partial extents
For partial extents, snapshot-aware defrag does not work as expected, since a) we use the wrong logical offset to search for parents, which should be disk_bytenr + extent_offset, not just disk_bytenr, b) 'offset' returned by the backref walking just refers to key.offset, not the 'offset' stored in btrfs_extent_data_ref which is (key.offset - extent_offset). The reproducer: $ mkfs.btrfs sda $ mount sda /mnt $ btrfs sub create /mnt/sub $ for i in `seq 5 -1 1`; do dd if=/dev/zero of=/mnt/sub/foo bs=5k count=1 seek=$i conv=notrunc oflag=sync; done $ btrfs sub snap /mnt/sub /mnt/snap1 $ btrfs sub snap /mnt/sub /mnt/snap2 $ sync; btrfs filesystem defrag /mnt/sub/foo; $ umount /mnt $ btrfs-debug-tree sda (Here we can check whether the defrag operation is snapshot-awared. This addresses the above two problems. Signed-off-by: Liu Bo <bo.li.liu@oracle.com> Signed-off-by: Josef Bacik <jbacik@fusionio.com> Signed-off-by: Chris Mason <chris.mason@fusionio.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/inode.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 0fd7647c8932..c72033ee6017 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -2166,16 +2166,23 @@ static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id,
2166 if (btrfs_file_extent_disk_bytenr(leaf, extent) != old->bytenr) 2166 if (btrfs_file_extent_disk_bytenr(leaf, extent) != old->bytenr)
2167 continue; 2167 continue;
2168 2168
2169 extent_offset = btrfs_file_extent_offset(leaf, extent); 2169 /*
2170 if (key.offset - extent_offset != offset) 2170 * 'offset' refers to the exact key.offset,
2171 * NOT the 'offset' field in btrfs_extent_data_ref, ie.
2172 * (key.offset - extent_offset).
2173 */
2174 if (key.offset != offset)
2171 continue; 2175 continue;
2172 2176
2177 extent_offset = btrfs_file_extent_offset(leaf, extent);
2173 num_bytes = btrfs_file_extent_num_bytes(leaf, extent); 2178 num_bytes = btrfs_file_extent_num_bytes(leaf, extent);
2179
2174 if (extent_offset >= old->extent_offset + old->offset + 2180 if (extent_offset >= old->extent_offset + old->offset +
2175 old->len || extent_offset + num_bytes <= 2181 old->len || extent_offset + num_bytes <=
2176 old->extent_offset + old->offset) 2182 old->extent_offset + old->offset)
2177 continue; 2183 continue;
2178 2184
2185 ret = 0;
2179 break; 2186 break;
2180 } 2187 }
2181 2188
@@ -2187,7 +2194,7 @@ static noinline int record_one_backref(u64 inum, u64 offset, u64 root_id,
2187 2194
2188 backref->root_id = root_id; 2195 backref->root_id = root_id;
2189 backref->inum = inum; 2196 backref->inum = inum;
2190 backref->file_pos = offset + extent_offset; 2197 backref->file_pos = offset;
2191 backref->num_bytes = num_bytes; 2198 backref->num_bytes = num_bytes;
2192 backref->extent_offset = extent_offset; 2199 backref->extent_offset = extent_offset;
2193 backref->generation = btrfs_file_extent_generation(leaf, extent); 2200 backref->generation = btrfs_file_extent_generation(leaf, extent);
@@ -2210,7 +2217,8 @@ static noinline bool record_extent_backrefs(struct btrfs_path *path,
2210 new->path = path; 2217 new->path = path;
2211 2218
2212 list_for_each_entry_safe(old, tmp, &new->head, list) { 2219 list_for_each_entry_safe(old, tmp, &new->head, list) {
2213 ret = iterate_inodes_from_logical(old->bytenr, fs_info, 2220 ret = iterate_inodes_from_logical(old->bytenr +
2221 old->extent_offset, fs_info,
2214 path, record_one_backref, 2222 path, record_one_backref,
2215 old); 2223 old);
2216 BUG_ON(ret < 0 && ret != -ENOENT); 2224 BUG_ON(ret < 0 && ret != -ENOENT);