LCOV - code coverage report
Current view: top level - fs/xfs/scrub - quota_repair.c (source / functions) Hit Total Coverage
Test: fstests of 6.5.0-rc4-xfsa @ Mon Jul 31 20:08:27 PDT 2023 Lines: 91 180 50.6 %
Date: 2023-07-31 20:08:27 Functions: 5 6 83.3 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-or-later
       2             : /*
       3             :  * Copyright (C) 2018-2023 Oracle.  All Rights Reserved.
       4             :  * Author: Darrick J. Wong <djwong@kernel.org>
       5             :  */
       6             : #include "xfs.h"
       7             : #include "xfs_fs.h"
       8             : #include "xfs_shared.h"
       9             : #include "xfs_format.h"
      10             : #include "xfs_trans_resv.h"
      11             : #include "xfs_mount.h"
      12             : #include "xfs_defer.h"
      13             : #include "xfs_btree.h"
      14             : #include "xfs_bit.h"
      15             : #include "xfs_log_format.h"
      16             : #include "xfs_trans.h"
      17             : #include "xfs_sb.h"
      18             : #include "xfs_inode.h"
      19             : #include "xfs_inode_fork.h"
      20             : #include "xfs_alloc.h"
      21             : #include "xfs_bmap.h"
      22             : #include "xfs_quota.h"
      23             : #include "xfs_qm.h"
      24             : #include "xfs_dquot.h"
      25             : #include "xfs_dquot_item.h"
      26             : #include "xfs_reflink.h"
      27             : #include "scrub/xfs_scrub.h"
      28             : #include "scrub/scrub.h"
      29             : #include "scrub/common.h"
      30             : #include "scrub/quota.h"
      31             : #include "scrub/trace.h"
      32             : #include "scrub/repair.h"
      33             : 
      34             : /*
      35             :  * Quota Repair
      36             :  * ============
      37             :  *
      38             :  * Quota repairs are fairly simplistic; we fix everything that the dquot
      39             :  * verifiers complain about, cap any counters or limits that make no sense,
      40             :  * and schedule a quotacheck if we had to fix anything.  We also repair any
      41             :  * data fork extent records that don't apply to metadata files.
      42             :  */
      43             : 
      44             : struct xrep_quota_info {
      45             :         struct xfs_scrub        *sc;
      46             :         bool                    need_quotacheck;
      47             : };
      48             : 
      49             : /* Scrub the fields in an individual quota item. */
      50             : STATIC int
      51       30426 : xrep_quota_item(
      52             :         struct xfs_dquot        *dqp,
      53             :         xfs_dqtype_t            dqtype,
      54             :         void                    *priv)
      55             : {
      56       30426 :         struct xrep_quota_info  *rqi = priv;
      57       30426 :         struct xfs_scrub        *sc = rqi->sc;
      58       30426 :         struct xfs_mount        *mp = sc->mp;
      59       30426 :         xfs_ino_t               fs_icount;
      60       30426 :         bool                    dirty = false;
      61       30426 :         int                     error = 0;
      62             : 
      63             :         /* Last chance to abort before we start committing fixes. */
      64       30426 :         if (xchk_should_terminate(sc, &error))
      65           0 :                 return error;
      66             : 
      67             :         /* Check the limits. */
      68       30426 :         if (dqp->q_blk.softlimit > dqp->q_blk.hardlimit) {
      69           0 :                 dqp->q_blk.softlimit = dqp->q_blk.hardlimit;
      70           0 :                 dirty = true;
      71             :         }
      72             : 
      73       30426 :         if (dqp->q_ino.softlimit > dqp->q_ino.hardlimit) {
      74           0 :                 dqp->q_ino.softlimit = dqp->q_ino.hardlimit;
      75           0 :                 dirty = true;
      76             :         }
      77             : 
      78       30426 :         if (dqp->q_rtb.softlimit > dqp->q_rtb.hardlimit) {
      79           0 :                 dqp->q_rtb.softlimit = dqp->q_rtb.hardlimit;
      80           0 :                 dirty = true;
      81             :         }
      82             : 
      83             :         /*
      84             :          * Check that usage doesn't exceed physical limits.  However, on
      85             :          * a reflink filesystem we're allowed to exceed physical space
      86             :          * if there are no quota limits.  We don't know what the real number
      87             :          * is, but we can make quotacheck find out for us.
      88             :          */
      89       30426 :         if (!xfs_has_reflink(mp) && dqp->q_blk.count > mp->m_sb.sb_dblocks) {
      90           0 :                 dqp->q_blk.reserved -= dqp->q_blk.count;
      91           0 :                 dqp->q_blk.reserved += mp->m_sb.sb_dblocks;
      92           0 :                 dqp->q_blk.count = mp->m_sb.sb_dblocks;
      93           0 :                 rqi->need_quotacheck = true;
      94           0 :                 dirty = true;
      95             :         }
      96       30426 :         fs_icount = percpu_counter_sum(&mp->m_icount);
      97       30426 :         if (dqp->q_ino.count > fs_icount) {
      98           0 :                 dqp->q_ino.reserved -= dqp->q_ino.count;
      99           0 :                 dqp->q_ino.reserved += fs_icount;
     100           0 :                 dqp->q_ino.count = fs_icount;
     101           0 :                 rqi->need_quotacheck = true;
     102           0 :                 dirty = true;
     103             :         }
     104       30426 :         if (!xfs_has_reflink(mp) && dqp->q_rtb.count > mp->m_sb.sb_rblocks) {
     105           0 :                 dqp->q_rtb.reserved -= dqp->q_rtb.count;
     106           0 :                 dqp->q_rtb.reserved += mp->m_sb.sb_rblocks;
     107           0 :                 dqp->q_rtb.count = mp->m_sb.sb_rblocks;
     108           0 :                 rqi->need_quotacheck = true;
     109           0 :                 dirty = true;
     110             :         }
     111             : 
     112       30426 :         if (!dirty)
     113             :                 return 0;
     114             : 
     115           0 :         trace_xrep_dquot_item(sc->mp, dqp->q_type, dqp->q_id);
     116             : 
     117           0 :         dqp->q_flags |= XFS_DQFLAG_DIRTY;
     118           0 :         xfs_trans_dqjoin(sc->tp, dqp);
     119           0 :         if (dqp->q_id) {
     120           0 :                 xfs_qm_adjust_dqlimits(dqp);
     121           0 :                 xfs_qm_adjust_dqtimers(dqp);
     122             :         }
     123           0 :         xfs_trans_log_dquot(sc->tp, dqp);
     124           0 :         error = xfs_trans_roll(&sc->tp);
     125           0 :         xfs_dqlock(dqp);
     126           0 :         return error;
     127             : }
     128             : 
     129             : /* Fix a quota timer so that we can pass the verifier. */
     130             : STATIC void
     131           0 : xrep_quota_fix_timer(
     132             :         struct xfs_mount        *mp,
     133             :         __be64                  softlimit,
     134             :         __be64                  countnow,
     135             :         __be32                  *timer,
     136             :         time64_t                timelimit)
     137             : {
     138           0 :         uint64_t                soft = be64_to_cpu(softlimit);
     139           0 :         uint64_t                count = be64_to_cpu(countnow);
     140           0 :         time64_t                new_timer;
     141             : 
     142           0 :         if (!soft || count <= soft || *timer != 0)
     143             :                 return;
     144             : 
     145           0 :         new_timer = xfs_dquot_set_timeout(mp,
     146           0 :                                 ktime_get_real_seconds() + timelimit);
     147           0 :         *timer = cpu_to_be32(new_timer);
     148             : }
     149             : 
     150             : /* Fix anything the verifiers complain about. */
     151             : STATIC int
     152    62449668 : xrep_quota_block(
     153             :         struct xfs_scrub        *sc,
     154             :         xfs_daddr_t             daddr,
     155             :         xfs_dqtype_t            dqtype,
     156             :         xfs_dqid_t              id)
     157             : {
     158    62449668 :         struct xfs_dqblk        *dqblk;
     159    62449668 :         struct xfs_disk_dquot   *ddq;
     160    62449668 :         struct xfs_quotainfo    *qi = sc->mp->m_quotainfo;
     161    62449668 :         struct xfs_def_quota    *defq = xfs_get_defquota(qi, dqtype);
     162    62449668 :         struct xfs_buf          *bp = NULL;
     163    62449668 :         enum xfs_blft           buftype = 0;
     164    62449668 :         int                     i;
     165    62449668 :         int                     error;
     166             : 
     167    62449668 :         error = xfs_trans_read_buf(sc->mp, sc->tp, sc->mp->m_ddev_targp, daddr,
     168    62449668 :                         qi->qi_dqchunklen, 0, &bp, &xfs_dquot_buf_ops);
     169    62449668 :         switch (error) {
     170           0 :         case -EFSBADCRC:
     171             :         case -EFSCORRUPTED:
     172             :                 /* Failed verifier, retry read with no ops. */
     173           0 :                 error = xfs_trans_read_buf(sc->mp, sc->tp,
     174           0 :                                 sc->mp->m_ddev_targp, daddr, qi->qi_dqchunklen,
     175             :                                 0, &bp, NULL);
     176           0 :                 if (error)
     177             :                         return error;
     178             :                 break;
     179    62449668 :         case 0:
     180    62449668 :                 dqblk = bp->b_addr;
     181    62449668 :                 ddq = &dqblk[0].dd_diskdq;
     182             : 
     183             :                 /*
     184             :                  * If there's nothing that would impede a dqiterate, we're
     185             :                  * done.
     186             :                  */
     187   124899336 :                 if ((ddq->d_type & XFS_DQTYPE_REC_MASK) != dqtype ||
     188    62449668 :                     id == be32_to_cpu(ddq->d_id)) {
     189    62449668 :                         xfs_trans_brelse(sc->tp, bp);
     190    62449668 :                         return 0;
     191             :                 }
     192             :                 break;
     193             :         default:
     194             :                 return error;
     195             :         }
     196             : 
     197             :         /* Something's wrong with the block, fix the whole thing. */
     198           0 :         dqblk = bp->b_addr;
     199           0 :         bp->b_ops = &xfs_dquot_buf_ops;
     200           0 :         for (i = 0; i < qi->qi_dqperchunk; i++, dqblk++) {
     201           0 :                 ddq = &dqblk->dd_diskdq;
     202             : 
     203           0 :                 trace_xrep_disk_dquot(sc->mp, dqtype, id + i);
     204             : 
     205           0 :                 ddq->d_magic = cpu_to_be16(XFS_DQUOT_MAGIC);
     206           0 :                 ddq->d_version = XFS_DQUOT_VERSION;
     207           0 :                 ddq->d_type = dqtype;
     208           0 :                 ddq->d_id = cpu_to_be32(id + i);
     209             : 
     210           0 :                 xrep_quota_fix_timer(sc->mp, ddq->d_blk_softlimit,
     211             :                                 ddq->d_bcount, &ddq->d_btimer,
     212             :                                 defq->blk.time);
     213             : 
     214           0 :                 xrep_quota_fix_timer(sc->mp, ddq->d_ino_softlimit,
     215             :                                 ddq->d_icount, &ddq->d_itimer,
     216             :                                 defq->ino.time);
     217             : 
     218           0 :                 xrep_quota_fix_timer(sc->mp, ddq->d_rtb_softlimit,
     219             :                                 ddq->d_rtbcount, &ddq->d_rtbtimer,
     220             :                                 defq->rtb.time);
     221             : 
     222             :                 /* We only support v5 filesystems so always set these. */
     223           0 :                 uuid_copy(&dqblk->dd_uuid, &sc->mp->m_sb.sb_meta_uuid);
     224           0 :                 xfs_update_cksum((char *)dqblk, sizeof(struct xfs_dqblk),
     225             :                                  XFS_DQUOT_CRC_OFF);
     226           0 :                 dqblk->dd_lsn = 0;
     227             :         }
     228           0 :         switch (dqtype) {
     229             :         case XFS_DQTYPE_USER:
     230             :                 buftype = XFS_BLFT_UDQUOT_BUF;
     231             :                 break;
     232             :         case XFS_DQTYPE_GROUP:
     233             :                 buftype = XFS_BLFT_GDQUOT_BUF;
     234             :                 break;
     235             :         case XFS_DQTYPE_PROJ:
     236             :                 buftype = XFS_BLFT_PDQUOT_BUF;
     237             :                 break;
     238             :         }
     239           0 :         xfs_trans_buf_set_type(sc->tp, bp, buftype);
     240           0 :         xfs_trans_log_buf(sc->tp, bp, 0, BBTOB(bp->b_length) - 1);
     241           0 :         return xrep_roll_trans(sc);
     242             : }
     243             : 
     244             : /*
     245             :  * Repair a quota file's data fork.  The function returns with the inode
     246             :  * joined.
     247             :  */
     248             : STATIC int
     249       30427 : xrep_quota_data_fork(
     250             :         struct xfs_scrub        *sc,
     251             :         xfs_dqtype_t            dqtype)
     252             : {
     253       30427 :         struct xfs_bmbt_irec    irec = { 0 };
     254       30427 :         struct xfs_iext_cursor  icur;
     255       30427 :         struct xfs_quotainfo    *qi = sc->mp->m_quotainfo;
     256       30427 :         struct xfs_ifork        *ifp;
     257       30427 :         xfs_fileoff_t           max_dqid_off;
     258       30427 :         xfs_fileoff_t           off;
     259       30427 :         xfs_fsblock_t           fsbno;
     260       30427 :         bool                    truncate = false;
     261       30427 :         int                     error = 0;
     262             : 
     263       30427 :         error = xrep_metadata_inode_forks(sc);
     264       30427 :         if (error)
     265           1 :                 goto out;
     266             : 
     267             :         /* Check for data fork problems that apply only to quota files. */
     268       30426 :         max_dqid_off = ((xfs_dqid_t)-1) / qi->qi_dqperchunk;
     269       30426 :         ifp = xfs_ifork_ptr(sc->ip, XFS_DATA_FORK);
     270    62476035 :         for_each_xfs_iext(ifp, &icur, &irec) {
     271    62445609 :                 if (isnullstartblock(irec.br_startblock)) {
     272           0 :                         error = -EFSCORRUPTED;
     273           0 :                         goto out;
     274             :                 }
     275             : 
     276    62445609 :                 if (irec.br_startoff > max_dqid_off ||
     277    62445609 :                     irec.br_startoff + irec.br_blockcount - 1 > max_dqid_off) {
     278             :                         truncate = true;
     279             :                         break;
     280             :                 }
     281             : 
     282             :                 /* Convert unwritten extents to real ones. */
     283    62445609 :                 if (irec.br_state == XFS_EXT_UNWRITTEN) {
     284           0 :                         struct xfs_bmbt_irec    nrec;
     285           0 :                         int                     nmap = 1;
     286             : 
     287           0 :                         xfs_trans_ijoin(sc->tp, sc->ip, 0);
     288             : 
     289           0 :                         error = xfs_bmapi_write(sc->tp, sc->ip,
     290             :                                         irec.br_startoff, irec.br_blockcount,
     291             :                                         XFS_BMAPI_CONVERT, 0, &nrec, &nmap);
     292           0 :                         if (error)
     293           0 :                                 goto out;
     294           0 :                         ASSERT(nmap == 1);
     295           0 :                         ASSERT(nrec.br_startoff == irec.br_startoff);
     296           0 :                         ASSERT(nrec.br_blockcount == irec.br_blockcount);
     297             : 
     298           0 :                         error = xfs_defer_finish(&sc->tp);
     299           0 :                         if (error)
     300           0 :                                 goto out;
     301             :                 }
     302             :         }
     303             : 
     304       30426 :         xfs_trans_ijoin(sc->tp, sc->ip, 0);
     305             : 
     306       30426 :         if (truncate) {
     307             :                 /* Erase everything after the block containing the max dquot */
     308           0 :                 error = xfs_bunmapi_range(&sc->tp, sc->ip, 0,
     309           0 :                                 max_dqid_off * sc->mp->m_sb.sb_blocksize,
     310             :                                 XFS_MAX_FILEOFF);
     311           0 :                 if (error)
     312           0 :                         goto out;
     313             : 
     314             :                 /* Remove all CoW reservations. */
     315           0 :                 error = xfs_reflink_cancel_cow_blocks(sc->ip, &sc->tp, 0,
     316             :                                 XFS_MAX_FILEOFF, true);
     317           0 :                 if (error)
     318           0 :                         goto out;
     319           0 :                 sc->ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;
     320             : 
     321             :                 /*
     322             :                  * Always re-log the inode so that our permanent transaction
     323             :                  * can keep on rolling it forward in the log.
     324             :                  */
     325           0 :                 xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);
     326             :         }
     327             : 
     328             :         /* Now go fix anything that fails the verifiers. */
     329    62476035 :         for_each_xfs_iext(ifp, &icur, &irec) {
     330    62445609 :                 for (fsbno = irec.br_startblock, off = irec.br_startoff;
     331   124895277 :                      fsbno < irec.br_startblock + irec.br_blockcount;
     332    62449668 :                      fsbno += XFS_DQUOT_CLUSTER_SIZE_FSB,
     333    62449668 :                                 off += XFS_DQUOT_CLUSTER_SIZE_FSB) {
     334    62449668 :                         error = xrep_quota_block(sc,
     335    62449668 :                                         XFS_FSB_TO_DADDR(sc->mp, fsbno),
     336    62449668 :                                         dqtype, off * qi->qi_dqperchunk);
     337    62449668 :                         if (error)
     338           0 :                                 goto out;
     339             :                 }
     340             :         }
     341             : 
     342       30426 : out:
     343       30427 :         return error;
     344             : }
     345             : 
     346             : /*
     347             :  * Go fix anything in the quota items that we could have been mad about.  Now
     348             :  * that we've checked the quota inode data fork we have to drop ILOCK_EXCL to
     349             :  * use the regular dquot functions.
     350             :  */
     351             : STATIC int
     352       30426 : xrep_quota_problems(
     353             :         struct xfs_scrub        *sc,
     354             :         xfs_dqtype_t            dqtype)
     355             : {
     356       30426 :         struct xrep_quota_info  rqi;
     357       30426 :         int                     error;
     358             : 
     359       30426 :         rqi.sc = sc;
     360       30426 :         rqi.need_quotacheck = false;
     361       30426 :         error = xfs_qm_dqiterate(sc->mp, dqtype, xrep_quota_item, &rqi);
     362       30426 :         if (error)
     363             :                 return error;
     364             : 
     365             :         /* Make a quotacheck happen. */
     366       30426 :         if (rqi.need_quotacheck)
     367           0 :                 xrep_force_quotacheck(sc, dqtype);
     368             :         return 0;
     369             : }
     370             : 
     371             : /* Repair all of a quota type's items. */
     372             : int
     373       30427 : xrep_quota(
     374             :         struct xfs_scrub        *sc)
     375             : {
     376       30427 :         xfs_dqtype_t            dqtype;
     377       30427 :         int                     error;
     378             : 
     379       30427 :         dqtype = xchk_quota_to_dqtype(sc);
     380             : 
     381             :         /*
     382             :          * Re-take the ILOCK so that we can fix any problems that we found
     383             :          * with the data fork mappings, or with the dquot bufs themselves.
     384             :          */
     385       30427 :         if (!(sc->ilock_flags & XFS_ILOCK_EXCL))
     386       30427 :                 xchk_ilock(sc, XFS_ILOCK_EXCL);
     387       30427 :         error = xrep_quota_data_fork(sc, dqtype);
     388       30427 :         if (error)
     389           1 :                 goto out;
     390             : 
     391             :         /*
     392             :          * Roll the transaction to unjoin the quota inode from transaction so
     393             :          * that we can unlock the quota inode; we play only with dquots from
     394             :          * now on.
     395             :          */
     396       30426 :         error = xfs_trans_roll(&sc->tp);
     397       30426 :         if (error)
     398           0 :                 goto out;
     399       30426 :         xchk_iunlock(sc, sc->ilock_flags);
     400             : 
     401             :         /* Fix anything the dquot verifiers don't complain about. */
     402       30426 :         error = xrep_quota_problems(sc, dqtype);
     403       30427 : out:
     404       30427 :         return error;
     405             : }

Generated by: LCOV version 1.14