aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2009-04-06 12:40:17 -0400
committerChristoph Hellwig <hch@brick.lst.de>2009-04-06 12:40:17 -0400
commit705db3fd4660174a27418bbcb874d209a76044eb (patch)
tree84ec380710246cb3b97cd46ee57b3555d3afd07b /fs/xfs
parenta6cb767e24b1dbedfcfa8077eab0aa2eab224038 (diff)
xfs: fix double free of inode
If we fail to initialise the VFS inode in inode_init_always(), it will call ->delete_inode internally resulting in the inode being freed. Hence we need to delay the call to inode_init_always() until after the XFS inode is sufficient set up to handle a call to ->delete_inode, and then if that fails do not touch the inode again at all as it has been freed. Signed-off-by: Dave Chinner <david@fromorbit.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/xfs')
-rw-r--r--fs/xfs/xfs_iget.c23
1 files changed, 14 insertions, 9 deletions
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
index 478e587087fe..89b81eedce6a 100644
--- a/fs/xfs/xfs_iget.c
+++ b/fs/xfs/xfs_iget.c
@@ -69,15 +69,6 @@ xfs_inode_alloc(
69 ASSERT(!spin_is_locked(&ip->i_flags_lock)); 69 ASSERT(!spin_is_locked(&ip->i_flags_lock));
70 ASSERT(completion_done(&ip->i_flush)); 70 ASSERT(completion_done(&ip->i_flush));
71 71
72 /*
73 * initialise the VFS inode here to get failures
74 * out of the way early.
75 */
76 if (!inode_init_always(mp->m_super, VFS_I(ip))) {
77 kmem_zone_free(xfs_inode_zone, ip);
78 return NULL;
79 }
80
81 /* initialise the xfs inode */ 72 /* initialise the xfs inode */
82 ip->i_ino = ino; 73 ip->i_ino = ino;
83 ip->i_mount = mp; 74 ip->i_mount = mp;
@@ -113,6 +104,20 @@ xfs_inode_alloc(
113#ifdef XFS_DIR2_TRACE 104#ifdef XFS_DIR2_TRACE
114 ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS); 105 ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS);
115#endif 106#endif
107 /*
108 * Now initialise the VFS inode. We do this after the xfs_inode
109 * initialisation as internal failures will result in ->destroy_inode
110 * being called and that will pass down through the reclaim path and
111 * free the XFS inode. This path requires the XFS inode to already be
112 * initialised. Hence if this call fails, the xfs_inode has already
113 * been freed and we should not reference it at all in the error
114 * handling.
115 */
116 if (!inode_init_always(mp->m_super, VFS_I(ip)))
117 return NULL;
118
119 /* prevent anyone from using this yet */
120 VFS_I(ip)->i_state = I_NEW|I_LOCK;
116 121
117 return ip; 122 return ip;
118} 123}