Skip to content

Commit 681ee24

Browse files
Darrick J. Wonggregkh
authored andcommitted
xfs: don't lose solo dquot update transactions
commit 07137e9 upstream. Quota counter updates are tracked via incore objects which hang off the xfs_trans object. These changes are then turned into dirty log items in xfs_trans_apply_dquot_deltas just prior to commiting the log items to the CIL. However, updating the incore deltas do not cause XFS_TRANS_DIRTY to be set on the transaction. In other words, a pure quota counter update will be silently discarded if there are no other dirty log items attached to the transaction. This is currently not the case anywhere in the filesystem because quota updates always dirty at least one other metadata item, but a subsequent bug fix will add dquot log item precommits, so we actually need a dirty dquot log item prior to xfs_trans_run_precommits. Also let's not leave a logic bomb. Cc: <[email protected]> # v2.6.35 Fixes: 0924378 ("xfs: split out iclog writing from xfs_trans_commit()") Signed-off-by: "Darrick J. Wong" <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 6b8aa79 commit 681ee24

File tree

3 files changed

+32
-14
lines changed

3 files changed

+32
-14
lines changed

fs/xfs/xfs_quota.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ extern void xfs_trans_free_dqinfo(struct xfs_trans *);
9696
extern void xfs_trans_mod_dquot_byino(struct xfs_trans *, struct xfs_inode *,
9797
uint, int64_t);
9898
extern void xfs_trans_apply_dquot_deltas(struct xfs_trans *);
99-
extern void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *);
99+
void xfs_trans_unreserve_and_mod_dquots(struct xfs_trans *tp,
100+
bool already_locked);
100101
int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp, struct xfs_inode *ip,
101102
int64_t dblocks, int64_t rblocks, bool force);
102103
extern int xfs_trans_reserve_quota_bydquots(struct xfs_trans *,
@@ -166,7 +167,7 @@ static inline void xfs_trans_mod_dquot_byino(struct xfs_trans *tp,
166167
{
167168
}
168169
#define xfs_trans_apply_dquot_deltas(tp)
169-
#define xfs_trans_unreserve_and_mod_dquots(tp)
170+
#define xfs_trans_unreserve_and_mod_dquots(tp, a)
170171
static inline int xfs_trans_reserve_quota_nblks(struct xfs_trans *tp,
171172
struct xfs_inode *ip, int64_t dblocks, int64_t rblocks,
172173
bool force)

fs/xfs/xfs_trans.c

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -840,6 +840,7 @@ __xfs_trans_commit(
840840
*/
841841
if (tp->t_flags & XFS_TRANS_SB_DIRTY)
842842
xfs_trans_apply_sb_deltas(tp);
843+
xfs_trans_apply_dquot_deltas(tp);
843844

844845
error = xfs_trans_run_precommits(tp);
845846
if (error)
@@ -868,11 +869,6 @@ __xfs_trans_commit(
868869

869870
ASSERT(tp->t_ticket != NULL);
870871

871-
/*
872-
* If we need to update the superblock, then do it now.
873-
*/
874-
xfs_trans_apply_dquot_deltas(tp);
875-
876872
xlog_cil_commit(log, tp, &commit_seq, regrant);
877873

878874
xfs_trans_free(tp);
@@ -898,7 +894,7 @@ __xfs_trans_commit(
898894
* the dqinfo portion to be. All that means is that we have some
899895
* (non-persistent) quota reservations that need to be unreserved.
900896
*/
901-
xfs_trans_unreserve_and_mod_dquots(tp);
897+
xfs_trans_unreserve_and_mod_dquots(tp, true);
902898
if (tp->t_ticket) {
903899
if (regrant && !xlog_is_shutdown(log))
904900
xfs_log_ticket_regrant(log, tp->t_ticket);
@@ -992,7 +988,7 @@ xfs_trans_cancel(
992988
}
993989
#endif
994990
xfs_trans_unreserve_and_mod_sb(tp);
995-
xfs_trans_unreserve_and_mod_dquots(tp);
991+
xfs_trans_unreserve_and_mod_dquots(tp, false);
996992

997993
if (tp->t_ticket) {
998994
xfs_log_ticket_ungrant(log, tp->t_ticket);

fs/xfs/xfs_trans_dquot.c

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,24 @@ xfs_trans_apply_dquot_deltas(
602602
ASSERT(dqp->q_blk.reserved >= dqp->q_blk.count);
603603
ASSERT(dqp->q_ino.reserved >= dqp->q_ino.count);
604604
ASSERT(dqp->q_rtb.reserved >= dqp->q_rtb.count);
605+
606+
/*
607+
* We've applied the count changes and given back
608+
* whatever reservation we didn't use. Zero out the
609+
* dqtrx fields.
610+
*/
611+
qtrx->qt_blk_res = 0;
612+
qtrx->qt_bcount_delta = 0;
613+
qtrx->qt_delbcnt_delta = 0;
614+
615+
qtrx->qt_rtblk_res = 0;
616+
qtrx->qt_rtblk_res_used = 0;
617+
qtrx->qt_rtbcount_delta = 0;
618+
qtrx->qt_delrtb_delta = 0;
619+
620+
qtrx->qt_ino_res = 0;
621+
qtrx->qt_ino_res_used = 0;
622+
qtrx->qt_icount_delta = 0;
605623
}
606624
}
607625
}
@@ -638,7 +656,8 @@ xfs_trans_unreserve_and_mod_dquots_hook(
638656
*/
639657
void
640658
xfs_trans_unreserve_and_mod_dquots(
641-
struct xfs_trans *tp)
659+
struct xfs_trans *tp,
660+
bool already_locked)
642661
{
643662
int i, j;
644663
struct xfs_dquot *dqp;
@@ -667,10 +686,12 @@ xfs_trans_unreserve_and_mod_dquots(
667686
* about the number of blocks used field, or deltas.
668687
* Also we don't bother to zero the fields.
669688
*/
670-
locked = false;
689+
locked = already_locked;
671690
if (qtrx->qt_blk_res) {
672-
xfs_dqlock(dqp);
673-
locked = true;
691+
if (!locked) {
692+
xfs_dqlock(dqp);
693+
locked = true;
694+
}
674695
dqp->q_blk.reserved -=
675696
(xfs_qcnt_t)qtrx->qt_blk_res;
676697
}
@@ -691,7 +712,7 @@ xfs_trans_unreserve_and_mod_dquots(
691712
dqp->q_rtb.reserved -=
692713
(xfs_qcnt_t)qtrx->qt_rtblk_res;
693714
}
694-
if (locked)
715+
if (locked && !already_locked)
695716
xfs_dqunlock(dqp);
696717

697718
}

0 commit comments

Comments
 (0)