162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2000-2005 Silicon Graphics, Inc.
462306a36Sopenharmony_ci * All Rights Reserved.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#ifndef __XFS_DQUOT_H__
762306a36Sopenharmony_ci#define __XFS_DQUOT_H__
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci/*
1062306a36Sopenharmony_ci * Dquots are structures that hold quota information about a user or a group,
1162306a36Sopenharmony_ci * much like inodes are for files. In fact, dquots share many characteristics
1262306a36Sopenharmony_ci * with inodes. However, dquots can also be a centralized resource, relative
1362306a36Sopenharmony_ci * to a collection of inodes. In this respect, dquots share some characteristics
1462306a36Sopenharmony_ci * of the superblock.
1562306a36Sopenharmony_ci * XFS dquots exploit both those in its algorithms. They make every attempt
1662306a36Sopenharmony_ci * to not be a bottleneck when quotas are on and have minimal impact, if any,
1762306a36Sopenharmony_ci * when quotas are off.
1862306a36Sopenharmony_ci */
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_cistruct xfs_mount;
2162306a36Sopenharmony_cistruct xfs_trans;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cienum {
2462306a36Sopenharmony_ci	XFS_QLOWSP_1_PCNT = 0,
2562306a36Sopenharmony_ci	XFS_QLOWSP_3_PCNT,
2662306a36Sopenharmony_ci	XFS_QLOWSP_5_PCNT,
2762306a36Sopenharmony_ci	XFS_QLOWSP_MAX
2862306a36Sopenharmony_ci};
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistruct xfs_dquot_res {
3162306a36Sopenharmony_ci	/* Total resources allocated and reserved. */
3262306a36Sopenharmony_ci	xfs_qcnt_t		reserved;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	/* Total resources allocated. */
3562306a36Sopenharmony_ci	xfs_qcnt_t		count;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci	/* Absolute and preferred limits. */
3862306a36Sopenharmony_ci	xfs_qcnt_t		hardlimit;
3962306a36Sopenharmony_ci	xfs_qcnt_t		softlimit;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	/*
4262306a36Sopenharmony_ci	 * For root dquots, this is the default grace period, in seconds.
4362306a36Sopenharmony_ci	 * Otherwise, this is when the quota grace period expires,
4462306a36Sopenharmony_ci	 * in seconds since the Unix epoch.
4562306a36Sopenharmony_ci	 */
4662306a36Sopenharmony_ci	time64_t		timer;
4762306a36Sopenharmony_ci};
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic inline bool
5062306a36Sopenharmony_cixfs_dquot_res_over_limits(
5162306a36Sopenharmony_ci	const struct xfs_dquot_res	*qres)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	if ((qres->softlimit && qres->softlimit < qres->reserved) ||
5462306a36Sopenharmony_ci	    (qres->hardlimit && qres->hardlimit < qres->reserved))
5562306a36Sopenharmony_ci		return true;
5662306a36Sopenharmony_ci	return false;
5762306a36Sopenharmony_ci}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci/*
6062306a36Sopenharmony_ci * The incore dquot structure
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_cistruct xfs_dquot {
6362306a36Sopenharmony_ci	struct list_head	q_lru;
6462306a36Sopenharmony_ci	struct xfs_mount	*q_mount;
6562306a36Sopenharmony_ci	xfs_dqtype_t		q_type;
6662306a36Sopenharmony_ci	uint16_t		q_flags;
6762306a36Sopenharmony_ci	xfs_dqid_t		q_id;
6862306a36Sopenharmony_ci	uint			q_nrefs;
6962306a36Sopenharmony_ci	int			q_bufoffset;
7062306a36Sopenharmony_ci	xfs_daddr_t		q_blkno;
7162306a36Sopenharmony_ci	xfs_fileoff_t		q_fileoffset;
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	struct xfs_dquot_res	q_blk;	/* regular blocks */
7462306a36Sopenharmony_ci	struct xfs_dquot_res	q_ino;	/* inodes */
7562306a36Sopenharmony_ci	struct xfs_dquot_res	q_rtb;	/* realtime blocks */
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci	struct xfs_dq_logitem	q_logitem;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	xfs_qcnt_t		q_prealloc_lo_wmark;
8062306a36Sopenharmony_ci	xfs_qcnt_t		q_prealloc_hi_wmark;
8162306a36Sopenharmony_ci	int64_t			q_low_space[XFS_QLOWSP_MAX];
8262306a36Sopenharmony_ci	struct mutex		q_qlock;
8362306a36Sopenharmony_ci	struct completion	q_flush;
8462306a36Sopenharmony_ci	atomic_t		q_pincount;
8562306a36Sopenharmony_ci	struct wait_queue_head	q_pinwait;
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci/*
8962306a36Sopenharmony_ci * Lock hierarchy for q_qlock:
9062306a36Sopenharmony_ci *	XFS_QLOCK_NORMAL is the implicit default,
9162306a36Sopenharmony_ci *	XFS_QLOCK_NESTED is the dquot with the higher id in xfs_dqlock2
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_cienum {
9462306a36Sopenharmony_ci	XFS_QLOCK_NORMAL = 0,
9562306a36Sopenharmony_ci	XFS_QLOCK_NESTED,
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/*
9962306a36Sopenharmony_ci * Manage the q_flush completion queue embedded in the dquot. This completion
10062306a36Sopenharmony_ci * queue synchronizes processes attempting to flush the in-core dquot back to
10162306a36Sopenharmony_ci * disk.
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_cistatic inline void xfs_dqflock(struct xfs_dquot *dqp)
10462306a36Sopenharmony_ci{
10562306a36Sopenharmony_ci	wait_for_completion(&dqp->q_flush);
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic inline bool xfs_dqflock_nowait(struct xfs_dquot *dqp)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	return try_wait_for_completion(&dqp->q_flush);
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic inline void xfs_dqfunlock(struct xfs_dquot *dqp)
11462306a36Sopenharmony_ci{
11562306a36Sopenharmony_ci	complete(&dqp->q_flush);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline int xfs_dqlock_nowait(struct xfs_dquot *dqp)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	return mutex_trylock(&dqp->q_qlock);
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_cistatic inline void xfs_dqlock(struct xfs_dquot *dqp)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	mutex_lock(&dqp->q_qlock);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic inline void xfs_dqunlock(struct xfs_dquot *dqp)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	mutex_unlock(&dqp->q_qlock);
13162306a36Sopenharmony_ci}
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_cistatic inline int
13462306a36Sopenharmony_cixfs_dquot_type(const struct xfs_dquot *dqp)
13562306a36Sopenharmony_ci{
13662306a36Sopenharmony_ci	return dqp->q_type & XFS_DQTYPE_REC_MASK;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic inline int xfs_this_quota_on(struct xfs_mount *mp, xfs_dqtype_t type)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	switch (type) {
14262306a36Sopenharmony_ci	case XFS_DQTYPE_USER:
14362306a36Sopenharmony_ci		return XFS_IS_UQUOTA_ON(mp);
14462306a36Sopenharmony_ci	case XFS_DQTYPE_GROUP:
14562306a36Sopenharmony_ci		return XFS_IS_GQUOTA_ON(mp);
14662306a36Sopenharmony_ci	case XFS_DQTYPE_PROJ:
14762306a36Sopenharmony_ci		return XFS_IS_PQUOTA_ON(mp);
14862306a36Sopenharmony_ci	default:
14962306a36Sopenharmony_ci		return 0;
15062306a36Sopenharmony_ci	}
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic inline struct xfs_dquot *xfs_inode_dquot(
15462306a36Sopenharmony_ci	struct xfs_inode	*ip,
15562306a36Sopenharmony_ci	xfs_dqtype_t		type)
15662306a36Sopenharmony_ci{
15762306a36Sopenharmony_ci	switch (type) {
15862306a36Sopenharmony_ci	case XFS_DQTYPE_USER:
15962306a36Sopenharmony_ci		return ip->i_udquot;
16062306a36Sopenharmony_ci	case XFS_DQTYPE_GROUP:
16162306a36Sopenharmony_ci		return ip->i_gdquot;
16262306a36Sopenharmony_ci	case XFS_DQTYPE_PROJ:
16362306a36Sopenharmony_ci		return ip->i_pdquot;
16462306a36Sopenharmony_ci	default:
16562306a36Sopenharmony_ci		return NULL;
16662306a36Sopenharmony_ci	}
16762306a36Sopenharmony_ci}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/* Decide if the dquot's limits are actually being enforced. */
17062306a36Sopenharmony_cistatic inline bool
17162306a36Sopenharmony_cixfs_dquot_is_enforced(
17262306a36Sopenharmony_ci	const struct xfs_dquot	*dqp)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	switch (xfs_dquot_type(dqp)) {
17562306a36Sopenharmony_ci	case XFS_DQTYPE_USER:
17662306a36Sopenharmony_ci		return XFS_IS_UQUOTA_ENFORCED(dqp->q_mount);
17762306a36Sopenharmony_ci	case XFS_DQTYPE_GROUP:
17862306a36Sopenharmony_ci		return XFS_IS_GQUOTA_ENFORCED(dqp->q_mount);
17962306a36Sopenharmony_ci	case XFS_DQTYPE_PROJ:
18062306a36Sopenharmony_ci		return XFS_IS_PQUOTA_ENFORCED(dqp->q_mount);
18162306a36Sopenharmony_ci	}
18262306a36Sopenharmony_ci	ASSERT(0);
18362306a36Sopenharmony_ci	return false;
18462306a36Sopenharmony_ci}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci/*
18762306a36Sopenharmony_ci * Check whether a dquot is under low free space conditions. We assume the quota
18862306a36Sopenharmony_ci * is enabled and enforced.
18962306a36Sopenharmony_ci */
19062306a36Sopenharmony_cistatic inline bool xfs_dquot_lowsp(struct xfs_dquot *dqp)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	int64_t freesp;
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	freesp = dqp->q_blk.hardlimit - dqp->q_blk.reserved;
19562306a36Sopenharmony_ci	if (freesp < dqp->q_low_space[XFS_QLOWSP_1_PCNT])
19662306a36Sopenharmony_ci		return true;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	return false;
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_civoid xfs_dquot_to_disk(struct xfs_disk_dquot *ddqp, struct xfs_dquot *dqp);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci#define XFS_DQ_IS_LOCKED(dqp)	(mutex_is_locked(&((dqp)->q_qlock)))
20462306a36Sopenharmony_ci#define XFS_DQ_IS_DIRTY(dqp)	((dqp)->q_flags & XFS_DQFLAG_DIRTY)
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_civoid		xfs_qm_dqdestroy(struct xfs_dquot *dqp);
20762306a36Sopenharmony_ciint		xfs_qm_dqflush(struct xfs_dquot *dqp, struct xfs_buf **bpp);
20862306a36Sopenharmony_civoid		xfs_qm_dqunpin_wait(struct xfs_dquot *dqp);
20962306a36Sopenharmony_civoid		xfs_qm_adjust_dqtimers(struct xfs_dquot *d);
21062306a36Sopenharmony_civoid		xfs_qm_adjust_dqlimits(struct xfs_dquot *d);
21162306a36Sopenharmony_cixfs_dqid_t	xfs_qm_id_for_quotatype(struct xfs_inode *ip,
21262306a36Sopenharmony_ci				xfs_dqtype_t type);
21362306a36Sopenharmony_ciint		xfs_qm_dqget(struct xfs_mount *mp, xfs_dqid_t id,
21462306a36Sopenharmony_ci				xfs_dqtype_t type, bool can_alloc,
21562306a36Sopenharmony_ci				struct xfs_dquot **dqpp);
21662306a36Sopenharmony_ciint		xfs_qm_dqget_inode(struct xfs_inode *ip, xfs_dqtype_t type,
21762306a36Sopenharmony_ci				bool can_alloc, struct xfs_dquot **dqpp);
21862306a36Sopenharmony_ciint		xfs_qm_dqget_next(struct xfs_mount *mp, xfs_dqid_t id,
21962306a36Sopenharmony_ci				xfs_dqtype_t type, struct xfs_dquot **dqpp);
22062306a36Sopenharmony_ciint		xfs_qm_dqget_uncached(struct xfs_mount *mp,
22162306a36Sopenharmony_ci				xfs_dqid_t id, xfs_dqtype_t type,
22262306a36Sopenharmony_ci				struct xfs_dquot **dqpp);
22362306a36Sopenharmony_civoid		xfs_qm_dqput(struct xfs_dquot *dqp);
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_civoid		xfs_dqlock2(struct xfs_dquot *, struct xfs_dquot *);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_civoid		xfs_dquot_set_prealloc_limits(struct xfs_dquot *);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_cistatic inline struct xfs_dquot *xfs_qm_dqhold(struct xfs_dquot *dqp)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	xfs_dqlock(dqp);
23262306a36Sopenharmony_ci	dqp->q_nrefs++;
23362306a36Sopenharmony_ci	xfs_dqunlock(dqp);
23462306a36Sopenharmony_ci	return dqp;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_citypedef int (*xfs_qm_dqiterate_fn)(struct xfs_dquot *dq,
23862306a36Sopenharmony_ci		xfs_dqtype_t type, void *priv);
23962306a36Sopenharmony_ciint xfs_qm_dqiterate(struct xfs_mount *mp, xfs_dqtype_t type,
24062306a36Sopenharmony_ci		xfs_qm_dqiterate_fn iter_fn, void *priv);
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_citime64_t xfs_dquot_set_timeout(struct xfs_mount *mp, time64_t timeout);
24362306a36Sopenharmony_citime64_t xfs_dquot_set_grace_period(time64_t grace);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci#endif /* __XFS_DQUOT_H__ */
246