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
xfs_health_unmount(struct xfs_mount * mp)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
xfs_fs_mark_sick(struct xfs_mount * mp,unsigned int mask)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
xfs_fs_mark_corrupt(struct xfs_mount * mp,unsigned int mask)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
xfs_fs_mark_healthy(struct xfs_mount * mp,unsigned int mask)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
xfs_fs_measure_sickness(struct xfs_mount * mp,unsigned int * sick,unsigned int * checked)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
xfs_rt_mark_sick(struct xfs_mount * mp,unsigned int mask)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
xfs_rt_mark_corrupt(struct xfs_mount * mp,unsigned int mask)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
xfs_rt_mark_healthy(struct xfs_mount * mp,unsigned int mask)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
xfs_rt_measure_sickness(struct xfs_mount * mp,unsigned int * sick,unsigned int * checked)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
xfs_agno_mark_sick(struct xfs_mount * mp,xfs_agnumber_t agno,unsigned int mask)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
xfs_ag_mark_sick(struct xfs_perag * pag,unsigned int mask)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
xfs_ag_mark_corrupt(struct xfs_perag * pag,unsigned int mask)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
xfs_ag_mark_healthy(struct xfs_perag * pag,unsigned int mask)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
xfs_ag_measure_sickness(struct xfs_perag * pag,unsigned int * sick,unsigned int * checked)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
xfs_inode_mark_sick(struct xfs_inode * ip,unsigned int mask)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
xfs_inode_mark_corrupt(struct xfs_inode * ip,unsigned int mask)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
xfs_inode_mark_healthy(struct xfs_inode * ip,unsigned int mask)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
xfs_inode_measure_sickness(struct xfs_inode * ip,unsigned int * sick,unsigned int * checked)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
xfgeo_health_tick(struct xfs_fsop_geom * geo,unsigned int sick,unsigned int checked,const struct ioctl_sick_map * m)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
xfs_fsop_geom_health(struct xfs_mount * mp,struct xfs_fsop_geom * geo)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
xfs_ag_geom_health(struct xfs_perag * pag,struct xfs_ag_geometry * ageo)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
xfs_bulkstat_health(struct xfs_inode * ip,struct xfs_bulkstat * bs)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
xfs_bmap_mark_sick(struct xfs_inode * ip,int whichfork)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
xfs_btree_mark_sick(struct xfs_btree_cur * cur)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
xfs_dirattr_mark_sick(struct xfs_inode * ip,int whichfork)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
xfs_da_mark_sick(struct xfs_da_args * args)582  xfs_da_mark_sick(
583  	struct xfs_da_args	*args)
584  {
585  	xfs_dirattr_mark_sick(args->dp, args->whichfork);
586  }
587