예제 #1
0
/*
 * 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(
    struct xfs_trans	*tp)
{
    int			i, j;
    struct xfs_dquot	*dqp;
    struct xfs_dqtrx	*qtrx, *qa;
    struct xfs_disk_dquot	*d;
    long			totalbdelta;
    long			totalrtbdelta;

    if (!(tp->t_flags & XFS_TRANS_DQ_DIRTY))
        return;

    ASSERT(tp->t_dqinfo);
    for (j = 0; j < XFS_QM_TRANS_DQTYPES; j++) {
        qa = tp->t_dqinfo->dqs[j];
        if (qa[0].qt_dquot == NULL)
            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(dqp->q_transp == tp);

            /*
             * 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 DEBUG
            if (totalbdelta < 0)
                ASSERT(be64_to_cpu(d->d_bcount) >=
                       -totalbdelta);

            if (totalrtbdelta < 0)
                ASSERT(be64_to_cpu(d->d_rtbcount) >=
                       -totalrtbdelta);

            if (qtrx->qt_icount_delta < 0)
                ASSERT(be64_to_cpu(d->d_icount) >=
                       -qtrx->qt_icount_delta);
#endif
            if (totalbdelta)
                be64_add_cpu(&d->d_bcount, (xfs_qcnt_t)totalbdelta);

            if (qtrx->qt_icount_delta)
                be64_add_cpu(&d->d_icount, (xfs_qcnt_t)qtrx->qt_icount_delta);

            if (totalrtbdelta)
                be64_add_cpu(&d->d_rtbcount, (xfs_qcnt_t)totalrtbdelta);

            /*
             * Get any default limits in use.
             * Start/reset the timer(s) if needed.
             */
            if (d->d_id) {
                xfs_qm_adjust_dqlimits(tp->t_mountp, dqp);
                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) {
                ulong blk_res_used = 0;

                if (qtrx->qt_bcount_delta > 0)
                    blk_res_used = qtrx->qt_bcount_delta;

                if (qtrx->qt_blk_res != blk_res_used) {
                    if (qtrx->qt_blk_res > blk_res_used)
                        dqp->q_res_bcount -= (xfs_qcnt_t)
                                             (qtrx->qt_blk_res -
                                              blk_res_used);
                    else
                        dqp->q_res_bcount -= (xfs_qcnt_t)
                                             (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_rtblk_res != qtrx->qt_rtblk_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;
            }

            ASSERT(dqp->q_res_bcount >=
                   be64_to_cpu(dqp->q_core.d_bcount));
            ASSERT(dqp->q_res_icount >=
                   be64_to_cpu(dqp->q_core.d_icount));
            ASSERT(dqp->q_res_rtbcount >=
                   be64_to_cpu(dqp->q_core.d_rtbcount));
        }
    }
}
예제 #2
0
/*
 * 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;
	}
}