/* * This is called to attempt to lock the dquot associated with this * dquot log item. Don't sleep on the dquot lock or the flush lock. * If the flush lock is already held, indicating that the dquot has * been or is in the process of being flushed, then see if we can * find the dquot's buffer in the buffer cache without sleeping. If * we can and it is marked delayed write, then we want to send it out. * We delay doing so until the push routine, though, to avoid sleeping * in any device strategy routines. */ STATIC uint xfs_qm_dquot_logitem_trylock( struct xfs_log_item *lip) { struct xfs_dquot *dqp = DQUOT_ITEM(lip)->qli_dquot; if (atomic_read(&dqp->q_pincount) > 0) return XFS_ITEM_PINNED; if (!xfs_dqlock_nowait(dqp)) return XFS_ITEM_LOCKED; if (!xfs_dqflock_nowait(dqp)) { /* * dquot has already been flushed to the backing buffer, * leave it locked, pushbuf routine will unlock it. */ return XFS_ITEM_PUSHBUF; } ASSERT(lip->li_flags & XFS_LI_IN_AIL); return XFS_ITEM_SUCCESS; }
STATIC void xfs_qm_dqreclaim_one( struct xfs_dquot *dqp, struct list_head *buffer_list, struct list_head *dispose_list) { struct xfs_mount *mp = dqp->q_mount; struct xfs_quotainfo *qi = mp->m_quotainfo; int error; if (!xfs_dqlock_nowait(dqp)) goto out_move_tail; /* * This dquot has acquired a reference in the meantime remove it from * the freelist and try again. */ if (dqp->q_nrefs) { xfs_dqunlock(dqp); trace_xfs_dqreclaim_want(dqp); XFS_STATS_INC(xs_qm_dqwants); list_del_init(&dqp->q_lru); qi->qi_lru_count--; XFS_STATS_DEC(xs_qm_dquot_unused); return; } /* * Try to grab the flush lock. If this dquot is in the process of * getting flushed to disk, we don't want to reclaim it. */ if (!xfs_dqflock_nowait(dqp)) goto out_unlock_move_tail; if (XFS_DQ_IS_DIRTY(dqp)) { struct xfs_buf *bp = NULL; trace_xfs_dqreclaim_dirty(dqp); error = xfs_qm_dqflush(dqp, &bp); if (error) { xfs_warn(mp, "%s: dquot %p flush failed", __func__, dqp); goto out_unlock_move_tail; } xfs_buf_delwri_queue(bp, buffer_list); xfs_buf_relse(bp); /* * Give the dquot another try on the freelist, as the * flushing will take some time. */ goto out_unlock_move_tail; } xfs_dqfunlock(dqp); /* * Prevent lookups now that we are past the point of no return. */ dqp->dq_flags |= XFS_DQ_FREEING; xfs_dqunlock(dqp); ASSERT(dqp->q_nrefs == 0); list_move_tail(&dqp->q_lru, dispose_list); qi->qi_lru_count--; XFS_STATS_DEC(xs_qm_dquot_unused); trace_xfs_dqreclaim_done(dqp); XFS_STATS_INC(xs_qm_dqreclaims); return; /* * Move the dquot to the tail of the list so that we don't spin on it. */ out_unlock_move_tail: xfs_dqunlock(dqp); out_move_tail: list_move_tail(&dqp->q_lru, &qi->qi_lru_list); trace_xfs_dqreclaim_busy(dqp); XFS_STATS_INC(xs_qm_dqreclaim_misses); }