diff options
Diffstat (limited to 'fs/xfs/xfs_iget.c')
| -rw-r--r-- | fs/xfs/xfs_iget.c | 23 | 
1 files changed, 14 insertions, 9 deletions
diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 478e587087f..89b81eedce6 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -69,15 +69,6 @@ xfs_inode_alloc(  	ASSERT(!spin_is_locked(&ip->i_flags_lock));  	ASSERT(completion_done(&ip->i_flush)); -	/* -	 * initialise the VFS inode here to get failures -	 * out of the way early. -	 */ -	if (!inode_init_always(mp->m_super, VFS_I(ip))) { -		kmem_zone_free(xfs_inode_zone, ip); -		return NULL; -	} -  	/* initialise the xfs inode */  	ip->i_ino = ino;  	ip->i_mount = mp; @@ -113,6 +104,20 @@ xfs_inode_alloc(  #ifdef XFS_DIR2_TRACE  	ip->i_dir_trace = ktrace_alloc(XFS_DIR2_KTRACE_SIZE, KM_NOFS);  #endif +	/* +	* Now initialise the VFS inode. We do this after the xfs_inode +	* initialisation as internal failures will result in ->destroy_inode +	* being called and that will pass down through the reclaim path and +	* free the XFS inode. This path requires the XFS inode to already be +	* initialised. Hence if this call fails, the xfs_inode has already +	* been freed and we should not reference it at all in the error +	* handling. +	*/ +	if (!inode_init_always(mp->m_super, VFS_I(ip))) +		return NULL; + +	/* prevent anyone from using this yet */ +	VFS_I(ip)->i_state = I_NEW|I_LOCK;  	return ip;  }  |