Re: [PATCH v3] xfs: return default quota limits for IDs without a dquot

Darrick J. Wong
2026-03-30T16:04:41Z

On Mon, Mar 30, 2026 at 02:14:14PM +0800, Ravi Singh wrote:
> When an ID has no dquot on disk, Q_XGETQUOTA returns -ENOENT even
> though default quota limits are configured and enforced against that
> ID. This means unprivileged users who have never used any resources
> cannot see the limits that apply to them.
>
> When xfs_qm_dqget() returns -ENOENT for a non-zero ID, return a
> zero-usage response with the default limits filled in from
> m_quotainfo rather than propagating the error. This is consistent
> with the enforcement behavior in xfs_qm_adjust_dqlimits(), which
> pushes the same default limits into a dquot when it is first
> allocated.
>
> Reviewed-by: Jan Kara <jack@suse.cz>
> Signed-off-by: Ravi Singh <ravising@redhat.com>

I think it's an improvement that you can now see the (default) limits
for an otherwise unused qid.

Reviewed-by: "Darrick J. Wong" <djwong@kernel.org>

--D

> ---
> v3:
> - Return -ENOENT when no default limits are configured
> instead of returning a zero-filled response (Darrick)
>
> v2:
> - Moved fix from VFS (fs/quota/quota.c) to XFS
> (fs/xfs/xfs_qm_syscalls.c) per review feedback
> - Return default limits on ENOENT instead of granting
> unprivileged access to ID 0's dquot
>
> fs/xfs/xfs_qm_syscalls.c | 43 +++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 42 insertions(+), 1 deletion(-)
>
> diff --git a/fs/xfs/xfs_qm_syscalls.c b/fs/xfs/xfs_qm_syscalls.c
> index d50b7318c..21a784986 100644
> --- a/fs/xfs/xfs_qm_syscalls.c
> +++ b/fs/xfs/xfs_qm_syscalls.c
> @@ -391,6 +391,38 @@ xfs_qm_scall_setqlim(
> return error;
> }
>
> +/*
> + * Fill out the default quota limits for an ID that has no dquot on disk.
> + * Returns 0 if default limits are configured
> + * and were filled in, -ENOENT otherwise.
> + */
> +static int
> +xfs_qm_scall_getquota_fill_defaults(
> + struct xfs_mount *mp,
> + xfs_dqtype_t type,
> + struct qc_dqblk *dst)
> +{
> + struct xfs_def_quota *defq;
> +
> + defq = xfs_get_defquota(mp->m_quotainfo, type);
> +
> + if (!defq->blk.soft && !defq->blk.hard &&
> + !defq->ino.soft && !defq->ino.hard &&
> + !defq->rtb.soft && !defq->rtb.hard) {
> + return -ENOENT;
> + }
> +
> + memset(dst, 0, sizeof(*dst));
> + dst->d_spc_softlimit = XFS_FSB_TO_B(mp, defq->blk.soft);
> + dst->d_spc_hardlimit = XFS_FSB_TO_B(mp, defq->blk.hard);
> + dst->d_ino_softlimit = defq->ino.soft;
> + dst->d_ino_hardlimit = defq->ino.hard;
> + dst->d_rt_spc_softlimit = XFS_FSB_TO_B(mp, defq->rtb.soft);
> + dst->d_rt_spc_hardlimit = XFS_FSB_TO_B(mp, defq->rtb.hard);
> +
> + return 0;
> +}
> +
> /* Fill out the quota context. */
> static void
> xfs_qm_scall_getquota_fill_qc(
> @@ -451,8 +483,17 @@ xfs_qm_scall_getquota(
> * set doalloc. If it doesn't exist, we'll get ENOENT back.
> */
> error = xfs_qm_dqget(mp, id, type, false, &dqp);
> - if (error)
> + if (error) {
> + /*
> + * If there is no dquot on disk and default limits are
> + * configured, return them with zero usage so that
> + * unprivileged users can see what limits apply to them.
> + */
> + if (error == -ENOENT && id != 0 &&
> + !xfs_qm_scall_getquota_fill_defaults(mp, type, dst))
> + return 0;
> return error;
> + }
>
> /*
> * If everything's NULL, this dquot doesn't quite exist as far as
> --
> 2.49.0
>
>