/* * Increment or reset warnings of a given dquot. */ int xfs_qm_dqwarn( xfs_disk_dquot_t *d, uint flags) { int warned; /* * root's limits are not real limits. */ if (INT_ISZERO(d->d_id, ARCH_CONVERT)) return (0); warned = 0; if (INT_GET(d->d_blk_softlimit, ARCH_CONVERT) && (INT_GET(d->d_bcount, ARCH_CONVERT) >= INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) { if (flags & XFS_QMOPT_DOWARN) { INT_MOD(d->d_bwarns, ARCH_CONVERT, +1); warned++; } } else { if (INT_ISZERO(d->d_blk_softlimit, ARCH_CONVERT) || (INT_GET(d->d_bcount, ARCH_CONVERT) < INT_GET(d->d_blk_softlimit, ARCH_CONVERT))) { INT_ZERO(d->d_bwarns, ARCH_CONVERT); } } if (INT_GET(d->d_ino_softlimit, ARCH_CONVERT) > 0 && (INT_GET(d->d_icount, ARCH_CONVERT) >= INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) { if (flags & XFS_QMOPT_DOWARN) { INT_MOD(d->d_iwarns, ARCH_CONVERT, +1); warned++; } } else { if ((INT_ISZERO(d->d_ino_softlimit, ARCH_CONVERT)) || (INT_GET(d->d_icount, ARCH_CONVERT) < INT_GET(d->d_ino_softlimit, ARCH_CONVERT))) { INT_ZERO(d->d_iwarns, ARCH_CONVERT); } } #ifdef QUOTADEBUG if (INT_GET(d->d_iwarns, ARCH_CONVERT)) cmn_err(CE_DEBUG, "--------@@Inode warnings running : %Lu >= %Lu", INT_GET(d->d_icount, ARCH_CONVERT), INT_GET(d->d_ino_softlimit, ARCH_CONVERT)); if (INT_GET(d->d_bwarns, ARCH_CONVERT)) cmn_err(CE_DEBUG, "--------@@Blks warnings running : %Lu >= %Lu", INT_GET(d->d_bcount, ARCH_CONVERT), INT_GET(d->d_blk_softlimit, ARCH_CONVERT)); #endif return (warned); }
/* * xfs_trans_apply_sb_deltas() is called from the commit code * to bring the superblock buffer into the current transaction * and modify it as requested by earlier calls to xfs_trans_mod_sb(). * * For now we just look at each field allowed to change and change * it if necessary. */ STATIC void xfs_trans_apply_sb_deltas( xfs_trans_t *tp) { xfs_sb_t *sbp; xfs_buf_t *bp; int whole = 0; bp = xfs_trans_getsb(tp, tp->t_mountp, 0); sbp = XFS_BUF_TO_SBP(bp); /* * Check that superblock mods match the mods made to AGF counters. */ ASSERT((tp->t_fdblocks_delta + tp->t_res_fdblocks_delta) == (tp->t_ag_freeblks_delta + tp->t_ag_flist_delta + tp->t_ag_btree_delta)); if (tp->t_icount_delta != 0) { INT_MOD(sbp->sb_icount, ARCH_CONVERT, tp->t_icount_delta); } if (tp->t_ifree_delta != 0) { INT_MOD(sbp->sb_ifree, ARCH_CONVERT, tp->t_ifree_delta); } if (tp->t_fdblocks_delta != 0) { INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_fdblocks_delta); } if (tp->t_res_fdblocks_delta != 0) { INT_MOD(sbp->sb_fdblocks, ARCH_CONVERT, tp->t_res_fdblocks_delta); } if (tp->t_frextents_delta != 0) { INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_frextents_delta); } if (tp->t_res_frextents_delta != 0) { INT_MOD(sbp->sb_frextents, ARCH_CONVERT, tp->t_res_frextents_delta); } if (tp->t_dblocks_delta != 0) { INT_MOD(sbp->sb_dblocks, ARCH_CONVERT, tp->t_dblocks_delta); whole = 1; } if (tp->t_agcount_delta != 0) { INT_MOD(sbp->sb_agcount, ARCH_CONVERT, tp->t_agcount_delta); whole = 1; } if (tp->t_imaxpct_delta != 0) { INT_MOD(sbp->sb_imax_pct, ARCH_CONVERT, tp->t_imaxpct_delta); whole = 1; } if (tp->t_rextsize_delta != 0) { INT_MOD(sbp->sb_rextsize, ARCH_CONVERT, tp->t_rextsize_delta); whole = 1; } if (tp->t_rbmblocks_delta != 0) { INT_MOD(sbp->sb_rbmblocks, ARCH_CONVERT, tp->t_rbmblocks_delta); whole = 1; } if (tp->t_rblocks_delta != 0) { INT_MOD(sbp->sb_rblocks, ARCH_CONVERT, tp->t_rblocks_delta); whole = 1; } if (tp->t_rextents_delta != 0) { INT_MOD(sbp->sb_rextents, ARCH_CONVERT, tp->t_rextents_delta); whole = 1; } if (tp->t_rextslog_delta != 0) { INT_MOD(sbp->sb_rextslog, ARCH_CONVERT, tp->t_rextslog_delta); whole = 1; } if (whole) /* * Log the whole thing, the fields are noncontiguous. */ xfs_trans_log_buf(tp, bp, 0, sizeof(xfs_sb_t) - 1); else /* * Since all the modifiable fields are contiguous, we * can get away with this. */ xfs_trans_log_buf(tp, bp, offsetof(xfs_sb_t, sb_icount), offsetof(xfs_sb_t, sb_frextents) + sizeof(sbp->sb_frextents) - 1); #ifdef XXXKAN XFS_MTOVFS(tp->t_mountp)->vfs_super->s_dirt = 1; #endif }
/* * Called by xfs_trans_commit() and similar in spirit to * xfs_trans_apply_sb_deltas(). * Go thru all the dquots belonging to this transaction and modify the * INCORE dquot to reflect the actual usages. * Unreserve just the reservations done by this transaction * dquot is still left locked at exit. */ void xfs_trans_apply_dquot_deltas( xfs_trans_t *tp) { int i, j; xfs_dquot_t *dqp; xfs_dqtrx_t *qtrx, *qa; xfs_disk_dquot_t *d; long totalbdelta; long totalrtbdelta; ASSERT(tp->t_dqinfo); qa = tp->t_dqinfo->dqa_usrdquots; for (j = 0; j < 2; j++) { if (qa[0].qt_dquot == NULL) { qa = tp->t_dqinfo->dqa_grpdquots; continue; } /* * Lock all of the dquots and join them to the transaction. */ xfs_trans_dqlockedjoin(tp, qa); for (i = 0; i < XFS_QM_TRANS_MAXDQS; i++) { qtrx = &qa[i]; /* * The array of dquots is filled * sequentially, not sparsely. */ if ((dqp = qtrx->qt_dquot) == NULL) break; ASSERT(XFS_DQ_IS_LOCKED(dqp)); ASSERT(XFS_DQ_IS_ADDEDTO_TRX(tp, dqp)); /* * adjust the actual number of blocks used */ d = &dqp->q_core; /* * The issue here is - sometimes we don't make a blkquota * reservation intentionally to be fair to users * (when the amount is small). On the other hand, * delayed allocs do make reservations, but that's * outside of a transaction, so we have no * idea how much was really reserved. * So, here we've accumulated delayed allocation blks and * non-delay blks. The assumption is that the * delayed ones are always reserved (outside of a * transaction), and the others may or may not have * quota reservations. */ totalbdelta = qtrx->qt_bcount_delta + qtrx->qt_delbcnt_delta; totalrtbdelta = qtrx->qt_rtbcount_delta + qtrx->qt_delrtb_delta; #ifdef QUOTADEBUG if (totalbdelta < 0) ASSERT(INT_GET(d->d_bcount, ARCH_CONVERT) >= (xfs_qcnt_t) -totalbdelta); if (totalrtbdelta < 0) ASSERT(INT_GET(d->d_rtbcount, ARCH_CONVERT) >= (xfs_qcnt_t) -totalrtbdelta); if (qtrx->qt_icount_delta < 0) ASSERT(INT_GET(d->d_icount, ARCH_CONVERT) >= (xfs_qcnt_t) -qtrx->qt_icount_delta); #endif if (totalbdelta) INT_MOD(d->d_bcount, ARCH_CONVERT, (xfs_qcnt_t)totalbdelta); if (qtrx->qt_icount_delta) INT_MOD(d->d_icount, ARCH_CONVERT, (xfs_qcnt_t)qtrx->qt_icount_delta); if (totalrtbdelta) INT_MOD(d->d_rtbcount, ARCH_CONVERT, (xfs_qcnt_t)totalrtbdelta); /* * Start/reset the timer(s) if needed. */ xfs_qm_adjust_dqtimers(tp->t_mountp, d); dqp->dq_flags |= XFS_DQ_DIRTY; /* * add this to the list of items to get logged */ xfs_trans_log_dquot(tp, dqp); /* * Take off what's left of the original reservation. * In case of delayed allocations, there's no * reservation that a transaction structure knows of. */ if (qtrx->qt_blk_res != 0) { if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) { if (qtrx->qt_blk_res > qtrx->qt_blk_res_used) dqp->q_res_bcount -= (xfs_qcnt_t) (qtrx->qt_blk_res - qtrx->qt_blk_res_used); else dqp->q_res_bcount -= (xfs_qcnt_t) (qtrx->qt_blk_res_used - qtrx->qt_blk_res); } } else { /* * These blks were never reserved, either inside * a transaction or outside one (in a delayed * allocation). Also, this isn't always a * negative number since we sometimes * deliberately skip quota reservations. */ if (qtrx->qt_bcount_delta) { dqp->q_res_bcount += (xfs_qcnt_t)qtrx->qt_bcount_delta; } } /* * Adjust the RT reservation. */ if (qtrx->qt_rtblk_res != 0) { if (qtrx->qt_blk_res != qtrx->qt_blk_res_used) { if (qtrx->qt_rtblk_res > qtrx->qt_rtblk_res_used) dqp->q_res_rtbcount -= (xfs_qcnt_t) (qtrx->qt_rtblk_res - qtrx->qt_rtblk_res_used); else dqp->q_res_rtbcount -= (xfs_qcnt_t) (qtrx->qt_rtblk_res_used - qtrx->qt_rtblk_res); } } else { if (qtrx->qt_rtbcount_delta) dqp->q_res_rtbcount += (xfs_qcnt_t)qtrx->qt_rtbcount_delta; } /* * Adjust the inode reservation. */ if (qtrx->qt_ino_res != 0) { ASSERT(qtrx->qt_ino_res >= qtrx->qt_ino_res_used); if (qtrx->qt_ino_res > qtrx->qt_ino_res_used) dqp->q_res_icount -= (xfs_qcnt_t) (qtrx->qt_ino_res - qtrx->qt_ino_res_used); } else { if (qtrx->qt_icount_delta) dqp->q_res_icount += (xfs_qcnt_t)qtrx->qt_icount_delta; } #ifdef QUOTADEBUG if (qtrx->qt_rtblk_res != 0) printk("RT res %d for 0x%p\n", (int) qtrx->qt_rtblk_res, dqp); #endif ASSERT(dqp->q_res_bcount >= INT_GET(dqp->q_core.d_bcount, ARCH_CONVERT)); ASSERT(dqp->q_res_icount >= INT_GET(dqp->q_core.d_icount, ARCH_CONVERT)); ASSERT(dqp->q_res_rtbcount >= INT_GET(dqp->q_core.d_rtbcount, ARCH_CONVERT)); } /* * Do the group quotas next */ qa = tp->t_dqinfo->dqa_grpdquots; } }