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>
This commit is contained in:
@@ -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(
|
|||||||
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(
|
|||||||
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(
|
|||||||
/*
|
/*
|
||||||
* 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;
|
||||||
|
|||||||
Reference in New Issue
Block a user