/* * This reserves disk blocks and inodes against a dquot. * Flags indicate if the dquot is to be locked here and also * if the blk reservation is for RT or regular blocks. * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check. * Returns EDQUOT if quota is exceeded. */ STATIC int xfs_trans_dqresv( xfs_trans_t *tp, xfs_dquot_t *dqp, long nblks, long ninos, uint flags) { int error; xfs_qcnt_t hardlimit; xfs_qcnt_t softlimit; time_t btimer; xfs_qcnt_t *resbcountp; if (! (flags & XFS_QMOPT_DQLOCK)) { xfs_dqlock(dqp); } ASSERT(XFS_DQ_IS_LOCKED(dqp)); if (flags & XFS_TRANS_DQ_RES_BLKS) { hardlimit = INT_GET(dqp->q_core.d_blk_hardlimit, ARCH_CONVERT); softlimit = INT_GET(dqp->q_core.d_blk_softlimit, ARCH_CONVERT); btimer = INT_GET(dqp->q_core.d_btimer, ARCH_CONVERT); resbcountp = &dqp->q_res_bcount; } else { ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS); hardlimit = INT_GET(dqp->q_core.d_rtb_hardlimit, ARCH_CONVERT); softlimit = INT_GET(dqp->q_core.d_rtb_softlimit, ARCH_CONVERT); btimer = INT_GET(dqp->q_core.d_rtbtimer, ARCH_CONVERT); resbcountp = &dqp->q_res_rtbcount; } error = 0; if ((flags & XFS_QMOPT_FORCE_RES) == 0 && !INT_ISZERO(dqp->q_core.d_id, ARCH_CONVERT) && XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) { #ifdef QUOTADEBUG printk("BLK Res: nblks=%ld + resbcount=%Ld > hardlimit=%Ld?\n", nblks, *resbcountp, hardlimit); #endif if (nblks > 0) { /* * dquot is locked already. See if we'd go over the * hardlimit or exceed the timelimit if we allocate * nblks. */ if (hardlimit > 0ULL && (hardlimit <= nblks + *resbcountp)) { error = EDQUOT; goto error_return; } if (softlimit > 0ULL && (softlimit <= nblks + *resbcountp)) { /* * If timer or warnings has expired, * return EDQUOT */ if ((btimer != 0 && CURRENT_TIME > btimer) || (!INT_ISZERO(dqp->q_core.d_bwarns, ARCH_CONVERT) && INT_GET(dqp->q_core.d_bwarns, ARCH_CONVERT) >= XFS_QI_BWARNLIMIT(dqp->q_mount))) { error = EDQUOT; goto error_return; } } } if (ninos > 0) { if (INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT) > 0ULL && INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= INT_GET(dqp->q_core.d_ino_hardlimit, ARCH_CONVERT)) { error = EDQUOT; goto error_return; } else if (INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT) > 0ULL && INT_GET(dqp->q_core.d_icount, ARCH_CONVERT) >= INT_GET(dqp->q_core.d_ino_softlimit, ARCH_CONVERT)) { /* * If timer or warnings has expired, * return EDQUOT */ if ((!INT_ISZERO(dqp->q_core.d_itimer, ARCH_CONVERT) && CURRENT_TIME > INT_GET(dqp->q_core.d_itimer, ARCH_CONVERT)) || (!INT_ISZERO(dqp->q_core.d_iwarns, ARCH_CONVERT) && INT_GET(dqp->q_core.d_iwarns, ARCH_CONVERT) >= XFS_QI_IWARNLIMIT(dqp->q_mount))) { error = EDQUOT; goto error_return; } } } } /* * Change the reservation, but not the actual usage. * Note that q_res_bcount = q_core.d_bcount + resv */ (*resbcountp) += (xfs_qcnt_t)nblks; if (ninos != 0) dqp->q_res_icount += (xfs_qcnt_t)ninos; /* * note the reservation amt in the trans struct too, * so that the transaction knows how much was reserved by * it against this particular dquot. * We don't do this when we are reserving for a delayed allocation, * because we don't have the luxury of a transaction envelope then. */ if (tp) { ASSERT(tp->t_dqinfo); ASSERT(flags & XFS_QMOPT_RESBLK_MASK); if (nblks != 0) xfs_trans_mod_dquot(tp, dqp, flags & XFS_QMOPT_RESBLK_MASK, nblks); if (ninos != 0) xfs_trans_mod_dquot(tp, dqp, XFS_TRANS_DQ_RES_INOS, ninos); } ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT)); ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT)); error_return: if (! (flags & XFS_QMOPT_DQLOCK)) { xfs_dqunlock(dqp); } return (error); }
/* * 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); }
/* * This reserves disk blocks and inodes against a dquot. * Flags indicate if the dquot is to be locked here and also * if the blk reservation is for RT or regular blocks. * Sending in XFS_QMOPT_FORCE_RES flag skips the quota check. * Returns EDQUOT if quota is exceeded. */ STATIC int xfs_trans_dqresv( xfs_trans_t *tp, xfs_mount_t *mp, xfs_dquot_t *dqp, long nblks, long ninos, uint flags) { int error; xfs_qcnt_t hardlimit; xfs_qcnt_t softlimit; time_t timer; xfs_qwarncnt_t warns; xfs_qwarncnt_t warnlimit; xfs_qcnt_t count; xfs_qcnt_t *resbcountp; xfs_quotainfo_t *q = mp->m_quotainfo; if (! (flags & XFS_QMOPT_DQLOCK)) { xfs_dqlock(dqp); } ASSERT(XFS_DQ_IS_LOCKED(dqp)); if (flags & XFS_TRANS_DQ_RES_BLKS) { hardlimit = be64_to_cpu(dqp->q_core.d_blk_hardlimit); if (!hardlimit) hardlimit = q->qi_bhardlimit; softlimit = be64_to_cpu(dqp->q_core.d_blk_softlimit); if (!softlimit) softlimit = q->qi_bsoftlimit; timer = be32_to_cpu(dqp->q_core.d_btimer); warns = be16_to_cpu(dqp->q_core.d_bwarns); warnlimit = XFS_QI_BWARNLIMIT(dqp->q_mount); resbcountp = &dqp->q_res_bcount; } else { ASSERT(flags & XFS_TRANS_DQ_RES_RTBLKS); hardlimit = be64_to_cpu(dqp->q_core.d_rtb_hardlimit); if (!hardlimit) hardlimit = q->qi_rtbhardlimit; softlimit = be64_to_cpu(dqp->q_core.d_rtb_softlimit); if (!softlimit) softlimit = q->qi_rtbsoftlimit; timer = be32_to_cpu(dqp->q_core.d_rtbtimer); warns = be16_to_cpu(dqp->q_core.d_rtbwarns); warnlimit = XFS_QI_RTBWARNLIMIT(dqp->q_mount); resbcountp = &dqp->q_res_rtbcount; } error = 0; if ((flags & XFS_QMOPT_FORCE_RES) == 0 && dqp->q_core.d_id && XFS_IS_QUOTA_ENFORCED(dqp->q_mount)) { #ifdef QUOTADEBUG cmn_err(CE_DEBUG, "BLK Res: nblks=%ld + resbcount=%Ld" " > hardlimit=%Ld?", nblks, *resbcountp, hardlimit); #endif if (nblks > 0) { /* * dquot is locked already. See if we'd go over the * hardlimit or exceed the timelimit if we allocate * nblks. */ if (hardlimit > 0ULL && (hardlimit <= nblks + *resbcountp)) { error = EDQUOT; goto error_return; } if (softlimit > 0ULL && (softlimit <= nblks + *resbcountp)) { /* * If timer or warnings has expired, * return EDQUOT */ if ((timer != 0 && get_seconds() > timer) || (warns != 0 && warns >= warnlimit)) { error = EDQUOT; goto error_return; } } } if (ninos > 0) { count = be64_to_cpu(dqp->q_core.d_icount); timer = be32_to_cpu(dqp->q_core.d_itimer); warns = be16_to_cpu(dqp->q_core.d_iwarns); warnlimit = XFS_QI_IWARNLIMIT(dqp->q_mount); hardlimit = be64_to_cpu(dqp->q_core.d_ino_hardlimit); if (!hardlimit) hardlimit = q->qi_ihardlimit; softlimit = be64_to_cpu(dqp->q_core.d_ino_softlimit); if (!softlimit) softlimit = q->qi_isoftlimit; if (hardlimit > 0ULL && count >= hardlimit) { error = EDQUOT; goto error_return; } else if (softlimit > 0ULL && count >= softlimit) { /* * If timer or warnings has expired, * return EDQUOT */ if ((timer != 0 && get_seconds() > timer) || (warns != 0 && warns >= warnlimit)) { error = EDQUOT; goto error_return; } } } } /* * Change the reservation, but not the actual usage. * Note that q_res_bcount = q_core.d_bcount + resv */ (*resbcountp) += (xfs_qcnt_t)nblks; if (ninos != 0) dqp->q_res_icount += (xfs_qcnt_t)ninos; /* * note the reservation amt in the trans struct too, * so that the transaction knows how much was reserved by * it against this particular dquot. * We don't do this when we are reserving for a delayed allocation, * because we don't have the luxury of a transaction envelope then. */ if (tp) { ASSERT(tp->t_dqinfo); ASSERT(flags & XFS_QMOPT_RESBLK_MASK); if (nblks != 0) xfs_trans_mod_dquot(tp, dqp, flags & XFS_QMOPT_RESBLK_MASK, nblks); if (ninos != 0) xfs_trans_mod_dquot(tp, dqp, XFS_TRANS_DQ_RES_INOS, ninos); } ASSERT(dqp->q_res_bcount >= be64_to_cpu(dqp->q_core.d_bcount)); ASSERT(dqp->q_res_rtbcount >= be64_to_cpu(dqp->q_core.d_rtbcount)); ASSERT(dqp->q_res_icount >= be64_to_cpu(dqp->q_core.d_icount)); error_return: if (! (flags & XFS_QMOPT_DQLOCK)) { xfs_dqunlock(dqp); } return (error); }