diff options
author | Josef Bacik <josef@redhat.com> | 2009-11-11 15:53:34 -0500 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2009-11-11 15:53:34 -0500 |
commit | a6dbd429d8dd3382bbd9594b8d2ec74843a260d9 (patch) | |
tree | 9cc6426da748996e4e1cc61d446052838703434f /fs | |
parent | 33b258086441dd07e00133c79fcd8cbc6a76d737 (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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/inode.c | 10 |
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); |
5242 | free: | ||
5233 | kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); | 5243 | kmem_cache_free(btrfs_inode_cachep, BTRFS_I(inode)); |
5234 | } | 5244 | } |
5235 | 5245 | ||