Commit 86bfd375 authored by Darrick J. Wong's avatar Darrick J. Wong

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: default avatarDarrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarBrian Foster <bfoster@redhat.com>
parent 9a4a5118
...@@ -1963,6 +1963,7 @@ xfs_iunlink( ...@@ -1963,6 +1963,7 @@ xfs_iunlink(
struct xfs_dinode *dip; struct xfs_dinode *dip;
struct xfs_buf *agibp; struct xfs_buf *agibp;
struct xfs_buf *ibp; struct xfs_buf *ibp;
xfs_agino_t next_agino;
xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, ip->i_ino); xfs_agnumber_t agno = XFS_INO_TO_AGNO(mp, ip->i_ino);
xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ip->i_ino); xfs_agino_t agino = XFS_INO_TO_AGINO(mp, ip->i_ino);
short bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS; short bucket_index = agino % XFS_AGI_UNLINKED_BUCKETS;
...@@ -1978,13 +1979,16 @@ xfs_iunlink( ...@@ -1978,13 +1979,16 @@ xfs_iunlink(
agi = XFS_BUF_TO_AGI(agibp); agi = XFS_BUF_TO_AGI(agibp);
/* /*
* Get the index into the agi hash table for the * Get the index into the agi hash table for the list this inode will
* list this inode will go on. * 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]); next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
ASSERT(be32_to_cpu(agi->agi_unlinked[bucket_index]) != agino); 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 * There is already another inode in the bucket we need
* to add ourselves to. Add us at the front of the list. * to add ourselves to. Add us at the front of the list.
...@@ -2045,17 +2049,17 @@ xfs_iunlink_remove( ...@@ -2045,17 +2049,17 @@ xfs_iunlink_remove(
agi = XFS_BUF_TO_AGI(agibp); agi = XFS_BUF_TO_AGI(agibp);
/* /*
* Get the index into the agi hash table for the * Get the index into the agi hash table for the list this inode will
* list this inode will go on. * go on. Make sure the head pointer isn't garbage.
*/ */
if (!xfs_verify_agino(mp, agno, next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
be32_to_cpu(agi->agi_unlinked[bucket_index]))) { if (!xfs_verify_agino(mp, agno, next_agino)) {
XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
agi, sizeof(*agi)); agi, sizeof(*agi));
return -EFSCORRUPTED; 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 * 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. * buffer to see if there is anyone after us on the list.
...@@ -2097,7 +2101,6 @@ xfs_iunlink_remove( ...@@ -2097,7 +2101,6 @@ xfs_iunlink_remove(
/* /*
* We need to search the list for the inode being freed. * We need to search the list for the inode being freed.
*/ */
next_agino = be32_to_cpu(agi->agi_unlinked[bucket_index]);
last_ibp = NULL; last_ibp = NULL;
while (next_agino != agino) { while (next_agino != agino) {
struct xfs_imap imap; struct xfs_imap imap;
......
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