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, and 24 * make sure we're not sitting on anything that would get in the way of 25 * recovery. 26 */ 27 void 28 xfs_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 point 72 * during this filesystem mount and have advised the 73 * administrator to run repair once the unmount completes. 74 * 75 * However, we must be careful -- when FSCOUNTERS are flagged 76 * unhealthy, the unmount procedure omits writing the clean 77 * unmount record to the log so that the next mount will run 78 * recovery and recompute the summary counters. In other 79 * words, we leave a dirty log to get the counters fixed. 80 * 81 * Unfortunately, xfs_repair cannot recover dirty logs, so if 82 * there were filesystem problems, FSCOUNTERS was flagged, and 83 * 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 the 86 * FSCOUNTERS healthy so that a subsequent repair run won't see 87 * 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. */ 95 void 96 xfs_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. */ 109 void 110 xfs_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. */ 124 void 125 xfs_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. */ 141 void 142 xfs_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. */ 154 void 155 xfs_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. */ 168 void 169 xfs_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. */ 183 void 184 xfs_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. */ 200 void 201 xfs_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. */ 213 void 214 xfs_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. */ 230 void 231 xfs_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. */ 244 void 245 xfs_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. */ 259 void 260 xfs_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. */ 276 void 277 xfs_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. */ 289 void 290 xfs_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. Scrub 303 * grabs inodes with DONTCACHE assuming that most inode are ok, which 304 * 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. */ 312 void 313 xfs_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. Scrub 327 * grabs inodes with DONTCACHE assuming that most inode are ok, which 328 * 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. */ 336 void 337 xfs_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. */ 353 void 354 xfs_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 367 struct ioctl_sick_map { 368 unsigned int sick_mask; 369 unsigned int ioctl_mask; 370 }; 371 372 static 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 382 static 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 388 static inline void 389 xfgeo_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. */ 402 void 403 xfs_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 423 static 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. */ 439 void 440 xfs_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 460 static 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. */ 478 void 479 xfs_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. */ 500 void 501 xfs_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. */ 526 void 527 xfs_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 tracking 553 * system. 554 */ 555 void 556 xfs_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 tracking 579 * system. 580 */ 581 void 582 xfs_da_mark_sick( 583 struct xfs_da_args *args) 584 { 585 xfs_dirattr_mark_sick(args->dp, args->whichfork); 586 } 587
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.