diff options
author | Yan Zheng <zheng.yan@oracle.com> | 2008-08-05 13:05:02 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:06 -0400 |
commit | 7ea394f1192bee1af67ea4762c88ef4b7b0487a8 (patch) | |
tree | e2c593d054d802bc71e86508a5b7523ff80cc1ea /fs | |
parent | 00e4e6b33a0f78aab4b788d6d31c884fd8bf88da (diff) |
Btrfs: Fix nodatacow for the new data=ordered mode
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/ctree.h | 3 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 11 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 60 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 1 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.c | 16 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.h | 6 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 11 |
7 files changed, 74 insertions, 34 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 116aee21bf77..f90e5a7ac161 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1403,7 +1403,8 @@ static inline struct dentry *fdentry(struct file *file) { | |||
1403 | } | 1403 | } |
1404 | 1404 | ||
1405 | /* extent-tree.c */ | 1405 | /* extent-tree.c */ |
1406 | int btrfs_cross_ref_exists(struct btrfs_root *root, | 1406 | int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans, |
1407 | struct btrfs_root *root, | ||
1407 | struct btrfs_key *key, u64 bytenr); | 1408 | struct btrfs_key *key, u64 bytenr); |
1408 | int btrfs_extent_post_op(struct btrfs_trans_handle *trans, | 1409 | int btrfs_extent_post_op(struct btrfs_trans_handle *trans, |
1409 | struct btrfs_root *root); | 1410 | struct btrfs_root *root); |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 33cb2ac4cb28..fff219ed61d9 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -893,10 +893,10 @@ out: | |||
893 | return ret; | 893 | return ret; |
894 | } | 894 | } |
895 | 895 | ||
896 | int btrfs_cross_ref_exists(struct btrfs_root *root, | 896 | int btrfs_cross_ref_exists(struct btrfs_trans_handle *trans, |
897 | struct btrfs_root *root, | ||
897 | struct btrfs_key *key, u64 bytenr) | 898 | struct btrfs_key *key, u64 bytenr) |
898 | { | 899 | { |
899 | struct btrfs_trans_handle *trans; | ||
900 | struct btrfs_root *old_root; | 900 | struct btrfs_root *old_root; |
901 | struct btrfs_path *path = NULL; | 901 | struct btrfs_path *path = NULL; |
902 | struct extent_buffer *eb; | 902 | struct extent_buffer *eb; |
@@ -908,6 +908,7 @@ int btrfs_cross_ref_exists(struct btrfs_root *root, | |||
908 | int level; | 908 | int level; |
909 | int ret; | 909 | int ret; |
910 | 910 | ||
911 | BUG_ON(trans == NULL); | ||
911 | BUG_ON(key->type != BTRFS_EXTENT_DATA_KEY); | 912 | BUG_ON(key->type != BTRFS_EXTENT_DATA_KEY); |
912 | ret = get_reference_status(root, bytenr, 0, key->objectid, | 913 | ret = get_reference_status(root, bytenr, 0, key->objectid, |
913 | &min_generation, &ref_count); | 914 | &min_generation, &ref_count); |
@@ -917,7 +918,6 @@ int btrfs_cross_ref_exists(struct btrfs_root *root, | |||
917 | if (ref_count != 1) | 918 | if (ref_count != 1) |
918 | return 1; | 919 | return 1; |
919 | 920 | ||
920 | trans = btrfs_start_transaction(root, 0); | ||
921 | old_root = root->dirty_root->root; | 921 | old_root = root->dirty_root->root; |
922 | ref_generation = old_root->root_key.offset; | 922 | ref_generation = old_root->root_key.offset; |
923 | 923 | ||
@@ -973,7 +973,6 @@ int btrfs_cross_ref_exists(struct btrfs_root *root, | |||
973 | out: | 973 | out: |
974 | if (path) | 974 | if (path) |
975 | btrfs_free_path(path); | 975 | btrfs_free_path(path); |
976 | btrfs_end_transaction(trans, root); | ||
977 | return ret; | 976 | return ret; |
978 | } | 977 | } |
979 | 978 | ||
@@ -3320,7 +3319,7 @@ again: | |||
3320 | mutex_unlock(&root->fs_info->alloc_mutex); | 3319 | mutex_unlock(&root->fs_info->alloc_mutex); |
3321 | 3320 | ||
3322 | btrfs_start_delalloc_inodes(root); | 3321 | btrfs_start_delalloc_inodes(root); |
3323 | btrfs_wait_ordered_extents(tree_root); | 3322 | btrfs_wait_ordered_extents(tree_root, 0); |
3324 | 3323 | ||
3325 | mutex_lock(&root->fs_info->alloc_mutex); | 3324 | mutex_lock(&root->fs_info->alloc_mutex); |
3326 | 3325 | ||
@@ -3407,7 +3406,7 @@ next: | |||
3407 | btrfs_clean_old_snapshots(tree_root); | 3406 | btrfs_clean_old_snapshots(tree_root); |
3408 | 3407 | ||
3409 | btrfs_start_delalloc_inodes(root); | 3408 | btrfs_start_delalloc_inodes(root); |
3410 | btrfs_wait_ordered_extents(tree_root); | 3409 | btrfs_wait_ordered_extents(tree_root, 0); |
3411 | 3410 | ||
3412 | trans = btrfs_start_transaction(tree_root, 1); | 3411 | trans = btrfs_start_transaction(tree_root, 1); |
3413 | btrfs_commit_transaction(trans, tree_root); | 3412 | btrfs_commit_transaction(trans, tree_root); |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 4d8ffc01931e..c33053ba3816 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -166,7 +166,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) | |||
166 | 166 | ||
167 | cur_alloc_size = ins.offset; | 167 | cur_alloc_size = ins.offset; |
168 | ret = btrfs_add_ordered_extent(inode, start, ins.objectid, | 168 | ret = btrfs_add_ordered_extent(inode, start, ins.objectid, |
169 | ins.offset); | 169 | ins.offset, 0); |
170 | BUG_ON(ret); | 170 | BUG_ON(ret); |
171 | if (num_bytes < cur_alloc_size) { | 171 | if (num_bytes < cur_alloc_size) { |
172 | printk("num_bytes %Lu cur_alloc %Lu\n", num_bytes, | 172 | printk("num_bytes %Lu cur_alloc %Lu\n", num_bytes, |
@@ -187,31 +187,32 @@ static int run_delalloc_nocow(struct inode *inode, u64 start, u64 end) | |||
187 | u64 extent_start; | 187 | u64 extent_start; |
188 | u64 extent_end; | 188 | u64 extent_end; |
189 | u64 bytenr; | 189 | u64 bytenr; |
190 | u64 cow_end; | ||
191 | u64 loops = 0; | 190 | u64 loops = 0; |
192 | u64 total_fs_bytes; | 191 | u64 total_fs_bytes; |
193 | struct btrfs_root *root = BTRFS_I(inode)->root; | 192 | struct btrfs_root *root = BTRFS_I(inode)->root; |
194 | struct btrfs_block_group_cache *block_group; | 193 | struct btrfs_block_group_cache *block_group; |
194 | struct btrfs_trans_handle *trans; | ||
195 | struct extent_buffer *leaf; | 195 | struct extent_buffer *leaf; |
196 | int found_type; | 196 | int found_type; |
197 | struct btrfs_path *path; | 197 | struct btrfs_path *path; |
198 | struct btrfs_file_extent_item *item; | 198 | struct btrfs_file_extent_item *item; |
199 | int ret; | 199 | int ret; |
200 | int err; | 200 | int err = 0; |
201 | struct btrfs_key found_key; | 201 | struct btrfs_key found_key; |
202 | 202 | ||
203 | total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); | 203 | total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); |
204 | path = btrfs_alloc_path(); | 204 | path = btrfs_alloc_path(); |
205 | BUG_ON(!path); | 205 | BUG_ON(!path); |
206 | trans = btrfs_join_transaction(root, 1); | ||
207 | BUG_ON(!trans); | ||
206 | again: | 208 | again: |
207 | ret = btrfs_lookup_file_extent(NULL, root, path, | 209 | ret = btrfs_lookup_file_extent(NULL, root, path, |
208 | inode->i_ino, start, 0); | 210 | inode->i_ino, start, 0); |
209 | if (ret < 0) { | 211 | if (ret < 0) { |
210 | btrfs_free_path(path); | 212 | err = ret; |
211 | return ret; | 213 | goto out; |
212 | } | 214 | } |
213 | 215 | ||
214 | cow_end = end; | ||
215 | if (ret != 0) { | 216 | if (ret != 0) { |
216 | if (path->slots[0] == 0) | 217 | if (path->slots[0] == 0) |
217 | goto not_found; | 218 | goto not_found; |
@@ -244,12 +245,11 @@ again: | |||
244 | if (start < extent_start || start >= extent_end) | 245 | if (start < extent_start || start >= extent_end) |
245 | goto not_found; | 246 | goto not_found; |
246 | 247 | ||
247 | cow_end = min(end, extent_end - 1); | ||
248 | bytenr = btrfs_file_extent_disk_bytenr(leaf, item); | 248 | bytenr = btrfs_file_extent_disk_bytenr(leaf, item); |
249 | if (bytenr == 0) | 249 | if (bytenr == 0) |
250 | goto not_found; | 250 | goto not_found; |
251 | 251 | ||
252 | if (btrfs_cross_ref_exists(root, &found_key, bytenr)) | 252 | if (btrfs_cross_ref_exists(trans, root, &found_key, bytenr)) |
253 | goto not_found; | 253 | goto not_found; |
254 | /* | 254 | /* |
255 | * we may be called by the resizer, make sure we're inside | 255 | * we may be called by the resizer, make sure we're inside |
@@ -260,24 +260,32 @@ again: | |||
260 | if (!block_group || block_group->ro) | 260 | if (!block_group || block_group->ro) |
261 | goto not_found; | 261 | goto not_found; |
262 | 262 | ||
263 | bytenr += btrfs_file_extent_offset(leaf, item); | ||
264 | extent_num_bytes = min(end + 1, extent_end) - start; | ||
265 | ret = btrfs_add_ordered_extent(inode, start, bytenr, | ||
266 | extent_num_bytes, 1); | ||
267 | if (ret) { | ||
268 | err = ret; | ||
269 | goto out; | ||
270 | } | ||
271 | |||
272 | btrfs_release_path(root, path); | ||
263 | start = extent_end; | 273 | start = extent_end; |
274 | if (start <= end) { | ||
275 | loops++; | ||
276 | goto again; | ||
277 | } | ||
264 | } else { | 278 | } else { |
265 | goto not_found; | 279 | not_found: |
266 | } | 280 | btrfs_end_transaction(trans, root); |
267 | loop: | ||
268 | if (start > end) { | ||
269 | btrfs_free_path(path); | 281 | btrfs_free_path(path); |
270 | return 0; | 282 | return cow_file_range(inode, start, end); |
271 | } | 283 | } |
272 | btrfs_release_path(root, path); | 284 | out: |
273 | loops++; | 285 | WARN_ON(err); |
274 | goto again; | 286 | btrfs_end_transaction(trans, root); |
275 | 287 | btrfs_free_path(path); | |
276 | not_found: | 288 | return err; |
277 | btrfs_release_path(root, path); | ||
278 | cow_file_range(inode, start, end); | ||
279 | start = end + 1; | ||
280 | goto loop; | ||
281 | } | 289 | } |
282 | 290 | ||
283 | static int run_delalloc_range(struct inode *inode, u64 start, u64 end) | 291 | static int run_delalloc_range(struct inode *inode, u64 start, u64 end) |
@@ -385,6 +393,11 @@ int btrfs_submit_bio_hook(struct inode *inode, int rw, struct bio *bio, | |||
385 | goto mapit; | 393 | goto mapit; |
386 | } | 394 | } |
387 | 395 | ||
396 | if (btrfs_test_opt(root, NODATASUM) || | ||
397 | btrfs_test_flag(inode, NODATASUM)) { | ||
398 | goto mapit; | ||
399 | } | ||
400 | |||
388 | return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, | 401 | return btrfs_wq_submit_bio(BTRFS_I(inode)->root->fs_info, |
389 | inode, rw, bio, mirror_num, | 402 | inode, rw, bio, mirror_num, |
390 | __btrfs_submit_bio_hook); | 403 | __btrfs_submit_bio_hook); |
@@ -527,6 +540,8 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
527 | 540 | ||
528 | ordered_extent = btrfs_lookup_ordered_extent(inode, start); | 541 | ordered_extent = btrfs_lookup_ordered_extent(inode, start); |
529 | BUG_ON(!ordered_extent); | 542 | BUG_ON(!ordered_extent); |
543 | if (test_bit(BTRFS_ORDERED_NOCOW, &ordered_extent->flags)) | ||
544 | goto nocow; | ||
530 | 545 | ||
531 | lock_extent(io_tree, ordered_extent->file_offset, | 546 | lock_extent(io_tree, ordered_extent->file_offset, |
532 | ordered_extent->file_offset + ordered_extent->len - 1, | 547 | ordered_extent->file_offset + ordered_extent->len - 1, |
@@ -567,6 +582,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
567 | unlock_extent(io_tree, ordered_extent->file_offset, | 582 | unlock_extent(io_tree, ordered_extent->file_offset, |
568 | ordered_extent->file_offset + ordered_extent->len - 1, | 583 | ordered_extent->file_offset + ordered_extent->len - 1, |
569 | GFP_NOFS); | 584 | GFP_NOFS); |
585 | nocow: | ||
570 | add_pending_csums(trans, inode, ordered_extent->file_offset, | 586 | add_pending_csums(trans, inode, ordered_extent->file_offset, |
571 | &ordered_extent->list); | 587 | &ordered_extent->list); |
572 | 588 | ||
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 3932c7cd0fae..59b64c738fd1 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/bit_spinlock.h> | 36 | #include <linux/bit_spinlock.h> |
37 | #include <linux/version.h> | 37 | #include <linux/version.h> |
38 | #include <linux/xattr.h> | 38 | #include <linux/xattr.h> |
39 | #include <linux/vmalloc.h> | ||
39 | #include "ctree.h" | 40 | #include "ctree.h" |
40 | #include "disk-io.h" | 41 | #include "disk-io.h" |
41 | #include "transaction.h" | 42 | #include "transaction.h" |
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index db200e6baf7e..da6d43eb41db 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
@@ -152,7 +152,7 @@ static inline struct rb_node *tree_search(struct btrfs_ordered_inode_tree *tree, | |||
152 | * inserted. | 152 | * inserted. |
153 | */ | 153 | */ |
154 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | 154 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, |
155 | u64 start, u64 len) | 155 | u64 start, u64 len, int nocow) |
156 | { | 156 | { |
157 | struct btrfs_ordered_inode_tree *tree; | 157 | struct btrfs_ordered_inode_tree *tree; |
158 | struct rb_node *node; | 158 | struct rb_node *node; |
@@ -168,6 +168,8 @@ int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | |||
168 | entry->start = start; | 168 | entry->start = start; |
169 | entry->len = len; | 169 | entry->len = len; |
170 | entry->inode = inode; | 170 | entry->inode = inode; |
171 | if (nocow) | ||
172 | set_bit(BTRFS_ORDERED_NOCOW, &entry->flags); | ||
171 | 173 | ||
172 | /* one ref for the tree */ | 174 | /* one ref for the tree */ |
173 | atomic_set(&entry->refs, 1); | 175 | atomic_set(&entry->refs, 1); |
@@ -303,10 +305,11 @@ int btrfs_remove_ordered_extent(struct inode *inode, | |||
303 | return 0; | 305 | return 0; |
304 | } | 306 | } |
305 | 307 | ||
306 | int btrfs_wait_ordered_extents(struct btrfs_root *root) | 308 | int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only) |
307 | { | 309 | { |
308 | struct list_head splice; | 310 | struct list_head splice; |
309 | struct list_head *cur; | 311 | struct list_head *cur; |
312 | struct list_head *tmp; | ||
310 | struct btrfs_ordered_extent *ordered; | 313 | struct btrfs_ordered_extent *ordered; |
311 | struct inode *inode; | 314 | struct inode *inode; |
312 | 315 | ||
@@ -314,10 +317,16 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root) | |||
314 | 317 | ||
315 | spin_lock(&root->fs_info->ordered_extent_lock); | 318 | spin_lock(&root->fs_info->ordered_extent_lock); |
316 | list_splice_init(&root->fs_info->ordered_extents, &splice); | 319 | list_splice_init(&root->fs_info->ordered_extents, &splice); |
317 | while(!list_empty(&splice)) { | 320 | list_for_each_safe(cur, tmp, &splice) { |
318 | cur = splice.next; | 321 | cur = splice.next; |
319 | ordered = list_entry(cur, struct btrfs_ordered_extent, | 322 | ordered = list_entry(cur, struct btrfs_ordered_extent, |
320 | root_extent_list); | 323 | root_extent_list); |
324 | if (nocow_only && | ||
325 | !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) { | ||
326 | cond_resched_lock(&root->fs_info->ordered_extent_lock); | ||
327 | continue; | ||
328 | } | ||
329 | |||
321 | list_del_init(&ordered->root_extent_list); | 330 | list_del_init(&ordered->root_extent_list); |
322 | atomic_inc(&ordered->refs); | 331 | atomic_inc(&ordered->refs); |
323 | inode = ordered->inode; | 332 | inode = ordered->inode; |
@@ -338,6 +347,7 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root) | |||
338 | 347 | ||
339 | spin_lock(&root->fs_info->ordered_extent_lock); | 348 | spin_lock(&root->fs_info->ordered_extent_lock); |
340 | } | 349 | } |
350 | list_splice_init(&splice, &root->fs_info->ordered_extents); | ||
341 | spin_unlock(&root->fs_info->ordered_extent_lock); | 351 | spin_unlock(&root->fs_info->ordered_extent_lock); |
342 | return 0; | 352 | return 0; |
343 | } | 353 | } |
diff --git a/fs/btrfs/ordered-data.h b/fs/btrfs/ordered-data.h index 5efe6b63c74c..fd45519f30a8 100644 --- a/fs/btrfs/ordered-data.h +++ b/fs/btrfs/ordered-data.h | |||
@@ -64,6 +64,8 @@ struct btrfs_ordered_sum { | |||
64 | 64 | ||
65 | #define BTRFS_ORDERED_COMPLETE 1 /* set when removed from the tree */ | 65 | #define BTRFS_ORDERED_COMPLETE 1 /* set when removed from the tree */ |
66 | 66 | ||
67 | #define BTRFS_ORDERED_NOCOW 2 /* set when we want to write in place */ | ||
68 | |||
67 | struct btrfs_ordered_extent { | 69 | struct btrfs_ordered_extent { |
68 | /* logical offset in the file */ | 70 | /* logical offset in the file */ |
69 | u64 file_offset; | 71 | u64 file_offset; |
@@ -125,7 +127,7 @@ int btrfs_remove_ordered_extent(struct inode *inode, | |||
125 | int btrfs_dec_test_ordered_pending(struct inode *inode, | 127 | int btrfs_dec_test_ordered_pending(struct inode *inode, |
126 | u64 file_offset, u64 io_size); | 128 | u64 file_offset, u64 io_size); |
127 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, | 129 | int btrfs_add_ordered_extent(struct inode *inode, u64 file_offset, |
128 | u64 start, u64 len); | 130 | u64 start, u64 len, int nocow); |
129 | int btrfs_add_ordered_sum(struct inode *inode, | 131 | int btrfs_add_ordered_sum(struct inode *inode, |
130 | struct btrfs_ordered_extent *entry, | 132 | struct btrfs_ordered_extent *entry, |
131 | struct btrfs_ordered_sum *sum); | 133 | struct btrfs_ordered_sum *sum); |
@@ -143,5 +145,5 @@ int btrfs_wait_on_page_writeback_range(struct address_space *mapping, | |||
143 | pgoff_t start, pgoff_t end); | 145 | pgoff_t start, pgoff_t end); |
144 | int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start, | 146 | int btrfs_fdatawrite_range(struct address_space *mapping, loff_t start, |
145 | loff_t end, int sync_mode); | 147 | loff_t end, int sync_mode); |
146 | int btrfs_wait_ordered_extents(struct btrfs_root *root); | 148 | int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only); |
147 | #endif | 149 | #endif |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index ebf5362da1d2..9d3d08e9f8d1 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -438,6 +438,7 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
438 | 438 | ||
439 | free_extent_buffer(root->commit_root); | 439 | free_extent_buffer(root->commit_root); |
440 | root->commit_root = NULL; | 440 | root->commit_root = NULL; |
441 | root->dirty_root = NULL; | ||
441 | 442 | ||
442 | spin_lock(&root->list_lock); | 443 | spin_lock(&root->list_lock); |
443 | list_del_init(&dirty->root->dead_list); | 444 | list_del_init(&dirty->root->dead_list); |
@@ -461,6 +462,7 @@ static noinline int add_dirty_roots(struct btrfs_trans_handle *trans, | |||
461 | sizeof(struct btrfs_disk_key)); | 462 | sizeof(struct btrfs_disk_key)); |
462 | root->root_item.drop_level = 0; | 463 | root->root_item.drop_level = 0; |
463 | root->commit_root = NULL; | 464 | root->commit_root = NULL; |
465 | root->dirty_root = NULL; | ||
464 | root->root_key.offset = root->fs_info->generation; | 466 | root->root_key.offset = root->fs_info->generation; |
465 | btrfs_set_root_bytenr(&root->root_item, | 467 | btrfs_set_root_bytenr(&root->root_item, |
466 | root->node->start); | 468 | root->node->start); |
@@ -762,7 +764,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
762 | } | 764 | } |
763 | 765 | ||
764 | do { | 766 | do { |
767 | int snap_pending = 0; | ||
765 | joined = cur_trans->num_joined; | 768 | joined = cur_trans->num_joined; |
769 | if (!list_empty(&trans->transaction->pending_snapshots)) | ||
770 | snap_pending = 1; | ||
771 | |||
766 | WARN_ON(cur_trans != trans->transaction); | 772 | WARN_ON(cur_trans != trans->transaction); |
767 | prepare_to_wait(&cur_trans->writer_wait, &wait, | 773 | prepare_to_wait(&cur_trans->writer_wait, &wait, |
768 | TASK_UNINTERRUPTIBLE); | 774 | TASK_UNINTERRUPTIBLE); |
@@ -774,6 +780,11 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans, | |||
774 | 780 | ||
775 | mutex_unlock(&root->fs_info->trans_mutex); | 781 | mutex_unlock(&root->fs_info->trans_mutex); |
776 | 782 | ||
783 | if (snap_pending) { | ||
784 | ret = btrfs_wait_ordered_extents(root, 1); | ||
785 | BUG_ON(ret); | ||
786 | } | ||
787 | |||
777 | schedule_timeout(timeout); | 788 | schedule_timeout(timeout); |
778 | 789 | ||
779 | mutex_lock(&root->fs_info->trans_mutex); | 790 | mutex_lock(&root->fs_info->trans_mutex); |