diff options
author | Darrick J. Wong <darrick.wong@oracle.com> | 2019-02-07 19:37:14 +0100 |
---|---|---|
committer | Darrick J. Wong <darrick.wong@oracle.com> | 2019-02-12 01:07:01 +0100 |
commit | 86bfd3750fb3070932ae2da4cb5b9ae743c13f99 (patch) | |
tree | fcd557e74d85c65c119e67fdb1c66bc7bb5664cf /fs/xfs/xfs_inode.c | |
parent | xfs: refactor AGI unlinked bucket updates (diff) | |
download | linux-86bfd3750fb3070932ae2da4cb5b9ae743c13f99.tar.xz linux-86bfd3750fb3070932ae2da4cb5b9ae743c13f99.zip |
xfs: strengthen AGI unlinked inode bucket pointer checks
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>
Diffstat (limited to '')
-rw-r--r-- | fs/xfs/xfs_inode.c | 25 |
1 files changed, 14 insertions, 11 deletions
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index f1de80e8b9a6..ba19cfd52b5e 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -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; @@ -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. @@ -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. @@ -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; |