diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/backref.c | 94 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 9 | ||||
-rw-r--r-- | fs/btrfs/disk-io.c | 1 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 4 |
4 files changed, 62 insertions, 46 deletions
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c index 8f7d1237b7a0..7301cdb4b2cb 100644 --- a/fs/btrfs/backref.c +++ b/fs/btrfs/backref.c | |||
@@ -179,61 +179,74 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id, | |||
179 | 179 | ||
180 | static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, | 180 | static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path, |
181 | struct ulist *parents, int level, | 181 | struct ulist *parents, int level, |
182 | struct btrfs_key *key, u64 time_seq, | 182 | struct btrfs_key *key_for_search, u64 time_seq, |
183 | u64 wanted_disk_byte, | 183 | u64 wanted_disk_byte, |
184 | const u64 *extent_item_pos) | 184 | const u64 *extent_item_pos) |
185 | { | 185 | { |
186 | int ret; | 186 | int ret = 0; |
187 | int slot = path->slots[level]; | 187 | int slot; |
188 | struct extent_buffer *eb = path->nodes[level]; | 188 | struct extent_buffer *eb; |
189 | struct btrfs_key key; | ||
189 | struct btrfs_file_extent_item *fi; | 190 | struct btrfs_file_extent_item *fi; |
190 | struct extent_inode_elem *eie = NULL; | 191 | struct extent_inode_elem *eie = NULL; |
191 | u64 disk_byte; | 192 | u64 disk_byte; |
192 | u64 wanted_objectid = key->objectid; | ||
193 | 193 | ||
194 | add_parent: | 194 | if (level != 0) { |
195 | if (level == 0 && extent_item_pos) { | 195 | eb = path->nodes[level]; |
196 | fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); | 196 | ret = ulist_add(parents, eb->start, 0, GFP_NOFS); |
197 | ret = check_extent_in_eb(key, eb, fi, *extent_item_pos, &eie); | ||
198 | if (ret < 0) | 197 | if (ret < 0) |
199 | return ret; | 198 | return ret; |
200 | } | ||
201 | ret = ulist_add(parents, eb->start, (unsigned long)eie, GFP_NOFS); | ||
202 | if (ret < 0) | ||
203 | return ret; | ||
204 | |||
205 | if (level != 0) | ||
206 | return 0; | 199 | return 0; |
200 | } | ||
207 | 201 | ||
208 | /* | 202 | /* |
209 | * if the current leaf is full with EXTENT_DATA items, we must | 203 | * We normally enter this function with the path already pointing to |
210 | * check the next one if that holds a reference as well. | 204 | * the first item to check. But sometimes, we may enter it with |
211 | * ref->count cannot be used to skip this check. | 205 | * slot==nritems. In that case, go to the next leaf before we continue. |
212 | * repeat this until we don't find any additional EXTENT_DATA items. | ||
213 | */ | 206 | */ |
214 | while (1) { | 207 | if (path->slots[0] >= btrfs_header_nritems(path->nodes[0])) |
215 | eie = NULL; | ||
216 | ret = btrfs_next_old_leaf(root, path, time_seq); | 208 | ret = btrfs_next_old_leaf(root, path, time_seq); |
217 | if (ret < 0) | ||
218 | return ret; | ||
219 | if (ret) | ||
220 | return 0; | ||
221 | 209 | ||
210 | while (!ret) { | ||
222 | eb = path->nodes[0]; | 211 | eb = path->nodes[0]; |
223 | for (slot = 0; slot < btrfs_header_nritems(eb); ++slot) { | 212 | slot = path->slots[0]; |
224 | btrfs_item_key_to_cpu(eb, key, slot); | 213 | |
225 | if (key->objectid != wanted_objectid || | 214 | btrfs_item_key_to_cpu(eb, &key, slot); |
226 | key->type != BTRFS_EXTENT_DATA_KEY) | 215 | |
227 | return 0; | 216 | if (key.objectid != key_for_search->objectid || |
228 | fi = btrfs_item_ptr(eb, slot, | 217 | key.type != BTRFS_EXTENT_DATA_KEY) |
229 | struct btrfs_file_extent_item); | 218 | break; |
230 | disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); | 219 | |
231 | if (disk_byte == wanted_disk_byte) | 220 | fi = btrfs_item_ptr(eb, slot, struct btrfs_file_extent_item); |
232 | goto add_parent; | 221 | disk_byte = btrfs_file_extent_disk_bytenr(eb, fi); |
222 | |||
223 | if (disk_byte == wanted_disk_byte) { | ||
224 | eie = NULL; | ||
225 | if (extent_item_pos) { | ||
226 | ret = check_extent_in_eb(&key, eb, fi, | ||
227 | *extent_item_pos, | ||
228 | &eie); | ||
229 | if (ret < 0) | ||
230 | break; | ||
231 | } | ||
232 | if (!ret) { | ||
233 | ret = ulist_add(parents, eb->start, | ||
234 | (unsigned long)eie, GFP_NOFS); | ||
235 | if (ret < 0) | ||
236 | break; | ||
237 | if (!extent_item_pos) { | ||
238 | ret = btrfs_next_old_leaf(root, path, | ||
239 | time_seq); | ||
240 | continue; | ||
241 | } | ||
242 | } | ||
233 | } | 243 | } |
244 | ret = btrfs_next_old_item(root, path, time_seq); | ||
234 | } | 245 | } |
235 | 246 | ||
236 | return 0; | 247 | if (ret > 0) |
248 | ret = 0; | ||
249 | return ret; | ||
237 | } | 250 | } |
238 | 251 | ||
239 | /* | 252 | /* |
@@ -250,7 +263,6 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
250 | struct btrfs_path *path; | 263 | struct btrfs_path *path; |
251 | struct btrfs_root *root; | 264 | struct btrfs_root *root; |
252 | struct btrfs_key root_key; | 265 | struct btrfs_key root_key; |
253 | struct btrfs_key key = {0}; | ||
254 | struct extent_buffer *eb; | 266 | struct extent_buffer *eb; |
255 | int ret = 0; | 267 | int ret = 0; |
256 | int root_level; | 268 | int root_level; |
@@ -295,11 +307,9 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info, | |||
295 | goto out; | 307 | goto out; |
296 | } | 308 | } |
297 | 309 | ||
298 | if (level == 0) | 310 | ret = add_all_parents(root, path, parents, level, &ref->key_for_search, |
299 | btrfs_item_key_to_cpu(eb, &key, path->slots[0]); | 311 | time_seq, ref->wanted_disk_byte, |
300 | 312 | extent_item_pos); | |
301 | ret = add_all_parents(root, path, parents, level, &key, time_seq, | ||
302 | ref->wanted_disk_byte, extent_item_pos); | ||
303 | out: | 313 | out: |
304 | btrfs_free_path(path); | 314 | btrfs_free_path(path); |
305 | return ret; | 315 | return ret; |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 8b73b2d4deb7..fa5c45b39075 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -2755,13 +2755,18 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans, | |||
2755 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); | 2755 | int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path); |
2756 | int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, | 2756 | int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path, |
2757 | u64 time_seq); | 2757 | u64 time_seq); |
2758 | static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p) | 2758 | static inline int btrfs_next_old_item(struct btrfs_root *root, |
2759 | struct btrfs_path *p, u64 time_seq) | ||
2759 | { | 2760 | { |
2760 | ++p->slots[0]; | 2761 | ++p->slots[0]; |
2761 | if (p->slots[0] >= btrfs_header_nritems(p->nodes[0])) | 2762 | if (p->slots[0] >= btrfs_header_nritems(p->nodes[0])) |
2762 | return btrfs_next_leaf(root, p); | 2763 | return btrfs_next_old_leaf(root, p, time_seq); |
2763 | return 0; | 2764 | return 0; |
2764 | } | 2765 | } |
2766 | static inline int btrfs_next_item(struct btrfs_root *root, struct btrfs_path *p) | ||
2767 | { | ||
2768 | return btrfs_next_old_item(root, p, 0); | ||
2769 | } | ||
2765 | int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); | 2770 | int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path); |
2766 | int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf); | 2771 | int btrfs_leaf_free_space(struct btrfs_root *root, struct extent_buffer *leaf); |
2767 | int __must_check btrfs_drop_snapshot(struct btrfs_root *root, | 2772 | int __must_check btrfs_drop_snapshot(struct btrfs_root *root, |
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c index e1890b1d3075..7b845ff4af99 100644 --- a/fs/btrfs/disk-io.c +++ b/fs/btrfs/disk-io.c | |||
@@ -3426,6 +3426,7 @@ int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans, | |||
3426 | mutex_unlock(&head->mutex); | 3426 | mutex_unlock(&head->mutex); |
3427 | btrfs_put_delayed_ref(ref); | 3427 | btrfs_put_delayed_ref(ref); |
3428 | 3428 | ||
3429 | spin_lock(&delayed_refs->lock); | ||
3429 | continue; | 3430 | continue; |
3430 | } | 3431 | } |
3431 | 3432 | ||
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a4f02501da40..d8bb0dbc4941 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -987,7 +987,7 @@ static noinline void async_cow_start(struct btrfs_work *work) | |||
987 | async_cow->start, async_cow->end, async_cow, | 987 | async_cow->start, async_cow->end, async_cow, |
988 | &num_added); | 988 | &num_added); |
989 | if (num_added == 0) { | 989 | if (num_added == 0) { |
990 | iput(async_cow->inode); | 990 | btrfs_add_delayed_iput(async_cow->inode); |
991 | async_cow->inode = NULL; | 991 | async_cow->inode = NULL; |
992 | } | 992 | } |
993 | } | 993 | } |
@@ -1023,7 +1023,7 @@ static noinline void async_cow_free(struct btrfs_work *work) | |||
1023 | struct async_cow *async_cow; | 1023 | struct async_cow *async_cow; |
1024 | async_cow = container_of(work, struct async_cow, work); | 1024 | async_cow = container_of(work, struct async_cow, work); |
1025 | if (async_cow->inode) | 1025 | if (async_cow->inode) |
1026 | iput(async_cow->inode); | 1026 | btrfs_add_delayed_iput(async_cow->inode); |
1027 | kfree(async_cow); | 1027 | kfree(async_cow); |
1028 | } | 1028 | } |
1029 | 1029 | ||