868 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Copyright (c) 2020-2024 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_log_format.h"13#include "xfs_trans.h"14#include "xfs_inode.h"15#include "xfs_quota.h"16#include "xfs_qm.h"17#include "xfs_icache.h"18#include "xfs_bmap_util.h"19#include "xfs_ialloc.h"20#include "xfs_ag.h"21#include "scrub/scrub.h"22#include "scrub/common.h"23#include "scrub/repair.h"24#include "scrub/xfile.h"25#include "scrub/xfarray.h"26#include "scrub/iscan.h"27#include "scrub/quota.h"28#include "scrub/quotacheck.h"29#include "scrub/trace.h"30 31/*32 * Live Quotacheck33 * ===============34 *35 * Quota counters are "summary" metadata, in the sense that they are computed36 * as the summation of the block usage counts for every file on the filesystem.37 * Therefore, we compute the correct icount, bcount, and rtbcount values by38 * creating a shadow quota counter structure and walking every inode.39 */40 41/* Track the quota deltas for a dquot in a transaction. */42struct xqcheck_dqtrx {43 xfs_dqtype_t q_type;44 xfs_dqid_t q_id;45 46 int64_t icount_delta;47 48 int64_t bcount_delta;49 int64_t delbcnt_delta;50 51 int64_t rtbcount_delta;52 int64_t delrtb_delta;53};54 55#define XQCHECK_MAX_NR_DQTRXS (XFS_QM_TRANS_DQTYPES * XFS_QM_TRANS_MAXDQS)56 57/*58 * Track the quota deltas for all dquots attached to a transaction if the59 * quota deltas are being applied to an inode that we already scanned.60 */61struct xqcheck_dqacct {62 struct rhash_head hash;63 uintptr_t tx_id;64 struct xqcheck_dqtrx dqtrx[XQCHECK_MAX_NR_DQTRXS];65 unsigned int refcount;66};67 68/* Free a shadow dquot accounting structure. */69static void70xqcheck_dqacct_free(71 void *ptr,72 void *arg)73{74 struct xqcheck_dqacct *dqa = ptr;75 76 kfree(dqa);77}78 79/* Set us up to scrub quota counters. */80int81xchk_setup_quotacheck(82 struct xfs_scrub *sc)83{84 if (!XFS_IS_QUOTA_ON(sc->mp))85 return -ENOENT;86 87 xchk_fsgates_enable(sc, XCHK_FSGATES_QUOTA);88 89 sc->buf = kzalloc(sizeof(struct xqcheck), XCHK_GFP_FLAGS);90 if (!sc->buf)91 return -ENOMEM;92 93 return xchk_setup_fs(sc);94}95 96/*97 * Part 1: Collecting dquot resource usage counts. For each xfs_dquot attached98 * to each inode, we create a shadow dquot, and compute the inode count and add99 * the data/rt block usage from what we see.100 *101 * To avoid false corruption reports in part 2, any failure in this part must102 * set the INCOMPLETE flag even when a negative errno is returned. This care103 * must be taken with certain errno values (i.e. EFSBADCRC, EFSCORRUPTED,104 * ECANCELED) that are absorbed into a scrub state flag update by105 * xchk_*_process_error. Scrub and repair share the same incore data106 * structures, so the INCOMPLETE flag is critical to prevent a repair based on107 * insufficient information.108 *109 * Because we are scanning a live filesystem, it's possible that another thread110 * will try to update the quota counters for an inode that we've already111 * scanned. This will cause our counts to be incorrect. Therefore, we hook112 * the live transaction code in two places: (1) when the callers update the113 * per-transaction dqtrx structure to log quota counter updates; and (2) when114 * transaction commit actually logs those updates to the incore dquot. By115 * shadowing transaction updates in this manner, live quotacheck can ensure116 * by locking the dquot and the shadow structure that its own copies are not117 * out of date. Because the hook code runs in a different process context from118 * the scrub code and the scrub state flags are not accessed atomically,119 * failures in the hook code must abort the iscan and the scrubber must notice120 * the aborted scan and set the incomplete flag.121 *122 * Note that we use srcu notifier hooks to minimize the overhead when live123 * quotacheck is /not/ running.124 */125 126/* Update an incore dquot counter information from a live update. */127static int128xqcheck_update_incore_counts(129 struct xqcheck *xqc,130 struct xfarray *counts,131 xfs_dqid_t id,132 int64_t inodes,133 int64_t nblks,134 int64_t rtblks)135{136 struct xqcheck_dquot xcdq;137 int error;138 139 error = xfarray_load_sparse(counts, id, &xcdq);140 if (error)141 return error;142 143 xcdq.flags |= XQCHECK_DQUOT_WRITTEN;144 xcdq.icount += inodes;145 xcdq.bcount += nblks;146 xcdq.rtbcount += rtblks;147 148 error = xfarray_store(counts, id, &xcdq);149 if (error == -EFBIG) {150 /*151 * EFBIG means we tried to store data at too high a byte offset152 * in the sparse array. IOWs, we cannot complete the check and153 * must notify userspace that the check was incomplete.154 */155 error = -ECANCELED;156 }157 return error;158}159 160/* Decide if this is the shadow dquot accounting structure for a transaction. */161static int162xqcheck_dqacct_obj_cmpfn(163 struct rhashtable_compare_arg *arg,164 const void *obj)165{166 const uintptr_t *tx_idp = arg->key;167 const struct xqcheck_dqacct *dqa = obj;168 169 if (dqa->tx_id != *tx_idp)170 return 1;171 return 0;172}173 174static const struct rhashtable_params xqcheck_dqacct_hash_params = {175 .min_size = 32,176 .key_len = sizeof(uintptr_t),177 .key_offset = offsetof(struct xqcheck_dqacct, tx_id),178 .head_offset = offsetof(struct xqcheck_dqacct, hash),179 .automatic_shrinking = true,180 .obj_cmpfn = xqcheck_dqacct_obj_cmpfn,181};182 183/* Find a shadow dqtrx slot for the given dquot. */184STATIC struct xqcheck_dqtrx *185xqcheck_get_dqtrx(186 struct xqcheck_dqacct *dqa,187 xfs_dqtype_t q_type,188 xfs_dqid_t q_id)189{190 int i;191 192 for (i = 0; i < XQCHECK_MAX_NR_DQTRXS; i++) {193 if (dqa->dqtrx[i].q_type == 0 ||194 (dqa->dqtrx[i].q_type == q_type &&195 dqa->dqtrx[i].q_id == q_id))196 return &dqa->dqtrx[i];197 }198 199 return NULL;200}201 202/*203 * Create and fill out a quota delta tracking structure to shadow the updates204 * going on in the regular quota code.205 */206static int207xqcheck_mod_live_ino_dqtrx(208 struct notifier_block *nb,209 unsigned long action,210 void *data)211{212 struct xfs_mod_ino_dqtrx_params *p = data;213 struct xqcheck *xqc;214 struct xqcheck_dqacct *dqa;215 struct xqcheck_dqtrx *dqtrx;216 int error;217 218 xqc = container_of(nb, struct xqcheck, qhook.mod_hook.nb);219 220 /* Skip quota reservation fields. */221 switch (action) {222 case XFS_TRANS_DQ_BCOUNT:223 case XFS_TRANS_DQ_DELBCOUNT:224 case XFS_TRANS_DQ_ICOUNT:225 case XFS_TRANS_DQ_RTBCOUNT:226 case XFS_TRANS_DQ_DELRTBCOUNT:227 break;228 default:229 return NOTIFY_DONE;230 }231 232 /* Ignore dqtrx updates for quota types we don't care about. */233 switch (p->q_type) {234 case XFS_DQTYPE_USER:235 if (!xqc->ucounts)236 return NOTIFY_DONE;237 break;238 case XFS_DQTYPE_GROUP:239 if (!xqc->gcounts)240 return NOTIFY_DONE;241 break;242 case XFS_DQTYPE_PROJ:243 if (!xqc->pcounts)244 return NOTIFY_DONE;245 break;246 default:247 return NOTIFY_DONE;248 }249 250 /* Skip inodes that haven't been scanned yet. */251 if (!xchk_iscan_want_live_update(&xqc->iscan, p->ino))252 return NOTIFY_DONE;253 254 /* Make a shadow quota accounting tracker for this transaction. */255 mutex_lock(&xqc->lock);256 dqa = rhashtable_lookup_fast(&xqc->shadow_dquot_acct, &p->tx_id,257 xqcheck_dqacct_hash_params);258 if (!dqa) {259 dqa = kzalloc(sizeof(struct xqcheck_dqacct), XCHK_GFP_FLAGS);260 if (!dqa)261 goto out_abort;262 263 dqa->tx_id = p->tx_id;264 error = rhashtable_insert_fast(&xqc->shadow_dquot_acct,265 &dqa->hash, xqcheck_dqacct_hash_params);266 if (error)267 goto out_abort;268 }269 270 /* Find the shadow dqtrx (or an empty slot) here. */271 dqtrx = xqcheck_get_dqtrx(dqa, p->q_type, p->q_id);272 if (!dqtrx)273 goto out_abort;274 if (dqtrx->q_type == 0) {275 dqtrx->q_type = p->q_type;276 dqtrx->q_id = p->q_id;277 dqa->refcount++;278 }279 280 /* Update counter */281 switch (action) {282 case XFS_TRANS_DQ_BCOUNT:283 dqtrx->bcount_delta += p->delta;284 break;285 case XFS_TRANS_DQ_DELBCOUNT:286 dqtrx->delbcnt_delta += p->delta;287 break;288 case XFS_TRANS_DQ_ICOUNT:289 dqtrx->icount_delta += p->delta;290 break;291 case XFS_TRANS_DQ_RTBCOUNT:292 dqtrx->rtbcount_delta += p->delta;293 break;294 case XFS_TRANS_DQ_DELRTBCOUNT:295 dqtrx->delrtb_delta += p->delta;296 break;297 }298 299 mutex_unlock(&xqc->lock);300 return NOTIFY_DONE;301 302out_abort:303 xchk_iscan_abort(&xqc->iscan);304 mutex_unlock(&xqc->lock);305 return NOTIFY_DONE;306}307 308/*309 * Apply the transaction quota deltas to our shadow quota accounting info when310 * the regular quota code are doing the same.311 */312static int313xqcheck_apply_live_dqtrx(314 struct notifier_block *nb,315 unsigned long action,316 void *data)317{318 struct xfs_apply_dqtrx_params *p = data;319 struct xqcheck *xqc;320 struct xqcheck_dqacct *dqa;321 struct xqcheck_dqtrx *dqtrx;322 struct xfarray *counts;323 int error;324 325 xqc = container_of(nb, struct xqcheck, qhook.apply_hook.nb);326 327 /* Map the dquot type to an incore counter object. */328 switch (p->q_type) {329 case XFS_DQTYPE_USER:330 counts = xqc->ucounts;331 break;332 case XFS_DQTYPE_GROUP:333 counts = xqc->gcounts;334 break;335 case XFS_DQTYPE_PROJ:336 counts = xqc->pcounts;337 break;338 default:339 return NOTIFY_DONE;340 }341 342 if (xchk_iscan_aborted(&xqc->iscan) || counts == NULL)343 return NOTIFY_DONE;344 345 /*346 * Find the shadow dqtrx for this transaction and dquot, if any deltas347 * need to be applied here. If not, we're finished early.348 */349 mutex_lock(&xqc->lock);350 dqa = rhashtable_lookup_fast(&xqc->shadow_dquot_acct, &p->tx_id,351 xqcheck_dqacct_hash_params);352 if (!dqa)353 goto out_unlock;354 dqtrx = xqcheck_get_dqtrx(dqa, p->q_type, p->q_id);355 if (!dqtrx || dqtrx->q_type == 0)356 goto out_unlock;357 358 /* Update our shadow dquot if we're committing. */359 if (action == XFS_APPLY_DQTRX_COMMIT) {360 error = xqcheck_update_incore_counts(xqc, counts, p->q_id,361 dqtrx->icount_delta,362 dqtrx->bcount_delta + dqtrx->delbcnt_delta,363 dqtrx->rtbcount_delta + dqtrx->delrtb_delta);364 if (error)365 goto out_abort;366 }367 368 /* Free the shadow accounting structure if that was the last user. */369 dqa->refcount--;370 if (dqa->refcount == 0) {371 error = rhashtable_remove_fast(&xqc->shadow_dquot_acct,372 &dqa->hash, xqcheck_dqacct_hash_params);373 if (error)374 goto out_abort;375 xqcheck_dqacct_free(dqa, NULL);376 }377 378 mutex_unlock(&xqc->lock);379 return NOTIFY_DONE;380 381out_abort:382 xchk_iscan_abort(&xqc->iscan);383out_unlock:384 mutex_unlock(&xqc->lock);385 return NOTIFY_DONE;386}387 388/* Record this inode's quota usage in our shadow quota counter data. */389STATIC int390xqcheck_collect_inode(391 struct xqcheck *xqc,392 struct xfs_inode *ip)393{394 struct xfs_trans *tp = xqc->sc->tp;395 xfs_filblks_t nblks, rtblks;396 uint ilock_flags = 0;397 xfs_dqid_t id;398 bool isreg = S_ISREG(VFS_I(ip)->i_mode);399 int error = 0;400 401 if (xfs_is_quota_inode(&tp->t_mountp->m_sb, ip->i_ino)) {402 /*403 * Quota files are never counted towards quota, so we do not404 * need to take the lock.405 */406 xchk_iscan_mark_visited(&xqc->iscan, ip);407 return 0;408 }409 410 /* Figure out the data / rt device block counts. */411 xfs_ilock(ip, XFS_IOLOCK_SHARED);412 if (isreg)413 xfs_ilock(ip, XFS_MMAPLOCK_SHARED);414 if (XFS_IS_REALTIME_INODE(ip)) {415 /*416 * Read in the data fork for rt files so that _count_blocks417 * can count the number of blocks allocated from the rt volume.418 * Inodes do not track that separately.419 */420 ilock_flags = xfs_ilock_data_map_shared(ip);421 error = xfs_iread_extents(tp, ip, XFS_DATA_FORK);422 if (error)423 goto out_abort;424 } else {425 ilock_flags = XFS_ILOCK_SHARED;426 xfs_ilock(ip, XFS_ILOCK_SHARED);427 }428 xfs_inode_count_blocks(tp, ip, &nblks, &rtblks);429 430 if (xchk_iscan_aborted(&xqc->iscan)) {431 error = -ECANCELED;432 goto out_incomplete;433 }434 435 /* Update the shadow dquot counters. */436 mutex_lock(&xqc->lock);437 if (xqc->ucounts) {438 id = xfs_qm_id_for_quotatype(ip, XFS_DQTYPE_USER);439 error = xqcheck_update_incore_counts(xqc, xqc->ucounts, id, 1,440 nblks, rtblks);441 if (error)442 goto out_mutex;443 }444 445 if (xqc->gcounts) {446 id = xfs_qm_id_for_quotatype(ip, XFS_DQTYPE_GROUP);447 error = xqcheck_update_incore_counts(xqc, xqc->gcounts, id, 1,448 nblks, rtblks);449 if (error)450 goto out_mutex;451 }452 453 if (xqc->pcounts) {454 id = xfs_qm_id_for_quotatype(ip, XFS_DQTYPE_PROJ);455 error = xqcheck_update_incore_counts(xqc, xqc->pcounts, id, 1,456 nblks, rtblks);457 if (error)458 goto out_mutex;459 }460 mutex_unlock(&xqc->lock);461 462 xchk_iscan_mark_visited(&xqc->iscan, ip);463 goto out_ilock;464 465out_mutex:466 mutex_unlock(&xqc->lock);467out_abort:468 xchk_iscan_abort(&xqc->iscan);469out_incomplete:470 xchk_set_incomplete(xqc->sc);471out_ilock:472 xfs_iunlock(ip, ilock_flags);473 if (isreg)474 xfs_iunlock(ip, XFS_MMAPLOCK_SHARED);475 xfs_iunlock(ip, XFS_IOLOCK_SHARED);476 return error;477}478 479/* Walk all the allocated inodes and run a quota scan on them. */480STATIC int481xqcheck_collect_counts(482 struct xqcheck *xqc)483{484 struct xfs_scrub *sc = xqc->sc;485 struct xfs_inode *ip;486 int error;487 488 /*489 * Set up for a potentially lengthy filesystem scan by reducing our490 * transaction resource usage for the duration. Specifically:491 *492 * Cancel the transaction to release the log grant space while we scan493 * the filesystem.494 *495 * Create a new empty transaction to eliminate the possibility of the496 * inode scan deadlocking on cyclical metadata.497 *498 * We pass the empty transaction to the file scanning function to avoid499 * repeatedly cycling empty transactions. This can be done without500 * risk of deadlock between sb_internal and the IOLOCK (we take the501 * IOLOCK to quiesce the file before scanning) because empty502 * transactions do not take sb_internal.503 */504 xchk_trans_cancel(sc);505 error = xchk_trans_alloc_empty(sc);506 if (error)507 return error;508 509 while ((error = xchk_iscan_iter(&xqc->iscan, &ip)) == 1) {510 error = xqcheck_collect_inode(xqc, ip);511 xchk_irele(sc, ip);512 if (error)513 break;514 515 if (xchk_should_terminate(sc, &error))516 break;517 }518 xchk_iscan_iter_finish(&xqc->iscan);519 if (error) {520 xchk_set_incomplete(sc);521 /*522 * If we couldn't grab an inode that was busy with a state523 * change, change the error code so that we exit to userspace524 * as quickly as possible.525 */526 if (error == -EBUSY)527 return -ECANCELED;528 return error;529 }530 531 /*532 * Switch out for a real transaction in preparation for building a new533 * tree.534 */535 xchk_trans_cancel(sc);536 return xchk_setup_fs(sc);537}538 539/*540 * Part 2: Comparing dquot resource counters. Walk each xfs_dquot, comparing541 * the resource usage counters against our shadow dquots; and then walk each542 * shadow dquot (that wasn't covered in the first part), comparing it against543 * the xfs_dquot.544 */545 546/*547 * Check the dquot data against what we observed. Caller must hold the dquot548 * lock.549 */550STATIC int551xqcheck_compare_dquot(552 struct xqcheck *xqc,553 xfs_dqtype_t dqtype,554 struct xfs_dquot *dq)555{556 struct xqcheck_dquot xcdq;557 struct xfarray *counts = xqcheck_counters_for(xqc, dqtype);558 int error;559 560 if (xchk_iscan_aborted(&xqc->iscan)) {561 xchk_set_incomplete(xqc->sc);562 return -ECANCELED;563 }564 565 mutex_lock(&xqc->lock);566 error = xfarray_load_sparse(counts, dq->q_id, &xcdq);567 if (error)568 goto out_unlock;569 570 if (xcdq.icount != dq->q_ino.count)571 xchk_qcheck_set_corrupt(xqc->sc, dqtype, dq->q_id);572 573 if (xcdq.bcount != dq->q_blk.count)574 xchk_qcheck_set_corrupt(xqc->sc, dqtype, dq->q_id);575 576 if (xcdq.rtbcount != dq->q_rtb.count)577 xchk_qcheck_set_corrupt(xqc->sc, dqtype, dq->q_id);578 579 xcdq.flags |= (XQCHECK_DQUOT_COMPARE_SCANNED | XQCHECK_DQUOT_WRITTEN);580 error = xfarray_store(counts, dq->q_id, &xcdq);581 if (error == -EFBIG) {582 /*583 * EFBIG means we tried to store data at too high a byte offset584 * in the sparse array. IOWs, we cannot complete the check and585 * must notify userspace that the check was incomplete. This586 * should never happen outside of the collection phase.587 */588 xchk_set_incomplete(xqc->sc);589 error = -ECANCELED;590 }591 mutex_unlock(&xqc->lock);592 if (error)593 return error;594 595 if (xqc->sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)596 return -ECANCELED;597 598 return 0;599 600out_unlock:601 mutex_unlock(&xqc->lock);602 return error;603}604 605/*606 * Walk all the observed dquots, and make sure there's a matching incore607 * dquot and that its counts match ours.608 */609STATIC int610xqcheck_walk_observations(611 struct xqcheck *xqc,612 xfs_dqtype_t dqtype)613{614 struct xqcheck_dquot xcdq;615 struct xfs_dquot *dq;616 struct xfarray *counts = xqcheck_counters_for(xqc, dqtype);617 xfarray_idx_t cur = XFARRAY_CURSOR_INIT;618 int error;619 620 mutex_lock(&xqc->lock);621 while ((error = xfarray_iter(counts, &cur, &xcdq)) == 1) {622 xfs_dqid_t id = cur - 1;623 624 if (xcdq.flags & XQCHECK_DQUOT_COMPARE_SCANNED)625 continue;626 627 mutex_unlock(&xqc->lock);628 629 error = xfs_qm_dqget(xqc->sc->mp, id, dqtype, false, &dq);630 if (error == -ENOENT) {631 xchk_qcheck_set_corrupt(xqc->sc, dqtype, id);632 return 0;633 }634 if (error)635 return error;636 637 error = xqcheck_compare_dquot(xqc, dqtype, dq);638 xfs_qm_dqput(dq);639 if (error)640 return error;641 642 if (xchk_should_terminate(xqc->sc, &error))643 return error;644 645 mutex_lock(&xqc->lock);646 }647 mutex_unlock(&xqc->lock);648 649 return error;650}651 652/* Compare the quota counters we observed against the live dquots. */653STATIC int654xqcheck_compare_dqtype(655 struct xqcheck *xqc,656 xfs_dqtype_t dqtype)657{658 struct xchk_dqiter cursor = { };659 struct xfs_scrub *sc = xqc->sc;660 struct xfs_dquot *dq;661 int error;662 663 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_CORRUPT)664 return 0;665 666 /* If the quota CHKD flag is cleared, we need to repair this quota. */667 if (!(xfs_quota_chkd_flag(dqtype) & sc->mp->m_qflags)) {668 xchk_qcheck_set_corrupt(xqc->sc, dqtype, 0);669 return 0;670 }671 672 /* Compare what we observed against the actual dquots. */673 xchk_dqiter_init(&cursor, sc, dqtype);674 while ((error = xchk_dquot_iter(&cursor, &dq)) == 1) {675 error = xqcheck_compare_dquot(xqc, dqtype, dq);676 xfs_qm_dqput(dq);677 if (error)678 break;679 }680 if (error)681 return error;682 683 /* Walk all the observed dquots and compare to the incore ones. */684 return xqcheck_walk_observations(xqc, dqtype);685}686 687/* Tear down everything associated with a quotacheck. */688static void689xqcheck_teardown_scan(690 void *priv)691{692 struct xqcheck *xqc = priv;693 struct xfs_quotainfo *qi = xqc->sc->mp->m_quotainfo;694 695 /* Discourage any hook functions that might be running. */696 xchk_iscan_abort(&xqc->iscan);697 698 /*699 * As noted above, the apply hook is responsible for cleaning up the700 * shadow dquot accounting data when a transaction completes. The mod701 * hook must be removed before the apply hook so that we don't702 * mistakenly leave an active shadow account for the mod hook to get703 * its hands on. No hooks should be running after these functions704 * return.705 */706 xfs_dqtrx_hook_del(qi, &xqc->qhook);707 708 if (xqc->shadow_dquot_acct.key_len) {709 rhashtable_free_and_destroy(&xqc->shadow_dquot_acct,710 xqcheck_dqacct_free, NULL);711 xqc->shadow_dquot_acct.key_len = 0;712 }713 714 if (xqc->pcounts) {715 xfarray_destroy(xqc->pcounts);716 xqc->pcounts = NULL;717 }718 719 if (xqc->gcounts) {720 xfarray_destroy(xqc->gcounts);721 xqc->gcounts = NULL;722 }723 724 if (xqc->ucounts) {725 xfarray_destroy(xqc->ucounts);726 xqc->ucounts = NULL;727 }728 729 xchk_iscan_teardown(&xqc->iscan);730 mutex_destroy(&xqc->lock);731 xqc->sc = NULL;732}733 734/*735 * Scan all inodes in the entire filesystem to generate quota counter data.736 * If the scan is successful, the quota data will be left alive for a repair.737 * If any error occurs, we'll tear everything down.738 */739STATIC int740xqcheck_setup_scan(741 struct xfs_scrub *sc,742 struct xqcheck *xqc)743{744 char *descr;745 struct xfs_quotainfo *qi = sc->mp->m_quotainfo;746 unsigned long long max_dquots = XFS_DQ_ID_MAX + 1ULL;747 int error;748 749 ASSERT(xqc->sc == NULL);750 xqc->sc = sc;751 752 mutex_init(&xqc->lock);753 754 /* Retry iget every tenth of a second for up to 30 seconds. */755 xchk_iscan_start(sc, 30000, 100, &xqc->iscan);756 757 error = -ENOMEM;758 if (xfs_this_quota_on(sc->mp, XFS_DQTYPE_USER)) {759 descr = xchk_xfile_descr(sc, "user dquot records");760 error = xfarray_create(descr, max_dquots,761 sizeof(struct xqcheck_dquot), &xqc->ucounts);762 kfree(descr);763 if (error)764 goto out_teardown;765 }766 767 if (xfs_this_quota_on(sc->mp, XFS_DQTYPE_GROUP)) {768 descr = xchk_xfile_descr(sc, "group dquot records");769 error = xfarray_create(descr, max_dquots,770 sizeof(struct xqcheck_dquot), &xqc->gcounts);771 kfree(descr);772 if (error)773 goto out_teardown;774 }775 776 if (xfs_this_quota_on(sc->mp, XFS_DQTYPE_PROJ)) {777 descr = xchk_xfile_descr(sc, "project dquot records");778 error = xfarray_create(descr, max_dquots,779 sizeof(struct xqcheck_dquot), &xqc->pcounts);780 kfree(descr);781 if (error)782 goto out_teardown;783 }784 785 /*786 * Set up hash table to map transactions to our internal shadow dqtrx787 * structures.788 */789 error = rhashtable_init(&xqc->shadow_dquot_acct,790 &xqcheck_dqacct_hash_params);791 if (error)792 goto out_teardown;793 794 /*795 * Hook into the quota code. The hook only triggers for inodes that796 * were already scanned, and the scanner thread takes each inode's797 * ILOCK, which means that any in-progress inode updates will finish798 * before we can scan the inode.799 *800 * The apply hook (which removes the shadow dquot accounting struct)801 * must be installed before the mod hook so that we never fail to catch802 * the end of a quota update sequence and leave stale shadow data.803 */804 ASSERT(sc->flags & XCHK_FSGATES_QUOTA);805 xfs_dqtrx_hook_setup(&xqc->qhook, xqcheck_mod_live_ino_dqtrx,806 xqcheck_apply_live_dqtrx);807 808 error = xfs_dqtrx_hook_add(qi, &xqc->qhook);809 if (error)810 goto out_teardown;811 812 /* Use deferred cleanup to pass the quota count data to repair. */813 sc->buf_cleanup = xqcheck_teardown_scan;814 return 0;815 816out_teardown:817 xqcheck_teardown_scan(xqc);818 return error;819}820 821/* Scrub all counters for a given quota type. */822int823xchk_quotacheck(824 struct xfs_scrub *sc)825{826 struct xqcheck *xqc = sc->buf;827 int error = 0;828 829 /* Check quota counters on the live filesystem. */830 error = xqcheck_setup_scan(sc, xqc);831 if (error)832 return error;833 834 /* Walk all inodes, picking up quota information. */835 error = xqcheck_collect_counts(xqc);836 if (!xchk_xref_process_error(sc, 0, 0, &error))837 return error;838 839 /* Fail fast if we're not playing with a full dataset. */840 if (xchk_iscan_aborted(&xqc->iscan))841 xchk_set_incomplete(sc);842 if (sc->sm->sm_flags & XFS_SCRUB_OFLAG_INCOMPLETE)843 return 0;844 845 /* Compare quota counters. */846 if (xqc->ucounts) {847 error = xqcheck_compare_dqtype(xqc, XFS_DQTYPE_USER);848 if (!xchk_xref_process_error(sc, 0, 0, &error))849 return error;850 }851 if (xqc->gcounts) {852 error = xqcheck_compare_dqtype(xqc, XFS_DQTYPE_GROUP);853 if (!xchk_xref_process_error(sc, 0, 0, &error))854 return error;855 }856 if (xqc->pcounts) {857 error = xqcheck_compare_dqtype(xqc, XFS_DQTYPE_PROJ);858 if (!xchk_xref_process_error(sc, 0, 0, &error))859 return error;860 }861 862 /* Check one last time for an incomplete dataset. */863 if (xchk_iscan_aborted(&xqc->iscan))864 xchk_set_incomplete(sc);865 866 return 0;867}868