587 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) 2019 Oracle. All Rights Reserved.4 * Author: Darrick J. Wong <darrick.wong@oracle.com>5 */6#include "xfs.h"7#include "xfs_fs.h"8#include "xfs_shared.h"9#include "xfs_format.h"10#include "xfs_log_format.h"11#include "xfs_trans_resv.h"12#include "xfs_mount.h"13#include "xfs_inode.h"14#include "xfs_trace.h"15#include "xfs_health.h"16#include "xfs_ag.h"17#include "xfs_btree.h"18#include "xfs_da_format.h"19#include "xfs_da_btree.h"20#include "xfs_quota_defs.h"21 22/*23 * Warn about metadata corruption that we detected but haven't fixed, and24 * make sure we're not sitting on anything that would get in the way of25 * recovery.26 */27void28xfs_health_unmount(29 struct xfs_mount *mp)30{31 struct xfs_perag *pag;32 xfs_agnumber_t agno;33 unsigned int sick = 0;34 unsigned int checked = 0;35 bool warn = false;36 37 if (xfs_is_shutdown(mp))38 return;39 40 /* Measure AG corruption levels. */41 for_each_perag(mp, agno, pag) {42 xfs_ag_measure_sickness(pag, &sick, &checked);43 if (sick) {44 trace_xfs_ag_unfixed_corruption(mp, agno, sick);45 warn = true;46 }47 }48 49 /* Measure realtime volume corruption levels. */50 xfs_rt_measure_sickness(mp, &sick, &checked);51 if (sick) {52 trace_xfs_rt_unfixed_corruption(mp, sick);53 warn = true;54 }55 56 /*57 * Measure fs corruption and keep the sample around for the warning.58 * See the note below for why we exempt FS_COUNTERS.59 */60 xfs_fs_measure_sickness(mp, &sick, &checked);61 if (sick & ~XFS_SICK_FS_COUNTERS) {62 trace_xfs_fs_unfixed_corruption(mp, sick);63 warn = true;64 }65 66 if (warn) {67 xfs_warn(mp,68"Uncorrected metadata errors detected; please run xfs_repair.");69 70 /*71 * We discovered uncorrected metadata problems at some point72 * during this filesystem mount and have advised the73 * administrator to run repair once the unmount completes.74 *75 * However, we must be careful -- when FSCOUNTERS are flagged76 * unhealthy, the unmount procedure omits writing the clean77 * unmount record to the log so that the next mount will run78 * recovery and recompute the summary counters. In other79 * words, we leave a dirty log to get the counters fixed.80 *81 * Unfortunately, xfs_repair cannot recover dirty logs, so if82 * there were filesystem problems, FSCOUNTERS was flagged, and83 * the administrator takes our advice to run xfs_repair,84 * they'll have to zap the log before repairing structures.85 * We don't really want to encourage this, so we mark the86 * FSCOUNTERS healthy so that a subsequent repair run won't see87 * a dirty log.88 */89 if (sick & XFS_SICK_FS_COUNTERS)90 xfs_fs_mark_healthy(mp, XFS_SICK_FS_COUNTERS);91 }92}93 94/* Mark unhealthy per-fs metadata. */95void96xfs_fs_mark_sick(97 struct xfs_mount *mp,98 unsigned int mask)99{100 ASSERT(!(mask & ~XFS_SICK_FS_ALL));101 trace_xfs_fs_mark_sick(mp, mask);102 103 spin_lock(&mp->m_sb_lock);104 mp->m_fs_sick |= mask;105 spin_unlock(&mp->m_sb_lock);106}107 108/* Mark per-fs metadata as having been checked and found unhealthy by fsck. */109void110xfs_fs_mark_corrupt(111 struct xfs_mount *mp,112 unsigned int mask)113{114 ASSERT(!(mask & ~XFS_SICK_FS_ALL));115 trace_xfs_fs_mark_corrupt(mp, mask);116 117 spin_lock(&mp->m_sb_lock);118 mp->m_fs_sick |= mask;119 mp->m_fs_checked |= mask;120 spin_unlock(&mp->m_sb_lock);121}122 123/* Mark a per-fs metadata healed. */124void125xfs_fs_mark_healthy(126 struct xfs_mount *mp,127 unsigned int mask)128{129 ASSERT(!(mask & ~XFS_SICK_FS_ALL));130 trace_xfs_fs_mark_healthy(mp, mask);131 132 spin_lock(&mp->m_sb_lock);133 mp->m_fs_sick &= ~mask;134 if (!(mp->m_fs_sick & XFS_SICK_FS_PRIMARY))135 mp->m_fs_sick &= ~XFS_SICK_FS_SECONDARY;136 mp->m_fs_checked |= mask;137 spin_unlock(&mp->m_sb_lock);138}139 140/* Sample which per-fs metadata are unhealthy. */141void142xfs_fs_measure_sickness(143 struct xfs_mount *mp,144 unsigned int *sick,145 unsigned int *checked)146{147 spin_lock(&mp->m_sb_lock);148 *sick = mp->m_fs_sick;149 *checked = mp->m_fs_checked;150 spin_unlock(&mp->m_sb_lock);151}152 153/* Mark unhealthy realtime metadata. */154void155xfs_rt_mark_sick(156 struct xfs_mount *mp,157 unsigned int mask)158{159 ASSERT(!(mask & ~XFS_SICK_RT_ALL));160 trace_xfs_rt_mark_sick(mp, mask);161 162 spin_lock(&mp->m_sb_lock);163 mp->m_rt_sick |= mask;164 spin_unlock(&mp->m_sb_lock);165}166 167/* Mark realtime metadata as having been checked and found unhealthy by fsck. */168void169xfs_rt_mark_corrupt(170 struct xfs_mount *mp,171 unsigned int mask)172{173 ASSERT(!(mask & ~XFS_SICK_RT_ALL));174 trace_xfs_rt_mark_corrupt(mp, mask);175 176 spin_lock(&mp->m_sb_lock);177 mp->m_rt_sick |= mask;178 mp->m_rt_checked |= mask;179 spin_unlock(&mp->m_sb_lock);180}181 182/* Mark a realtime metadata healed. */183void184xfs_rt_mark_healthy(185 struct xfs_mount *mp,186 unsigned int mask)187{188 ASSERT(!(mask & ~XFS_SICK_RT_ALL));189 trace_xfs_rt_mark_healthy(mp, mask);190 191 spin_lock(&mp->m_sb_lock);192 mp->m_rt_sick &= ~mask;193 if (!(mp->m_rt_sick & XFS_SICK_RT_PRIMARY))194 mp->m_rt_sick &= ~XFS_SICK_RT_SECONDARY;195 mp->m_rt_checked |= mask;196 spin_unlock(&mp->m_sb_lock);197}198 199/* Sample which realtime metadata are unhealthy. */200void201xfs_rt_measure_sickness(202 struct xfs_mount *mp,203 unsigned int *sick,204 unsigned int *checked)205{206 spin_lock(&mp->m_sb_lock);207 *sick = mp->m_rt_sick;208 *checked = mp->m_rt_checked;209 spin_unlock(&mp->m_sb_lock);210}211 212/* Mark unhealthy per-ag metadata given a raw AG number. */213void214xfs_agno_mark_sick(215 struct xfs_mount *mp,216 xfs_agnumber_t agno,217 unsigned int mask)218{219 struct xfs_perag *pag = xfs_perag_get(mp, agno);220 221 /* per-ag structure not set up yet? */222 if (!pag)223 return;224 225 xfs_ag_mark_sick(pag, mask);226 xfs_perag_put(pag);227}228 229/* Mark unhealthy per-ag metadata. */230void231xfs_ag_mark_sick(232 struct xfs_perag *pag,233 unsigned int mask)234{235 ASSERT(!(mask & ~XFS_SICK_AG_ALL));236 trace_xfs_ag_mark_sick(pag->pag_mount, pag->pag_agno, mask);237 238 spin_lock(&pag->pag_state_lock);239 pag->pag_sick |= mask;240 spin_unlock(&pag->pag_state_lock);241}242 243/* Mark per-ag metadata as having been checked and found unhealthy by fsck. */244void245xfs_ag_mark_corrupt(246 struct xfs_perag *pag,247 unsigned int mask)248{249 ASSERT(!(mask & ~XFS_SICK_AG_ALL));250 trace_xfs_ag_mark_corrupt(pag->pag_mount, pag->pag_agno, mask);251 252 spin_lock(&pag->pag_state_lock);253 pag->pag_sick |= mask;254 pag->pag_checked |= mask;255 spin_unlock(&pag->pag_state_lock);256}257 258/* Mark per-ag metadata ok. */259void260xfs_ag_mark_healthy(261 struct xfs_perag *pag,262 unsigned int mask)263{264 ASSERT(!(mask & ~XFS_SICK_AG_ALL));265 trace_xfs_ag_mark_healthy(pag->pag_mount, pag->pag_agno, mask);266 267 spin_lock(&pag->pag_state_lock);268 pag->pag_sick &= ~mask;269 if (!(pag->pag_sick & XFS_SICK_AG_PRIMARY))270 pag->pag_sick &= ~XFS_SICK_AG_SECONDARY;271 pag->pag_checked |= mask;272 spin_unlock(&pag->pag_state_lock);273}274 275/* Sample which per-ag metadata are unhealthy. */276void277xfs_ag_measure_sickness(278 struct xfs_perag *pag,279 unsigned int *sick,280 unsigned int *checked)281{282 spin_lock(&pag->pag_state_lock);283 *sick = pag->pag_sick;284 *checked = pag->pag_checked;285 spin_unlock(&pag->pag_state_lock);286}287 288/* Mark the unhealthy parts of an inode. */289void290xfs_inode_mark_sick(291 struct xfs_inode *ip,292 unsigned int mask)293{294 ASSERT(!(mask & ~XFS_SICK_INO_ALL));295 trace_xfs_inode_mark_sick(ip, mask);296 297 spin_lock(&ip->i_flags_lock);298 ip->i_sick |= mask;299 spin_unlock(&ip->i_flags_lock);300 301 /*302 * Keep this inode around so we don't lose the sickness report. Scrub303 * grabs inodes with DONTCACHE assuming that most inode are ok, which304 * is not the case here.305 */306 spin_lock(&VFS_I(ip)->i_lock);307 VFS_I(ip)->i_state &= ~I_DONTCACHE;308 spin_unlock(&VFS_I(ip)->i_lock);309}310 311/* Mark inode metadata as having been checked and found unhealthy by fsck. */312void313xfs_inode_mark_corrupt(314 struct xfs_inode *ip,315 unsigned int mask)316{317 ASSERT(!(mask & ~XFS_SICK_INO_ALL));318 trace_xfs_inode_mark_corrupt(ip, mask);319 320 spin_lock(&ip->i_flags_lock);321 ip->i_sick |= mask;322 ip->i_checked |= mask;323 spin_unlock(&ip->i_flags_lock);324 325 /*326 * Keep this inode around so we don't lose the sickness report. Scrub327 * grabs inodes with DONTCACHE assuming that most inode are ok, which328 * is not the case here.329 */330 spin_lock(&VFS_I(ip)->i_lock);331 VFS_I(ip)->i_state &= ~I_DONTCACHE;332 spin_unlock(&VFS_I(ip)->i_lock);333}334 335/* Mark parts of an inode healed. */336void337xfs_inode_mark_healthy(338 struct xfs_inode *ip,339 unsigned int mask)340{341 ASSERT(!(mask & ~XFS_SICK_INO_ALL));342 trace_xfs_inode_mark_healthy(ip, mask);343 344 spin_lock(&ip->i_flags_lock);345 ip->i_sick &= ~mask;346 if (!(ip->i_sick & XFS_SICK_INO_PRIMARY))347 ip->i_sick &= ~XFS_SICK_INO_SECONDARY;348 ip->i_checked |= mask;349 spin_unlock(&ip->i_flags_lock);350}351 352/* Sample which parts of an inode are unhealthy. */353void354xfs_inode_measure_sickness(355 struct xfs_inode *ip,356 unsigned int *sick,357 unsigned int *checked)358{359 spin_lock(&ip->i_flags_lock);360 *sick = ip->i_sick;361 *checked = ip->i_checked;362 spin_unlock(&ip->i_flags_lock);363}364 365/* Mappings between internal sick masks and ioctl sick masks. */366 367struct ioctl_sick_map {368 unsigned int sick_mask;369 unsigned int ioctl_mask;370};371 372static const struct ioctl_sick_map fs_map[] = {373 { XFS_SICK_FS_COUNTERS, XFS_FSOP_GEOM_SICK_COUNTERS},374 { XFS_SICK_FS_UQUOTA, XFS_FSOP_GEOM_SICK_UQUOTA },375 { XFS_SICK_FS_GQUOTA, XFS_FSOP_GEOM_SICK_GQUOTA },376 { XFS_SICK_FS_PQUOTA, XFS_FSOP_GEOM_SICK_PQUOTA },377 { XFS_SICK_FS_QUOTACHECK, XFS_FSOP_GEOM_SICK_QUOTACHECK },378 { XFS_SICK_FS_NLINKS, XFS_FSOP_GEOM_SICK_NLINKS },379 { 0, 0 },380};381 382static const struct ioctl_sick_map rt_map[] = {383 { XFS_SICK_RT_BITMAP, XFS_FSOP_GEOM_SICK_RT_BITMAP },384 { XFS_SICK_RT_SUMMARY, XFS_FSOP_GEOM_SICK_RT_SUMMARY },385 { 0, 0 },386};387 388static inline void389xfgeo_health_tick(390 struct xfs_fsop_geom *geo,391 unsigned int sick,392 unsigned int checked,393 const struct ioctl_sick_map *m)394{395 if (checked & m->sick_mask)396 geo->checked |= m->ioctl_mask;397 if (sick & m->sick_mask)398 geo->sick |= m->ioctl_mask;399}400 401/* Fill out fs geometry health info. */402void403xfs_fsop_geom_health(404 struct xfs_mount *mp,405 struct xfs_fsop_geom *geo)406{407 const struct ioctl_sick_map *m;408 unsigned int sick;409 unsigned int checked;410 411 geo->sick = 0;412 geo->checked = 0;413 414 xfs_fs_measure_sickness(mp, &sick, &checked);415 for (m = fs_map; m->sick_mask; m++)416 xfgeo_health_tick(geo, sick, checked, m);417 418 xfs_rt_measure_sickness(mp, &sick, &checked);419 for (m = rt_map; m->sick_mask; m++)420 xfgeo_health_tick(geo, sick, checked, m);421}422 423static const struct ioctl_sick_map ag_map[] = {424 { XFS_SICK_AG_SB, XFS_AG_GEOM_SICK_SB },425 { XFS_SICK_AG_AGF, XFS_AG_GEOM_SICK_AGF },426 { XFS_SICK_AG_AGFL, XFS_AG_GEOM_SICK_AGFL },427 { XFS_SICK_AG_AGI, XFS_AG_GEOM_SICK_AGI },428 { XFS_SICK_AG_BNOBT, XFS_AG_GEOM_SICK_BNOBT },429 { XFS_SICK_AG_CNTBT, XFS_AG_GEOM_SICK_CNTBT },430 { XFS_SICK_AG_INOBT, XFS_AG_GEOM_SICK_INOBT },431 { XFS_SICK_AG_FINOBT, XFS_AG_GEOM_SICK_FINOBT },432 { XFS_SICK_AG_RMAPBT, XFS_AG_GEOM_SICK_RMAPBT },433 { XFS_SICK_AG_REFCNTBT, XFS_AG_GEOM_SICK_REFCNTBT },434 { XFS_SICK_AG_INODES, XFS_AG_GEOM_SICK_INODES },435 { 0, 0 },436};437 438/* Fill out ag geometry health info. */439void440xfs_ag_geom_health(441 struct xfs_perag *pag,442 struct xfs_ag_geometry *ageo)443{444 const struct ioctl_sick_map *m;445 unsigned int sick;446 unsigned int checked;447 448 ageo->ag_sick = 0;449 ageo->ag_checked = 0;450 451 xfs_ag_measure_sickness(pag, &sick, &checked);452 for (m = ag_map; m->sick_mask; m++) {453 if (checked & m->sick_mask)454 ageo->ag_checked |= m->ioctl_mask;455 if (sick & m->sick_mask)456 ageo->ag_sick |= m->ioctl_mask;457 }458}459 460static const struct ioctl_sick_map ino_map[] = {461 { XFS_SICK_INO_CORE, XFS_BS_SICK_INODE },462 { XFS_SICK_INO_BMBTD, XFS_BS_SICK_BMBTD },463 { XFS_SICK_INO_BMBTA, XFS_BS_SICK_BMBTA },464 { XFS_SICK_INO_BMBTC, XFS_BS_SICK_BMBTC },465 { XFS_SICK_INO_DIR, XFS_BS_SICK_DIR },466 { XFS_SICK_INO_XATTR, XFS_BS_SICK_XATTR },467 { XFS_SICK_INO_SYMLINK, XFS_BS_SICK_SYMLINK },468 { XFS_SICK_INO_PARENT, XFS_BS_SICK_PARENT },469 { XFS_SICK_INO_BMBTD_ZAPPED, XFS_BS_SICK_BMBTD },470 { XFS_SICK_INO_BMBTA_ZAPPED, XFS_BS_SICK_BMBTA },471 { XFS_SICK_INO_DIR_ZAPPED, XFS_BS_SICK_DIR },472 { XFS_SICK_INO_SYMLINK_ZAPPED, XFS_BS_SICK_SYMLINK },473 { XFS_SICK_INO_DIRTREE, XFS_BS_SICK_DIRTREE },474 { 0, 0 },475};476 477/* Fill out bulkstat health info. */478void479xfs_bulkstat_health(480 struct xfs_inode *ip,481 struct xfs_bulkstat *bs)482{483 const struct ioctl_sick_map *m;484 unsigned int sick;485 unsigned int checked;486 487 bs->bs_sick = 0;488 bs->bs_checked = 0;489 490 xfs_inode_measure_sickness(ip, &sick, &checked);491 for (m = ino_map; m->sick_mask; m++) {492 if (checked & m->sick_mask)493 bs->bs_checked |= m->ioctl_mask;494 if (sick & m->sick_mask)495 bs->bs_sick |= m->ioctl_mask;496 }497}498 499/* Mark a block mapping sick. */500void501xfs_bmap_mark_sick(502 struct xfs_inode *ip,503 int whichfork)504{505 unsigned int mask;506 507 switch (whichfork) {508 case XFS_DATA_FORK:509 mask = XFS_SICK_INO_BMBTD;510 break;511 case XFS_ATTR_FORK:512 mask = XFS_SICK_INO_BMBTA;513 break;514 case XFS_COW_FORK:515 mask = XFS_SICK_INO_BMBTC;516 break;517 default:518 ASSERT(0);519 return;520 }521 522 xfs_inode_mark_sick(ip, mask);523}524 525/* Record observations of btree corruption with the health tracking system. */526void527xfs_btree_mark_sick(528 struct xfs_btree_cur *cur)529{530 switch (cur->bc_ops->type) {531 case XFS_BTREE_TYPE_MEM:532 /* no health state tracking for ephemeral btrees */533 return;534 case XFS_BTREE_TYPE_AG:535 ASSERT(cur->bc_ops->sick_mask);536 xfs_ag_mark_sick(cur->bc_ag.pag, cur->bc_ops->sick_mask);537 return;538 case XFS_BTREE_TYPE_INODE:539 if (xfs_btree_is_bmap(cur->bc_ops)) {540 xfs_bmap_mark_sick(cur->bc_ino.ip,541 cur->bc_ino.whichfork);542 return;543 }544 fallthrough;545 default:546 ASSERT(0);547 return;548 }549}550 551/*552 * Record observations of dir/attr btree corruption with the health tracking553 * system.554 */555void556xfs_dirattr_mark_sick(557 struct xfs_inode *ip,558 int whichfork)559{560 unsigned int mask;561 562 switch (whichfork) {563 case XFS_DATA_FORK:564 mask = XFS_SICK_INO_DIR;565 break;566 case XFS_ATTR_FORK:567 mask = XFS_SICK_INO_XATTR;568 break;569 default:570 ASSERT(0);571 return;572 }573 574 xfs_inode_mark_sick(ip, mask);575}576 577/*578 * Record observations of dir/attr btree corruption with the health tracking579 * system.580 */581void582xfs_da_mark_sick(583 struct xfs_da_args *args)584{585 xfs_dirattr_mark_sick(args->dp, args->whichfork);586}587