Commit 91fb9afc authored by Darrick J. Wong's avatar Darrick J. Wong

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: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
parent 52c732ee
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include "xfs_bmap.h" #include "xfs_bmap.h"
#include "xfs_dir2.h" #include "xfs_dir2.h"
#include "xfs_dir2_priv.h" #include "xfs_dir2_priv.h"
#include "xfs_ialloc.h"
#include "xfs_error.h" #include "xfs_error.h"
#include "xfs_trace.h" #include "xfs_trace.h"
...@@ -202,22 +203,8 @@ xfs_dir_ino_validate( ...@@ -202,22 +203,8 @@ xfs_dir_ino_validate(
xfs_mount_t *mp, xfs_mount_t *mp,
xfs_ino_t ino) xfs_ino_t ino)
{ {
xfs_agblock_t agblkno; bool ino_ok = xfs_verify_dir_ino(mp, ino);
xfs_agino_t agino;
xfs_agnumber_t agno;
int ino_ok;
int ioff;
agno = XFS_INO_TO_AGNO(mp, ino);
agblkno = XFS_INO_TO_AGBNO(mp, ino);
ioff = XFS_INO_TO_OFFSET(mp, ino);
agino = XFS_OFFBNO_TO_AGINO(mp, agblkno, ioff);
ino_ok =
agno < mp->m_sb.sb_agcount &&
agblkno < mp->m_sb.sb_agblocks &&
agblkno != 0 &&
ioff < (1 << mp->m_sb.sb_inopblog) &&
XFS_AGINO_TO_INO(mp, agno, agino) == ino;
if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) { if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) {
xfs_warn(mp, "Invalid inode number 0x%Lx", xfs_warn(mp, "Invalid inode number 0x%Lx",
(unsigned long long) ino); (unsigned long long) ino);
......
...@@ -2664,3 +2664,93 @@ xfs_ialloc_pagi_init( ...@@ -2664,3 +2664,93 @@ xfs_ialloc_pagi_init(
xfs_trans_brelse(tp, bp); xfs_trans_brelse(tp, bp);
return 0; return 0;
} }
/* Calculate the first and last possible inode number in an AG. */
void
xfs_ialloc_agino_range(
struct xfs_mount *mp,
xfs_agnumber_t agno,
xfs_agino_t *first,
xfs_agino_t *last)
{
xfs_agblock_t bno;
xfs_agblock_t eoag;
eoag = xfs_ag_block_count(mp, agno);
/*
* Calculate the first inode, which will be in the first
* cluster-aligned block after the AGFL.
*/
bno = round_up(XFS_AGFL_BLOCK(mp) + 1,
xfs_ialloc_cluster_alignment(mp));
*first = XFS_OFFBNO_TO_AGINO(mp, bno, 0);
/*
* Calculate the last inode, which will be at the end of the
* last (aligned) cluster that can be allocated in the AG.
*/
bno = round_down(eoag, xfs_ialloc_cluster_alignment(mp));
*last = XFS_OFFBNO_TO_AGINO(mp, bno, 0) - 1;
}
/*
* Verify that an AG inode number pointer neither points outside the AG
* nor points at static metadata.
*/
bool
xfs_verify_agino(
struct xfs_mount *mp,
xfs_agnumber_t agno,
xfs_agino_t agino)
{
xfs_agino_t first;
xfs_agino_t last;
xfs_ialloc_agino_range(mp, agno, &first, &last);
return agino >= first && agino <= last;
}
/*
* Verify that an FS inode number pointer neither points outside the
* filesystem nor points at static AG metadata.
*/
bool
xfs_verify_ino(
struct xfs_mount *mp,
xfs_ino_t ino)
{
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, ino);
xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ino);
if (agno >= mp->m_sb.sb_agcount)
return false;
if (XFS_AGINO_TO_INO(mp, agno, agino) != ino)
return false;
return xfs_verify_agino(mp, agno, agino);
}
/* Is this an internal inode number? */
bool
xfs_internal_inum(
struct xfs_mount *mp,
xfs_ino_t ino)
{
return ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
(xfs_sb_version_hasquota(&mp->m_sb) &&
xfs_is_quota_inode(&mp->m_sb, ino));
}
/*
* Verify that a directory entry's inode number doesn't point at an internal
* inode, empty space, or static AG metadata.
*/
bool
xfs_verify_dir_ino(
struct xfs_mount *mp,
xfs_ino_t ino)
{
if (xfs_internal_inum(mp, ino))
return false;
return xfs_verify_ino(mp, ino);
}
...@@ -173,5 +173,12 @@ void xfs_inobt_btrec_to_irec(struct xfs_mount *mp, union xfs_btree_rec *rec, ...@@ -173,5 +173,12 @@ void xfs_inobt_btrec_to_irec(struct xfs_mount *mp, union xfs_btree_rec *rec,
struct xfs_inobt_rec_incore *irec); struct xfs_inobt_rec_incore *irec);
int xfs_ialloc_cluster_alignment(struct xfs_mount *mp); int xfs_ialloc_cluster_alignment(struct xfs_mount *mp);
void xfs_ialloc_agino_range(struct xfs_mount *mp, xfs_agnumber_t agno,
xfs_agino_t *first, xfs_agino_t *last);
bool xfs_verify_agino(struct xfs_mount *mp, xfs_agnumber_t agno,
xfs_agino_t agino);
bool xfs_verify_ino(struct xfs_mount *mp, xfs_ino_t ino);
bool xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino);
bool xfs_verify_dir_ino(struct xfs_mount *mp, xfs_ino_t ino);
#endif /* __XFS_IALLOC_H__ */ #endif /* __XFS_IALLOC_H__ */
...@@ -31,16 +31,6 @@ ...@@ -31,16 +31,6 @@
#include "xfs_trace.h" #include "xfs_trace.h"
#include "xfs_icache.h" #include "xfs_icache.h"
int
xfs_internal_inum(
xfs_mount_t *mp,
xfs_ino_t ino)
{
return (ino == mp->m_sb.sb_rbmino || ino == mp->m_sb.sb_rsumino ||
(xfs_sb_version_hasquota(&mp->m_sb) &&
xfs_is_quota_inode(&mp->m_sb, ino)));
}
/* /*
* Return stat information for one inode. * Return stat information for one inode.
* Return 0 if ok, else errno. * Return 0 if ok, else errno.
......
...@@ -96,6 +96,4 @@ xfs_inumbers( ...@@ -96,6 +96,4 @@ xfs_inumbers(
void __user *buffer, /* buffer with inode info */ void __user *buffer, /* buffer with inode info */
inumbers_fmt_pf formatter); inumbers_fmt_pf formatter);
int xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino);
#endif /* __XFS_ITABLE_H__ */ #endif /* __XFS_ITABLE_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment