LCOV - code coverage report
Current view: top level - fs/xfs - xfs_dquot_item_recover.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 57 73 78.1 %
Date: 2023-07-31 20:08:27 Functions: 2 3 66.7 %

          Line data    Source code
       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             : 
      23             : STATIC void
      24     5766100 : xlog_recover_dquot_ra_pass2(
      25             :         struct xlog                     *log,
      26             :         struct xlog_recover_item        *item)
      27             : {
      28     5766100 :         struct xfs_mount        *mp = log->l_mp;
      29     5766100 :         struct xfs_disk_dquot   *recddq;
      30     5766100 :         struct xfs_dq_logformat *dq_f;
      31     5766100 :         uint                    type;
      32             : 
      33     5766100 :         if (mp->m_qflags == 0)
      34             :                 return;
      35             : 
      36     5766100 :         recddq = item->ri_buf[1].i_addr;
      37     5766100 :         if (recddq == NULL)
      38             :                 return;
      39     5766100 :         if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot))
      40             :                 return;
      41             : 
      42     5766100 :         type = recddq->d_type & XFS_DQTYPE_REC_MASK;
      43     5766100 :         ASSERT(type);
      44     5766100 :         if (log->l_quotaoffs_flag & type)
      45             :                 return;
      46             : 
      47     5766100 :         dq_f = item->ri_buf[0].i_addr;
      48     5766100 :         ASSERT(dq_f);
      49     5766100 :         ASSERT(dq_f->qlf_len == 1);
      50             : 
      51     5766100 :         xlog_buf_readahead(log, dq_f->qlf_blkno,
      52     5766100 :                         XFS_FSB_TO_BB(mp, dq_f->qlf_len),
      53             :                         &xfs_dquot_buf_ra_ops);
      54             : }
      55             : 
      56             : /*
      57             :  * Recover a dquot record
      58             :  */
      59             : STATIC int
      60     5766100 : xlog_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     5766100 :         struct xfs_mount                *mp = log->l_mp;
      67     5766100 :         struct xfs_buf                  *bp;
      68     5766100 :         struct xfs_disk_dquot           *ddq, *recddq;
      69     5766100 :         struct xfs_dq_logformat         *dq_f;
      70     5766100 :         xfs_failaddr_t                  fa;
      71     5766100 :         int                             error;
      72     5766100 :         uint                            type;
      73             : 
      74             :         /*
      75             :          * Filesystems are required to send in quota flags at mount time.
      76             :          */
      77     5766100 :         if (mp->m_qflags == 0)
      78             :                 return 0;
      79             : 
      80     5766100 :         recddq = item->ri_buf[1].i_addr;
      81     5766100 :         if (recddq == NULL) {
      82           0 :                 xfs_alert(log->l_mp, "NULL dquot in %s.", __func__);
      83           0 :                 return -EFSCORRUPTED;
      84             :         }
      85     5766100 :         if (item->ri_buf[1].i_len < sizeof(struct xfs_disk_dquot)) {
      86           0 :                 xfs_alert(log->l_mp, "dquot too small (%d) in %s.",
      87             :                         item->ri_buf[1].i_len, __func__);
      88           0 :                 return -EFSCORRUPTED;
      89             :         }
      90             : 
      91             :         /*
      92             :          * This type of quotas was turned off, so ignore this record.
      93             :          */
      94     5766100 :         type = recddq->d_type & XFS_DQTYPE_REC_MASK;
      95     5766100 :         ASSERT(type);
      96     5766100 :         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     5766100 :         dq_f = item->ri_buf[0].i_addr;
     110     5766100 :         ASSERT(dq_f);
     111     5766100 :         fa = xfs_dquot_verify(mp, recddq, dq_f->qlf_id);
     112     5766100 :         if (fa) {
     113           0 :                 xfs_alert(mp, "corrupt dquot ID 0x%x in log at %pS",
     114             :                                 dq_f->qlf_id, fa);
     115           0 :                 return -EFSCORRUPTED;
     116             :         }
     117     5766100 :         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     5766100 :         error = xfs_trans_read_buf(mp, NULL, mp->m_ddev_targp, dq_f->qlf_blkno,
     127     5766100 :                                    XFS_FSB_TO_BB(mp, dq_f->qlf_len), 0, &bp,
     128             :                                    &xfs_dquot_buf_ops);
     129     5766100 :         if (error)
     130             :                 return error;
     131             : 
     132     5766100 :         ASSERT(bp);
     133     5766100 :         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     5766100 :         if (xfs_has_crc(mp)) {
     140     5766100 :                 struct xfs_dqblk *dqb = (struct xfs_dqblk *)ddq;
     141     5766100 :                 xfs_lsn_t       lsn = be64_to_cpu(dqb->dd_lsn);
     142             : 
     143     5766100 :                 if (lsn && lsn != -1 && XFS_LSN_CMP(lsn, current_lsn) >= 0) {
     144        3770 :                         goto out_release;
     145             :                 }
     146             :         }
     147             : 
     148    11524660 :         memcpy(ddq, recddq, item->ri_buf[1].i_len);
     149     5762330 :         if (xfs_has_crc(mp)) {
     150     5762330 :                 xfs_update_cksum((char *)ddq, sizeof(struct xfs_dqblk),
     151             :                                  XFS_DQUOT_CRC_OFF);
     152             :         }
     153             : 
     154     5762330 :         ASSERT(dq_f->qlf_size == 2);
     155     5762330 :         ASSERT(bp->b_mount == mp);
     156     5762330 :         bp->b_flags |= _XBF_LOGRECOVERY;
     157     5762330 :         xfs_buf_delwri_queue(bp, buffer_list);
     158             : 
     159     5766100 : out_release:
     160     5766100 :         xfs_buf_relse(bp);
     161     5766100 :         return 0;
     162             : }
     163             : 
     164             : const 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             :  */
     175             : STATIC int
     176           0 : xlog_recover_quotaoff_commit_pass1(
     177             :         struct xlog                     *log,
     178             :         struct xlog_recover_item        *item)
     179             : {
     180           0 :         struct xfs_qoff_logformat       *qoff_f = item->ri_buf[0].i_addr;
     181           0 :         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           0 :         if (qoff_f->qf_flags & XFS_UQUOTA_ACCT)
     188           0 :                 log->l_quotaoffs_flag |= XFS_DQTYPE_USER;
     189           0 :         if (qoff_f->qf_flags & XFS_PQUOTA_ACCT)
     190           0 :                 log->l_quotaoffs_flag |= XFS_DQTYPE_PROJ;
     191           0 :         if (qoff_f->qf_flags & XFS_GQUOTA_ACCT)
     192           0 :                 log->l_quotaoffs_flag |= XFS_DQTYPE_GROUP;
     193             : 
     194           0 :         return 0;
     195             : }
     196             : 
     197             : const 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             : };

Generated by: LCOV version 1.14