diff options
Diffstat (limited to 'fs/xfs/xfs_super.c')
-rw-r--r-- | fs/xfs/xfs_super.c | 32 |
1 files changed, 28 insertions, 4 deletions
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c index a2dab05332ac..79f1cd1a0221 100644 --- a/fs/xfs/xfs_super.c +++ b/fs/xfs/xfs_super.c @@ -637,22 +637,46 @@ xfs_fs_destroy_inode( struct inode *inode) { struct xfs_inode *ip = XFS_I(inode); + struct xfs_mount *mp = ip->i_mount; trace_xfs_destroy_inode(ip); ASSERT(!rwsem_is_locked(&inode->i_rwsem)); - XFS_STATS_INC(ip->i_mount, vn_rele); - XFS_STATS_INC(ip->i_mount, vn_remove); + XFS_STATS_INC(mp, vn_rele); + XFS_STATS_INC(mp, vn_remove); + + /* + * If a quota type is turned off but we still have a dquot attached to + * the inode, detach it before processing this inode to avoid delaying + * quotaoff for longer than is necessary. + * + * The inode has no VFS state and hasn't been tagged for any kind of + * reclamation, which means that iget, quotaoff, blockgc, and reclaim + * will not touch it. It is therefore safe to do this locklessly + * because we have the only reference here. + */ + if (!XFS_IS_UQUOTA_ON(mp)) { + xfs_qm_dqrele(ip->i_udquot); + ip->i_udquot = NULL; + } + if (!XFS_IS_GQUOTA_ON(mp)) { + xfs_qm_dqrele(ip->i_gdquot); + ip->i_gdquot = NULL; + } + if (!XFS_IS_PQUOTA_ON(mp)) { + xfs_qm_dqrele(ip->i_pdquot); + ip->i_pdquot = NULL; + } xfs_inactive(ip); - if (!XFS_FORCED_SHUTDOWN(ip->i_mount) && ip->i_delayed_blks) { + if (!XFS_FORCED_SHUTDOWN(mp) && ip->i_delayed_blks) { xfs_check_delalloc(ip, XFS_DATA_FORK); xfs_check_delalloc(ip, XFS_COW_FORK); ASSERT(0); } - XFS_STATS_INC(ip->i_mount, vn_reclaim); + XFS_STATS_INC(mp, vn_reclaim); /* * We should never get here with one of the reclaim flags already set. |