struct xfs_log_item             *lip;
        struct xfs_buf                  *bplist[XFS_DEFER_OPS_NR_BUFS];
        struct xfs_inode                *iplist[XFS_DEFER_OPS_NR_INODES];
+       unsigned int                    ordered = 0; /* bitmap */
        int                             bpcount = 0, ipcount = 0;
        int                             i;
        int                             error;
 
+       BUILD_BUG_ON(NBBY * sizeof(ordered) < XFS_DEFER_OPS_NR_BUFS);
+
        list_for_each_entry(lip, &tp->t_items, li_trans) {
                switch (lip->li_type) {
                case XFS_LI_BUF:
                                        ASSERT(0);
                                        return -EFSCORRUPTED;
                                }
-                               xfs_trans_dirty_buf(tp, bli->bli_buf);
+                               if (bli->bli_flags & XFS_BLI_ORDERED)
+                                       ordered |= (1U << bpcount);
+                               else
+                                       xfs_trans_dirty_buf(tp, bli->bli_buf);
                                bplist[bpcount++] = bli->bli_buf;
                        }
                        break;
        /* Rejoin the buffers and dirty them so the log moves forward. */
        for (i = 0; i < bpcount; i++) {
                xfs_trans_bjoin(tp, bplist[i]);
+               if (ordered & (1U << i))
+                       xfs_trans_ordered_buf(tp, bplist[i]);
                xfs_trans_bhold(tp, bplist[i]);
        }
 
 
  */
 STATIC void
 xfs_qm_init_dquot_blk(
-       xfs_trans_t     *tp,
-       xfs_mount_t     *mp,
-       xfs_dqid_t      id,
-       uint            type,
-       xfs_buf_t       *bp)
+       struct xfs_trans        *tp,
+       struct xfs_mount        *mp,
+       xfs_dqid_t              id,
+       uint                    type,
+       struct xfs_buf          *bp)
 {
        struct xfs_quotainfo    *q = mp->m_quotainfo;
-       xfs_dqblk_t     *d;
-       xfs_dqid_t      curid;
-       int             i;
+       struct xfs_dqblk        *d;
+       xfs_dqid_t              curid;
+       unsigned int            qflag;
+       unsigned int            blftype;
+       int                     i;
 
        ASSERT(tp);
        ASSERT(xfs_buf_islocked(bp));
                }
        }
 
-       xfs_trans_dquot_buf(tp, bp,
-                           (type & XFS_DQ_USER ? XFS_BLF_UDQUOT_BUF :
-                           ((type & XFS_DQ_PROJ) ? XFS_BLF_PDQUOT_BUF :
-                            XFS_BLF_GDQUOT_BUF)));
-       xfs_trans_log_buf(tp, bp, 0, BBTOB(q->qi_dqchunklen) - 1);
+       if (type & XFS_DQ_USER) {
+               qflag = XFS_UQUOTA_CHKD;
+               blftype = XFS_BLF_UDQUOT_BUF;
+       } else if (type & XFS_DQ_PROJ) {
+               qflag = XFS_PQUOTA_CHKD;
+               blftype = XFS_BLF_PDQUOT_BUF;
+       } else {
+               qflag = XFS_GQUOTA_CHKD;
+               blftype = XFS_BLF_GDQUOT_BUF;
+       }
+
+       xfs_trans_dquot_buf(tp, bp, blftype);
+
+       /*
+        * quotacheck uses delayed writes to update all the dquots on disk in an
+        * efficient manner instead of logging the individual dquot changes as
+        * they are made. However if we log the buffer allocated here and crash
+        * after quotacheck while the logged initialisation is still in the
+        * active region of the log, log recovery can replay the dquot buffer
+        * initialisation over the top of the checked dquots and corrupt quota
+        * accounting.
+        *
+        * To avoid this problem, quotacheck cannot log the initialised buffer.
+        * We must still dirty the buffer and write it back before the
+        * allocation transaction clears the log. Therefore, mark the buffer as
+        * ordered instead of logging it directly. This is safe for quotacheck
+        * because it detects and repairs allocated but initialized dquot blocks
+        * in the quota inodes.
+        */
+       if (!(mp->m_qflags & qflag))
+               xfs_trans_ordered_buf(tp, bp);
+       else
+               xfs_trans_log_buf(tp, bp, 0, BBTOB(q->qi_dqchunklen) - 1);
 }
 
 /*