569 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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 "xfs_bmap_btree.h"28#include "xfs_trans_space.h"29#include "scrub/xfs_scrub.h"30#include "scrub/scrub.h"31#include "scrub/common.h"32#include "scrub/quota.h"33#include "scrub/trace.h"34#include "scrub/repair.h"35 36/*37 * Quota Repair38 * ============39 *40 * Quota repairs are fairly simplistic; we fix everything that the dquot41 * verifiers complain about, cap any counters or limits that make no sense,42 * and schedule a quotacheck if we had to fix anything. We also repair any43 * data fork extent records that don't apply to metadata files.44 */45 46struct xrep_quota_info {47 struct xfs_scrub *sc;48 bool need_quotacheck;49};50 51/*52 * Allocate a new block into a sparse hole in the quota file backing this53 * dquot, initialize the block, and commit the whole mess.54 */55STATIC int56xrep_quota_item_fill_bmap_hole(57 struct xfs_scrub *sc,58 struct xfs_dquot *dq,59 struct xfs_bmbt_irec *irec)60{61 struct xfs_buf *bp;62 struct xfs_mount *mp = sc->mp;63 int nmaps = 1;64 int error;65 66 xfs_trans_ijoin(sc->tp, sc->ip, 0);67 68 /* Map a block into the file. */69 error = xfs_trans_reserve_more(sc->tp, XFS_QM_DQALLOC_SPACE_RES(mp),70 0);71 if (error)72 return error;73 74 error = xfs_bmapi_write(sc->tp, sc->ip, dq->q_fileoffset,75 XFS_DQUOT_CLUSTER_SIZE_FSB, XFS_BMAPI_METADATA, 0,76 irec, &nmaps);77 if (error)78 return error;79 80 dq->q_blkno = XFS_FSB_TO_DADDR(mp, irec->br_startblock);81 82 trace_xrep_dquot_item_fill_bmap_hole(sc->mp, dq->q_type, dq->q_id);83 84 /* Initialize the new block. */85 error = xfs_trans_get_buf(sc->tp, mp->m_ddev_targp, dq->q_blkno,86 mp->m_quotainfo->qi_dqchunklen, 0, &bp);87 if (error)88 return error;89 bp->b_ops = &xfs_dquot_buf_ops;90 91 xfs_qm_init_dquot_blk(sc->tp, dq->q_id, dq->q_type, bp);92 xfs_buf_set_ref(bp, XFS_DQUOT_REF);93 94 /*95 * Finish the mapping transactions and roll one more time to96 * disconnect sc->ip from sc->tp.97 */98 error = xrep_defer_finish(sc);99 if (error)100 return error;101 return xfs_trans_roll(&sc->tp);102}103 104/* Make sure there's a written block backing this dquot */105STATIC int106xrep_quota_item_bmap(107 struct xfs_scrub *sc,108 struct xfs_dquot *dq,109 bool *dirty)110{111 struct xfs_bmbt_irec irec;112 struct xfs_mount *mp = sc->mp;113 struct xfs_quotainfo *qi = mp->m_quotainfo;114 xfs_fileoff_t offset = dq->q_id / qi->qi_dqperchunk;115 int nmaps = 1;116 int error;117 118 /* The computed file offset should always be valid. */119 if (!xfs_verify_fileoff(mp, offset)) {120 ASSERT(xfs_verify_fileoff(mp, offset));121 return -EFSCORRUPTED;122 }123 dq->q_fileoffset = offset;124 125 error = xfs_bmapi_read(sc->ip, offset, 1, &irec, &nmaps, 0);126 if (error)127 return error;128 129 if (nmaps < 1 || !xfs_bmap_is_real_extent(&irec)) {130 /* Hole/delalloc extent; allocate a real block. */131 error = xrep_quota_item_fill_bmap_hole(sc, dq, &irec);132 if (error)133 return error;134 } else if (irec.br_state != XFS_EXT_NORM) {135 /* Unwritten extent, which we already took care of? */136 ASSERT(irec.br_state == XFS_EXT_NORM);137 return -EFSCORRUPTED;138 } else if (dq->q_blkno != XFS_FSB_TO_DADDR(mp, irec.br_startblock)) {139 /*140 * If the cached daddr is incorrect, repair probably punched a141 * hole out of the quota file and filled it back in with a new142 * block. Update the block mapping in the dquot.143 */144 dq->q_blkno = XFS_FSB_TO_DADDR(mp, irec.br_startblock);145 }146 147 *dirty = true;148 return 0;149}150 151/* Reset quota timers if incorrectly set. */152static inline void153xrep_quota_item_timer(154 struct xfs_scrub *sc,155 const struct xfs_dquot_res *res,156 bool *dirty)157{158 if ((res->softlimit && res->count > res->softlimit) ||159 (res->hardlimit && res->count > res->hardlimit)) {160 if (!res->timer)161 *dirty = true;162 } else {163 if (res->timer)164 *dirty = true;165 }166}167 168/* Scrub the fields in an individual quota item. */169STATIC int170xrep_quota_item(171 struct xrep_quota_info *rqi,172 struct xfs_dquot *dq)173{174 struct xfs_scrub *sc = rqi->sc;175 struct xfs_mount *mp = sc->mp;176 xfs_ino_t fs_icount;177 bool dirty = false;178 int error = 0;179 180 /* Last chance to abort before we start committing fixes. */181 if (xchk_should_terminate(sc, &error))182 return error;183 184 /*185 * We might need to fix holes in the bmap record for the storage186 * backing this dquot, so we need to lock the dquot and the quota file.187 * dqiterate gave us a locked dquot, so drop the dquot lock to get the188 * ILOCK_EXCL.189 */190 xfs_dqunlock(dq);191 xchk_ilock(sc, XFS_ILOCK_EXCL);192 xfs_dqlock(dq);193 194 error = xrep_quota_item_bmap(sc, dq, &dirty);195 xchk_iunlock(sc, XFS_ILOCK_EXCL);196 if (error)197 return error;198 199 /* Check the limits. */200 if (dq->q_blk.softlimit > dq->q_blk.hardlimit) {201 dq->q_blk.softlimit = dq->q_blk.hardlimit;202 dirty = true;203 }204 205 if (dq->q_ino.softlimit > dq->q_ino.hardlimit) {206 dq->q_ino.softlimit = dq->q_ino.hardlimit;207 dirty = true;208 }209 210 if (dq->q_rtb.softlimit > dq->q_rtb.hardlimit) {211 dq->q_rtb.softlimit = dq->q_rtb.hardlimit;212 dirty = true;213 }214 215 /*216 * Check that usage doesn't exceed physical limits. However, on217 * a reflink filesystem we're allowed to exceed physical space218 * if there are no quota limits. We don't know what the real number219 * is, but we can make quotacheck find out for us.220 */221 if (!xfs_has_reflink(mp) && dq->q_blk.count > mp->m_sb.sb_dblocks) {222 dq->q_blk.reserved -= dq->q_blk.count;223 dq->q_blk.reserved += mp->m_sb.sb_dblocks;224 dq->q_blk.count = mp->m_sb.sb_dblocks;225 rqi->need_quotacheck = true;226 dirty = true;227 }228 fs_icount = percpu_counter_sum(&mp->m_icount);229 if (dq->q_ino.count > fs_icount) {230 dq->q_ino.reserved -= dq->q_ino.count;231 dq->q_ino.reserved += fs_icount;232 dq->q_ino.count = fs_icount;233 rqi->need_quotacheck = true;234 dirty = true;235 }236 if (dq->q_rtb.count > mp->m_sb.sb_rblocks) {237 dq->q_rtb.reserved -= dq->q_rtb.count;238 dq->q_rtb.reserved += mp->m_sb.sb_rblocks;239 dq->q_rtb.count = mp->m_sb.sb_rblocks;240 rqi->need_quotacheck = true;241 dirty = true;242 }243 244 xrep_quota_item_timer(sc, &dq->q_blk, &dirty);245 xrep_quota_item_timer(sc, &dq->q_ino, &dirty);246 xrep_quota_item_timer(sc, &dq->q_rtb, &dirty);247 248 if (!dirty)249 return 0;250 251 trace_xrep_dquot_item(sc->mp, dq->q_type, dq->q_id);252 253 dq->q_flags |= XFS_DQFLAG_DIRTY;254 xfs_trans_dqjoin(sc->tp, dq);255 if (dq->q_id) {256 xfs_qm_adjust_dqlimits(dq);257 xfs_qm_adjust_dqtimers(dq);258 }259 xfs_trans_log_dquot(sc->tp, dq);260 error = xfs_trans_roll(&sc->tp);261 xfs_dqlock(dq);262 return error;263}264 265/* Fix a quota timer so that we can pass the verifier. */266STATIC void267xrep_quota_fix_timer(268 struct xfs_mount *mp,269 const struct xfs_disk_dquot *ddq,270 __be64 softlimit,271 __be64 countnow,272 __be32 *timer,273 time64_t timelimit)274{275 uint64_t soft = be64_to_cpu(softlimit);276 uint64_t count = be64_to_cpu(countnow);277 time64_t new_timer;278 uint32_t t;279 280 if (!soft || count <= soft || *timer != 0)281 return;282 283 new_timer = xfs_dquot_set_timeout(mp,284 ktime_get_real_seconds() + timelimit);285 if (ddq->d_type & XFS_DQTYPE_BIGTIME)286 t = xfs_dq_unix_to_bigtime(new_timer);287 else288 t = new_timer;289 290 *timer = cpu_to_be32(t);291}292 293/* Fix anything the verifiers complain about. */294STATIC int295xrep_quota_block(296 struct xfs_scrub *sc,297 xfs_daddr_t daddr,298 xfs_dqtype_t dqtype,299 xfs_dqid_t id)300{301 struct xfs_dqblk *dqblk;302 struct xfs_disk_dquot *ddq;303 struct xfs_quotainfo *qi = sc->mp->m_quotainfo;304 struct xfs_def_quota *defq = xfs_get_defquota(qi, dqtype);305 struct xfs_buf *bp = NULL;306 enum xfs_blft buftype = 0;307 int i;308 int error;309 310 error = xfs_trans_read_buf(sc->mp, sc->tp, sc->mp->m_ddev_targp, daddr,311 qi->qi_dqchunklen, 0, &bp, &xfs_dquot_buf_ops);312 switch (error) {313 case -EFSBADCRC:314 case -EFSCORRUPTED:315 /* Failed verifier, retry read with no ops. */316 error = xfs_trans_read_buf(sc->mp, sc->tp,317 sc->mp->m_ddev_targp, daddr, qi->qi_dqchunklen,318 0, &bp, NULL);319 if (error)320 return error;321 break;322 case 0:323 dqblk = bp->b_addr;324 ddq = &dqblk[0].dd_diskdq;325 326 /*327 * If there's nothing that would impede a dqiterate, we're328 * done.329 */330 if ((ddq->d_type & XFS_DQTYPE_REC_MASK) != dqtype ||331 id == be32_to_cpu(ddq->d_id)) {332 xfs_trans_brelse(sc->tp, bp);333 return 0;334 }335 break;336 default:337 return error;338 }339 340 /* Something's wrong with the block, fix the whole thing. */341 dqblk = bp->b_addr;342 bp->b_ops = &xfs_dquot_buf_ops;343 for (i = 0; i < qi->qi_dqperchunk; i++, dqblk++) {344 ddq = &dqblk->dd_diskdq;345 346 trace_xrep_disk_dquot(sc->mp, dqtype, id + i);347 348 ddq->d_magic = cpu_to_be16(XFS_DQUOT_MAGIC);349 ddq->d_version = XFS_DQUOT_VERSION;350 ddq->d_type = dqtype;351 ddq->d_id = cpu_to_be32(id + i);352 353 if (xfs_has_bigtime(sc->mp) && ddq->d_id)354 ddq->d_type |= XFS_DQTYPE_BIGTIME;355 356 xrep_quota_fix_timer(sc->mp, ddq, ddq->d_blk_softlimit,357 ddq->d_bcount, &ddq->d_btimer,358 defq->blk.time);359 360 xrep_quota_fix_timer(sc->mp, ddq, ddq->d_ino_softlimit,361 ddq->d_icount, &ddq->d_itimer,362 defq->ino.time);363 364 xrep_quota_fix_timer(sc->mp, ddq, ddq->d_rtb_softlimit,365 ddq->d_rtbcount, &ddq->d_rtbtimer,366 defq->rtb.time);367 368 /* We only support v5 filesystems so always set these. */369 uuid_copy(&dqblk->dd_uuid, &sc->mp->m_sb.sb_meta_uuid);370 xfs_update_cksum((char *)dqblk, sizeof(struct xfs_dqblk),371 XFS_DQUOT_CRC_OFF);372 dqblk->dd_lsn = 0;373 }374 switch (dqtype) {375 case XFS_DQTYPE_USER:376 buftype = XFS_BLFT_UDQUOT_BUF;377 break;378 case XFS_DQTYPE_GROUP:379 buftype = XFS_BLFT_GDQUOT_BUF;380 break;381 case XFS_DQTYPE_PROJ:382 buftype = XFS_BLFT_PDQUOT_BUF;383 break;384 }385 xfs_trans_buf_set_type(sc->tp, bp, buftype);386 xfs_trans_log_buf(sc->tp, bp, 0, BBTOB(bp->b_length) - 1);387 return xrep_roll_trans(sc);388}389 390/*391 * Repair a quota file's data fork. The function returns with the inode392 * joined.393 */394STATIC int395xrep_quota_data_fork(396 struct xfs_scrub *sc,397 xfs_dqtype_t dqtype)398{399 struct xfs_bmbt_irec irec = { 0 };400 struct xfs_iext_cursor icur;401 struct xfs_quotainfo *qi = sc->mp->m_quotainfo;402 struct xfs_ifork *ifp;403 xfs_fileoff_t max_dqid_off;404 xfs_fileoff_t off;405 xfs_fsblock_t fsbno;406 bool truncate = false;407 bool joined = false;408 int error = 0;409 410 error = xrep_metadata_inode_forks(sc);411 if (error)412 goto out;413 414 /* Check for data fork problems that apply only to quota files. */415 max_dqid_off = XFS_DQ_ID_MAX / qi->qi_dqperchunk;416 ifp = xfs_ifork_ptr(sc->ip, XFS_DATA_FORK);417 for_each_xfs_iext(ifp, &icur, &irec) {418 if (isnullstartblock(irec.br_startblock)) {419 error = -EFSCORRUPTED;420 goto out;421 }422 423 if (irec.br_startoff > max_dqid_off ||424 irec.br_startoff + irec.br_blockcount - 1 > max_dqid_off) {425 truncate = true;426 break;427 }428 429 /* Convert unwritten extents to real ones. */430 if (irec.br_state == XFS_EXT_UNWRITTEN) {431 struct xfs_bmbt_irec nrec;432 int nmap = 1;433 434 if (!joined) {435 xfs_trans_ijoin(sc->tp, sc->ip, 0);436 joined = true;437 }438 439 error = xfs_bmapi_write(sc->tp, sc->ip,440 irec.br_startoff, irec.br_blockcount,441 XFS_BMAPI_CONVERT, 0, &nrec, &nmap);442 if (error)443 goto out;444 ASSERT(nrec.br_startoff == irec.br_startoff);445 ASSERT(nrec.br_blockcount == irec.br_blockcount);446 447 error = xfs_defer_finish(&sc->tp);448 if (error)449 goto out;450 }451 }452 453 if (!joined) {454 xfs_trans_ijoin(sc->tp, sc->ip, 0);455 joined = true;456 }457 458 if (truncate) {459 /* Erase everything after the block containing the max dquot */460 error = xfs_bunmapi_range(&sc->tp, sc->ip, 0,461 max_dqid_off * sc->mp->m_sb.sb_blocksize,462 XFS_MAX_FILEOFF);463 if (error)464 goto out;465 466 /* Remove all CoW reservations. */467 error = xfs_reflink_cancel_cow_blocks(sc->ip, &sc->tp, 0,468 XFS_MAX_FILEOFF, true);469 if (error)470 goto out;471 sc->ip->i_diflags2 &= ~XFS_DIFLAG2_REFLINK;472 473 /*474 * Always re-log the inode so that our permanent transaction475 * can keep on rolling it forward in the log.476 */477 xfs_trans_log_inode(sc->tp, sc->ip, XFS_ILOG_CORE);478 }479 480 /* Now go fix anything that fails the verifiers. */481 for_each_xfs_iext(ifp, &icur, &irec) {482 for (fsbno = irec.br_startblock, off = irec.br_startoff;483 fsbno < irec.br_startblock + irec.br_blockcount;484 fsbno += XFS_DQUOT_CLUSTER_SIZE_FSB,485 off += XFS_DQUOT_CLUSTER_SIZE_FSB) {486 error = xrep_quota_block(sc,487 XFS_FSB_TO_DADDR(sc->mp, fsbno),488 dqtype, off * qi->qi_dqperchunk);489 if (error)490 goto out;491 }492 }493 494out:495 return error;496}497 498/*499 * Go fix anything in the quota items that we could have been mad about. Now500 * that we've checked the quota inode data fork we have to drop ILOCK_EXCL to501 * use the regular dquot functions.502 */503STATIC int504xrep_quota_problems(505 struct xfs_scrub *sc,506 xfs_dqtype_t dqtype)507{508 struct xchk_dqiter cursor = { };509 struct xrep_quota_info rqi = { .sc = sc };510 struct xfs_dquot *dq;511 int error;512 513 xchk_dqiter_init(&cursor, sc, dqtype);514 while ((error = xchk_dquot_iter(&cursor, &dq)) == 1) {515 error = xrep_quota_item(&rqi, dq);516 xfs_qm_dqput(dq);517 if (error)518 break;519 }520 if (error)521 return error;522 523 /* Make a quotacheck happen. */524 if (rqi.need_quotacheck)525 xrep_force_quotacheck(sc, dqtype);526 return 0;527}528 529/* Repair all of a quota type's items. */530int531xrep_quota(532 struct xfs_scrub *sc)533{534 xfs_dqtype_t dqtype;535 int error;536 537 dqtype = xchk_quota_to_dqtype(sc);538 539 /*540 * Re-take the ILOCK so that we can fix any problems that we found541 * with the data fork mappings, or with the dquot bufs themselves.542 */543 if (!(sc->ilock_flags & XFS_ILOCK_EXCL))544 xchk_ilock(sc, XFS_ILOCK_EXCL);545 error = xrep_quota_data_fork(sc, dqtype);546 if (error)547 return error;548 549 /*550 * Finish deferred items and roll the transaction to unjoin the quota551 * inode from transaction so that we can unlock the quota inode; we552 * play only with dquots from now on.553 */554 error = xrep_defer_finish(sc);555 if (error)556 return error;557 error = xfs_trans_roll(&sc->tp);558 if (error)559 return error;560 xchk_iunlock(sc, sc->ilock_flags);561 562 /* Fix anything the dquot verifiers don't complain about. */563 error = xrep_quota_problems(sc, dqtype);564 if (error)565 return error;566 567 return xrep_trans_commit(sc);568}569