aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2008-09-08 11:18:08 -0400
committerChris Mason <chris.mason@oracle.com>2008-09-25 11:04:07 -0400
commit4bef084857ab8fe71cf49eae349c25e440a49150 (patch)
tree7a9a850515538421c2976f8ee4c1bea5ceced59c /fs/btrfs/extent-tree.c
parent325cd4bafeb6cfb44addd6e807a9b74170d1be31 (diff)
Btrfs: Tree logging fixes
* Pin down data blocks to prevent them from being reallocated like so: trans 1: allocate file extent trans 2: free file extent trans 3: free file extent during old snapshot deletion trans 3: allocate file extent to new file trans 3: fsync new file Before the tree logging code, this was legal because the fsync would commit the transation that did the final data extent free and the transaction that allocated the extent to the new file at the same time. With the tree logging code, the tree log subtransaction can commit before the transaction that freed the extent. If we crash, we're left with two different files using the extent. * Don't wait in start_transaction if log replay is going on. This avoids deadlocks from iput while we're cleaning up link counts in the replay code. * Don't deadlock in replay_one_name by trying to read an inode off the disk while holding paths for the directory * Hold the buffer lock while we mark a buffer as written. This closes a race where someone is changing a buffer while we write it. They are supposed to mark it dirty again after they change it, but this violates the cow rules. Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r--fs/btrfs/extent-tree.c20
1 files changed, 17 insertions, 3 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 646b9148ca21..3181759da1cf 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -1590,13 +1590,17 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
1590} 1590}
1591 1591
1592static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes, 1592static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes,
1593 int pending) 1593 int is_data, int pending)
1594{ 1594{
1595 int err = 0; 1595 int err = 0;
1596 1596
1597 WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex)); 1597 WARN_ON(!mutex_is_locked(&root->fs_info->alloc_mutex));
1598 if (!pending) { 1598 if (!pending) {
1599 struct extent_buffer *buf; 1599 struct extent_buffer *buf;
1600
1601 if (is_data)
1602 goto pinit;
1603
1600 buf = btrfs_find_tree_block(root, bytenr, num_bytes); 1604 buf = btrfs_find_tree_block(root, bytenr, num_bytes);
1601 if (buf) { 1605 if (buf) {
1602 /* we can reuse a block if it hasn't been written 1606 /* we can reuse a block if it hasn't been written
@@ -1624,6 +1628,7 @@ static int pin_down_bytes(struct btrfs_root *root, u64 bytenr, u32 num_bytes,
1624 } 1628 }
1625 free_extent_buffer(buf); 1629 free_extent_buffer(buf);
1626 } 1630 }
1631pinit:
1627 btrfs_update_pinned_extents(root, bytenr, num_bytes, 1); 1632 btrfs_update_pinned_extents(root, bytenr, num_bytes, 1);
1628 } else { 1633 } else {
1629 set_extent_bits(&root->fs_info->pending_del, 1634 set_extent_bits(&root->fs_info->pending_del,
@@ -1744,7 +1749,8 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root
1744#endif 1749#endif
1745 1750
1746 if (pin) { 1751 if (pin) {
1747 ret = pin_down_bytes(root, bytenr, num_bytes, 0); 1752 ret = pin_down_bytes(root, bytenr, num_bytes,
1753 owner_objectid >= BTRFS_FIRST_FREE_OBJECTID, 0);
1748 if (ret > 0) 1754 if (ret > 0)
1749 mark_free = 1; 1755 mark_free = 1;
1750 BUG_ON(ret < 0); 1756 BUG_ON(ret < 0);
@@ -1862,9 +1868,17 @@ static int __btrfs_free_extent(struct btrfs_trans_handle *trans,
1862 ref_generation = 0; 1868 ref_generation = 0;
1863 1869
1864 if (root == extent_root) { 1870 if (root == extent_root) {
1865 pin_down_bytes(root, bytenr, num_bytes, 1); 1871 pin_down_bytes(root, bytenr, num_bytes, 0, 1);
1866 return 0; 1872 return 0;
1867 } 1873 }
1874 /* if metadata always pin */
1875 if (owner_objectid < BTRFS_FIRST_FREE_OBJECTID)
1876 pin = 1;
1877
1878 /* if data pin when any transaction has committed this */
1879 if (ref_generation != trans->transid)
1880 pin = 1;
1881
1868 ret = __free_extent(trans, root, bytenr, num_bytes, root_objectid, 1882 ret = __free_extent(trans, root, bytenr, num_bytes, root_objectid,
1869 ref_generation, owner_objectid, owner_offset, 1883 ref_generation, owner_objectid, owner_offset,
1870 pin, pin == 0); 1884 pin, pin == 0);