Skip to content

Commit

Permalink
xfs: strengthen AGI unlinked inode bucket pointer checks
Browse files Browse the repository at this point in the history
Strengthen our checking of the AGI unlinked pointers when we start to
use them for updating the metadata.

Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Brian Foster <bfoster@redhat.com>
  • Loading branch information
Darrick J. Wong committed Feb 12, 2019
1 parent 9a4a511 commit 86bfd37
Showing 1 changed file with 14 additions and 11 deletions.
25 changes: 14 additions & 11 deletions fs/xfs/xfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1963,6 +1963,7 @@ xfs_iunlink(
struct xfs_dinode *dip;
struct xfs_buf *agibp;
struct xfs_buf *ibp;
xfs_agino_t next_agino;
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
short bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
Expand All @@ -1978,13 +1979,16 @@ xfs_iunlink(
agi = XFS_BUF_TO_AGI(agibp);

/*
* Get the index into the agi hash table for the
* list this inode will go on.
* Get the index into the agi hash table for the list this inode will
* go on. Make sure the pointer isn't garbage and that this inode
* isn't already on the list.
*/
ASSERT(agi->agi_unlinked[bucket_index]);
ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != agino);
next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
if (next_agino == agino ||
!xfs_verify_agino_or_null(mp, agno, next_agino))
return -EFSCORRUPTED;

if (agi->agi_unlinked[bucket_index] != cpu_to_be32(NULLAGINO)) {
if (next_agino != NULLAGINO) {
/*
* There is already another inode in the bucket we need
* to add ourselves to. Add us at the front of the list.
Expand Down Expand Up @@ -2045,17 +2049,17 @@ xfs_iunlink_remove(
agi = XFS_BUF_TO_AGI(agibp);

/*
* Get the index into the agi hash table for the
* list this inode will go on.
* Get the index into the agi hash table for the list this inode will
* go on. Make sure the head pointer isn't garbage.
*/
if (!xfs_verify_agino(mp, agno,
be32_to_cpu(agi->agi_unlinked[bucket_index]))) {
next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
if (!xfs_verify_agino(mp, agno, next_agino)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
agi, sizeof(*agi));
return -EFSCORRUPTED;
}

if (be32_to_cpu(agi->agi_unlinked[bucket_index]) == agino) {
if (next_agino == agino) {
/*
* We're at the head of the list. Get the inode's on-disk
* buffer to see if there is anyone after us on the list.
Expand Down Expand Up @@ -2097,7 +2101,6 @@ xfs_iunlink_remove(
/*
* We need to search the list for the inode being freed.
*/
next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
last_ibp = NULL;
while (next_agino != agino) {
struct xfs_imap imap;
Expand Down

0 comments on commit 86bfd37

Please sign in to comment.