int
xfs_qm_scall_quotaoff(
xfs_mount_t *mp,
uint flags)
{ /* * No file system can have quotas enabled on disk but not in core. * Note that quota utilities (like quotaoff) _expect_ * errno == -EEXIST here.
*/ if ((mp->m_qflags & flags) == 0) return -EEXIST;
/* * We do not support actually turning off quota accounting any more. * Just log a warning and ignore the accounting related flags.
*/ if (flags & XFS_ALL_QUOTA_ACCT)
xfs_info(mp, "disabling of quota accounting not supported.");
if (flags & XFS_QMOPT_UQUOTA) {
error = xfs_qm_scall_trunc_qfile(mp, XFS_DQTYPE_USER); if (error) return error;
} if (flags & XFS_QMOPT_GQUOTA) {
error = xfs_qm_scall_trunc_qfile(mp, XFS_DQTYPE_GROUP); if (error) return error;
} if (flags & XFS_QMOPT_PQUOTA)
error = xfs_qm_scall_trunc_qfile(mp, XFS_DQTYPE_PROJ);
return error;
}
/* * Switch on (a given) quota enforcement for a filesystem. This takes * effect immediately. * (Switching on quota accounting must be done at mount time.)
*/ int
xfs_qm_scall_quotaon(
xfs_mount_t *mp,
uint flags)
{ int error;
uint qf;
/* * Switching on quota accounting must be done at mount time, * only consider quota enforcement stuff here.
*/
flags &= XFS_ALL_QUOTA_ENFD;
if (flags == 0) {
xfs_debug(mp, "%s: zero flags, m_qflags=%x",
__func__, mp->m_qflags); return -EINVAL;
}
/* * Can't enforce without accounting. We check the superblock * qflags here instead of m_qflags because rootfs can have * quota acct on ondisk without m_qflags' knowing.
*/ if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
(flags & XFS_UQUOTA_ENFD)) ||
((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
(flags & XFS_GQUOTA_ENFD)) ||
((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
(flags & XFS_PQUOTA_ENFD))) {
xfs_debug(mp, "%s: Can't enforce without acct, flags=%x sbflags=%x",
__func__, flags, mp->m_sb.sb_qflags); return -EINVAL;
} /* * If everything's up to-date incore, then don't waste time.
*/ if ((mp->m_qflags & flags) == flags) return -EEXIST;
/* * Change sb_qflags on disk but not incore mp->qflags * if this is the root filesystem.
*/
spin_lock(&mp->m_sb_lock);
qf = mp->m_sb.sb_qflags;
mp->m_sb.sb_qflags = qf | flags;
spin_unlock(&mp->m_sb_lock);
/* * There's nothing to change if it's the same.
*/ if ((qf & flags) == flags) return -EEXIST;
error = xfs_sync_sb(mp, false); if (error) return error; /* * If we aren't trying to switch on quota enforcement, we are done.
*/ 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))) return 0;
if (!XFS_IS_QUOTA_ON(mp)) return -ESRCH;
/* * Switch on quota enforcement in core.
*/
mutex_lock(&mp->m_quotainfo->qi_quotaofflock);
mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
mutex_unlock(&mp->m_quotainfo->qi_quotaofflock);
/* * Adjust limits of this quota, and the defaults if passed in. Returns true * if the new limits made sense and were applied, false otherwise.
*/ staticinlinebool
xfs_setqlim_limits( struct xfs_mount *mp, struct xfs_dquot_res *res, struct xfs_quota_limits *qlim,
xfs_qcnt_t hard,
xfs_qcnt_t soft, constchar *tag)
{ /* The hard limit can't be less than the soft limit. */ if (hard != 0 && hard < soft) {
xfs_debug(mp, "%shard %lld < %ssoft %lld", tag, hard, tag,
soft); returnfalse;
}
if (newlim->d_fieldmask & ~XFS_QC_MASK) return -EINVAL; if ((newlim->d_fieldmask & XFS_QC_MASK) == 0) return 0;
/* * Get the dquot (locked) before we start, as we need to do a * transaction to allocate it if it doesn't exist. Once we have the * dquot, unlock it so we can start the next transaction safely. We hold * a reference to the dquot, so it's safe to do this unlock/lock without * it being reclaimed in the mean time.
*/
error = xfs_qm_dqget(mp, id, type, true, &dqp); if (error) {
ASSERT(error != -ENOENT); return error;
}
/* * Update quota limits, warnings, and timers, and the defaults * if we're touching id == 0. * * Make sure that hardlimits are >= soft limits before changing. * * Update warnings counter(s) if requested. * * 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. * * For other IDs, userspace can bump out the grace period if over * the soft limit.
*/
/* Blocks on the data device. */
hard = (newlim->d_fieldmask & QC_SPC_HARD) ?
(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_hardlimit) :
dqp->q_blk.hardlimit;
soft = (newlim->d_fieldmask & QC_SPC_SOFT) ?
(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_softlimit) :
dqp->q_blk.softlimit;
res = &dqp->q_blk;
qlim = id == 0 ? &defq->blk : NULL;
if (xfs_setqlim_limits(mp, res, qlim, hard, soft, "blk"))
xfs_dquot_set_prealloc_limits(dqp); if (newlim->d_fieldmask & QC_SPC_TIMER)
xfs_setqlim_timer(mp, res, qlim, newlim->d_spc_timer);
/* Blocks on the realtime device. */
hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ?
(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_hardlimit) :
dqp->q_rtb.hardlimit;
soft = (newlim->d_fieldmask & QC_RT_SPC_SOFT) ?
(xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_softlimit) :
dqp->q_rtb.softlimit;
res = &dqp->q_rtb;
qlim = id == 0 ? &defq->rtb : NULL;
if (id != 0) { /* * 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(dqp);
}
dqp->q_flags |= XFS_DQFLAG_DIRTY;
xfs_trans_log_dquot(tp, dqp);
/* * Internally, we don't reset all the timers when quota enforcement * gets turned off. No need to confuse the user level code, * so return zeroes in that case.
*/ if (!xfs_dquot_is_enforced(dqp)) {
dst->d_spc_timer = 0;
dst->d_ino_timer = 0;
dst->d_rt_spc_timer = 0;
}
}
/* Return the quota information for the dquot matching id. */ int
xfs_qm_scall_getquota( struct xfs_mount *mp,
xfs_dqid_t id,
xfs_dqtype_t type, struct qc_dqblk *dst)
{ struct xfs_dquot *dqp; int error;
/* * Expedite pending inodegc work at the start of a quota reporting * scan but don't block waiting for it to complete.
*/ if (id == 0)
xfs_inodegc_push(mp);
/* * Try to get the dquot. We don't want it allocated on disk, so don't * set doalloc. If it doesn't exist, we'll get ENOENT back.
*/
error = xfs_qm_dqget(mp, id, type, false, &dqp); if (error) return error;
/* * If everything's NULL, this dquot doesn't quite exist as far as * our utility programs are concerned.
*/ if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
error = -ENOENT; goto out_put;
}
/* * Return the quota information for the first initialized dquot whose id * is at least as high as id.
*/ int
xfs_qm_scall_getquota_next( struct xfs_mount *mp,
xfs_dqid_t *id,
xfs_dqtype_t type, struct qc_dqblk *dst)
{ struct xfs_dquot *dqp; int error;
/* Flush inodegc work at the start of a quota reporting scan. */ if (*id == 0)
xfs_inodegc_push(mp);
error = xfs_qm_dqget_next(mp, *id, type, &dqp); if (error) return error;
/* Fill in the ID we actually read from disk */
*id = dqp->q_id;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.