0001
0002
0003
0004
0005
0006
0007
0008 #include "xfs.h"
0009 #include "xfs_fs.h"
0010 #include "xfs_shared.h"
0011 #include "xfs_format.h"
0012 #include "xfs_log_format.h"
0013 #include "xfs_trans_resv.h"
0014 #include "xfs_sb.h"
0015 #include "xfs_mount.h"
0016 #include "xfs_inode.h"
0017 #include "xfs_trans.h"
0018 #include "xfs_quota.h"
0019 #include "xfs_qm.h"
0020 #include "xfs_icache.h"
0021
0022 int
0023 xfs_qm_scall_quotaoff(
0024 xfs_mount_t *mp,
0025 uint flags)
0026 {
0027
0028
0029
0030
0031
0032 if ((mp->m_qflags & flags) == 0)
0033 return -EEXIST;
0034
0035
0036
0037
0038
0039 if (flags & XFS_ALL_QUOTA_ACCT)
0040 xfs_info(mp, "disabling of quota accounting not supported.");
0041
0042 mutex_lock(&mp->m_quotainfo->qi_quotaofflock);
0043 mp->m_qflags &= ~(flags & XFS_ALL_QUOTA_ENFD);
0044 spin_lock(&mp->m_sb_lock);
0045 mp->m_sb.sb_qflags = mp->m_qflags;
0046 spin_unlock(&mp->m_sb_lock);
0047 mutex_unlock(&mp->m_quotainfo->qi_quotaofflock);
0048
0049
0050 return xfs_sync_sb(mp, false);
0051 }
0052
0053 STATIC int
0054 xfs_qm_scall_trunc_qfile(
0055 struct xfs_mount *mp,
0056 xfs_ino_t ino)
0057 {
0058 struct xfs_inode *ip;
0059 struct xfs_trans *tp;
0060 int error;
0061
0062 if (ino == NULLFSINO)
0063 return 0;
0064
0065 error = xfs_iget(mp, NULL, ino, 0, 0, &ip);
0066 if (error)
0067 return error;
0068
0069 xfs_ilock(ip, XFS_IOLOCK_EXCL);
0070
0071 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, &tp);
0072 if (error) {
0073 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
0074 goto out_put;
0075 }
0076
0077 xfs_ilock(ip, XFS_ILOCK_EXCL);
0078 xfs_trans_ijoin(tp, ip, 0);
0079
0080 ip->i_disk_size = 0;
0081 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
0082
0083 error = xfs_itruncate_extents(&tp, ip, XFS_DATA_FORK, 0);
0084 if (error) {
0085 xfs_trans_cancel(tp);
0086 goto out_unlock;
0087 }
0088
0089 ASSERT(ip->i_df.if_nextents == 0);
0090
0091 xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
0092 error = xfs_trans_commit(tp);
0093
0094 out_unlock:
0095 xfs_iunlock(ip, XFS_ILOCK_EXCL | XFS_IOLOCK_EXCL);
0096 out_put:
0097 xfs_irele(ip);
0098 return error;
0099 }
0100
0101 int
0102 xfs_qm_scall_trunc_qfiles(
0103 xfs_mount_t *mp,
0104 uint flags)
0105 {
0106 int error = -EINVAL;
0107
0108 if (!xfs_has_quota(mp) || flags == 0 ||
0109 (flags & ~XFS_QMOPT_QUOTALL)) {
0110 xfs_debug(mp, "%s: flags=%x m_qflags=%x",
0111 __func__, flags, mp->m_qflags);
0112 return -EINVAL;
0113 }
0114
0115 if (flags & XFS_QMOPT_UQUOTA) {
0116 error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_uquotino);
0117 if (error)
0118 return error;
0119 }
0120 if (flags & XFS_QMOPT_GQUOTA) {
0121 error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_gquotino);
0122 if (error)
0123 return error;
0124 }
0125 if (flags & XFS_QMOPT_PQUOTA)
0126 error = xfs_qm_scall_trunc_qfile(mp, mp->m_sb.sb_pquotino);
0127
0128 return error;
0129 }
0130
0131
0132
0133
0134
0135
0136 int
0137 xfs_qm_scall_quotaon(
0138 xfs_mount_t *mp,
0139 uint flags)
0140 {
0141 int error;
0142 uint qf;
0143
0144
0145
0146
0147
0148 flags &= XFS_ALL_QUOTA_ENFD;
0149
0150 if (flags == 0) {
0151 xfs_debug(mp, "%s: zero flags, m_qflags=%x",
0152 __func__, mp->m_qflags);
0153 return -EINVAL;
0154 }
0155
0156
0157
0158
0159
0160
0161 if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) == 0 &&
0162 (flags & XFS_UQUOTA_ENFD)) ||
0163 ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) == 0 &&
0164 (flags & XFS_GQUOTA_ENFD)) ||
0165 ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) == 0 &&
0166 (flags & XFS_PQUOTA_ENFD))) {
0167 xfs_debug(mp,
0168 "%s: Can't enforce without acct, flags=%x sbflags=%x",
0169 __func__, flags, mp->m_sb.sb_qflags);
0170 return -EINVAL;
0171 }
0172
0173
0174
0175 if ((mp->m_qflags & flags) == flags)
0176 return -EEXIST;
0177
0178
0179
0180
0181
0182 spin_lock(&mp->m_sb_lock);
0183 qf = mp->m_sb.sb_qflags;
0184 mp->m_sb.sb_qflags = qf | flags;
0185 spin_unlock(&mp->m_sb_lock);
0186
0187
0188
0189
0190 if ((qf & flags) == flags)
0191 return -EEXIST;
0192
0193 error = xfs_sync_sb(mp, false);
0194 if (error)
0195 return error;
0196
0197
0198
0199 if (((mp->m_sb.sb_qflags & XFS_UQUOTA_ACCT) !=
0200 (mp->m_qflags & XFS_UQUOTA_ACCT)) ||
0201 ((mp->m_sb.sb_qflags & XFS_PQUOTA_ACCT) !=
0202 (mp->m_qflags & XFS_PQUOTA_ACCT)) ||
0203 ((mp->m_sb.sb_qflags & XFS_GQUOTA_ACCT) !=
0204 (mp->m_qflags & XFS_GQUOTA_ACCT)))
0205 return 0;
0206
0207 if (!XFS_IS_QUOTA_ON(mp))
0208 return -ESRCH;
0209
0210
0211
0212
0213 mutex_lock(&mp->m_quotainfo->qi_quotaofflock);
0214 mp->m_qflags |= (flags & XFS_ALL_QUOTA_ENFD);
0215 mutex_unlock(&mp->m_quotainfo->qi_quotaofflock);
0216
0217 return 0;
0218 }
0219
0220 #define XFS_QC_MASK (QC_LIMIT_MASK | QC_TIMER_MASK)
0221
0222
0223
0224
0225
0226 static inline bool
0227 xfs_setqlim_limits(
0228 struct xfs_mount *mp,
0229 struct xfs_dquot_res *res,
0230 struct xfs_quota_limits *qlim,
0231 xfs_qcnt_t hard,
0232 xfs_qcnt_t soft,
0233 const char *tag)
0234 {
0235
0236 if (hard != 0 && hard < soft) {
0237 xfs_debug(mp, "%shard %lld < %ssoft %lld", tag, hard, tag,
0238 soft);
0239 return false;
0240 }
0241
0242 res->hardlimit = hard;
0243 res->softlimit = soft;
0244 if (qlim) {
0245 qlim->hard = hard;
0246 qlim->soft = soft;
0247 }
0248
0249 return true;
0250 }
0251
0252 static inline void
0253 xfs_setqlim_timer(
0254 struct xfs_mount *mp,
0255 struct xfs_dquot_res *res,
0256 struct xfs_quota_limits *qlim,
0257 s64 timer)
0258 {
0259 if (qlim) {
0260
0261 res->timer = xfs_dquot_set_grace_period(timer);
0262 qlim->time = res->timer;
0263 } else {
0264
0265 res->timer = xfs_dquot_set_timeout(mp, timer);
0266 }
0267 }
0268
0269
0270
0271
0272 int
0273 xfs_qm_scall_setqlim(
0274 struct xfs_mount *mp,
0275 xfs_dqid_t id,
0276 xfs_dqtype_t type,
0277 struct qc_dqblk *newlim)
0278 {
0279 struct xfs_quotainfo *q = mp->m_quotainfo;
0280 struct xfs_dquot *dqp;
0281 struct xfs_trans *tp;
0282 struct xfs_def_quota *defq;
0283 struct xfs_dquot_res *res;
0284 struct xfs_quota_limits *qlim;
0285 int error;
0286 xfs_qcnt_t hard, soft;
0287
0288 if (newlim->d_fieldmask & ~XFS_QC_MASK)
0289 return -EINVAL;
0290 if ((newlim->d_fieldmask & XFS_QC_MASK) == 0)
0291 return 0;
0292
0293
0294
0295
0296
0297
0298
0299
0300 error = xfs_qm_dqget(mp, id, type, true, &dqp);
0301 if (error) {
0302 ASSERT(error != -ENOENT);
0303 return error;
0304 }
0305
0306 defq = xfs_get_defquota(q, xfs_dquot_type(dqp));
0307 xfs_dqunlock(dqp);
0308
0309 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_qm_setqlim, 0, 0, 0, &tp);
0310 if (error)
0311 goto out_rele;
0312
0313 xfs_dqlock(dqp);
0314 xfs_trans_dqjoin(tp, dqp);
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334 hard = (newlim->d_fieldmask & QC_SPC_HARD) ?
0335 (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_hardlimit) :
0336 dqp->q_blk.hardlimit;
0337 soft = (newlim->d_fieldmask & QC_SPC_SOFT) ?
0338 (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_spc_softlimit) :
0339 dqp->q_blk.softlimit;
0340 res = &dqp->q_blk;
0341 qlim = id == 0 ? &defq->blk : NULL;
0342
0343 if (xfs_setqlim_limits(mp, res, qlim, hard, soft, "blk"))
0344 xfs_dquot_set_prealloc_limits(dqp);
0345 if (newlim->d_fieldmask & QC_SPC_TIMER)
0346 xfs_setqlim_timer(mp, res, qlim, newlim->d_spc_timer);
0347
0348
0349 hard = (newlim->d_fieldmask & QC_RT_SPC_HARD) ?
0350 (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_hardlimit) :
0351 dqp->q_rtb.hardlimit;
0352 soft = (newlim->d_fieldmask & QC_RT_SPC_SOFT) ?
0353 (xfs_qcnt_t) XFS_B_TO_FSB(mp, newlim->d_rt_spc_softlimit) :
0354 dqp->q_rtb.softlimit;
0355 res = &dqp->q_rtb;
0356 qlim = id == 0 ? &defq->rtb : NULL;
0357
0358 xfs_setqlim_limits(mp, res, qlim, hard, soft, "rtb");
0359 if (newlim->d_fieldmask & QC_RT_SPC_TIMER)
0360 xfs_setqlim_timer(mp, res, qlim, newlim->d_rt_spc_timer);
0361
0362
0363 hard = (newlim->d_fieldmask & QC_INO_HARD) ?
0364 (xfs_qcnt_t) newlim->d_ino_hardlimit :
0365 dqp->q_ino.hardlimit;
0366 soft = (newlim->d_fieldmask & QC_INO_SOFT) ?
0367 (xfs_qcnt_t) newlim->d_ino_softlimit :
0368 dqp->q_ino.softlimit;
0369 res = &dqp->q_ino;
0370 qlim = id == 0 ? &defq->ino : NULL;
0371
0372 xfs_setqlim_limits(mp, res, qlim, hard, soft, "ino");
0373 if (newlim->d_fieldmask & QC_INO_TIMER)
0374 xfs_setqlim_timer(mp, res, qlim, newlim->d_ino_timer);
0375
0376 if (id != 0) {
0377
0378
0379
0380
0381
0382
0383
0384 xfs_qm_adjust_dqtimers(dqp);
0385 }
0386 dqp->q_flags |= XFS_DQFLAG_DIRTY;
0387 xfs_trans_log_dquot(tp, dqp);
0388
0389 error = xfs_trans_commit(tp);
0390
0391 out_rele:
0392 xfs_qm_dqrele(dqp);
0393 return error;
0394 }
0395
0396
0397 static void
0398 xfs_qm_scall_getquota_fill_qc(
0399 struct xfs_mount *mp,
0400 xfs_dqtype_t type,
0401 const struct xfs_dquot *dqp,
0402 struct qc_dqblk *dst)
0403 {
0404 memset(dst, 0, sizeof(*dst));
0405 dst->d_spc_hardlimit = XFS_FSB_TO_B(mp, dqp->q_blk.hardlimit);
0406 dst->d_spc_softlimit = XFS_FSB_TO_B(mp, dqp->q_blk.softlimit);
0407 dst->d_ino_hardlimit = dqp->q_ino.hardlimit;
0408 dst->d_ino_softlimit = dqp->q_ino.softlimit;
0409 dst->d_space = XFS_FSB_TO_B(mp, dqp->q_blk.reserved);
0410 dst->d_ino_count = dqp->q_ino.reserved;
0411 dst->d_spc_timer = dqp->q_blk.timer;
0412 dst->d_ino_timer = dqp->q_ino.timer;
0413 dst->d_ino_warns = 0;
0414 dst->d_spc_warns = 0;
0415 dst->d_rt_spc_hardlimit = XFS_FSB_TO_B(mp, dqp->q_rtb.hardlimit);
0416 dst->d_rt_spc_softlimit = XFS_FSB_TO_B(mp, dqp->q_rtb.softlimit);
0417 dst->d_rt_space = XFS_FSB_TO_B(mp, dqp->q_rtb.reserved);
0418 dst->d_rt_spc_timer = dqp->q_rtb.timer;
0419 dst->d_rt_spc_warns = 0;
0420
0421
0422
0423
0424
0425
0426 if (!xfs_dquot_is_enforced(dqp)) {
0427 dst->d_spc_timer = 0;
0428 dst->d_ino_timer = 0;
0429 dst->d_rt_spc_timer = 0;
0430 }
0431
0432 #ifdef DEBUG
0433 if (xfs_dquot_is_enforced(dqp) && dqp->q_id != 0) {
0434 if ((dst->d_space > dst->d_spc_softlimit) &&
0435 (dst->d_spc_softlimit > 0)) {
0436 ASSERT(dst->d_spc_timer != 0);
0437 }
0438 if ((dst->d_ino_count > dqp->q_ino.softlimit) &&
0439 (dqp->q_ino.softlimit > 0)) {
0440 ASSERT(dst->d_ino_timer != 0);
0441 }
0442 }
0443 #endif
0444 }
0445
0446
0447 int
0448 xfs_qm_scall_getquota(
0449 struct xfs_mount *mp,
0450 xfs_dqid_t id,
0451 xfs_dqtype_t type,
0452 struct qc_dqblk *dst)
0453 {
0454 struct xfs_dquot *dqp;
0455 int error;
0456
0457
0458
0459
0460
0461 if (id == 0)
0462 xfs_inodegc_push(mp);
0463
0464
0465
0466
0467
0468 error = xfs_qm_dqget(mp, id, type, false, &dqp);
0469 if (error)
0470 return error;
0471
0472
0473
0474
0475
0476 if (XFS_IS_DQUOT_UNINITIALIZED(dqp)) {
0477 error = -ENOENT;
0478 goto out_put;
0479 }
0480
0481 xfs_qm_scall_getquota_fill_qc(mp, type, dqp, dst);
0482
0483 out_put:
0484 xfs_qm_dqput(dqp);
0485 return error;
0486 }
0487
0488
0489
0490
0491
0492 int
0493 xfs_qm_scall_getquota_next(
0494 struct xfs_mount *mp,
0495 xfs_dqid_t *id,
0496 xfs_dqtype_t type,
0497 struct qc_dqblk *dst)
0498 {
0499 struct xfs_dquot *dqp;
0500 int error;
0501
0502
0503 if (*id == 0)
0504 xfs_inodegc_push(mp);
0505
0506 error = xfs_qm_dqget_next(mp, *id, type, &dqp);
0507 if (error)
0508 return error;
0509
0510
0511 *id = dqp->q_id;
0512
0513 xfs_qm_scall_getquota_fill_qc(mp, type, dqp, dst);
0514
0515 xfs_qm_dqput(dqp);
0516 return error;
0517 }