On Wed, Feb 15, 2017 at 10:40:47AM -0500, Brian Foster wrote: > The quotaoff operation has a race with inode allocation that results > in a livelock. An inode allocation that occurs before the quota > status flags are updated acquires the appropriate dquots for the > inode via xfs_qm_vop_dqalloc(). It then inserts the XFS_INEW inode > into the perag radix tree, sometime later attaches the dquots to the > inode and finally clears the XFS_INEW flag. Quotaoff expects to > release the dquots from all inodes in the filesystem via > xfs_qm_dqrele_all_inodes(). This invokes the AG inode iterator, > which skips inodes in the XFS_INEW state because they are not fully > constructed. If the scan occurs after dquots have been attached to > an inode, but before XFS_INEW is cleared, the newly allocated inode > will continue to hold a reference to the applicable dquots. When > quotaoff invokes xfs_qm_dqpurge_all(), the reference count of those > dquot(s) remain elevated and the dqpurge scan spins indefinitely. > > To address this problem, update the xfs_qm_dqrele_all_inodes() scan > to wait on inodes marked on the XFS_INEW state. We wait on the > inodes explicitly rather than skip and retry to avoid continuous > retry loops due to a parallel inode allocation workload. Since > quotaoff updates the quota state flags and uses a synchronous > transaction before the dqrele scan, and dquots are attached to > inodes after radix tree insertion iff quota is enabled, one INEW > waiting pass through the AG guarantees that the scan has processed > all inodes that could possibly hold dquot references. > > Reported-by: Eryu Guan <eguan@xxxxxxxxxx> > Signed-off-by: Brian Foster <bfoster@xxxxxxxxxx> Looks ok, Reviewed-by: Darrick J. Wong <darrick.wong@xxxxxxxxxx> --D > --- > fs/xfs/xfs_qm_syscalls.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > > diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c > index dbb6802..40b7c3f 100644 > --- a/fs/xfs/xfs_qm_syscalls.c > +++ b/fs/xfs/xfs_qm_syscalls.c > @@ -765,5 +765,6 @@ xfs_qm_dqrele_all_inodes( > uint flags) > { > ASSERT(mp->m_quotainfo); > - xfs_inode_ag_iterator(mp, xfs_dqrele_inode, flags, NULL); > + xfs_inode_ag_iterator_flags(mp, xfs_dqrele_inode, flags, NULL, > + XFS_AGITER_INEW_WAIT); > } > -- > 2.7.4 > > -- > To unsubscribe from this list: send the line "unsubscribe linux-xfs" in > the body of a message to majordomo@xxxxxxxxxxxxxxx > More majordomo info at http://vger.kernel.org/majordomo-info.html -- To unsubscribe from this list: send the line "unsubscribe linux-xfs" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html