fs/xfs/xfs_qm.c

Source file repositories/reference/linux-study-clean/fs/xfs/xfs_qm.c

File Facts

System
Linux kernel
Corpus path
fs/xfs/xfs_qm.c
Extension
.c
Size
51638 bytes
Lines
2139
Domain
Core OS
Bucket
VFS And Filesystem Core
Inferred role
Core OS: implementation source
Status
source implementation candidate

Why This File Exists

Core operating-system implementation surface: boot, tasks, memory, VFS, syscall-facing interfaces, synchronization, credentials, and isolation.

Dependency Surface

Detected Declarations

Annotated Snippet

struct xfs_qm_isolate {
	struct list_head	buffers;
	struct list_head	dispose;
};

static enum lru_status
xfs_qm_dquot_isolate(
	struct list_head	*item,
	struct list_lru_one	*lru,
	void			*arg)
		__releases(&lru->lock) __acquires(&lru->lock)
{
	struct xfs_dquot	*dqp = container_of(item,
						struct xfs_dquot, q_lru);
	struct xfs_qm_isolate	*isol = arg;
	enum lru_status		ret = LRU_SKIP;

	if (!spin_trylock(&dqp->q_lockref.lock))
		goto out_miss_busy;

	/*
	 * If something else is freeing this dquot and hasn't yet removed it
	 * from the LRU, leave it for the freeing task to complete the freeing
	 * process rather than risk it being free from under us here.
	 */
	if (__lockref_is_dead(&dqp->q_lockref))
		goto out_miss_unlock;

	/*
	 * If the dquot is pinned or dirty, rotate it to the end of the LRU to
	 * give some time for it to be cleaned before we try to isolate it
	 * again.
	 */
	ret = LRU_ROTATE;
	if (XFS_DQ_IS_DIRTY(dqp) || atomic_read(&dqp->q_pincount) > 0)
		goto out_miss_unlock;

	/*
	 * This dquot has acquired a reference in the meantime remove it from
	 * the freelist and try again.
	 */
	if (dqp->q_lockref.count) {
		spin_unlock(&dqp->q_lockref.lock);
		XFS_STATS_INC(dqp->q_mount, xs_qm_dqwants);

		trace_xfs_dqreclaim_want(dqp);
		list_lru_isolate(lru, &dqp->q_lru);
		XFS_STATS_DEC(dqp->q_mount, xs_qm_dquot_unused);
		return LRU_REMOVED;
	}

	/*
	 * The dquot may still be under IO, in which case the flush lock will be
	 * held. If we can't get the flush lock now, just skip over the dquot as
	 * if it was dirty.
	 */
	if (!xfs_dqflock_nowait(dqp))
		goto out_miss_unlock;

	ASSERT(!XFS_DQ_IS_DIRTY(dqp));
	xfs_dquot_detach_buf(dqp);
	xfs_dqfunlock(dqp);

	/*
	 * Prevent lookups now that we are past the point of no return.
	 */
	lockref_mark_dead(&dqp->q_lockref);
	spin_unlock(&dqp->q_lockref.lock);

	list_lru_isolate_move(lru, &dqp->q_lru, &isol->dispose);
	XFS_STATS_DEC(dqp->q_mount, xs_qm_dquot_unused);
	trace_xfs_dqreclaim_done(dqp);
	XFS_STATS_INC(dqp->q_mount, xs_qm_dqreclaims);
	return LRU_REMOVED;

out_miss_unlock:
	spin_unlock(&dqp->q_lockref.lock);
out_miss_busy:
	trace_xfs_dqreclaim_busy(dqp);
	XFS_STATS_INC(dqp->q_mount, xs_qm_dqreclaim_misses);
	return ret;
}

static unsigned long
xfs_qm_shrink_scan(
	struct shrinker		*shrink,
	struct shrink_control	*sc)
{
	struct xfs_quotainfo	*qi = shrink->private_data;
	struct xfs_qm_isolate	isol;

Annotation

Implementation Notes