diff options
author | Zheng Yan <zheng.yan@oracle.com> | 2008-09-26 10:05:38 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-26 10:05:38 -0400 |
commit | 5b21f2ed3f2947b5195b65c9fdbdd9e52904cc03 (patch) | |
tree | 9af8f539ac487c163f3207bc065767c3c8b37ae7 | |
parent | e465768938f95388723b0fd3c50a0ae48173edb9 (diff) |
Btrfs: extent_map and data=ordered fixes for space balancing
* Add an EXTENT_BOUNDARY state bit to keep the writepage code
from merging data extents that are in the process of being
relocated. This allows us to do accounting for them properly.
* The balancing code relocates data extents indepdent of the underlying
inode. The extent_map code was modified to properly account for
things moving around (invalidating extent_map caches in the inode).
* Don't take the drop_mutex in the create_subvol ioctl. It isn't
required.
* Fix walking of the ordered extent list to avoid races with sys_unlink
* Change the lock ordering rules. Transaction start goes outside
the drop_mutex. This allows btrfs_commit_transaction to directly
drop the relocation trees.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r-- | fs/btrfs/ctree.c | 9 | ||||
-rw-r--r-- | fs/btrfs/ctree.h | 11 | ||||
-rw-r--r-- | fs/btrfs/extent_io.c | 13 | ||||
-rw-r--r-- | fs/btrfs/extent_io.h | 1 | ||||
-rw-r--r-- | fs/btrfs/file.c | 31 | ||||
-rw-r--r-- | fs/btrfs/inode-map.c | 4 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 52 | ||||
-rw-r--r-- | fs/btrfs/ioctl.c | 2 | ||||
-rw-r--r-- | fs/btrfs/ordered-data.c | 26 | ||||
-rw-r--r-- | fs/btrfs/transaction.c | 8 |
10 files changed, 108 insertions, 49 deletions
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c index 50aea8cb653a..f9cd40967d04 100644 --- a/fs/btrfs/ctree.c +++ b/fs/btrfs/ctree.c | |||
@@ -290,7 +290,6 @@ int noinline btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
290 | struct extent_buffer **cow_ret, u64 prealloc_dest) | 290 | struct extent_buffer **cow_ret, u64 prealloc_dest) |
291 | { | 291 | { |
292 | u64 search_start; | 292 | u64 search_start; |
293 | u64 header_trans; | ||
294 | int ret; | 293 | int ret; |
295 | 294 | ||
296 | if (trans->transaction != root->fs_info->running_transaction) { | 295 | if (trans->transaction != root->fs_info->running_transaction) { |
@@ -304,9 +303,9 @@ int noinline btrfs_cow_block(struct btrfs_trans_handle *trans, | |||
304 | WARN_ON(1); | 303 | WARN_ON(1); |
305 | } | 304 | } |
306 | 305 | ||
307 | header_trans = btrfs_header_generation(buf); | ||
308 | spin_lock(&root->fs_info->hash_lock); | 306 | spin_lock(&root->fs_info->hash_lock); |
309 | if (header_trans == trans->transid && | 307 | if (btrfs_header_generation(buf) == trans->transid && |
308 | btrfs_header_owner(buf) == root->root_key.objectid && | ||
310 | !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { | 309 | !btrfs_header_flag(buf, BTRFS_HEADER_FLAG_WRITTEN)) { |
311 | *cow_ret = buf; | 310 | *cow_ret = buf; |
312 | spin_unlock(&root->fs_info->hash_lock); | 311 | spin_unlock(&root->fs_info->hash_lock); |
@@ -1300,6 +1299,7 @@ again: | |||
1300 | /* is a cow on this block not required */ | 1299 | /* is a cow on this block not required */ |
1301 | spin_lock(&root->fs_info->hash_lock); | 1300 | spin_lock(&root->fs_info->hash_lock); |
1302 | if (btrfs_header_generation(b) == trans->transid && | 1301 | if (btrfs_header_generation(b) == trans->transid && |
1302 | btrfs_header_owner(b) == root->root_key.objectid && | ||
1303 | !btrfs_header_flag(b, BTRFS_HEADER_FLAG_WRITTEN)) { | 1303 | !btrfs_header_flag(b, BTRFS_HEADER_FLAG_WRITTEN)) { |
1304 | spin_unlock(&root->fs_info->hash_lock); | 1304 | spin_unlock(&root->fs_info->hash_lock); |
1305 | goto cow_done; | 1305 | goto cow_done; |
@@ -1396,7 +1396,8 @@ cow_done: | |||
1396 | 1396 | ||
1397 | /* this is only true while dropping a snapshot */ | 1397 | /* this is only true while dropping a snapshot */ |
1398 | if (level == lowest_level) { | 1398 | if (level == lowest_level) { |
1399 | break; | 1399 | ret = 0; |
1400 | goto done; | ||
1400 | } | 1401 | } |
1401 | 1402 | ||
1402 | blocknr = btrfs_node_blockptr(b, slot); | 1403 | blocknr = btrfs_node_blockptr(b, slot); |
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index b9f9f815ed09..3e62a1b0a1f7 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -1486,6 +1486,9 @@ static inline struct dentry *fdentry(struct file *file) | |||
1486 | 1486 | ||
1487 | /* extent-tree.c */ | 1487 | /* extent-tree.c */ |
1488 | int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len); | 1488 | int btrfs_lookup_extent(struct btrfs_root *root, u64 start, u64 len); |
1489 | int btrfs_lookup_extent_ref(struct btrfs_trans_handle *trans, | ||
1490 | struct btrfs_root *root, u64 bytenr, | ||
1491 | u64 num_bytes, u32 *refs); | ||
1489 | int btrfs_update_pinned_extents(struct btrfs_root *root, | 1492 | int btrfs_update_pinned_extents(struct btrfs_root *root, |
1490 | u64 bytenr, u64 num, int pin); | 1493 | u64 bytenr, u64 num, int pin); |
1491 | int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, | 1494 | int btrfs_drop_leaf_ref(struct btrfs_trans_handle *trans, |
@@ -1812,6 +1815,8 @@ void btrfs_destroy_inode(struct inode *inode); | |||
1812 | int btrfs_init_cachep(void); | 1815 | int btrfs_init_cachep(void); |
1813 | void btrfs_destroy_cachep(void); | 1816 | void btrfs_destroy_cachep(void); |
1814 | long btrfs_ioctl_trans_end(struct file *file); | 1817 | long btrfs_ioctl_trans_end(struct file *file); |
1818 | struct inode *btrfs_ilookup(struct super_block *s, u64 objectid, | ||
1819 | struct btrfs_root *root, int wait); | ||
1815 | struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid, | 1820 | struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid, |
1816 | struct btrfs_root *root); | 1821 | struct btrfs_root *root); |
1817 | struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, | 1822 | struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location, |
@@ -1824,13 +1829,17 @@ struct extent_map *btrfs_get_extent(struct inode *inode, struct page *page, | |||
1824 | int btrfs_update_inode(struct btrfs_trans_handle *trans, | 1829 | int btrfs_update_inode(struct btrfs_trans_handle *trans, |
1825 | struct btrfs_root *root, | 1830 | struct btrfs_root *root, |
1826 | struct inode *inode); | 1831 | struct inode *inode); |
1832 | int btrfs_orphan_add(struct btrfs_trans_handle *trans, struct inode *inode); | ||
1833 | int btrfs_orphan_del(struct btrfs_trans_handle *trans, struct inode *inode); | ||
1834 | void btrfs_orphan_cleanup(struct btrfs_root *root); | ||
1827 | 1835 | ||
1828 | /* ioctl.c */ | 1836 | /* ioctl.c */ |
1829 | long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); | 1837 | long btrfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg); |
1830 | 1838 | ||
1831 | /* file.c */ | 1839 | /* file.c */ |
1832 | int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync); | 1840 | int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync); |
1833 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end); | 1841 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, |
1842 | int skip_pinned); | ||
1834 | int btrfs_check_file(struct btrfs_root *root, struct inode *inode); | 1843 | int btrfs_check_file(struct btrfs_root *root, struct inode *inode); |
1835 | extern struct file_operations btrfs_file_operations; | 1844 | extern struct file_operations btrfs_file_operations; |
1836 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, | 1845 | int btrfs_drop_extents(struct btrfs_trans_handle *trans, |
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c index e3a25be5c663..8bd1b402f3fd 100644 --- a/fs/btrfs/extent_io.c +++ b/fs/btrfs/extent_io.c | |||
@@ -292,7 +292,7 @@ static int merge_state(struct extent_io_tree *tree, | |||
292 | struct extent_state *other; | 292 | struct extent_state *other; |
293 | struct rb_node *other_node; | 293 | struct rb_node *other_node; |
294 | 294 | ||
295 | if (state->state & EXTENT_IOBITS) | 295 | if (state->state & (EXTENT_IOBITS | EXTENT_BOUNDARY)) |
296 | return 0; | 296 | return 0; |
297 | 297 | ||
298 | other_node = rb_prev(&state->rb_node); | 298 | other_node = rb_prev(&state->rb_node); |
@@ -1070,7 +1070,8 @@ search_again: | |||
1070 | 1070 | ||
1071 | while(1) { | 1071 | while(1) { |
1072 | state = rb_entry(node, struct extent_state, rb_node); | 1072 | state = rb_entry(node, struct extent_state, rb_node); |
1073 | if (found && state->start != cur_start) { | 1073 | if (found && (state->start != cur_start || |
1074 | (state->state & EXTENT_BOUNDARY))) { | ||
1074 | goto out; | 1075 | goto out; |
1075 | } | 1076 | } |
1076 | if (!(state->state & EXTENT_DELALLOC)) { | 1077 | if (!(state->state & EXTENT_DELALLOC)) { |
@@ -1078,7 +1079,7 @@ search_again: | |||
1078 | *end = state->end; | 1079 | *end = state->end; |
1079 | goto out; | 1080 | goto out; |
1080 | } | 1081 | } |
1081 | if (!found) { | 1082 | if (!found && !(state->state & EXTENT_BOUNDARY)) { |
1082 | struct extent_state *prev_state; | 1083 | struct extent_state *prev_state; |
1083 | struct rb_node *prev_node = node; | 1084 | struct rb_node *prev_node = node; |
1084 | while(1) { | 1085 | while(1) { |
@@ -1088,7 +1089,11 @@ search_again: | |||
1088 | prev_state = rb_entry(prev_node, | 1089 | prev_state = rb_entry(prev_node, |
1089 | struct extent_state, | 1090 | struct extent_state, |
1090 | rb_node); | 1091 | rb_node); |
1091 | if (!(prev_state->state & EXTENT_DELALLOC)) | 1092 | if ((prev_state->end + 1 != state->start) || |
1093 | !(prev_state->state & EXTENT_DELALLOC)) | ||
1094 | break; | ||
1095 | if ((cur_start - prev_state->start) * 2 > | ||
1096 | max_bytes) | ||
1092 | break; | 1097 | break; |
1093 | state = prev_state; | 1098 | state = prev_state; |
1094 | node = prev_node; | 1099 | node = prev_node; |
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h index 3cb411a5f4d3..c9d1908a1ae3 100644 --- a/fs/btrfs/extent_io.h +++ b/fs/btrfs/extent_io.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #define EXTENT_BUFFER_FILLED (1 << 8) | 15 | #define EXTENT_BUFFER_FILLED (1 << 8) |
16 | #define EXTENT_ORDERED (1 << 9) | 16 | #define EXTENT_ORDERED (1 << 9) |
17 | #define EXTENT_ORDERED_METADATA (1 << 10) | 17 | #define EXTENT_ORDERED_METADATA (1 << 10) |
18 | #define EXTENT_BOUNDARY (1 << 11) | ||
18 | #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) | 19 | #define EXTENT_IOBITS (EXTENT_LOCKED | EXTENT_WRITEBACK) |
19 | 20 | ||
20 | /* | 21 | /* |
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c index 8856570a0ebd..1b7e51a9db0f 100644 --- a/fs/btrfs/file.c +++ b/fs/btrfs/file.c | |||
@@ -294,7 +294,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
294 | last_pos_in_file, | 294 | last_pos_in_file, |
295 | 0, 0, hole_size, 0); | 295 | 0, 0, hole_size, 0); |
296 | btrfs_drop_extent_cache(inode, last_pos_in_file, | 296 | btrfs_drop_extent_cache(inode, last_pos_in_file, |
297 | last_pos_in_file + hole_size -1); | 297 | last_pos_in_file + hole_size - 1, 0); |
298 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | 298 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); |
299 | btrfs_check_file(root, inode); | 299 | btrfs_check_file(root, inode); |
300 | } | 300 | } |
@@ -337,7 +337,7 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, | |||
337 | inline_size -= start_pos; | 337 | inline_size -= start_pos; |
338 | err = insert_inline_extent(trans, root, inode, start_pos, | 338 | err = insert_inline_extent(trans, root, inode, start_pos, |
339 | inline_size, pages, 0, num_pages); | 339 | inline_size, pages, 0, num_pages); |
340 | btrfs_drop_extent_cache(inode, start_pos, aligned_end - 1); | 340 | btrfs_drop_extent_cache(inode, start_pos, aligned_end - 1, 0); |
341 | BUG_ON(err); | 341 | BUG_ON(err); |
342 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | 342 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); |
343 | 343 | ||
@@ -362,7 +362,8 @@ out_unlock: | |||
362 | return err; | 362 | return err; |
363 | } | 363 | } |
364 | 364 | ||
365 | int noinline btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | 365 | int btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end, |
366 | int skip_pinned) | ||
366 | { | 367 | { |
367 | struct extent_map *em; | 368 | struct extent_map *em; |
368 | struct extent_map *split = NULL; | 369 | struct extent_map *split = NULL; |
@@ -371,6 +372,7 @@ int noinline btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
371 | u64 len = end - start + 1; | 372 | u64 len = end - start + 1; |
372 | int ret; | 373 | int ret; |
373 | int testend = 1; | 374 | int testend = 1; |
375 | unsigned long flags; | ||
374 | 376 | ||
375 | WARN_ON(end < start); | 377 | WARN_ON(end < start); |
376 | if (end == (u64)-1) { | 378 | if (end == (u64)-1) { |
@@ -389,6 +391,23 @@ int noinline btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
389 | spin_unlock(&em_tree->lock); | 391 | spin_unlock(&em_tree->lock); |
390 | break; | 392 | break; |
391 | } | 393 | } |
394 | flags = em->flags; | ||
395 | if (skip_pinned && test_bit(EXTENT_FLAG_PINNED, &em->flags)) { | ||
396 | spin_unlock(&em_tree->lock); | ||
397 | if (em->start <= start && | ||
398 | (!testend || em->start + em->len >= start + len)) { | ||
399 | free_extent_map(em); | ||
400 | break; | ||
401 | } | ||
402 | if (start < em->start) { | ||
403 | len = em->start - start; | ||
404 | } else { | ||
405 | len = start + len - (em->start + em->len); | ||
406 | start = em->start + em->len; | ||
407 | } | ||
408 | free_extent_map(em); | ||
409 | continue; | ||
410 | } | ||
392 | clear_bit(EXTENT_FLAG_PINNED, &em->flags); | 411 | clear_bit(EXTENT_FLAG_PINNED, &em->flags); |
393 | remove_extent_mapping(em_tree, em); | 412 | remove_extent_mapping(em_tree, em); |
394 | 413 | ||
@@ -398,7 +417,7 @@ int noinline btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
398 | split->len = start - em->start; | 417 | split->len = start - em->start; |
399 | split->block_start = em->block_start; | 418 | split->block_start = em->block_start; |
400 | split->bdev = em->bdev; | 419 | split->bdev = em->bdev; |
401 | split->flags = em->flags; | 420 | split->flags = flags; |
402 | ret = add_extent_mapping(em_tree, split); | 421 | ret = add_extent_mapping(em_tree, split); |
403 | BUG_ON(ret); | 422 | BUG_ON(ret); |
404 | free_extent_map(split); | 423 | free_extent_map(split); |
@@ -412,7 +431,7 @@ int noinline btrfs_drop_extent_cache(struct inode *inode, u64 start, u64 end) | |||
412 | split->start = start + len; | 431 | split->start = start + len; |
413 | split->len = em->start + em->len - (start + len); | 432 | split->len = em->start + em->len - (start + len); |
414 | split->bdev = em->bdev; | 433 | split->bdev = em->bdev; |
415 | split->flags = em->flags; | 434 | split->flags = flags; |
416 | 435 | ||
417 | split->block_start = em->block_start + diff; | 436 | split->block_start = em->block_start + diff; |
418 | 437 | ||
@@ -541,7 +560,7 @@ int noinline btrfs_drop_extents(struct btrfs_trans_handle *trans, | |||
541 | int recow; | 560 | int recow; |
542 | int ret; | 561 | int ret; |
543 | 562 | ||
544 | btrfs_drop_extent_cache(inode, start, end - 1); | 563 | btrfs_drop_extent_cache(inode, start, end - 1, 0); |
545 | 564 | ||
546 | path = btrfs_alloc_path(); | 565 | path = btrfs_alloc_path(); |
547 | if (!path) | 566 | if (!path) |
diff --git a/fs/btrfs/inode-map.c b/fs/btrfs/inode-map.c index cd6171c2da42..80038c5ef7cf 100644 --- a/fs/btrfs/inode-map.c +++ b/fs/btrfs/inode-map.c | |||
@@ -117,10 +117,14 @@ int btrfs_find_free_objectid(struct btrfs_trans_handle *trans, | |||
117 | *objectid = last_ino; | 117 | *objectid = last_ino; |
118 | goto found; | 118 | goto found; |
119 | } | 119 | } |
120 | } else if (key.objectid > search_start) { | ||
121 | *objectid = search_start; | ||
122 | goto found; | ||
120 | } | 123 | } |
121 | } | 124 | } |
122 | if (key.objectid >= BTRFS_LAST_FREE_OBJECTID) | 125 | if (key.objectid >= BTRFS_LAST_FREE_OBJECTID) |
123 | break; | 126 | break; |
127 | |||
124 | start_found = 1; | 128 | start_found = 1; |
125 | last_ino = key.objectid + 1; | 129 | last_ino = key.objectid + 1; |
126 | path->slots[0]++; | 130 | path->slots[0]++; |
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index 48a3dc030807..4516fbf01671 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c | |||
@@ -135,7 +135,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) | |||
135 | 135 | ||
136 | BUG_ON(num_bytes > btrfs_super_total_bytes(&root->fs_info->super_copy)); | 136 | BUG_ON(num_bytes > btrfs_super_total_bytes(&root->fs_info->super_copy)); |
137 | mutex_lock(&BTRFS_I(inode)->extent_mutex); | 137 | mutex_lock(&BTRFS_I(inode)->extent_mutex); |
138 | btrfs_drop_extent_cache(inode, start, start + num_bytes - 1); | 138 | btrfs_drop_extent_cache(inode, start, start + num_bytes - 1, 0); |
139 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | 139 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); |
140 | 140 | ||
141 | while(num_bytes > 0) { | 141 | while(num_bytes > 0) { |
@@ -163,7 +163,7 @@ static int cow_file_range(struct inode *inode, u64 start, u64 end) | |||
163 | break; | 163 | break; |
164 | } | 164 | } |
165 | btrfs_drop_extent_cache(inode, start, | 165 | btrfs_drop_extent_cache(inode, start, |
166 | start + ins.offset - 1); | 166 | start + ins.offset - 1, 0); |
167 | } | 167 | } |
168 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | 168 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); |
169 | 169 | ||
@@ -587,7 +587,7 @@ static int btrfs_finish_ordered_io(struct inode *inode, u64 start, u64 end) | |||
587 | 587 | ||
588 | btrfs_drop_extent_cache(inode, ordered_extent->file_offset, | 588 | btrfs_drop_extent_cache(inode, ordered_extent->file_offset, |
589 | ordered_extent->file_offset + | 589 | ordered_extent->file_offset + |
590 | ordered_extent->len - 1); | 590 | ordered_extent->len - 1, 0); |
591 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | 591 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); |
592 | 592 | ||
593 | ins.objectid = ordered_extent->start; | 593 | ins.objectid = ordered_extent->start; |
@@ -880,7 +880,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
880 | int ret = 0, nr_unlink = 0, nr_truncate = 0; | 880 | int ret = 0, nr_unlink = 0, nr_truncate = 0; |
881 | 881 | ||
882 | /* don't do orphan cleanup if the fs is readonly. */ | 882 | /* don't do orphan cleanup if the fs is readonly. */ |
883 | if (root->inode->i_sb->s_flags & MS_RDONLY) | 883 | if (root->fs_info->sb->s_flags & MS_RDONLY) |
884 | return; | 884 | return; |
885 | 885 | ||
886 | path = btrfs_alloc_path(); | 886 | path = btrfs_alloc_path(); |
@@ -892,8 +892,6 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
892 | btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY); | 892 | btrfs_set_key_type(&key, BTRFS_ORPHAN_ITEM_KEY); |
893 | key.offset = (u64)-1; | 893 | key.offset = (u64)-1; |
894 | 894 | ||
895 | trans = btrfs_start_transaction(root, 1); | ||
896 | btrfs_set_trans_block_group(trans, root->inode); | ||
897 | 895 | ||
898 | while (1) { | 896 | while (1) { |
899 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 897 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
@@ -933,7 +931,7 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
933 | * crossing root thing. we store the inode number in the | 931 | * crossing root thing. we store the inode number in the |
934 | * offset of the orphan item. | 932 | * offset of the orphan item. |
935 | */ | 933 | */ |
936 | inode = btrfs_iget_locked(root->inode->i_sb, | 934 | inode = btrfs_iget_locked(root->fs_info->sb, |
937 | found_key.offset, root); | 935 | found_key.offset, root); |
938 | if (!inode) | 936 | if (!inode) |
939 | break; | 937 | break; |
@@ -965,7 +963,9 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
965 | * do a destroy_inode | 963 | * do a destroy_inode |
966 | */ | 964 | */ |
967 | if (is_bad_inode(inode)) { | 965 | if (is_bad_inode(inode)) { |
966 | trans = btrfs_start_transaction(root, 1); | ||
968 | btrfs_orphan_del(trans, inode); | 967 | btrfs_orphan_del(trans, inode); |
968 | btrfs_end_transaction(trans, root); | ||
969 | iput(inode); | 969 | iput(inode); |
970 | continue; | 970 | continue; |
971 | } | 971 | } |
@@ -988,7 +988,6 @@ void btrfs_orphan_cleanup(struct btrfs_root *root) | |||
988 | printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate); | 988 | printk(KERN_INFO "btrfs: truncated %d orphans\n", nr_truncate); |
989 | 989 | ||
990 | btrfs_free_path(path); | 990 | btrfs_free_path(path); |
991 | btrfs_end_transaction(trans, root); | ||
992 | } | 991 | } |
993 | 992 | ||
994 | void btrfs_read_locked_inode(struct inode *inode) | 993 | void btrfs_read_locked_inode(struct inode *inode) |
@@ -1343,8 +1342,7 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans, | |||
1343 | u64 mask = root->sectorsize - 1; | 1342 | u64 mask = root->sectorsize - 1; |
1344 | 1343 | ||
1345 | if (root->ref_cows) | 1344 | if (root->ref_cows) |
1346 | btrfs_drop_extent_cache(inode, | 1345 | btrfs_drop_extent_cache(inode, new_size & (~mask), (u64)-1, 0); |
1347 | new_size & (~mask), (u64)-1); | ||
1348 | path = btrfs_alloc_path(); | 1346 | path = btrfs_alloc_path(); |
1349 | path->reada = -1; | 1347 | path->reada = -1; |
1350 | BUG_ON(!path); | 1348 | BUG_ON(!path); |
@@ -1677,7 +1675,7 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr) | |||
1677 | hole_start, 0, 0, | 1675 | hole_start, 0, 0, |
1678 | hole_size, 0); | 1676 | hole_size, 0); |
1679 | btrfs_drop_extent_cache(inode, hole_start, | 1677 | btrfs_drop_extent_cache(inode, hole_start, |
1680 | (u64)-1); | 1678 | (u64)-1, 0); |
1681 | btrfs_check_file(root, inode); | 1679 | btrfs_check_file(root, inode); |
1682 | } | 1680 | } |
1683 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); | 1681 | mutex_unlock(&BTRFS_I(inode)->extent_mutex); |
@@ -1843,6 +1841,24 @@ static int btrfs_find_actor(struct inode *inode, void *opaque) | |||
1843 | args->root == BTRFS_I(inode)->root); | 1841 | args->root == BTRFS_I(inode)->root); |
1844 | } | 1842 | } |
1845 | 1843 | ||
1844 | struct inode *btrfs_ilookup(struct super_block *s, u64 objectid, | ||
1845 | struct btrfs_root *root, int wait) | ||
1846 | { | ||
1847 | struct inode *inode; | ||
1848 | struct btrfs_iget_args args; | ||
1849 | args.ino = objectid; | ||
1850 | args.root = root; | ||
1851 | |||
1852 | if (wait) { | ||
1853 | inode = ilookup5(s, objectid, btrfs_find_actor, | ||
1854 | (void *)&args); | ||
1855 | } else { | ||
1856 | inode = ilookup5_nowait(s, objectid, btrfs_find_actor, | ||
1857 | (void *)&args); | ||
1858 | } | ||
1859 | return inode; | ||
1860 | } | ||
1861 | |||
1846 | struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid, | 1862 | struct inode *btrfs_iget_locked(struct super_block *s, u64 objectid, |
1847 | struct btrfs_root *root) | 1863 | struct btrfs_root *root) |
1848 | { | 1864 | { |
@@ -3266,7 +3282,7 @@ void btrfs_destroy_inode(struct inode *inode) | |||
3266 | btrfs_put_ordered_extent(ordered); | 3282 | btrfs_put_ordered_extent(ordered); |
3267 | } | 3283 | } |
3268 | } | 3284 | } |
3269 | btrfs_drop_extent_cache(inode, 0, (u64)-1); | 3285 | btrfs_drop_extent_cache(inode, 0, (u64)-1, 0); |
3270 | kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); | 3286 | kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); |
3271 | } | 3287 | } |
3272 | 3288 | ||
@@ -3412,16 +3428,22 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root) | |||
3412 | { | 3428 | { |
3413 | struct list_head *head = &root->fs_info->delalloc_inodes; | 3429 | struct list_head *head = &root->fs_info->delalloc_inodes; |
3414 | struct btrfs_inode *binode; | 3430 | struct btrfs_inode *binode; |
3431 | struct inode *inode; | ||
3415 | unsigned long flags; | 3432 | unsigned long flags; |
3416 | 3433 | ||
3417 | spin_lock_irqsave(&root->fs_info->delalloc_lock, flags); | 3434 | spin_lock_irqsave(&root->fs_info->delalloc_lock, flags); |
3418 | while(!list_empty(head)) { | 3435 | while(!list_empty(head)) { |
3419 | binode = list_entry(head->next, struct btrfs_inode, | 3436 | binode = list_entry(head->next, struct btrfs_inode, |
3420 | delalloc_inodes); | 3437 | delalloc_inodes); |
3421 | atomic_inc(&binode->vfs_inode.i_count); | 3438 | inode = igrab(&binode->vfs_inode); |
3439 | if (!inode) | ||
3440 | list_del_init(&binode->delalloc_inodes); | ||
3422 | spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags); | 3441 | spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags); |
3423 | filemap_write_and_wait(binode->vfs_inode.i_mapping); | 3442 | if (inode) { |
3424 | iput(&binode->vfs_inode); | 3443 | filemap_write_and_wait(inode->i_mapping); |
3444 | iput(inode); | ||
3445 | } | ||
3446 | cond_resched(); | ||
3425 | spin_lock_irqsave(&root->fs_info->delalloc_lock, flags); | 3447 | spin_lock_irqsave(&root->fs_info->delalloc_lock, flags); |
3426 | } | 3448 | } |
3427 | spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags); | 3449 | spin_unlock_irqrestore(&root->fs_info->delalloc_lock, flags); |
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 4c6e0c15754d..04de767a8db2 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -444,12 +444,10 @@ static noinline int btrfs_ioctl_snap_create(struct btrfs_root *root, | |||
444 | goto out; | 444 | goto out; |
445 | } | 445 | } |
446 | 446 | ||
447 | mutex_lock(&root->fs_info->drop_mutex); | ||
448 | if (root == root->fs_info->tree_root) | 447 | if (root == root->fs_info->tree_root) |
449 | ret = create_subvol(root, vol_args->name, namelen); | 448 | ret = create_subvol(root, vol_args->name, namelen); |
450 | else | 449 | else |
451 | ret = create_snapshot(root, vol_args->name, namelen); | 450 | ret = create_snapshot(root, vol_args->name, namelen); |
452 | mutex_unlock(&root->fs_info->drop_mutex); | ||
453 | out: | 451 | out: |
454 | kfree(vol_args); | 452 | kfree(vol_args); |
455 | return ret; | 453 | return ret; |
diff --git a/fs/btrfs/ordered-data.c b/fs/btrfs/ordered-data.c index da6d43eb41db..951eacff2420 100644 --- a/fs/btrfs/ordered-data.c +++ b/fs/btrfs/ordered-data.c | |||
@@ -309,7 +309,6 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only) | |||
309 | { | 309 | { |
310 | struct list_head splice; | 310 | struct list_head splice; |
311 | struct list_head *cur; | 311 | struct list_head *cur; |
312 | struct list_head *tmp; | ||
313 | struct btrfs_ordered_extent *ordered; | 312 | struct btrfs_ordered_extent *ordered; |
314 | struct inode *inode; | 313 | struct inode *inode; |
315 | 314 | ||
@@ -317,37 +316,38 @@ int btrfs_wait_ordered_extents(struct btrfs_root *root, int nocow_only) | |||
317 | 316 | ||
318 | spin_lock(&root->fs_info->ordered_extent_lock); | 317 | spin_lock(&root->fs_info->ordered_extent_lock); |
319 | list_splice_init(&root->fs_info->ordered_extents, &splice); | 318 | list_splice_init(&root->fs_info->ordered_extents, &splice); |
320 | list_for_each_safe(cur, tmp, &splice) { | 319 | while (!list_empty(&splice)) { |
321 | cur = splice.next; | 320 | cur = splice.next; |
322 | ordered = list_entry(cur, struct btrfs_ordered_extent, | 321 | ordered = list_entry(cur, struct btrfs_ordered_extent, |
323 | root_extent_list); | 322 | root_extent_list); |
324 | if (nocow_only && | 323 | if (nocow_only && |
325 | !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) { | 324 | !test_bit(BTRFS_ORDERED_NOCOW, &ordered->flags)) { |
325 | list_move(&ordered->root_extent_list, | ||
326 | &root->fs_info->ordered_extents); | ||
326 | cond_resched_lock(&root->fs_info->ordered_extent_lock); | 327 | cond_resched_lock(&root->fs_info->ordered_extent_lock); |
327 | continue; | 328 | continue; |
328 | } | 329 | } |
329 | 330 | ||
330 | list_del_init(&ordered->root_extent_list); | 331 | list_del_init(&ordered->root_extent_list); |
331 | atomic_inc(&ordered->refs); | 332 | atomic_inc(&ordered->refs); |
332 | inode = ordered->inode; | ||
333 | 333 | ||
334 | /* | 334 | /* |
335 | * the inode can't go away until all the pages are gone | 335 | * the inode may be getting freed (in sys_unlink path). |
336 | * and the pages won't go away while there is still | ||
337 | * an ordered extent and the ordered extent won't go | ||
338 | * away until it is off this list. So, we can safely | ||
339 | * increment i_count here and call iput later | ||
340 | */ | 336 | */ |
341 | atomic_inc(&inode->i_count); | 337 | inode = igrab(ordered->inode); |
338 | |||
342 | spin_unlock(&root->fs_info->ordered_extent_lock); | 339 | spin_unlock(&root->fs_info->ordered_extent_lock); |
343 | 340 | ||
344 | btrfs_start_ordered_extent(inode, ordered, 1); | 341 | if (inode) { |
345 | btrfs_put_ordered_extent(ordered); | 342 | btrfs_start_ordered_extent(inode, ordered, 1); |
346 | iput(inode); | 343 | btrfs_put_ordered_extent(ordered); |
344 | iput(inode); | ||
345 | } else { | ||
346 | btrfs_put_ordered_extent(ordered); | ||
347 | } | ||
347 | 348 | ||
348 | spin_lock(&root->fs_info->ordered_extent_lock); | 349 | spin_lock(&root->fs_info->ordered_extent_lock); |
349 | } | 350 | } |
350 | list_splice_init(&splice, &root->fs_info->ordered_extents); | ||
351 | spin_unlock(&root->fs_info->ordered_extent_lock); | 351 | spin_unlock(&root->fs_info->ordered_extent_lock); |
352 | return 0; | 352 | return 0; |
353 | } | 353 | } |
diff --git a/fs/btrfs/transaction.c b/fs/btrfs/transaction.c index 656baefa5255..8c83cf464c83 100644 --- a/fs/btrfs/transaction.c +++ b/fs/btrfs/transaction.c | |||
@@ -109,6 +109,7 @@ noinline int btrfs_record_root_in_trans(struct btrfs_root *root) | |||
109 | spin_lock_init(&dirty->root->node_lock); | 109 | spin_lock_init(&dirty->root->node_lock); |
110 | spin_lock_init(&dirty->root->list_lock); | 110 | spin_lock_init(&dirty->root->list_lock); |
111 | mutex_init(&dirty->root->objectid_mutex); | 111 | mutex_init(&dirty->root->objectid_mutex); |
112 | mutex_init(&dirty->root->log_mutex); | ||
112 | INIT_LIST_HEAD(&dirty->root->dead_list); | 113 | INIT_LIST_HEAD(&dirty->root->dead_list); |
113 | dirty->root->node = root->commit_root; | 114 | dirty->root->node = root->commit_root; |
114 | dirty->root->commit_root = NULL; | 115 | dirty->root->commit_root = NULL; |
@@ -590,13 +591,14 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root, | |||
590 | root = dirty->latest_root; | 591 | root = dirty->latest_root; |
591 | atomic_inc(&root->fs_info->throttles); | 592 | atomic_inc(&root->fs_info->throttles); |
592 | 593 | ||
593 | mutex_lock(&root->fs_info->drop_mutex); | ||
594 | while(1) { | 594 | while(1) { |
595 | trans = btrfs_start_transaction(tree_root, 1); | 595 | trans = btrfs_start_transaction(tree_root, 1); |
596 | mutex_lock(&root->fs_info->drop_mutex); | ||
596 | ret = btrfs_drop_snapshot(trans, dirty->root); | 597 | ret = btrfs_drop_snapshot(trans, dirty->root); |
597 | if (ret != -EAGAIN) { | 598 | if (ret != -EAGAIN) { |
598 | break; | 599 | break; |
599 | } | 600 | } |
601 | mutex_unlock(&root->fs_info->drop_mutex); | ||
600 | 602 | ||
601 | err = btrfs_update_root(trans, | 603 | err = btrfs_update_root(trans, |
602 | tree_root, | 604 | tree_root, |
@@ -608,10 +610,8 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root, | |||
608 | ret = btrfs_end_transaction(trans, tree_root); | 610 | ret = btrfs_end_transaction(trans, tree_root); |
609 | BUG_ON(ret); | 611 | BUG_ON(ret); |
610 | 612 | ||
611 | mutex_unlock(&root->fs_info->drop_mutex); | ||
612 | btrfs_btree_balance_dirty(tree_root, nr); | 613 | btrfs_btree_balance_dirty(tree_root, nr); |
613 | cond_resched(); | 614 | cond_resched(); |
614 | mutex_lock(&root->fs_info->drop_mutex); | ||
615 | } | 615 | } |
616 | BUG_ON(ret); | 616 | BUG_ON(ret); |
617 | atomic_dec(&root->fs_info->throttles); | 617 | atomic_dec(&root->fs_info->throttles); |
@@ -689,7 +689,7 @@ static noinline int create_pending_snapshot(struct btrfs_trans_handle *trans, | |||
689 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); | 689 | memcpy(new_root_item, &root->root_item, sizeof(*new_root_item)); |
690 | 690 | ||
691 | key.objectid = objectid; | 691 | key.objectid = objectid; |
692 | key.offset = 1; | 692 | key.offset = trans->transid; |
693 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); | 693 | btrfs_set_key_type(&key, BTRFS_ROOT_ITEM_KEY); |
694 | 694 | ||
695 | old = btrfs_lock_root_node(root); | 695 | old = btrfs_lock_root_node(root); |