• Brian Foster's avatar
    xfs: wait on new inodes during quotaoff dquot release · e20c8a51
    Brian Foster authored
    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: 's avatarEryu Guan <eguan@redhat.com>
    Signed-off-by: 's avatarBrian Foster <bfoster@redhat.com>
    Reviewed-by: 's avatarDarrick J. Wong <darrick.wong@oracle.com>
    Signed-off-by: 's avatarDarrick J. Wong <darrick.wong@oracle.com>