diff options
author | Liu Bo <bo.li.liu@oracle.com> | 2013-07-01 10:13:26 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@fusionio.com> | 2013-08-09 19:29:17 -0400 |
commit | e68afa49aec5f0851e550ee1de48fcc3a9bf5ef7 (patch) | |
tree | 7588f986736b53f7d6e3117a5c3afdff1f638e13 /fs/btrfs/inode.c | |
parent | 7cddc193924ef6ce679ef0977e01e96d0aedfd1d (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/btrfs/inode.c')
-rw-r--r-- | fs/btrfs/inode.c | 16 |
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); |