Skip to content

Commit

Permalink
xfs: create inode pointer verifiers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Darrick J. Wong committed Oct 26, 2017
1 parent 52c732e commit 91fb9af
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 28 deletions.
19 changes: 3 additions & 16 deletions fs/xfs/libxfs/xfs_dir2.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "xfs_bmap.h"
#include "xfs_dir2.h"
#include "xfs_dir2_priv.h"
#include "xfs_ialloc.h"
#include "xfs_error.h"
#include "xfs_trace.h"

Expand Down Expand Up @@ -202,22 +203,8 @@ xfs_dir_ino_validate(
xfs_mount_t *mp,
xfs_ino_t ino)
{
xfs_agblock_t agblkno;
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;
bool ino_ok = xfs_verify_dir_ino(mp, ino);

if (unlikely(XFS_TEST_ERROR(!ino_ok, mp, XFS_ERRTAG_DIR_INO_VALIDATE))) {
xfs_warn(mp, "Invalid inode number 0x%Lx",
(unsigned long long) ino);
Expand Down
90 changes: 90 additions & 0 deletions fs/xfs/libxfs/xfs_ialloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -2664,3 +2664,93 @@ xfs_ialloc_pagi_init(
xfs_trans_brelse(tp, bp);
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);
}
7 changes: 7 additions & 0 deletions fs/xfs/libxfs/xfs_ialloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

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__ */
10 changes: 0 additions & 10 deletions fs/xfs/xfs_itable.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,6 @@
#include "xfs_trace.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 0 if ok, else errno.
Expand Down
2 changes: 0 additions & 2 deletions fs/xfs/xfs_itable.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,4 @@ xfs_inumbers(
void __user *buffer, /* buffer with inode info */
inumbers_fmt_pf formatter);

int xfs_internal_inum(struct xfs_mount *mp, xfs_ino_t ino);

#endif /* __XFS_ITABLE_H__ */

0 comments on commit 91fb9af

Please sign in to comment.