xfs_dquot_item_recover.c (5243B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (c) 2000-2006 Silicon Graphics, Inc. 4 * All Rights Reserved. 5 */ 6#include "xfs.h" 7#include "xfs_fs.h" 8#include "xfs_shared.h" 9#include "xfs_format.h" 10#include "xfs_log_format.h" 11#include "xfs_trans_resv.h" 12#include "xfs_mount.h" 13#include "xfs_inode.h" 14#include "xfs_quota.h" 15#include "xfs_trans.h" 16#include "xfs_buf_item.h" 17#include "xfs_trans_priv.h" 18#include "xfs_qm.h" 19#include "xfs_log.h" 20#include "xfs_log_priv.h" 21#include "xfs_log_recover.h" 22 23STATIC void 24xlog_recover_dquot_ra_pass2( 25 struct xlog *log, 26 struct xlog_recover_item *item) 27{ 28 struct xfs_mount *mp = log->l_mp; 29 struct xfs_disk_dquot *recddq; 30 struct xfs_dq_logformat *dq_f; 31 uint type; 32 33 if (mp->m_qflags == 0) 34 return; 35 36 recddq = item->ri_buf[1].i_addr; 37 if (recddq == NULL) 38 return; 39 if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) 40 return; 41 42 type = recddq->d_type & XFS_DQTYPE_REC_MASK; 43 ASSERT(type); 44 if (log->l_quotaoffs_flag & type) 45 return; 46 47 dq_f = item->ri_buf[0].i_addr; 48 ASSERT(dq_f); 49 ASSERT(dq_f->qlf_len == 1); 50 51 xlog_buf_readahead(log, dq_f->qlf_blkno, 52 XFS_FSB_TO_BB(mp, dq_f->qlf_len), 53 &xfs_dquot_buf_ra_ops); 54} 55 56/* 57 * Recover a dquot record 58 */ 59STATIC int 60xlog_recover_dquot_commit_pass2( 61 struct xlog *log, 62 struct list_head *buffer_list, 63 struct xlog_recover_item *item, 64 xfs_lsn_t current_lsn) 65{ 66 struct xfs_mount *mp = log->l_mp; 67 struct xfs_buf *bp; 68 struct xfs_disk_dquot *ddq, *recddq; 69 struct xfs_dq_logformat *dq_f; 70 xfs_failaddr_t fa; 71 int error; 72 uint type; 73 74 /* 75 * Filesystems are required to send in quota flags at mount time. 76 */ 77 if (mp->m_qflags == 0) 78 return 0; 79 80 recddq = item->ri_buf[1].i_addr; 81 if (recddq == NULL) { 82 xfs_alert(log->l_mp, "NULL dquot in %s.", __func__); 83 return -EFSCORRUPTED; 84 } 85 if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) { 86 xfs_alert(log->l_mp, "dquot too small (%d) in %s.", 87 item->ri_buf[1].i_len, __func__); 88 return -EFSCORRUPTED; 89 } 90 91 /* 92 * This type of quotas was turned off, so ignore this record. 93 */ 94 type = recddq->d_type & XFS_DQTYPE_REC_MASK; 95 ASSERT(type); 96 if (log->l_quotaoffs_flag & type) 97 return 0; 98 99 /* 100 * At this point we know that quota was _not_ turned off. 101 * Since the mount flags are not indicating to us otherwise, this 102 * must mean that quota is on, and the dquot needs to be replayed. 103 * Remember that we may not have fully recovered the superblock yet, 104 * so we can't do the usual trick of looking at the SB quota bits. 105 * 106 * The other possibility, of course, is that the quota subsystem was 107 * removed since the last mount - ENOSYS. 108 */ 109 dq_f = item->ri_buf[0].i_addr; 110 ASSERT(dq_f); 111 fa = xfs_dquot_verify(mp, recddq, dq_f->qlf_id); 112 if (fa) { 113 xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS", 114 dq_f->qlf_id, fa); 115 return -EFSCORRUPTED; 116 } 117 ASSERT(dq_f->qlf_len == 1); 118 119 /* 120 * At this point we are assuming that the dquots have been allocated 121 * and hence the buffer has valid dquots stamped in it. It should, 122 * therefore, pass verifier validation. If the dquot is bad, then the 123 * we'll return an error here, so we don't need to specifically check 124 * the dquot in the buffer after the verifier has run. 125 */ 126 error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno, 127 XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp, 128 &xfs_dquot_buf_ops); 129 if (error) 130 return error; 131 132 ASSERT(bp); 133 ddq = xfs_buf_offset(bp, dq_f->qlf_boffset); 134 135 /* 136 * If the dquot has an LSN in it, recover the dquot only if it's less 137 * than the lsn of the transaction we are replaying. 138 */ 139 if (xfs_has_crc(mp)) { 140 struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddq; 141 xfs_lsn_t lsn = be64_to_cpu(dqb->dd_lsn); 142 143 if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) { 144 goto out_release; 145 } 146 } 147 148 memcpy(ddq, recddq, item->ri_buf[1].i_len); 149 if (xfs_has_crc(mp)) { 150 xfs_update_cksum((char *)ddq, sizeof(struct xfs_dqblk), 151 XFS_DQUOT_CRC_OFF); 152 } 153 154 ASSERT(dq_f->qlf_size == 2); 155 ASSERT(bp->b_mount == mp); 156 bp->b_flags |= _XBF_LOGRECOVERY; 157 xfs_buf_delwri_queue(bp, buffer_list); 158 159out_release: 160 xfs_buf_relse(bp); 161 return 0; 162} 163 164const struct xlog_recover_item_ops xlog_dquot_item_ops = { 165 .item_type = XFS_LI_DQUOT, 166 .ra_pass2 = xlog_recover_dquot_ra_pass2, 167 .commit_pass2 = xlog_recover_dquot_commit_pass2, 168}; 169 170/* 171 * Recover QUOTAOFF records. We simply make a note of it in the xlog 172 * structure, so that we know not to do any dquot item or dquot buffer recovery, 173 * of that type. 174 */ 175STATIC int 176xlog_recover_quotaoff_commit_pass1( 177 struct xlog *log, 178 struct xlog_recover_item *item) 179{ 180 struct xfs_qoff_logformat *qoff_f = item->ri_buf[0].i_addr; 181 ASSERT(qoff_f); 182 183 /* 184 * The logitem format's flag tells us if this was user quotaoff, 185 * group/project quotaoff or both. 186 */ 187 if (qoff_f->qf_flags & XFS_UQUOTA_ACCT) 188 log->l_quotaoffs_flag |= XFS_DQTYPE_USER; 189 if (qoff_f->qf_flags & XFS_PQUOTA_ACCT) 190 log->l_quotaoffs_flag |= XFS_DQTYPE_PROJ; 191 if (qoff_f->qf_flags & XFS_GQUOTA_ACCT) 192 log->l_quotaoffs_flag |= XFS_DQTYPE_GROUP; 193 194 return 0; 195} 196 197const struct xlog_recover_item_ops xlog_quotaoff_item_ops = { 198 .item_type = XFS_LI_QUOTAOFF, 199 .commit_pass1 = xlog_recover_quotaoff_commit_pass1, 200 /* nothing to commit in pass2 */ 201};