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. */ |
42 | struct 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 | */ |
61 | struct 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. */ |
69 | static void |
70 | xqcheck_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. */ |
80 | int |
81 | xchk_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. */ |
127 | static int |
128 | xqcheck_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. */ |
161 | static int |
162 | xqcheck_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 | |
174 | static 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. */ |
184 | STATIC struct xqcheck_dqtrx * |
185 | xqcheck_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 | */ |
206 | static int |
207 | xqcheck_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 | |
302 | out_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 | */ |
312 | static int |
313 | xqcheck_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 | |
381 | out_abort: |
382 | xchk_iscan_abort(&xqc->iscan); |
383 | out_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. */ |
389 | STATIC int |
390 | xqcheck_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 | |
465 | out_mutex: |
466 | mutex_unlock(&xqc->lock); |
467 | out_abort: |
468 | xchk_iscan_abort(&xqc->iscan); |
469 | out_incomplete: |
470 | xchk_set_incomplete(xqc->sc); |
471 | out_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. */ |
480 | STATIC int |
481 | xqcheck_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 | */ |
550 | STATIC int |
551 | xqcheck_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 | |
600 | out_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 | */ |
609 | STATIC int |
610 | xqcheck_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. */ |
653 | STATIC int |
654 | xqcheck_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. */ |
688 | static void |
689 | xqcheck_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 | */ |
739 | STATIC int |
740 | xqcheck_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 | |
816 | out_teardown: |
817 | xqcheck_teardown_scan(priv: xqc); |
818 | return error; |
819 | } |
820 | |
821 | /* Scrub all counters for a given quota type. */ |
822 | int |
823 | xchk_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 | |