aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <josef@redhat.com>2009-11-11 15:53:34 -0500
committerChris Mason <chris.mason@oracle.com>2009-11-11 15:53:34 -0500
commita6dbd429d8dd3382bbd9594b8d2ec74843a260d9 (patch)
tree9cc6426da748996e4e1cc61d446052838703434f
parent33b258086441dd07e00133c79fcd8cbc6a76d737 (diff)
Btrfs: fix panic when trying to destroy a newly allocated
There is a problem where iget5_locked will look for an inode, not find it, and then subsequently try to allocate it. Another CPU will have raced in and allocated the inode instead, so when iget5_locked gets the inode spin lock again and does a search, it finds the new inode. So it goes ahead and calls destroy_inode on the inode it just allocated. The problem is we don't set BTRFS_I(inode)->root until the new inode is completely initialized. This patch makes us set root to NULL when alloc'ing a new inode, so when we get to btrfs_destroy_inode and we see that root is NULL we can just free up the memory and continue on. This fixes the panic http://www.kerneloops.org/submitresult.php?number=812690 Thanks, Signed-off-by: Josef Bacik <josef@redhat.com> Signed-off-by: Chris Mason <chris.mason@oracle.com>
-rw-r--r--fs/btrfs/inode.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index d3d7d46a6af2..ee92801fc5db 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5180,6 +5180,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
5180 ei->logged_trans = 0; 5180 ei->logged_trans = 0;
5181 ei->outstanding_extents = 0; 5181 ei->outstanding_extents = 0;
5182 ei->reserved_extents = 0; 5182 ei->reserved_extents = 0;
5183 ei->root = NULL;
5183 spin_lock_init(&ei->accounting_lock); 5184 spin_lock_init(&ei->accounting_lock);
5184 btrfs_ordered_inode_tree_init(&ei->ordered_tree); 5185 btrfs_ordered_inode_tree_init(&ei->ordered_tree);
5185 INIT_LIST_HEAD(&ei->i_orphan); 5186 INIT_LIST_HEAD(&ei->i_orphan);
@@ -5196,6 +5197,14 @@ void btrfs_destroy_inode(struct inode *inode)
5196 WARN_ON(inode->i_data.nrpages); 5197 WARN_ON(inode->i_data.nrpages);
5197 5198
5198 /* 5199 /*
5200 * This can happen where we create an inode, but somebody else also
5201 * created the same inode and we need to destroy the one we already
5202 * created.
5203 */
5204 if (!root)
5205 goto free;
5206
5207 /*
5199 * Make sure we're properly removed from the ordered operation 5208 * Make sure we're properly removed from the ordered operation
5200 * lists. 5209 * lists.
5201 */ 5210 */
@@ -5230,6 +5239,7 @@ void btrfs_destroy_inode(struct inode *inode)
5230 } 5239 }
5231 inode_tree_del(inode); 5240 inode_tree_del(inode);
5232 btrfs_drop_extent_cache(inode, 0, (u64)-1, 0); 5241 btrfs_drop_extent_cache(inode, 0, (u64)-1, 0);
5242free:
5233 kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); 5243 kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode));
5234} 5244}
5235 5245