/*
 * Return quota status information, such as uquota-off, enforcements, etc.
 */
STATIC int
xfs_qm_scall_getqstat(
	xfs_mount_t	*mp,
	fs_quota_stat_t *out)
{
	xfs_inode_t	*uip, *gip;
	boolean_t	tempuqip, tempgqip;

	uip = gip = NULL;
	tempuqip = tempgqip = B_FALSE;
	memset(out, 0, sizeof(fs_quota_stat_t));

	out->qs_version = FS_QSTAT_VERSION;
	if (! XFS_SB_VERSION_HASQUOTA(&mp->m_sb)) {
		out->qs_uquota.qfs_ino = NULLFSINO;
		out->qs_gquota.qfs_ino = NULLFSINO;
		return (0);
	}
	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
							(XFS_ALL_QUOTA_ACCT|
							 XFS_ALL_QUOTA_ENFD));
	out->qs_pad = 0;
	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;

	if (mp->m_quotainfo) {
		uip = mp->m_quotainfo->qi_uquotaip;
		gip = mp->m_quotainfo->qi_gquotaip;
	}
	if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
		if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
					0, 0, &uip, 0) == 0)
			tempuqip = B_TRUE;
	}
	if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
		if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
					0, 0, &gip, 0) == 0)
			tempgqip = B_TRUE;
	}
	if (uip) {
		out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
		out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
		if (tempuqip)
			VN_RELE(XFS_ITOV(uip));
	}
	if (gip) {
		out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
		out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
		if (tempgqip)
			VN_RELE(XFS_ITOV(gip));
	}
	if (mp->m_quotainfo) {
		out->qs_incoredqs = XFS_QI_MPLNDQUOTS(mp);
		out->qs_btimelimit = XFS_QI_BTIMELIMIT(mp);
		out->qs_itimelimit = XFS_QI_ITIMELIMIT(mp);
		out->qs_rtbtimelimit = XFS_QI_RTBTIMELIMIT(mp);
		out->qs_bwarnlimit = XFS_QI_BWARNLIMIT(mp);
		out->qs_iwarnlimit = XFS_QI_IWARNLIMIT(mp);
	}
	return (0);
}
/*
 * Return quota status information, such as uquota-off, enforcements, etc.
 * for Q_XGETQSTAT command.
 */
int
xfs_qm_scall_getqstat(
    struct xfs_mount	*mp,
    struct fs_quota_stat	*out)
{
    struct xfs_quotainfo	*q = mp->m_quotainfo;
    struct xfs_inode	*uip = NULL;
    struct xfs_inode	*gip = NULL;
    struct xfs_inode	*pip = NULL;
    bool                    tempuqip = false;
    bool                    tempgqip = false;
    bool                    temppqip = false;

    memset(out, 0, sizeof(fs_quota_stat_t));

    out->qs_version = FS_QSTAT_VERSION;
    if (!xfs_sb_version_hasquota(&mp->m_sb)) {
        out->qs_uquota.qfs_ino = NULLFSINO;
        out->qs_gquota.qfs_ino = NULLFSINO;
        return (0);
    }

    out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
                    (XFS_ALL_QUOTA_ACCT|
                     XFS_ALL_QUOTA_ENFD));
    if (q) {
        uip = q->qi_uquotaip;
        gip = q->qi_gquotaip;
        pip = q->qi_pquotaip;
    }
    if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
        if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
                     0, 0, &uip) == 0)
            tempuqip = true;
    }
    if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
        if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
                     0, 0, &gip) == 0)
            tempgqip = true;
    }
    /*
     * Q_XGETQSTAT doesn't have room for both group and project quotas.
     * So, allow the project quota values to be copied out only if
     * there is no group quota information available.
     */
    if (!gip) {
        if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) {
            if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
                         0, 0, &pip) == 0)
                temppqip = true;
        }
    } else
        pip = NULL;
    if (uip) {
        out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
        out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
        out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
        if (tempuqip)
            IRELE(uip);
    }

    if (gip) {
        out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
        out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
        out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
        if (tempgqip)
            IRELE(gip);
    }
    if (pip) {
        out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
        out->qs_gquota.qfs_nblks = pip->i_d.di_nblocks;
        out->qs_gquota.qfs_nextents = pip->i_d.di_nextents;
        if (temppqip)
            IRELE(pip);
    }
    if (q) {
        out->qs_incoredqs = q->qi_dquots;
        out->qs_btimelimit = q->qi_btimelimit;
        out->qs_itimelimit = q->qi_itimelimit;
        out->qs_rtbtimelimit = q->qi_rtbtimelimit;
        out->qs_bwarnlimit = q->qi_bwarnlimit;
        out->qs_iwarnlimit = q->qi_iwarnlimit;
    }
    return 0;
}
/*
 * Return quota status information, such as uquota-off, enforcements, etc.
 * for Q_XGETQSTATV command, to support separate project quota field.
 */
int
xfs_qm_scall_getqstatv(
    struct xfs_mount	*mp,
    struct fs_quota_statv	*out)
{
    struct xfs_quotainfo	*q = mp->m_quotainfo;
    struct xfs_inode	*uip = NULL;
    struct xfs_inode	*gip = NULL;
    struct xfs_inode	*pip = NULL;
    bool                    tempuqip = false;
    bool                    tempgqip = false;
    bool                    temppqip = false;

    if (!xfs_sb_version_hasquota(&mp->m_sb)) {
        out->qs_uquota.qfs_ino = NULLFSINO;
        out->qs_gquota.qfs_ino = NULLFSINO;
        out->qs_pquota.qfs_ino = NULLFSINO;
        return (0);
    }

    out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
                    (XFS_ALL_QUOTA_ACCT|
                     XFS_ALL_QUOTA_ENFD));
    out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
    out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;
    out->qs_pquota.qfs_ino = mp->m_sb.sb_pquotino;

    if (q) {
        uip = q->qi_uquotaip;
        gip = q->qi_gquotaip;
        pip = q->qi_pquotaip;
    }
    if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
        if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
                     0, 0, &uip) == 0)
            tempuqip = true;
    }
    if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
        if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
                     0, 0, &gip) == 0)
            tempgqip = true;
    }
    if (!pip && mp->m_sb.sb_pquotino != NULLFSINO) {
        if (xfs_iget(mp, NULL, mp->m_sb.sb_pquotino,
                     0, 0, &pip) == 0)
            temppqip = true;
    }
    if (uip) {
        out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
        out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
        if (tempuqip)
            IRELE(uip);
    }

    if (gip) {
        out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
        out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
        if (tempgqip)
            IRELE(gip);
    }
    if (pip) {
        out->qs_pquota.qfs_nblks = pip->i_d.di_nblocks;
        out->qs_pquota.qfs_nextents = pip->i_d.di_nextents;
        if (temppqip)
            IRELE(pip);
    }
    if (q) {
        out->qs_incoredqs = q->qi_dquots;
        out->qs_btimelimit = q->qi_btimelimit;
        out->qs_itimelimit = q->qi_itimelimit;
        out->qs_rtbtimelimit = q->qi_rtbtimelimit;
        out->qs_bwarnlimit = q->qi_bwarnlimit;
        out->qs_iwarnlimit = q->qi_iwarnlimit;
    }
    return 0;
}
/*
 * Return quota status information, such as uquota-off, enforcements, etc.
 */
int
xfs_qm_scall_getqstat(
	struct xfs_mount	*mp,
	struct fs_quota_stat	*out)
{
	struct xfs_quotainfo	*q = mp->m_quotainfo;
	struct xfs_inode	*uip, *gip;
	boolean_t		tempuqip, tempgqip;

	uip = gip = NULL;
	tempuqip = tempgqip = B_FALSE;
	memset(out, 0, sizeof(fs_quota_stat_t));

	out->qs_version = FS_QSTAT_VERSION;
	if (!xfs_sb_version_hasquota(&mp->m_sb)) {
		out->qs_uquota.qfs_ino = NULLFSINO;
		out->qs_gquota.qfs_ino = NULLFSINO;
		return (0);
	}
	out->qs_flags = (__uint16_t) xfs_qm_export_flags(mp->m_qflags &
							(XFS_ALL_QUOTA_ACCT|
							 XFS_ALL_QUOTA_ENFD));
	out->qs_pad = 0;
	out->qs_uquota.qfs_ino = mp->m_sb.sb_uquotino;
	out->qs_gquota.qfs_ino = mp->m_sb.sb_gquotino;

	if (q) {
		uip = q->qi_uquotaip;
		gip = q->qi_gquotaip;
	}
	if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) {
		if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino,
					0, 0, &uip) == 0)
			tempuqip = B_TRUE;
	}
	if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) {
		if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino,
					0, 0, &gip) == 0)
			tempgqip = B_TRUE;
	}
	if (uip) {
		out->qs_uquota.qfs_nblks = uip->i_d.di_nblocks;
		out->qs_uquota.qfs_nextents = uip->i_d.di_nextents;
		if (tempuqip)
			IRELE(uip);
	}
	if (gip) {
		out->qs_gquota.qfs_nblks = gip->i_d.di_nblocks;
		out->qs_gquota.qfs_nextents = gip->i_d.di_nextents;
		if (tempgqip)
			IRELE(gip);
	}
	if (q) {
		out->qs_incoredqs = q->qi_dquots;
		out->qs_btimelimit = q->qi_btimelimit;
		out->qs_itimelimit = q->qi_itimelimit;
		out->qs_rtbtimelimit = q->qi_rtbtimelimit;
		out->qs_bwarnlimit = q->qi_bwarnlimit;
		out->qs_iwarnlimit = q->qi_iwarnlimit;
	}
	return 0;
}