📄 xfs_qm_syscalls.c
字号:
*/ if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) != (mp->m_qflags & XFS_UQUOTA_ACCT)) || ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) != (mp->m_qflags & XFS_PQUOTA_ACCT)) || ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) != (mp->m_qflags & XFS_GQUOTA_ACCT)) || (flags & XFS_ALL_QUOTA_ENFD) == 0) return (0); if (! XFS_IS_QUOTA_RUNNING(mp)) return XFS_ERROR(ESRCH); /* * Switch on quota enforcement in core. */ mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD); mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD); mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); return (0);}/* * Return quota status information, such as uquota-off, enforcements, etc. */STATIC intxfs_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);}/* * Adjust quota limits, and start/stop timers accordingly. */STATIC intxfs_qm_scall_setqlim( xfs_mount_t *mp, xfs_dqid_t id, uint type, fs_disk_quota_t *newlim){ xfs_disk_dquot_t *ddq; xfs_dquot_t *dqp; xfs_trans_t *tp; int error; xfs_qcnt_t hard, soft; if (!capable(CAP_SYS_ADMIN)) return XFS_ERROR(EPERM); if ((newlim->d_fieldmask & (FS_DQ_LIMIT_MASK|FS_DQ_TIMER_MASK|FS_DQ_WARNS_MASK)) == 0) return (0); tp = xfs_trans_alloc(mp, XFS_TRANS_QM_SETQLIM); if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_disk_dquot_t) + 128, 0, 0, XFS_DEFAULT_LOG_COUNT))) { xfs_trans_cancel(tp, 0); return (error); } /* * We don't want to race with a quotaoff so take the quotaoff lock. * (We don't hold an inode lock, so there's nothing else to stop * a quotaoff from happening). (XXXThis doesn't currently happen * because we take the vfslock before calling xfs_qm_sysent). */ mutex_lock(&(XFS_QI_QOFFLOCK(mp)), PINOD); /* * Get the dquot (locked), and join it to the transaction. * Allocate the dquot if this doesn't exist. */ if ((error = xfs_qm_dqget(mp, NULL, id, type, XFS_QMOPT_DQALLOC, &dqp))) { xfs_trans_cancel(tp, XFS_TRANS_ABORT); mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); ASSERT(error != ENOENT); return (error); } xfs_dqtrace_entry(dqp, "Q_SETQLIM: AFT DQGET"); xfs_trans_dqjoin(tp, dqp); ddq = &dqp->q_core; /* * Make sure that hardlimits are >= soft limits before changing. */ hard = (newlim->d_fieldmask & FS_DQ_BHARD) ? (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_hardlimit) : be64_to_cpu(ddq->d_blk_hardlimit); soft = (newlim->d_fieldmask & FS_DQ_BSOFT) ? (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_blk_softlimit) : be64_to_cpu(ddq->d_blk_softlimit); if (hard == 0 || hard >= soft) { ddq->d_blk_hardlimit = cpu_to_be64(hard); ddq->d_blk_softlimit = cpu_to_be64(soft); if (id == 0) { mp->m_quotainfo->qi_bhardlimit = hard; mp->m_quotainfo->qi_bsoftlimit = soft; } } else { qdprintk("blkhard %Ld < blksoft %Ld\n", hard, soft); } hard = (newlim->d_fieldmask & FS_DQ_RTBHARD) ? (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_hardlimit) : be64_to_cpu(ddq->d_rtb_hardlimit); soft = (newlim->d_fieldmask & FS_DQ_RTBSOFT) ? (xfs_qcnt_t) XFS_BB_TO_FSB(mp, newlim->d_rtb_softlimit) : be64_to_cpu(ddq->d_rtb_softlimit); if (hard == 0 || hard >= soft) { ddq->d_rtb_hardlimit = cpu_to_be64(hard); ddq->d_rtb_softlimit = cpu_to_be64(soft); if (id == 0) { mp->m_quotainfo->qi_rtbhardlimit = hard; mp->m_quotainfo->qi_rtbsoftlimit = soft; } } else { qdprintk("rtbhard %Ld < rtbsoft %Ld\n", hard, soft); } hard = (newlim->d_fieldmask & FS_DQ_IHARD) ? (xfs_qcnt_t) newlim->d_ino_hardlimit : be64_to_cpu(ddq->d_ino_hardlimit); soft = (newlim->d_fieldmask & FS_DQ_ISOFT) ? (xfs_qcnt_t) newlim->d_ino_softlimit : be64_to_cpu(ddq->d_ino_softlimit); if (hard == 0 || hard >= soft) { ddq->d_ino_hardlimit = cpu_to_be64(hard); ddq->d_ino_softlimit = cpu_to_be64(soft); if (id == 0) { mp->m_quotainfo->qi_ihardlimit = hard; mp->m_quotainfo->qi_isoftlimit = soft; } } else { qdprintk("ihard %Ld < isoft %Ld\n", hard, soft); } /* * Update warnings counter(s) if requested */ if (newlim->d_fieldmask & FS_DQ_BWARNS) ddq->d_bwarns = cpu_to_be16(newlim->d_bwarns); if (newlim->d_fieldmask & FS_DQ_IWARNS) ddq->d_iwarns = cpu_to_be16(newlim->d_iwarns); if (newlim->d_fieldmask & FS_DQ_RTBWARNS) ddq->d_rtbwarns = cpu_to_be16(newlim->d_rtbwarns); if (id == 0) { /* * Timelimits for the super user set the relative time * the other users can be over quota for this file system. * If it is zero a default is used. Ditto for the default * soft and hard limit values (already done, above), and * for warnings. */ if (newlim->d_fieldmask & FS_DQ_BTIMER) { mp->m_quotainfo->qi_btimelimit = newlim->d_btimer; ddq->d_btimer = cpu_to_be32(newlim->d_btimer); } if (newlim->d_fieldmask & FS_DQ_ITIMER) { mp->m_quotainfo->qi_itimelimit = newlim->d_itimer; ddq->d_itimer = cpu_to_be32(newlim->d_itimer); } if (newlim->d_fieldmask & FS_DQ_RTBTIMER) { mp->m_quotainfo->qi_rtbtimelimit = newlim->d_rtbtimer; ddq->d_rtbtimer = cpu_to_be32(newlim->d_rtbtimer); } if (newlim->d_fieldmask & FS_DQ_BWARNS) mp->m_quotainfo->qi_bwarnlimit = newlim->d_bwarns; if (newlim->d_fieldmask & FS_DQ_IWARNS) mp->m_quotainfo->qi_iwarnlimit = newlim->d_iwarns; if (newlim->d_fieldmask & FS_DQ_RTBWARNS) mp->m_quotainfo->qi_rtbwarnlimit = newlim->d_rtbwarns; } else { /* * If the user is now over quota, start the timelimit. * The user will not be 'warned'. * Note that we keep the timers ticking, whether enforcement * is on or off. We don't really want to bother with iterating * over all ondisk dquots and turning the timers on/off. */ xfs_qm_adjust_dqtimers(mp, ddq); } dqp->dq_flags |= XFS_DQ_DIRTY; xfs_trans_log_dquot(tp, dqp); xfs_dqtrace_entry(dqp, "Q_SETQLIM: COMMIT"); xfs_trans_commit(tp, 0, NULL); xfs_qm_dqprint(dqp); xfs_qm_dqrele(dqp); mutex_unlock(&(XFS_QI_QOFFLOCK(mp))); return (0);}STATIC intxfs_qm_scall_getquota( xfs_mount_t *mp, xfs_dqid_t id, uint type, fs_disk_quota_t *out){ xfs_dquot_t *dqp; int error; /* * Try to get the dquot. We don't want it allocated on disk, so * we aren't passing the XFS_QMOPT_DOALLOC flag. If it doesn't * exist, we'll get ENOENT back. */ if ((error = xfs_qm_dqget(mp, NULL, id, type, 0, &dqp))) { return (error); } xfs_dqtrace_entry(dqp, "Q_GETQUOTA SUCCESS"); /* * If everything's NULL, this dquot doesn't quite exist as far as * our utility programs are concerned. */ if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) { xfs_qm_dqput(dqp); return XFS_ERROR(ENOENT); } /* xfs_qm_dqprint(dqp); */ /* * Convert the disk dquot to the exportable format */ xfs_qm_export_dquot(mp, &dqp->q_core, out); xfs_qm_dqput(dqp); return (error ? XFS_ERROR(EFAULT) : 0);}STATIC intxfs_qm_log_quotaoff_end( xfs_mount_t *mp, xfs_qoff_logitem_t *startqoff, uint flags){ xfs_trans_t *tp; int error; xfs_qoff_logitem_t *qoffi; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF_END); if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2, 0, 0, XFS_DEFAULT_LOG_COUNT))) { xfs_trans_cancel(tp, 0); return (error); } qoffi = xfs_trans_get_qoff_item(tp, startqoff, flags & XFS_ALL_QUOTA_ACCT); xfs_trans_log_quotaoff_item(tp, qoffi); /* * We have to make sure that the transaction is secure on disk before we * return and actually stop quota accounting. So, make it synchronous. * We don't care about quotoff's performance. */ xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0, NULL); return (error);}STATIC intxfs_qm_log_quotaoff( xfs_mount_t *mp, xfs_qoff_logitem_t **qoffstartp, uint flags){ xfs_trans_t *tp; int error; unsigned long s; xfs_qoff_logitem_t *qoffi=NULL; uint oldsbqflag=0; tp = xfs_trans_alloc(mp, XFS_TRANS_QM_QUOTAOFF); if ((error = xfs_trans_reserve(tp, 0, sizeof(xfs_qoff_logitem_t) * 2 + mp->m_sb.sb_sectsize + 128, 0, 0, XFS_DEFAULT_LOG_COUNT))) { goto error0; } qoffi = xfs_trans_get_qoff_item(tp, NULL, flags & XFS_ALL_QUOTA_ACCT); xfs_trans_log_quotaoff_item(tp, qoffi); s = XFS_SB_LOCK(mp); oldsbqflag = mp->m_sb.sb_qflags; mp->m_sb.sb_qflags = (mp->m_qflags & ~(flags)) & XFS_MOUNT_QUOTA_ALL; XFS_SB_UNLOCK(mp, s); xfs_mod_sb(tp, XFS_SB_QFLAGS); /* * We have to make sure that the transaction is secure on disk before we * return and actually stop quota accounting. So, make it synchronous. * We don't care about quotoff's performance. */ xfs_trans_set_sync(tp); error = xfs_trans_commit(tp, 0, NULL);error0: if (error) { xfs_trans_cancel(tp, 0); /* * No one else is modifying sb_qflags, so this is OK. * We still hold the quotaofflock. */ s = XFS_SB_LOCK(mp); mp->m_sb.sb_qflags = oldsbqflag; XFS_SB_UNLOCK(mp, s); } *qoffstartp = qoffi; return (error);}/* * Translate an internal style on-disk-dquot to the exportable format. * The main differences are that the counters/limits are all in Basic * Blocks (BBs) instead of the internal FSBs, and all on-disk data has * to be converted to the native endianness. */STATIC voidxfs_qm_export_dquot( xfs_mount_t *mp, xfs_disk_dquot_t *src, struct fs_disk_quota *dst){ memset(dst, 0, sizeof(*dst)); dst->d_version = FS_DQUOT_VERSION; /* different from src->d_version */ dst->d_flags = xfs_qm_export_qtype_flags(src->d_flags); dst->d_id = be32_to_cpu(src->d_id); dst->d_blk_hardlimit = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_blk_hardlimit)); dst->d_blk_softlimit = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_blk_softlimit)); dst->d_ino_hardlimit = be64_to_cpu(src->d_ino_hardlimit); dst->d_ino_softlimit = be64_to_cpu(src->d_ino_softlimit); dst->d_bcount = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_bcount)); dst->d_icount = be64_to_cpu(src->d_icount); dst->d_btimer = be32_to_cpu(src->d_btimer); dst->d_itimer = be32_to_cpu(src->d_itimer); dst->d_iwarns = be16_to_cpu(src->d_iwarns); dst->d_bwarns = be16_to_cpu(src->d_bwarns); dst->d_rtb_hardlimit = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtb_hardlimit)); dst->d_rtb_softlimit = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtb_softlimit)); dst->d_rtbcount = XFS_FSB_TO_BB(mp, be64_to_cpu(src->d_rtbcount)); dst->d_rtbtimer = be32_to_cpu(src->d_rtbtimer); dst->d_rtbwarns = be16_to_cpu(src->d_rtbwarns); /* * Internally, we don't reset all the timers when quota enforcement * gets turned off. No need to confuse the userlevel code, * so return zeroes in that case. */ if (! XFS_IS_QUOTA_ENFORCED(mp)) { dst->d_btimer = 0; dst->d_itimer = 0; dst->d_rtbtimer = 0; }#ifdef DEBUG if (XFS_IS_QUOTA_ENFORCED(mp) && dst->d_id != 0) { if (((int) dst->d_bcount >= (int) dst->d_blk_softlimit) && (dst->d_blk_softlimit > 0)) { ASSERT(dst->d_btimer != 0); } if (((int) dst->d_icount >= (int) dst->d_ino_softlimit) && (dst->d_ino_softlimit > 0)) { ASSERT(dst->d_itimer != 0); } }#endif}STATIC uintxfs_qm_import_qtype_flags( uint uflags){ uint oflags = 0; /* * Can't be more than one, or none. */ if (((uflags & (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) == (XFS_GROUP_QUOTA | XFS_USER_QUOTA)) || ((uflags & (XFS_GROUP_QUOTA | XFS_PROJ_QUOTA)) == (XFS_GROUP_QUOTA | XFS_PROJ_QUOTA)) || ((uflags & (XFS_USER_QUOTA | XFS_PROJ_QUOTA)) == (XFS_USER_QUOTA | XFS_PROJ_QUOTA)) || ((uflags & (XFS_GROUP_QUOTA|XFS_USER_QUOTA|XFS_PROJ_QUOTA)) == 0)) return (0); oflags |= (uflags & XFS_USER_QUOTA) ? XFS_DQ_USER : 0; oflags |= (uflags & XFS_PROJ_QUOTA) ? XFS_DQ_PROJ : 0; oflags |= (uflags & XFS_GROUP_QUOTA) ? XFS_DQ_GROUP: 0; return oflags;}STATIC uintxfs_qm_export_qtype_flags( uint flags){ /* * Can't be more than one, or none. */ ASSERT((flags & (XFS_PROJ_QUOTA | XFS_USER_QUOTA)) != (XFS_PROJ_QUOTA | XFS_USER_QUOTA)); ASSERT((flags & (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)) != (XFS_PROJ_QUOTA | XFS_GROUP_QUOTA)); ASSERT((flags & (XFS_USER_QUOTA | XFS_GROUP_QUOTA)) != (XFS_USER_QUOTA | XFS_GROUP_QUOTA)); ASSERT((flags & (XFS_PROJ_QUOTA|XFS_USER_QUOTA|XFS_GROUP_QUOTA)) != 0); return (flags & XFS_DQ_USER) ? XFS_USER_QUOTA : (flags & XFS_DQ_PROJ) ? XFS_PROJ_QUOTA : XFS_GROUP_QUOTA;}STATIC uintxfs_qm_import_flags( uint uflags){ uint flags = 0; if (uflags & XFS_QUOTA_UDQ_ACCT) flags |= XFS_UQUOTA_ACCT; if (uflags & XFS_QUOTA_PDQ_ACCT) flags |= XFS_PQUOTA_ACCT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -