diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2017-10-18 00:37:34 -0400 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2017-10-26 18:38:23 -0400 |
commit | 91fb9afc0847926ef6ea7695b8125c8fbe7974d6 (patch) | |
tree | 3081f56bd69cad0fcd0906c80a151a8dd463ffca | |
parent | 52c732eee78b47ac2eb828b1c7fa611cd37b0090 (diff) |
xfs: create inode pointer verifiers
Create some helper functions to check that inode pointers point to
somewhere within the filesystem and not at the static AG metadata.
Move xfs_internal_inum and create a directory inode check function.
We will use these functions in scrub and elsewhere.
Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
-rw-r--r-- | fs/xfs/libxfs/xfs_dir2.c | 19 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_ialloc.c | 90 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_ialloc.h | 7 | ||||
-rw-r--r-- | fs/xfs/xfs_itable.c | 10 | ||||
-rw-r--r-- | fs/xfs/xfs_itable.h | 2 |
5 files changed, 100 insertions, 28 deletions
diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c index ccf9783fd3f0..ee5e9160eb01 100644 --- a/fs/xfs/libxfs/xfs_dir2.c +++ b/fs/xfs/libxfs/xfs_dir2.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include "xfs_bmap.h" | 30 | #include "xfs_bmap.h" |
31 | #include "xfs_dir2.h" | 31 | #include "xfs_dir2.h" |
32 | #include "xfs_dir2_priv.h" | 32 | #include "xfs_dir2_priv.h" |
33 | #include "xfs_ialloc.h" | ||
33 | #include "xfs_error.h" | 34 | #include "xfs_error.h" |
34 | #include "xfs_trace.h" | 35 | #include "xfs_trace.h" |
35 | 36 | ||
@@ -202,22 +203,8 @@ xfs_dir_ino_validate( | |||
202 | xfs_mount_t *mp, | 203 | xfs_mount_t *mp, |
203 | xfs_ino_t ino) | 204 | xfs_ino_t ino) |
204 | { | 205 | { |
205 | xfs_agblock_t agblkno; | 206 | bool ino_ok = xfs_verify_dir_ino(mp, ino); |
206 | xfs_agino_t agino; | 207 | |
207 | xfs_agnumber_t agno; | ||
208 | int ino_ok; | ||
209 | int ioff; | ||
210 | |||
211 | agno = XFS_INO_TO_AGNO(mp, ino); | ||
212 | agblkno = XFS_INO_TO_AGBNO(mp, ino); | ||
213 | ioff = XFS_INO_TO_OFFSET(mp, ino); | ||
214 | agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff); | ||
215 | ino_ok = | ||
216 | agno < mp->m_sb.sb_agcount && | ||
217 | agblkno < mp->m_sb.sb_agblocks && | ||
218 | agblkno != 0 && | ||
219 | ioff < (1 << mp->m_sb.sb_inopblog) && | ||
220 | XFS_AGINO_TO_INO(mp, agno, agino) == ino; | ||
221 | if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) { | 208 | if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) { |
222 | xfs_warn(mp, "Invalid inode number 0x%Lx", | 209 | xfs_warn(mp, "Invalid inode number 0x%Lx", |
223 | (unsigned long long) ino); | 210 | (unsigned long long) ino); |
diff --git a/fs/xfs/libxfs/xfs_ialloc.c b/fs/xfs/libxfs/xfs_ialloc.c index dfd643909f85..e11f8af8a725 100644 --- a/fs/xfs/libxfs/xfs_ialloc.c +++ b/fs/xfs/libxfs/xfs_ialloc.c | |||
@@ -2664,3 +2664,93 @@ xfs_ialloc_pagi_init( | |||
2664 | xfs_trans_brelse(tp, bp); | 2664 | xfs_trans_brelse(tp, bp); |
2665 | return 0; | 2665 | return 0; |
2666 | } | 2666 | } |
2667 | |||
2668 | /* Calculate the first and last possible inode number in an AG. */ | ||
2669 | void | ||
2670 | xfs_ialloc_agino_range( | ||
2671 | struct xfs_mount *mp, | ||
2672 | xfs_agnumber_t agno, | ||
2673 | xfs_agino_t *first, | ||
2674 | xfs_agino_t *last) | ||
2675 | { | ||
2676 | xfs_agblock_t bno; | ||
2677 | xfs_agblock_t eoag; | ||
2678 | |||
2679 | eoag = xfs_ag_block_count(mp, agno); | ||
2680 | |||
2681 | /* | ||
2682 | * Calculate the first inode, which will be in the first | ||
2683 | * cluster-aligned block after the AGFL. | ||
2684 | */ | ||
2685 | bno = round_up(XFS_AGFL_BLOCK(mp) + 1, | ||
2686 | xfs_ialloc_cluster_alignment(mp)); | ||
2687 | *first = XFS_OFFBNO_TO_AGINO(mp, bno, 0); | ||
2688 | |||
2689 | /* | ||
2690 | * Calculate the last inode, which will be at the end of the | ||
2691 | * last (aligned) cluster that can be allocated in the AG. | ||
2692 | */ | ||
2693 | bno = round_down(eoag, xfs_ialloc_cluster_alignment(mp)); | ||
2694 | *last = XFS_OFFBNO_TO_AGINO(mp, bno, 0) - 1; | ||
2695 | } | ||
2696 | |||
2697 | /* | ||
2698 | * Verify that an AG inode number pointer neither points outside the AG | ||
2699 | * nor points at static metadata. | ||
2700 | */ | ||
2701 | bool | ||
2702 | xfs_verify_agino( | ||
2703 | struct xfs_mount *mp, | ||
2704 | xfs_agnumber_t agno, | ||
2705 | xfs_agino_t agino) | ||
2706 | { | ||
2707 | xfs_agino_t first; | ||
2708 | xfs_agino_t last; | ||
2709 | |||
2710 | xfs_ialloc_agino_range(mp, agno, &first, &last); | ||
2711 | return agino >= first && agino <= last; | ||
2712 | } | ||
2713 | |||
2714 | /* | ||
2715 | * Verify that an FS inode number pointer neither points outside the | ||
2716 | * filesystem nor points at static AG metadata. | ||
2717 | */ | ||
2718 | bool | ||
2719 | xfs_verify_ino( | ||
2720 | struct xfs_mount *mp, | ||
2721 | xfs_ino_t ino) | ||
2722 | { | ||
2723 | xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, ino); | ||
2724 | xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ino); | ||
2725 | |||
2726 | if (agno >= mp->m_sb.sb_agcount) | ||
2727 | return false; | ||
2728 | if (XFS_AGINO_TO_INO(mp, agno, agino) != ino) | ||
2729 | return false; | ||
2730 | return xfs_verify_agino(mp, agno, agino); | ||
2731 | } | ||
2732 | |||
2733 | /* Is this an internal inode number? */ | ||
2734 | bool | ||
2735 | xfs_internal_inum( | ||
2736 | struct xfs_mount *mp, | ||
2737 | xfs_ino_t ino) | ||
2738 | { | ||
2739 | return ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino || | ||
2740 | (xfs_sb_version_hasquota(&mp->m_sb) && | ||
2741 | xfs_is_quota_inode(&mp->m_sb, ino)); | ||
2742 | } | ||
2743 | |||
2744 | /* | ||
2745 | * Verify that a directory entry's inode number doesn't point at an internal | ||
2746 | * inode, empty space, or static AG metadata. | ||
2747 | */ | ||
2748 | bool | ||
2749 | xfs_verify_dir_ino( | ||
2750 | struct xfs_mount *mp, | ||
2751 | xfs_ino_t ino) | ||
2752 | { | ||
2753 | if (xfs_internal_inum(mp, ino)) | ||
2754 | return false; | ||
2755 | return xfs_verify_ino(mp, ino); | ||
2756 | } | ||
diff --git a/fs/xfs/libxfs/xfs_ialloc.h b/fs/xfs/libxfs/xfs_ialloc.h index b32cfb5aeb5b..d2bdcd5e7312 100644 --- a/fs/xfs/libxfs/xfs_ialloc.h +++ b/fs/xfs/libxfs/xfs_ialloc.h | |||
@@ -173,5 +173,12 @@ void xfs_inobt_btrec_to_irec(struct xfs_mount *mp, union xfs_btree_rec *rec, | |||
173 | struct xfs_inobt_rec_incore *irec); | 173 | struct xfs_inobt_rec_incore *irec); |
174 | 174 | ||
175 | int xfs_ialloc_cluster_alignment(struct xfs_mount *mp); | 175 | int xfs_ialloc_cluster_alignment(struct xfs_mount *mp); |
176 | void xfs_ialloc_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno, | ||
177 | xfs_agino_t *first, xfs_agino_t *last); | ||
178 | bool xfs_verify_agino(struct xfs_mount *mp, xfs_agnumber_t agno, | ||
179 | xfs_agino_t agino); | ||
180 | bool xfs_verify_ino(struct xfs_mount *mp, xfs_ino_t ino); | ||
181 | bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino); | ||
182 | bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino); | ||
176 | 183 | ||
177 | #endif /* __XFS_IALLOC_H__ */ | 184 | #endif /* __XFS_IALLOC_H__ */ |
diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index c393a2f6d8c3..0172d0b72c95 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c | |||
@@ -31,16 +31,6 @@ | |||
31 | #include "xfs_trace.h" | 31 | #include "xfs_trace.h" |
32 | #include "xfs_icache.h" | 32 | #include "xfs_icache.h" |
33 | 33 | ||
34 | int | ||
35 | xfs_internal_inum( | ||
36 | xfs_mount_t *mp, | ||
37 | xfs_ino_t ino) | ||
38 | { | ||
39 | return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino || | ||
40 | (xfs_sb_version_hasquota(&mp->m_sb) && | ||
41 | xfs_is_quota_inode(&mp->m_sb, ino))); | ||
42 | } | ||
43 | |||
44 | /* | 34 | /* |
45 | * Return stat information for one inode. | 35 | * Return stat information for one inode. |
46 | * Return 0 if ok, else errno. | 36 | * Return 0 if ok, else errno. |
diff --git a/fs/xfs/xfs_itable.h b/fs/xfs/xfs_itable.h index 17e86e0541af..6ea8b3912fa4 100644 --- a/fs/xfs/xfs_itable.h +++ b/fs/xfs/xfs_itable.h | |||
@@ -96,6 +96,4 @@ xfs_inumbers( | |||
96 | void __user *buffer, /* buffer with inode info */ | 96 | void __user *buffer, /* buffer with inode info */ |
97 | inumbers_fmt_pf formatter); | 97 | inumbers_fmt_pf formatter); |
98 | 98 | ||
99 | int xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino); | ||
100 | |||
101 | #endif /* __XFS_ITABLE_H__ */ | 99 | #endif /* __XFS_ITABLE_H__ */ |