aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/disk-io.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/disk-io.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/disk-io.c')
-rw-r--r--fs/btrfs/disk-io.c33
1 files changed, 30 insertions, 3 deletions
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index a4373db5967a..42bf99168056 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -307,9 +307,7 @@ int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
307 goto err; 307 goto err;
308 } 308 }
309 found_level = btrfs_header_level(eb); 309 found_level = btrfs_header_level(eb);
310 spin_lock(&root->fs_info->hash_lock); 310
311 btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
312 spin_unlock(&root->fs_info->hash_lock);
313 csum_tree_block(root, eb, 0); 311 csum_tree_block(root, eb, 0);
314err: 312err:
315 free_extent_buffer(eb); 313 free_extent_buffer(eb);
@@ -1998,7 +1996,36 @@ int btrfs_read_buffer(struct extent_buffer *buf, u64 parent_transid)
1998 return ret; 1996 return ret;
1999} 1997}
2000 1998
1999int btree_lock_page_hook(struct page *page)
2000{
2001 struct inode *inode = page->mapping->host;
2002 struct btrfs_root *root = BTRFS_I(inode)->root;
2003 struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
2004 struct extent_buffer *eb;
2005 unsigned long len;
2006 u64 bytenr = page_offset(page);
2007
2008 if (page->private == EXTENT_PAGE_PRIVATE)
2009 goto out;
2010
2011 len = page->private >> 2;
2012 eb = find_extent_buffer(io_tree, bytenr, len, GFP_NOFS);
2013 if (!eb)
2014 goto out;
2015
2016 btrfs_tree_lock(eb);
2017 spin_lock(&root->fs_info->hash_lock);
2018 btrfs_set_header_flag(eb, BTRFS_HEADER_FLAG_WRITTEN);
2019 spin_unlock(&root->fs_info->hash_lock);
2020 btrfs_tree_unlock(eb);
2021 free_extent_buffer(eb);
2022out:
2023 lock_page(page);
2024 return 0;
2025}
2026
2001static struct extent_io_ops btree_extent_io_ops = { 2027static struct extent_io_ops btree_extent_io_ops = {
2028 .write_cache_pages_lock_hook = btree_lock_page_hook,
2002 .writepage_io_hook = btree_writepage_io_hook, 2029 .writepage_io_hook = btree_writepage_io_hook,
2003 .readpage_end_io_hook = btree_readpage_end_io_hook, 2030 .readpage_end_io_hook = btree_readpage_end_io_hook,
2004 .submit_bio_hook = btree_submit_bio_hook, 2031 .submit_bio_hook = btree_submit_bio_hook,