diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-09-08 11:18:08 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:07 -0400 |
commit | 4bef084857ab8fe71cf49eae349c25e440a49150 (patch) | |
tree | 7a9a850515538421c2976f8ee4c1bea5ceced59c /fs/btrfs/disk-io.c | |
parent | 325cd4bafeb6cfb44addd6e807a9b74170d1be31 (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.c | 33 |
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); |
314 | err: | 312 | err: |
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 | ||
1999 | int 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); | ||
2022 | out: | ||
2023 | lock_page(page); | ||
2024 | return 0; | ||
2025 | } | ||
2026 | |||
2001 | static struct extent_io_ops btree_extent_io_ops = { | 2027 | static 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, |