186ffa471SDarrick J. Wong // SPDX-License-Identifier: GPL-2.0
286ffa471SDarrick J. Wong /*
386ffa471SDarrick J. Wong * Copyright (c) 2000-2006 Silicon Graphics, Inc.
486ffa471SDarrick J. Wong * All Rights Reserved.
586ffa471SDarrick J. Wong */
686ffa471SDarrick J. Wong #include "xfs.h"
786ffa471SDarrick J. Wong #include "xfs_fs.h"
886ffa471SDarrick J. Wong #include "xfs_shared.h"
986ffa471SDarrick J. Wong #include "xfs_format.h"
1086ffa471SDarrick J. Wong #include "xfs_log_format.h"
1186ffa471SDarrick J. Wong #include "xfs_trans_resv.h"
1286ffa471SDarrick J. Wong #include "xfs_mount.h"
1386ffa471SDarrick J. Wong #include "xfs_inode.h"
1486ffa471SDarrick J. Wong #include "xfs_quota.h"
1586ffa471SDarrick J. Wong #include "xfs_trans.h"
1686ffa471SDarrick J. Wong #include "xfs_buf_item.h"
1786ffa471SDarrick J. Wong #include "xfs_trans_priv.h"
1886ffa471SDarrick J. Wong #include "xfs_qm.h"
1986ffa471SDarrick J. Wong #include "xfs_log.h"
2086ffa471SDarrick J. Wong #include "xfs_log_priv.h"
2186ffa471SDarrick J. Wong #include "xfs_log_recover.h"
22*3581868fSDarrick J. Wong #include "xfs_error.h"
2386ffa471SDarrick J. Wong
248ea5682dSDarrick J. Wong STATIC void
xlog_recover_dquot_ra_pass2(struct xlog * log,struct xlog_recover_item * item)258ea5682dSDarrick J. Wong xlog_recover_dquot_ra_pass2(
268ea5682dSDarrick J. Wong struct xlog *log,
278ea5682dSDarrick J. Wong struct xlog_recover_item *item)
288ea5682dSDarrick J. Wong {
298ea5682dSDarrick J. Wong struct xfs_mount *mp = log->l_mp;
308ea5682dSDarrick J. Wong struct xfs_disk_dquot *recddq;
318ea5682dSDarrick J. Wong struct xfs_dq_logformat *dq_f;
328ea5682dSDarrick J. Wong uint type;
338ea5682dSDarrick J. Wong
348ea5682dSDarrick J. Wong if (mp->m_qflags == 0)
358ea5682dSDarrick J. Wong return;
368ea5682dSDarrick J. Wong
378ea5682dSDarrick J. Wong recddq = item->ri_buf[1].i_addr;
388ea5682dSDarrick J. Wong if (recddq == NULL)
398ea5682dSDarrick J. Wong return;
408ea5682dSDarrick J. Wong if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot))
418ea5682dSDarrick J. Wong return;
428ea5682dSDarrick J. Wong
43d8c1af0dSDarrick J. Wong type = recddq->d_type & XFS_DQTYPE_REC_MASK;
448ea5682dSDarrick J. Wong ASSERT(type);
458ea5682dSDarrick J. Wong if (log->l_quotaoffs_flag & type)
468ea5682dSDarrick J. Wong return;
478ea5682dSDarrick J. Wong
488ea5682dSDarrick J. Wong dq_f = item->ri_buf[0].i_addr;
498ea5682dSDarrick J. Wong ASSERT(dq_f);
508ea5682dSDarrick J. Wong ASSERT(dq_f->qlf_len == 1);
518ea5682dSDarrick J. Wong
528ea5682dSDarrick J. Wong xlog_buf_readahead(log, dq_f->qlf_blkno,
538ea5682dSDarrick J. Wong XFS_FSB_TO_BB(mp, dq_f->qlf_len),
548ea5682dSDarrick J. Wong &xfs_dquot_buf_ra_ops);
558ea5682dSDarrick J. Wong }
568ea5682dSDarrick J. Wong
57fcbdf91eSDarrick J. Wong /*
58fcbdf91eSDarrick J. Wong * Recover a dquot record
59fcbdf91eSDarrick J. Wong */
60fcbdf91eSDarrick J. Wong STATIC int
xlog_recover_dquot_commit_pass2(struct xlog * log,struct list_head * buffer_list,struct xlog_recover_item * item,xfs_lsn_t current_lsn)61fcbdf91eSDarrick J. Wong xlog_recover_dquot_commit_pass2(
62fcbdf91eSDarrick J. Wong struct xlog *log,
63fcbdf91eSDarrick J. Wong struct list_head *buffer_list,
64fcbdf91eSDarrick J. Wong struct xlog_recover_item *item,
65fcbdf91eSDarrick J. Wong xfs_lsn_t current_lsn)
66fcbdf91eSDarrick J. Wong {
67fcbdf91eSDarrick J. Wong struct xfs_mount *mp = log->l_mp;
68fcbdf91eSDarrick J. Wong struct xfs_buf *bp;
69d744e578SDarrick J. Wong struct xfs_dqblk *dqb;
70fcbdf91eSDarrick J. Wong struct xfs_disk_dquot *ddq, *recddq;
71fcbdf91eSDarrick J. Wong struct xfs_dq_logformat *dq_f;
72fcbdf91eSDarrick J. Wong xfs_failaddr_t fa;
73fcbdf91eSDarrick J. Wong int error;
74fcbdf91eSDarrick J. Wong uint type;
75fcbdf91eSDarrick J. Wong
76fcbdf91eSDarrick J. Wong /*
77fcbdf91eSDarrick J. Wong * Filesystems are required to send in quota flags at mount time.
78fcbdf91eSDarrick J. Wong */
79fcbdf91eSDarrick J. Wong if (mp->m_qflags == 0)
80fcbdf91eSDarrick J. Wong return 0;
81fcbdf91eSDarrick J. Wong
82fcbdf91eSDarrick J. Wong recddq = item->ri_buf[1].i_addr;
83fcbdf91eSDarrick J. Wong if (recddq == NULL) {
84fcbdf91eSDarrick J. Wong xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);
85fcbdf91eSDarrick J. Wong return -EFSCORRUPTED;
86fcbdf91eSDarrick J. Wong }
87fcbdf91eSDarrick J. Wong if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) {
88fcbdf91eSDarrick J. Wong xfs_alert(log->l_mp, "dquot too small (%d) in %s.",
89fcbdf91eSDarrick J. Wong item->ri_buf[1].i_len, __func__);
90fcbdf91eSDarrick J. Wong return -EFSCORRUPTED;
91fcbdf91eSDarrick J. Wong }
92fcbdf91eSDarrick J. Wong
93fcbdf91eSDarrick J. Wong /*
94fcbdf91eSDarrick J. Wong * This type of quotas was turned off, so ignore this record.
95fcbdf91eSDarrick J. Wong */
96d8c1af0dSDarrick J. Wong type = recddq->d_type & XFS_DQTYPE_REC_MASK;
97fcbdf91eSDarrick J. Wong ASSERT(type);
98fcbdf91eSDarrick J. Wong if (log->l_quotaoffs_flag & type)
99fcbdf91eSDarrick J. Wong return 0;
100fcbdf91eSDarrick J. Wong
101fcbdf91eSDarrick J. Wong /*
102fcbdf91eSDarrick J. Wong * At this point we know that quota was _not_ turned off.
103fcbdf91eSDarrick J. Wong * Since the mount flags are not indicating to us otherwise, this
104fcbdf91eSDarrick J. Wong * must mean that quota is on, and the dquot needs to be replayed.
105fcbdf91eSDarrick J. Wong * Remember that we may not have fully recovered the superblock yet,
106fcbdf91eSDarrick J. Wong * so we can't do the usual trick of looking at the SB quota bits.
107fcbdf91eSDarrick J. Wong *
108fcbdf91eSDarrick J. Wong * The other possibility, of course, is that the quota subsystem was
109fcbdf91eSDarrick J. Wong * removed since the last mount - ENOSYS.
110fcbdf91eSDarrick J. Wong */
111fcbdf91eSDarrick J. Wong dq_f = item->ri_buf[0].i_addr;
112fcbdf91eSDarrick J. Wong ASSERT(dq_f);
113f9751c4aSDarrick J. Wong fa = xfs_dquot_verify(mp, recddq, dq_f->qlf_id);
114fcbdf91eSDarrick J. Wong if (fa) {
115fcbdf91eSDarrick J. Wong xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS",
116fcbdf91eSDarrick J. Wong dq_f->qlf_id, fa);
117fcbdf91eSDarrick J. Wong return -EFSCORRUPTED;
118fcbdf91eSDarrick J. Wong }
119fcbdf91eSDarrick J. Wong ASSERT(dq_f->qlf_len == 1);
120fcbdf91eSDarrick J. Wong
121fcbdf91eSDarrick J. Wong /*
122fcbdf91eSDarrick J. Wong * At this point we are assuming that the dquots have been allocated
123fcbdf91eSDarrick J. Wong * and hence the buffer has valid dquots stamped in it. It should,
124fcbdf91eSDarrick J. Wong * therefore, pass verifier validation. If the dquot is bad, then the
125fcbdf91eSDarrick J. Wong * we'll return an error here, so we don't need to specifically check
126fcbdf91eSDarrick J. Wong * the dquot in the buffer after the verifier has run.
127fcbdf91eSDarrick J. Wong */
128fcbdf91eSDarrick J. Wong error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,
129fcbdf91eSDarrick J. Wong XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp,
130fcbdf91eSDarrick J. Wong &xfs_dquot_buf_ops);
131fcbdf91eSDarrick J. Wong if (error)
132fcbdf91eSDarrick J. Wong return error;
133fcbdf91eSDarrick J. Wong
134fcbdf91eSDarrick J. Wong ASSERT(bp);
135d744e578SDarrick J. Wong dqb = xfs_buf_offset(bp, dq_f->qlf_boffset);
136d744e578SDarrick J. Wong ddq = &dqb->dd_diskdq;
137fcbdf91eSDarrick J. Wong
138fcbdf91eSDarrick J. Wong /*
139fcbdf91eSDarrick J. Wong * If the dquot has an LSN in it, recover the dquot only if it's less
140fcbdf91eSDarrick J. Wong * than the lsn of the transaction we are replaying.
141fcbdf91eSDarrick J. Wong */
14238c26bfdSDave Chinner if (xfs_has_crc(mp)) {
143fcbdf91eSDarrick J. Wong xfs_lsn_t lsn = be64_to_cpu(dqb->dd_lsn);
144fcbdf91eSDarrick J. Wong
145fcbdf91eSDarrick J. Wong if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
146fcbdf91eSDarrick J. Wong goto out_release;
147fcbdf91eSDarrick J. Wong }
148fcbdf91eSDarrick J. Wong }
149fcbdf91eSDarrick J. Wong
150fcbdf91eSDarrick J. Wong memcpy(ddq, recddq, item->ri_buf[1].i_len);
15138c26bfdSDave Chinner if (xfs_has_crc(mp)) {
152d744e578SDarrick J. Wong xfs_update_cksum((char *)dqb, sizeof(struct xfs_dqblk),
153fcbdf91eSDarrick J. Wong XFS_DQUOT_CRC_OFF);
154fcbdf91eSDarrick J. Wong }
155fcbdf91eSDarrick J. Wong
156*3581868fSDarrick J. Wong /* Validate the recovered dquot. */
157*3581868fSDarrick J. Wong fa = xfs_dqblk_verify(log->l_mp, dqb, dq_f->qlf_id);
158*3581868fSDarrick J. Wong if (fa) {
159*3581868fSDarrick J. Wong XFS_CORRUPTION_ERROR("Bad dquot after recovery",
160*3581868fSDarrick J. Wong XFS_ERRLEVEL_LOW, mp, dqb,
161*3581868fSDarrick J. Wong sizeof(struct xfs_dqblk));
162*3581868fSDarrick J. Wong xfs_alert(mp,
163*3581868fSDarrick J. Wong "Metadata corruption detected at %pS, dquot 0x%x",
164*3581868fSDarrick J. Wong fa, dq_f->qlf_id);
165*3581868fSDarrick J. Wong error = -EFSCORRUPTED;
166*3581868fSDarrick J. Wong goto out_release;
167*3581868fSDarrick J. Wong }
168*3581868fSDarrick J. Wong
169fcbdf91eSDarrick J. Wong ASSERT(dq_f->qlf_size == 2);
170fcbdf91eSDarrick J. Wong ASSERT(bp->b_mount == mp);
1719fe5c77cSDave Chinner bp->b_flags |= _XBF_LOGRECOVERY;
172fcbdf91eSDarrick J. Wong xfs_buf_delwri_queue(bp, buffer_list);
173fcbdf91eSDarrick J. Wong
174fcbdf91eSDarrick J. Wong out_release:
175fcbdf91eSDarrick J. Wong xfs_buf_relse(bp);
176fcbdf91eSDarrick J. Wong return 0;
177fcbdf91eSDarrick J. Wong }
178fcbdf91eSDarrick J. Wong
17986ffa471SDarrick J. Wong const struct xlog_recover_item_ops xlog_dquot_item_ops = {
18086ffa471SDarrick J. Wong .item_type = XFS_LI_DQUOT,
1818ea5682dSDarrick J. Wong .ra_pass2 = xlog_recover_dquot_ra_pass2,
182fcbdf91eSDarrick J. Wong .commit_pass2 = xlog_recover_dquot_commit_pass2,
18386ffa471SDarrick J. Wong };
18486ffa471SDarrick J. Wong
1853304a4faSDarrick J. Wong /*
1863304a4faSDarrick J. Wong * Recover QUOTAOFF records. We simply make a note of it in the xlog
1873304a4faSDarrick J. Wong * structure, so that we know not to do any dquot item or dquot buffer recovery,
1883304a4faSDarrick J. Wong * of that type.
1893304a4faSDarrick J. Wong */
1903304a4faSDarrick J. Wong STATIC int
xlog_recover_quotaoff_commit_pass1(struct xlog * log,struct xlog_recover_item * item)1913304a4faSDarrick J. Wong xlog_recover_quotaoff_commit_pass1(
1923304a4faSDarrick J. Wong struct xlog *log,
1933304a4faSDarrick J. Wong struct xlog_recover_item *item)
1943304a4faSDarrick J. Wong {
1953304a4faSDarrick J. Wong struct xfs_qoff_logformat *qoff_f = item->ri_buf[0].i_addr;
1963304a4faSDarrick J. Wong ASSERT(qoff_f);
1973304a4faSDarrick J. Wong
1983304a4faSDarrick J. Wong /*
1993304a4faSDarrick J. Wong * The logitem format's flag tells us if this was user quotaoff,
2003304a4faSDarrick J. Wong * group/project quotaoff or both.
2013304a4faSDarrick J. Wong */
2023304a4faSDarrick J. Wong if (qoff_f->qf_flags & XFS_UQUOTA_ACCT)
2038cd4901dSDarrick J. Wong log->l_quotaoffs_flag |= XFS_DQTYPE_USER;
2043304a4faSDarrick J. Wong if (qoff_f->qf_flags & XFS_PQUOTA_ACCT)
2058cd4901dSDarrick J. Wong log->l_quotaoffs_flag |= XFS_DQTYPE_PROJ;
2063304a4faSDarrick J. Wong if (qoff_f->qf_flags & XFS_GQUOTA_ACCT)
2078cd4901dSDarrick J. Wong log->l_quotaoffs_flag |= XFS_DQTYPE_GROUP;
2083304a4faSDarrick J. Wong
2093304a4faSDarrick J. Wong return 0;
2103304a4faSDarrick J. Wong }
2113304a4faSDarrick J. Wong
21286ffa471SDarrick J. Wong const struct xlog_recover_item_ops xlog_quotaoff_item_ops = {
21386ffa471SDarrick J. Wong .item_type = XFS_LI_QUOTAOFF,
2143304a4faSDarrick J. Wong .commit_pass1 = xlog_recover_quotaoff_commit_pass1,
2152565a11bSDarrick J. Wong /* nothing to commit in pass2 */
21686ffa471SDarrick J. Wong };
217