提交 3efa4ffd 编写于 作者: B Brian Foster 提交者: Dave Chinner

xfs: update the finobt on inode free

An inode free operation can have several effects on the finobt. If
all inodes have been freed and the chunk deallocated, we remove the
finobt record. If the inode chunk was previously full, we must
insert a new record based on the existing inobt record. Otherwise,
we modify the record in place.

Create the xfs_difree_finobt() function to identify the potential
scenarios and update the finobt appropriately.
Signed-off-by: NBrian Foster <bfoster@redhat.com>
Reviewed-by: NDave Chinner <dchinner@redhat.com>
Signed-off-by: NDave Chinner <david@fromorbit.com>
上级 2b64ee5c
......@@ -1558,6 +1558,99 @@ xfs_difree_inobt(
return error;
}
/*
* Free an inode in the free inode btree.
*/
STATIC int
xfs_difree_finobt(
struct xfs_mount *mp,
struct xfs_trans *tp,
struct xfs_buf *agbp,
xfs_agino_t agino,
struct xfs_inobt_rec_incore *ibtrec) /* inobt record */
{
struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
struct xfs_btree_cur *cur;
struct xfs_inobt_rec_incore rec;
int offset = agino - ibtrec->ir_startino;
int error;
int i;
cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
if (error)
goto error;
if (i == 0) {
/*
* If the record does not exist in the finobt, we must have just
* freed an inode in a previously fully allocated chunk. If not,
* something is out of sync.
*/
XFS_WANT_CORRUPTED_GOTO(ibtrec->ir_freecount == 1, error);
error = xfs_inobt_insert_rec(cur, ibtrec->ir_freecount,
ibtrec->ir_free, &i);
if (error)
goto error;
ASSERT(i == 1);
goto out;
}
/*
* Read and update the existing record. We could just copy the ibtrec
* across here, but that would defeat the purpose of having redundant
* metadata. By making the modifications independently, we can catch
* corruptions that we wouldn't see if we just copied from one record
* to another.
*/
error = xfs_inobt_get_rec(cur, &rec, &i);
if (error)
goto error;
XFS_WANT_CORRUPTED_GOTO(i == 1, error);
rec.ir_free |= XFS_INOBT_MASK(offset);
rec.ir_freecount++;
XFS_WANT_CORRUPTED_GOTO((rec.ir_free == ibtrec->ir_free) &&
(rec.ir_freecount == ibtrec->ir_freecount),
error);
/*
* The content of inobt records should always match between the inobt
* and finobt. The lifecycle of records in the finobt is different from
* the inobt in that the finobt only tracks records with at least one
* free inode. Hence, if all of the inodes are free and we aren't
* keeping inode chunks permanently on disk, remove the record.
* Otherwise, update the record with the new information.
*/
if (rec.ir_freecount == mp->m_ialloc_inos &&
!(mp->m_flags & XFS_MOUNT_IKEEP)) {
error = xfs_btree_delete(cur, &i);
if (error)
goto error;
ASSERT(i == 1);
} else {
error = xfs_inobt_update(cur, &rec);
if (error)
goto error;
}
out:
error = xfs_check_agi_freecount(cur, agi);
if (error)
goto error;
xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
return 0;
error:
xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
return error;
}
/*
* Free disk inode. Carefully avoids touching the incore inode, all
* manipulations incore are the caller's responsibility.
......@@ -1626,6 +1719,15 @@ xfs_difree(
if (error)
goto error0;
/*
* Fix up the free inode btree.
*/
if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
error = xfs_difree_finobt(mp, tp, agbp, agino, &rec);
if (error)
goto error0;
}
return 0;
error0:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册