1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
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 Quotacheck
33 * ===============
34 *
35 * Quota counters are "summary" metadata, in the sense that they are computed
36 * 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 by
38 * 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 the
59 * 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 void
70xqcheck_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. */
80int
81xchk_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 attached
98 * to each inode, we create a shadow dquot, and compute the inode count and add
99 * the data/rt block usage from what we see.
100 *
101 * To avoid false corruption reports in part 2, any failure in this part must
102 * set the INCOMPLETE flag even when a negative errno is returned. This care
103 * must be taken with certain errno values (i.e. EFSBADCRC, EFSCORRUPTED,
104 * ECANCELED) that are absorbed into a scrub state flag update by
105 * xchk_*_process_error. Scrub and repair share the same incore data
106 * structures, so the INCOMPLETE flag is critical to prevent a repair based on
107 * insufficient information.
108 *
109 * Because we are scanning a live filesystem, it's possible that another thread
110 * will try to update the quota counters for an inode that we've already
111 * scanned. This will cause our counts to be incorrect. Therefore, we hook
112 * the live transaction code in two places: (1) when the callers update the
113 * per-transaction dqtrx structure to log quota counter updates; and (2) when
114 * transaction commit actually logs those updates to the incore dquot. By
115 * shadowing transaction updates in this manner, live quotacheck can ensure
116 * by locking the dquot and the shadow structure that its own copies are not
117 * out of date. Because the hook code runs in a different process context from
118 * 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 notice
120 * the aborted scan and set the incomplete flag.
121 *
122 * Note that we use srcu notifier hooks to minimize the overhead when live
123 * quotacheck is /not/ running.
124 */
125
126/* Update an incore dquot counter information from a live update. */
127static int
128xqcheck_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 offset
152 * in the sparse array. IOWs, we cannot complete the check and
153 * 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 int
162xqcheck_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 updates
204 * going on in the regular quota code.
205 */
206static int
207xqcheck_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 when
310 * the regular quota code are doing the same.
311 */
312static int
313xqcheck_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 deltas
347 * 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 int
390xqcheck_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 not
404 * 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_blocks
417 * 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 int
481xqcheck_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 our
490 * transaction resource usage for the duration. Specifically:
491 *
492 * Cancel the transaction to release the log grant space while we scan
493 * the filesystem.
494 *
495 * Create a new empty transaction to eliminate the possibility of the
496 * inode scan deadlocking on cyclical metadata.
497 *
498 * We pass the empty transaction to the file scanning function to avoid
499 * repeatedly cycling empty transactions. This can be done without
500 * risk of deadlock between sb_internal and the IOLOCK (we take the
501 * IOLOCK to quiesce the file before scanning) because empty
502 * 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 state
523 * change, change the error code so that we exit to userspace
524 * 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 new
533 * 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, comparing
541 * the resource usage counters against our shadow dquots; and then walk each
542 * shadow dquot (that wasn't covered in the first part), comparing it against
543 * the xfs_dquot.
544 */
545
546/*
547 * Check the dquot data against what we observed. Caller must hold the dquot
548 * lock.
549 */
550STATIC int
551xqcheck_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 offset
584 * in the sparse array. IOWs, we cannot complete the check and
585 * must notify userspace that the check was incomplete. This
586 * 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 incore
607 * dquot and that its counts match ours.
608 */
609STATIC int
610xqcheck_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 int
654xqcheck_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 void
689xqcheck_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 the
700 * shadow dquot accounting data when a transaction completes. The mod
701 * hook must be removed before the apply hook so that we don't
702 * mistakenly leave an active shadow account for the mod hook to get
703 * its hands on. No hooks should be running after these functions
704 * 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 int
740xqcheck_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 dqtrx
787 * 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 that
796 * were already scanned, and the scanner thread takes each inode's
797 * ILOCK, which means that any in-progress inode updates will finish
798 * 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 catch
802 * 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(priv: xqc);
818 return error;
819}
820
821/* Scrub all counters for a given quota type. */
822int
823xchk_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

source code of linux/fs/xfs/scrub/quotacheck.c