Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (c) 2000-2006 Silicon Graphics, Inc.
0004  * All Rights Reserved.
0005  */
0006 #include "xfs.h"
0007 #include "xfs_fs.h"
0008 #include "xfs_shared.h"
0009 #include "xfs_format.h"
0010 #include "xfs_log_format.h"
0011 #include "xfs_trans_resv.h"
0012 #include "xfs_mount.h"
0013 #include "xfs_inode.h"
0014 #include "xfs_quota.h"
0015 #include "xfs_trans.h"
0016 #include "xfs_buf_item.h"
0017 #include "xfs_trans_priv.h"
0018 #include "xfs_qm.h"
0019 #include "xfs_log.h"
0020 #include "xfs_log_priv.h"
0021 #include "xfs_log_recover.h"
0022 
0023 STATIC void
0024 xlog_recover_dquot_ra_pass2(
0025     struct xlog         *log,
0026     struct xlog_recover_item    *item)
0027 {
0028     struct xfs_mount    *mp = log->l_mp;
0029     struct xfs_disk_dquot   *recddq;
0030     struct xfs_dq_logformat *dq_f;
0031     uint            type;
0032 
0033     if (mp->m_qflags == 0)
0034         return;
0035 
0036     recddq = item->ri_buf[1].i_addr;
0037     if (recddq == NULL)
0038         return;
0039     if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot))
0040         return;
0041 
0042     type = recddq->d_type & XFS_DQTYPE_REC_MASK;
0043     ASSERT(type);
0044     if (log->l_quotaoffs_flag & type)
0045         return;
0046 
0047     dq_f = item->ri_buf[0].i_addr;
0048     ASSERT(dq_f);
0049     ASSERT(dq_f->qlf_len == 1);
0050 
0051     xlog_buf_readahead(log, dq_f->qlf_blkno,
0052             XFS_FSB_TO_BB(mp, dq_f->qlf_len),
0053             &xfs_dquot_buf_ra_ops);
0054 }
0055 
0056 /*
0057  * Recover a dquot record
0058  */
0059 STATIC int
0060 xlog_recover_dquot_commit_pass2(
0061     struct xlog         *log,
0062     struct list_head        *buffer_list,
0063     struct xlog_recover_item    *item,
0064     xfs_lsn_t           current_lsn)
0065 {
0066     struct xfs_mount        *mp = log->l_mp;
0067     struct xfs_buf          *bp;
0068     struct xfs_disk_dquot       *ddq, *recddq;
0069     struct xfs_dq_logformat     *dq_f;
0070     xfs_failaddr_t          fa;
0071     int             error;
0072     uint                type;
0073 
0074     /*
0075      * Filesystems are required to send in quota flags at mount time.
0076      */
0077     if (mp->m_qflags == 0)
0078         return 0;
0079 
0080     recddq = item->ri_buf[1].i_addr;
0081     if (recddq == NULL) {
0082         xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);
0083         return -EFSCORRUPTED;
0084     }
0085     if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) {
0086         xfs_alert(log->l_mp, "dquot too small (%d) in %s.",
0087             item->ri_buf[1].i_len, __func__);
0088         return -EFSCORRUPTED;
0089     }
0090 
0091     /*
0092      * This type of quotas was turned off, so ignore this record.
0093      */
0094     type = recddq->d_type & XFS_DQTYPE_REC_MASK;
0095     ASSERT(type);
0096     if (log->l_quotaoffs_flag & type)
0097         return 0;
0098 
0099     /*
0100      * At this point we know that quota was _not_ turned off.
0101      * Since the mount flags are not indicating to us otherwise, this
0102      * must mean that quota is on, and the dquot needs to be replayed.
0103      * Remember that we may not have fully recovered the superblock yet,
0104      * so we can't do the usual trick of looking at the SB quota bits.
0105      *
0106      * The other possibility, of course, is that the quota subsystem was
0107      * removed since the last mount - ENOSYS.
0108      */
0109     dq_f = item->ri_buf[0].i_addr;
0110     ASSERT(dq_f);
0111     fa = xfs_dquot_verify(mp, recddq, dq_f->qlf_id);
0112     if (fa) {
0113         xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS",
0114                 dq_f->qlf_id, fa);
0115         return -EFSCORRUPTED;
0116     }
0117     ASSERT(dq_f->qlf_len == 1);
0118 
0119     /*
0120      * At this point we are assuming that the dquots have been allocated
0121      * and hence the buffer has valid dquots stamped in it. It should,
0122      * therefore, pass verifier validation. If the dquot is bad, then the
0123      * we'll return an error here, so we don't need to specifically check
0124      * the dquot in the buffer after the verifier has run.
0125      */
0126     error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,
0127                    XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp,
0128                    &xfs_dquot_buf_ops);
0129     if (error)
0130         return error;
0131 
0132     ASSERT(bp);
0133     ddq = xfs_buf_offset(bp, dq_f->qlf_boffset);
0134 
0135     /*
0136      * If the dquot has an LSN in it, recover the dquot only if it's less
0137      * than the lsn of the transaction we are replaying.
0138      */
0139     if (xfs_has_crc(mp)) {
0140         struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddq;
0141         xfs_lsn_t   lsn = be64_to_cpu(dqb->dd_lsn);
0142 
0143         if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
0144             goto out_release;
0145         }
0146     }
0147 
0148     memcpy(ddq, recddq, item->ri_buf[1].i_len);
0149     if (xfs_has_crc(mp)) {
0150         xfs_update_cksum((char *)ddq, sizeof(struct xfs_dqblk),
0151                  XFS_DQUOT_CRC_OFF);
0152     }
0153 
0154     ASSERT(dq_f->qlf_size == 2);
0155     ASSERT(bp->b_mount == mp);
0156     bp->b_flags |= _XBF_LOGRECOVERY;
0157     xfs_buf_delwri_queue(bp, buffer_list);
0158 
0159 out_release:
0160     xfs_buf_relse(bp);
0161     return 0;
0162 }
0163 
0164 const struct xlog_recover_item_ops xlog_dquot_item_ops = {
0165     .item_type      = XFS_LI_DQUOT,
0166     .ra_pass2       = xlog_recover_dquot_ra_pass2,
0167     .commit_pass2       = xlog_recover_dquot_commit_pass2,
0168 };
0169 
0170 /*
0171  * Recover QUOTAOFF records. We simply make a note of it in the xlog
0172  * structure, so that we know not to do any dquot item or dquot buffer recovery,
0173  * of that type.
0174  */
0175 STATIC int
0176 xlog_recover_quotaoff_commit_pass1(
0177     struct xlog         *log,
0178     struct xlog_recover_item    *item)
0179 {
0180     struct xfs_qoff_logformat   *qoff_f = item->ri_buf[0].i_addr;
0181     ASSERT(qoff_f);
0182 
0183     /*
0184      * The logitem format's flag tells us if this was user quotaoff,
0185      * group/project quotaoff or both.
0186      */
0187     if (qoff_f->qf_flags & XFS_UQUOTA_ACCT)
0188         log->l_quotaoffs_flag |= XFS_DQTYPE_USER;
0189     if (qoff_f->qf_flags & XFS_PQUOTA_ACCT)
0190         log->l_quotaoffs_flag |= XFS_DQTYPE_PROJ;
0191     if (qoff_f->qf_flags & XFS_GQUOTA_ACCT)
0192         log->l_quotaoffs_flag |= XFS_DQTYPE_GROUP;
0193 
0194     return 0;
0195 }
0196 
0197 const struct xlog_recover_item_ops xlog_quotaoff_item_ops = {
0198     .item_type      = XFS_LI_QUOTAOFF,
0199     .commit_pass1       = xlog_recover_quotaoff_commit_pass1,
0200     /* nothing to commit in pass2 */
0201 };