162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2000-2005 Silicon Graphics, Inc. 462306a36Sopenharmony_ci * All Rights Reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "xfs.h" 962306a36Sopenharmony_ci#include "xfs_fs.h" 1062306a36Sopenharmony_ci#include "xfs_shared.h" 1162306a36Sopenharmony_ci#include "xfs_format.h" 1262306a36Sopenharmony_ci#include "xfs_log_format.h" 1362306a36Sopenharmony_ci#include "xfs_trans_resv.h" 1462306a36Sopenharmony_ci#include "xfs_sb.h" 1562306a36Sopenharmony_ci#include "xfs_mount.h" 1662306a36Sopenharmony_ci#include "xfs_inode.h" 1762306a36Sopenharmony_ci#include "xfs_trans.h" 1862306a36Sopenharmony_ci#include "xfs_quota.h" 1962306a36Sopenharmony_ci#include "xfs_qm.h" 2062306a36Sopenharmony_ci#include "xfs_icache.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ciint 2362306a36Sopenharmony_cixfs_qm_scall_quotaoff( 2462306a36Sopenharmony_ci xfs_mount_t *mp, 2562306a36Sopenharmony_ci uint flags) 2662306a36Sopenharmony_ci{ 2762306a36Sopenharmony_ci /* 2862306a36Sopenharmony_ci * No file system can have quotas enabled on disk but not in core. 2962306a36Sopenharmony_ci * Note that quota utilities (like quotaoff) _expect_ 3062306a36Sopenharmony_ci * errno == -EEXIST here. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci if ((mp->m_qflags & flags) == 0) 3362306a36Sopenharmony_ci return -EEXIST; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci /* 3662306a36Sopenharmony_ci * We do not support actually turning off quota accounting any more. 3762306a36Sopenharmony_ci * Just log a warning and ignore the accounting related flags. 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci if (flags & XFS_ALL_QUOTA_ACCT) 4062306a36Sopenharmony_ci xfs_info(mp, "disabling of quota accounting not supported."); 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci mutex_lock(&mp->m_quotainfo->qi_quotaofflock); 4362306a36Sopenharmony_ci mp->m_qflags &= ~(flags & XFS_ALL_QUOTA_ENFD); 4462306a36Sopenharmony_ci spin_lock(&mp->m_sb_lock); 4562306a36Sopenharmony_ci mp->m_sb.sb_qflags = mp->m_qflags; 4662306a36Sopenharmony_ci spin_unlock(&mp->m_sb_lock); 4762306a36Sopenharmony_ci mutex_unlock(&mp->m_quotainfo->qi_quotaofflock); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci /* XXX what to do if error ? Revert back to old vals incore ? */ 5062306a36Sopenharmony_ci return xfs_sync_sb(mp, false); 5162306a36Sopenharmony_ci} 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ciSTATIC int 5462306a36Sopenharmony_cixfs_qm_scall_trunc_qfile( 5562306a36Sopenharmony_ci struct xfs_mount *mp, 5662306a36Sopenharmony_ci xfs_ino_t ino) 5762306a36Sopenharmony_ci{ 5862306a36Sopenharmony_ci struct xfs_inode *ip; 5962306a36Sopenharmony_ci struct xfs_trans *tp; 6062306a36Sopenharmony_ci int error; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if (ino == NULLFSINO) 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci error = xfs_iget(mp, NULL, ino, 0, 0, &ip); 6662306a36Sopenharmony_ci if (error) 6762306a36Sopenharmony_ci return error; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci xfs_ilock(ip, XFS_IOLOCK_EXCL); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp); 7262306a36Sopenharmony_ci if (error) { 7362306a36Sopenharmony_ci xfs_iunlock(ip, XFS_IOLOCK_EXCL); 7462306a36Sopenharmony_ci goto out_put; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci xfs_ilock(ip, XFS_ILOCK_EXCL); 7862306a36Sopenharmony_ci xfs_trans_ijoin(tp, ip, 0); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci ip->i_disk_size = 0; 8162306a36Sopenharmony_ci xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0); 8462306a36Sopenharmony_ci if (error) { 8562306a36Sopenharmony_ci xfs_trans_cancel(tp); 8662306a36Sopenharmony_ci goto out_unlock; 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci ASSERT(ip->i_df.if_nextents == 0); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG); 9262306a36Sopenharmony_ci error = xfs_trans_commit(tp); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ciout_unlock: 9562306a36Sopenharmony_ci xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL); 9662306a36Sopenharmony_ciout_put: 9762306a36Sopenharmony_ci xfs_irele(ip); 9862306a36Sopenharmony_ci return error; 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ciint 10262306a36Sopenharmony_cixfs_qm_scall_trunc_qfiles( 10362306a36Sopenharmony_ci xfs_mount_t *mp, 10462306a36Sopenharmony_ci uint flags) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci int error = -EINVAL; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci if (!xfs_has_quota(mp) || flags == 0 || 10962306a36Sopenharmony_ci (flags & ~XFS_QMOPT_QUOTALL)) { 11062306a36Sopenharmony_ci xfs_debug(mp, "%s: flags=%x m_qflags=%x", 11162306a36Sopenharmony_ci __func__, flags, mp->m_qflags); 11262306a36Sopenharmony_ci return -EINVAL; 11362306a36Sopenharmony_ci } 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (flags & XFS_QMOPT_UQUOTA) { 11662306a36Sopenharmony_ci error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino); 11762306a36Sopenharmony_ci if (error) 11862306a36Sopenharmony_ci return error; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci if (flags & XFS_QMOPT_GQUOTA) { 12162306a36Sopenharmony_ci error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino); 12262306a36Sopenharmony_ci if (error) 12362306a36Sopenharmony_ci return error; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci if (flags & XFS_QMOPT_PQUOTA) 12662306a36Sopenharmony_ci error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_pquotino); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return error; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* 13262306a36Sopenharmony_ci * Switch on (a given) quota enforcement for a filesystem. This takes 13362306a36Sopenharmony_ci * effect immediately. 13462306a36Sopenharmony_ci * (Switching on quota accounting must be done at mount time.) 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ciint 13762306a36Sopenharmony_cixfs_qm_scall_quotaon( 13862306a36Sopenharmony_ci xfs_mount_t *mp, 13962306a36Sopenharmony_ci uint flags) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci int error; 14262306a36Sopenharmony_ci uint qf; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci /* 14562306a36Sopenharmony_ci * Switching on quota accounting must be done at mount time, 14662306a36Sopenharmony_ci * only consider quota enforcement stuff here. 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_ci flags &= XFS_ALL_QUOTA_ENFD; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (flags == 0) { 15162306a36Sopenharmony_ci xfs_debug(mp, "%s: zero flags, m_qflags=%x", 15262306a36Sopenharmony_ci __func__, mp->m_qflags); 15362306a36Sopenharmony_ci return -EINVAL; 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* 15762306a36Sopenharmony_ci * Can't enforce without accounting. We check the superblock 15862306a36Sopenharmony_ci * qflags here instead of m_qflags because rootfs can have 15962306a36Sopenharmony_ci * quota acct on ondisk without m_qflags' knowing. 16062306a36Sopenharmony_ci */ 16162306a36Sopenharmony_ci if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 && 16262306a36Sopenharmony_ci (flags & XFS_UQUOTA_ENFD)) || 16362306a36Sopenharmony_ci ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 && 16462306a36Sopenharmony_ci (flags & XFS_GQUOTA_ENFD)) || 16562306a36Sopenharmony_ci ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 && 16662306a36Sopenharmony_ci (flags & XFS_PQUOTA_ENFD))) { 16762306a36Sopenharmony_ci xfs_debug(mp, 16862306a36Sopenharmony_ci "%s: Can't enforce without acct, flags=%x sbflags=%x", 16962306a36Sopenharmony_ci __func__, flags, mp->m_sb.sb_qflags); 17062306a36Sopenharmony_ci return -EINVAL; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci /* 17362306a36Sopenharmony_ci * If everything's up to-date incore, then don't waste time. 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci if ((mp->m_qflags & flags) == flags) 17662306a36Sopenharmony_ci return -EEXIST; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* 17962306a36Sopenharmony_ci * Change sb_qflags on disk but not incore mp->qflags 18062306a36Sopenharmony_ci * if this is the root filesystem. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci spin_lock(&mp->m_sb_lock); 18362306a36Sopenharmony_ci qf = mp->m_sb.sb_qflags; 18462306a36Sopenharmony_ci mp->m_sb.sb_qflags = qf | flags; 18562306a36Sopenharmony_ci spin_unlock(&mp->m_sb_lock); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci /* 18862306a36Sopenharmony_ci * There's nothing to change if it's the same. 18962306a36Sopenharmony_ci */ 19062306a36Sopenharmony_ci if ((qf & flags) == flags) 19162306a36Sopenharmony_ci return -EEXIST; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci error = xfs_sync_sb(mp, false); 19462306a36Sopenharmony_ci if (error) 19562306a36Sopenharmony_ci return error; 19662306a36Sopenharmony_ci /* 19762306a36Sopenharmony_ci * If we aren't trying to switch on quota enforcement, we are done. 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) != 20062306a36Sopenharmony_ci (mp->m_qflags & XFS_UQUOTA_ACCT)) || 20162306a36Sopenharmony_ci ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) != 20262306a36Sopenharmony_ci (mp->m_qflags & XFS_PQUOTA_ACCT)) || 20362306a36Sopenharmony_ci ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) != 20462306a36Sopenharmony_ci (mp->m_qflags & XFS_GQUOTA_ACCT))) 20562306a36Sopenharmony_ci return 0; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (!XFS_IS_QUOTA_ON(mp)) 20862306a36Sopenharmony_ci return -ESRCH; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* 21162306a36Sopenharmony_ci * Switch on quota enforcement in core. 21262306a36Sopenharmony_ci */ 21362306a36Sopenharmony_ci mutex_lock(&mp->m_quotainfo->qi_quotaofflock); 21462306a36Sopenharmony_ci mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD); 21562306a36Sopenharmony_ci mutex_unlock(&mp->m_quotainfo->qi_quotaofflock); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci return 0; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci#define XFS_QC_MASK (QC_LIMIT_MASK | QC_TIMER_MASK) 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci/* 22362306a36Sopenharmony_ci * Adjust limits of this quota, and the defaults if passed in. Returns true 22462306a36Sopenharmony_ci * if the new limits made sense and were applied, false otherwise. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_cistatic inline bool 22762306a36Sopenharmony_cixfs_setqlim_limits( 22862306a36Sopenharmony_ci struct xfs_mount *mp, 22962306a36Sopenharmony_ci struct xfs_dquot_res *res, 23062306a36Sopenharmony_ci struct xfs_quota_limits *qlim, 23162306a36Sopenharmony_ci xfs_qcnt_t hard, 23262306a36Sopenharmony_ci xfs_qcnt_t soft, 23362306a36Sopenharmony_ci const char *tag) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci /* The hard limit can't be less than the soft limit. */ 23662306a36Sopenharmony_ci if (hard != 0 && hard < soft) { 23762306a36Sopenharmony_ci xfs_debug(mp, "%shard %lld < %ssoft %lld", tag, hard, tag, 23862306a36Sopenharmony_ci soft); 23962306a36Sopenharmony_ci return false; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci res->hardlimit = hard; 24362306a36Sopenharmony_ci res->softlimit = soft; 24462306a36Sopenharmony_ci if (qlim) { 24562306a36Sopenharmony_ci qlim->hard = hard; 24662306a36Sopenharmony_ci qlim->soft = soft; 24762306a36Sopenharmony_ci } 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci return true; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic inline void 25362306a36Sopenharmony_cixfs_setqlim_timer( 25462306a36Sopenharmony_ci struct xfs_mount *mp, 25562306a36Sopenharmony_ci struct xfs_dquot_res *res, 25662306a36Sopenharmony_ci struct xfs_quota_limits *qlim, 25762306a36Sopenharmony_ci s64 timer) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci if (qlim) { 26062306a36Sopenharmony_ci /* Set the length of the default grace period. */ 26162306a36Sopenharmony_ci res->timer = xfs_dquot_set_grace_period(timer); 26262306a36Sopenharmony_ci qlim->time = res->timer; 26362306a36Sopenharmony_ci } else { 26462306a36Sopenharmony_ci /* Set the grace period expiration on a quota. */ 26562306a36Sopenharmony_ci res->timer = xfs_dquot_set_timeout(mp, timer); 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci/* 27062306a36Sopenharmony_ci * Adjust quota limits, and start/stop timers accordingly. 27162306a36Sopenharmony_ci */ 27262306a36Sopenharmony_ciint 27362306a36Sopenharmony_cixfs_qm_scall_setqlim( 27462306a36Sopenharmony_ci struct xfs_mount *mp, 27562306a36Sopenharmony_ci xfs_dqid_t id, 27662306a36Sopenharmony_ci xfs_dqtype_t type, 27762306a36Sopenharmony_ci struct qc_dqblk *newlim) 27862306a36Sopenharmony_ci{ 27962306a36Sopenharmony_ci struct xfs_quotainfo *q = mp->m_quotainfo; 28062306a36Sopenharmony_ci struct xfs_dquot *dqp; 28162306a36Sopenharmony_ci struct xfs_trans *tp; 28262306a36Sopenharmony_ci struct xfs_def_quota *defq; 28362306a36Sopenharmony_ci struct xfs_dquot_res *res; 28462306a36Sopenharmony_ci struct xfs_quota_limits *qlim; 28562306a36Sopenharmony_ci int error; 28662306a36Sopenharmony_ci xfs_qcnt_t hard, soft; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (newlim->d_fieldmask & ~XFS_QC_MASK) 28962306a36Sopenharmony_ci return -EINVAL; 29062306a36Sopenharmony_ci if ((newlim->d_fieldmask & XFS_QC_MASK) == 0) 29162306a36Sopenharmony_ci return 0; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * Get the dquot (locked) before we start, as we need to do a 29562306a36Sopenharmony_ci * transaction to allocate it if it doesn't exist. Once we have the 29662306a36Sopenharmony_ci * dquot, unlock it so we can start the next transaction safely. We hold 29762306a36Sopenharmony_ci * a reference to the dquot, so it's safe to do this unlock/lock without 29862306a36Sopenharmony_ci * it being reclaimed in the mean time. 29962306a36Sopenharmony_ci */ 30062306a36Sopenharmony_ci error = xfs_qm_dqget(mp, id, type, true, &dqp); 30162306a36Sopenharmony_ci if (error) { 30262306a36Sopenharmony_ci ASSERT(error != -ENOENT); 30362306a36Sopenharmony_ci return error; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci defq = xfs_get_defquota(q, xfs_dquot_type(dqp)); 30762306a36Sopenharmony_ci xfs_dqunlock(dqp); 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_setqlim, 0, 0, 0, &tp); 31062306a36Sopenharmony_ci if (error) 31162306a36Sopenharmony_ci goto out_rele; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci xfs_dqlock(dqp); 31462306a36Sopenharmony_ci xfs_trans_dqjoin(tp, dqp); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* 31762306a36Sopenharmony_ci * Update quota limits, warnings, and timers, and the defaults 31862306a36Sopenharmony_ci * if we're touching id == 0. 31962306a36Sopenharmony_ci * 32062306a36Sopenharmony_ci * Make sure that hardlimits are >= soft limits before changing. 32162306a36Sopenharmony_ci * 32262306a36Sopenharmony_ci * Update warnings counter(s) if requested. 32362306a36Sopenharmony_ci * 32462306a36Sopenharmony_ci * Timelimits for the super user set the relative time the other users 32562306a36Sopenharmony_ci * can be over quota for this file system. If it is zero a default is 32662306a36Sopenharmony_ci * used. Ditto for the default soft and hard limit values (already 32762306a36Sopenharmony_ci * done, above), and for warnings. 32862306a36Sopenharmony_ci * 32962306a36Sopenharmony_ci * For other IDs, userspace can bump out the grace period if over 33062306a36Sopenharmony_ci * the soft limit. 33162306a36Sopenharmony_ci */ 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci /* Blocks on the data device. */ 33462306a36Sopenharmony_ci hard = (newlim->d_fieldmask & QC_SPC_HARD) ? 33562306a36Sopenharmony_ci (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_hardlimit) : 33662306a36Sopenharmony_ci dqp->q_blk.hardlimit; 33762306a36Sopenharmony_ci soft = (newlim->d_fieldmask & QC_SPC_SOFT) ? 33862306a36Sopenharmony_ci (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_softlimit) : 33962306a36Sopenharmony_ci dqp->q_blk.softlimit; 34062306a36Sopenharmony_ci res = &dqp->q_blk; 34162306a36Sopenharmony_ci qlim = id == 0 ? &defq->blk : NULL; 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci if (xfs_setqlim_limits(mp, res, qlim, hard, soft, "blk")) 34462306a36Sopenharmony_ci xfs_dquot_set_prealloc_limits(dqp); 34562306a36Sopenharmony_ci if (newlim->d_fieldmask & QC_SPC_TIMER) 34662306a36Sopenharmony_ci xfs_setqlim_timer(mp, res, qlim, newlim->d_spc_timer); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* Blocks on the realtime device. */ 34962306a36Sopenharmony_ci hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ? 35062306a36Sopenharmony_ci (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_hardlimit) : 35162306a36Sopenharmony_ci dqp->q_rtb.hardlimit; 35262306a36Sopenharmony_ci soft = (newlim->d_fieldmask & QC_RT_SPC_SOFT) ? 35362306a36Sopenharmony_ci (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_softlimit) : 35462306a36Sopenharmony_ci dqp->q_rtb.softlimit; 35562306a36Sopenharmony_ci res = &dqp->q_rtb; 35662306a36Sopenharmony_ci qlim = id == 0 ? &defq->rtb : NULL; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci xfs_setqlim_limits(mp, res, qlim, hard, soft, "rtb"); 35962306a36Sopenharmony_ci if (newlim->d_fieldmask & QC_RT_SPC_TIMER) 36062306a36Sopenharmony_ci xfs_setqlim_timer(mp, res, qlim, newlim->d_rt_spc_timer); 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* Inodes */ 36362306a36Sopenharmony_ci hard = (newlim->d_fieldmask & QC_INO_HARD) ? 36462306a36Sopenharmony_ci (xfs_qcnt_t) newlim->d_ino_hardlimit : 36562306a36Sopenharmony_ci dqp->q_ino.hardlimit; 36662306a36Sopenharmony_ci soft = (newlim->d_fieldmask & QC_INO_SOFT) ? 36762306a36Sopenharmony_ci (xfs_qcnt_t) newlim->d_ino_softlimit : 36862306a36Sopenharmony_ci dqp->q_ino.softlimit; 36962306a36Sopenharmony_ci res = &dqp->q_ino; 37062306a36Sopenharmony_ci qlim = id == 0 ? &defq->ino : NULL; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci xfs_setqlim_limits(mp, res, qlim, hard, soft, "ino"); 37362306a36Sopenharmony_ci if (newlim->d_fieldmask & QC_INO_TIMER) 37462306a36Sopenharmony_ci xfs_setqlim_timer(mp, res, qlim, newlim->d_ino_timer); 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci if (id != 0) { 37762306a36Sopenharmony_ci /* 37862306a36Sopenharmony_ci * If the user is now over quota, start the timelimit. 37962306a36Sopenharmony_ci * The user will not be 'warned'. 38062306a36Sopenharmony_ci * Note that we keep the timers ticking, whether enforcement 38162306a36Sopenharmony_ci * is on or off. We don't really want to bother with iterating 38262306a36Sopenharmony_ci * over all ondisk dquots and turning the timers on/off. 38362306a36Sopenharmony_ci */ 38462306a36Sopenharmony_ci xfs_qm_adjust_dqtimers(dqp); 38562306a36Sopenharmony_ci } 38662306a36Sopenharmony_ci dqp->q_flags |= XFS_DQFLAG_DIRTY; 38762306a36Sopenharmony_ci xfs_trans_log_dquot(tp, dqp); 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci error = xfs_trans_commit(tp); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ciout_rele: 39262306a36Sopenharmony_ci xfs_qm_dqrele(dqp); 39362306a36Sopenharmony_ci return error; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci/* Fill out the quota context. */ 39762306a36Sopenharmony_cistatic void 39862306a36Sopenharmony_cixfs_qm_scall_getquota_fill_qc( 39962306a36Sopenharmony_ci struct xfs_mount *mp, 40062306a36Sopenharmony_ci xfs_dqtype_t type, 40162306a36Sopenharmony_ci const struct xfs_dquot *dqp, 40262306a36Sopenharmony_ci struct qc_dqblk *dst) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci memset(dst, 0, sizeof(*dst)); 40562306a36Sopenharmony_ci dst->d_spc_hardlimit = XFS_FSB_TO_B(mp, dqp->q_blk.hardlimit); 40662306a36Sopenharmony_ci dst->d_spc_softlimit = XFS_FSB_TO_B(mp, dqp->q_blk.softlimit); 40762306a36Sopenharmony_ci dst->d_ino_hardlimit = dqp->q_ino.hardlimit; 40862306a36Sopenharmony_ci dst->d_ino_softlimit = dqp->q_ino.softlimit; 40962306a36Sopenharmony_ci dst->d_space = XFS_FSB_TO_B(mp, dqp->q_blk.reserved); 41062306a36Sopenharmony_ci dst->d_ino_count = dqp->q_ino.reserved; 41162306a36Sopenharmony_ci dst->d_spc_timer = dqp->q_blk.timer; 41262306a36Sopenharmony_ci dst->d_ino_timer = dqp->q_ino.timer; 41362306a36Sopenharmony_ci dst->d_ino_warns = 0; 41462306a36Sopenharmony_ci dst->d_spc_warns = 0; 41562306a36Sopenharmony_ci dst->d_rt_spc_hardlimit = XFS_FSB_TO_B(mp, dqp->q_rtb.hardlimit); 41662306a36Sopenharmony_ci dst->d_rt_spc_softlimit = XFS_FSB_TO_B(mp, dqp->q_rtb.softlimit); 41762306a36Sopenharmony_ci dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_rtb.reserved); 41862306a36Sopenharmony_ci dst->d_rt_spc_timer = dqp->q_rtb.timer; 41962306a36Sopenharmony_ci dst->d_rt_spc_warns = 0; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* 42262306a36Sopenharmony_ci * Internally, we don't reset all the timers when quota enforcement 42362306a36Sopenharmony_ci * gets turned off. No need to confuse the user level code, 42462306a36Sopenharmony_ci * so return zeroes in that case. 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_ci if (!xfs_dquot_is_enforced(dqp)) { 42762306a36Sopenharmony_ci dst->d_spc_timer = 0; 42862306a36Sopenharmony_ci dst->d_ino_timer = 0; 42962306a36Sopenharmony_ci dst->d_rt_spc_timer = 0; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci#ifdef DEBUG 43362306a36Sopenharmony_ci if (xfs_dquot_is_enforced(dqp) && dqp->q_id != 0) { 43462306a36Sopenharmony_ci if ((dst->d_space > dst->d_spc_softlimit) && 43562306a36Sopenharmony_ci (dst->d_spc_softlimit > 0)) { 43662306a36Sopenharmony_ci ASSERT(dst->d_spc_timer != 0); 43762306a36Sopenharmony_ci } 43862306a36Sopenharmony_ci if ((dst->d_ino_count > dqp->q_ino.softlimit) && 43962306a36Sopenharmony_ci (dqp->q_ino.softlimit > 0)) { 44062306a36Sopenharmony_ci ASSERT(dst->d_ino_timer != 0); 44162306a36Sopenharmony_ci } 44262306a36Sopenharmony_ci } 44362306a36Sopenharmony_ci#endif 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci/* Return the quota information for the dquot matching id. */ 44762306a36Sopenharmony_ciint 44862306a36Sopenharmony_cixfs_qm_scall_getquota( 44962306a36Sopenharmony_ci struct xfs_mount *mp, 45062306a36Sopenharmony_ci xfs_dqid_t id, 45162306a36Sopenharmony_ci xfs_dqtype_t type, 45262306a36Sopenharmony_ci struct qc_dqblk *dst) 45362306a36Sopenharmony_ci{ 45462306a36Sopenharmony_ci struct xfs_dquot *dqp; 45562306a36Sopenharmony_ci int error; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* 45862306a36Sopenharmony_ci * Expedite pending inodegc work at the start of a quota reporting 45962306a36Sopenharmony_ci * scan but don't block waiting for it to complete. 46062306a36Sopenharmony_ci */ 46162306a36Sopenharmony_ci if (id == 0) 46262306a36Sopenharmony_ci xfs_inodegc_push(mp); 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci /* 46562306a36Sopenharmony_ci * Try to get the dquot. We don't want it allocated on disk, so don't 46662306a36Sopenharmony_ci * set doalloc. If it doesn't exist, we'll get ENOENT back. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci error = xfs_qm_dqget(mp, id, type, false, &dqp); 46962306a36Sopenharmony_ci if (error) 47062306a36Sopenharmony_ci return error; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci /* 47362306a36Sopenharmony_ci * If everything's NULL, this dquot doesn't quite exist as far as 47462306a36Sopenharmony_ci * our utility programs are concerned. 47562306a36Sopenharmony_ci */ 47662306a36Sopenharmony_ci if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) { 47762306a36Sopenharmony_ci error = -ENOENT; 47862306a36Sopenharmony_ci goto out_put; 47962306a36Sopenharmony_ci } 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci xfs_qm_scall_getquota_fill_qc(mp, type, dqp, dst); 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ciout_put: 48462306a36Sopenharmony_ci xfs_qm_dqput(dqp); 48562306a36Sopenharmony_ci return error; 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci/* 48962306a36Sopenharmony_ci * Return the quota information for the first initialized dquot whose id 49062306a36Sopenharmony_ci * is at least as high as id. 49162306a36Sopenharmony_ci */ 49262306a36Sopenharmony_ciint 49362306a36Sopenharmony_cixfs_qm_scall_getquota_next( 49462306a36Sopenharmony_ci struct xfs_mount *mp, 49562306a36Sopenharmony_ci xfs_dqid_t *id, 49662306a36Sopenharmony_ci xfs_dqtype_t type, 49762306a36Sopenharmony_ci struct qc_dqblk *dst) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci struct xfs_dquot *dqp; 50062306a36Sopenharmony_ci int error; 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci /* Flush inodegc work at the start of a quota reporting scan. */ 50362306a36Sopenharmony_ci if (*id == 0) 50462306a36Sopenharmony_ci xfs_inodegc_push(mp); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci error = xfs_qm_dqget_next(mp, *id, type, &dqp); 50762306a36Sopenharmony_ci if (error) 50862306a36Sopenharmony_ci return error; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci /* Fill in the ID we actually read from disk */ 51162306a36Sopenharmony_ci *id = dqp->q_id; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci xfs_qm_scall_getquota_fill_qc(mp, type, dqp, dst); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci xfs_qm_dqput(dqp); 51662306a36Sopenharmony_ci return error; 51762306a36Sopenharmony_ci} 518