aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_ialloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_ialloc.c')
-rw-r--r--fs/xfs/xfs_ialloc.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c
index 0283e98a8130..6ac0c2986c32 100644
--- a/fs/xfs/xfs_ialloc.c
+++ b/fs/xfs/xfs_ialloc.c
@@ -1559,6 +1559,99 @@ error0:
1559} 1559}
1560 1560
1561/* 1561/*
1562 * Free an inode in the free inode btree.
1563 */
1564STATIC int
1565xfs_difree_finobt(
1566 struct xfs_mount *mp,
1567 struct xfs_trans *tp,
1568 struct xfs_buf *agbp,
1569 xfs_agino_t agino,
1570 struct xfs_inobt_rec_incore *ibtrec) /* inobt record */
1571{
1572 struct xfs_agi *agi = XFS_BUF_TO_AGI(agbp);
1573 xfs_agnumber_t agno = be32_to_cpu(agi->agi_seqno);
1574 struct xfs_btree_cur *cur;
1575 struct xfs_inobt_rec_incore rec;
1576 int offset = agino - ibtrec->ir_startino;
1577 int error;
1578 int i;
1579
1580 cur = xfs_inobt_init_cursor(mp, tp, agbp, agno, XFS_BTNUM_FINO);
1581
1582 error = xfs_inobt_lookup(cur, ibtrec->ir_startino, XFS_LOOKUP_EQ, &i);
1583 if (error)
1584 goto error;
1585 if (i == 0) {
1586 /*
1587 * If the record does not exist in the finobt, we must have just
1588 * freed an inode in a previously fully allocated chunk. If not,
1589 * something is out of sync.
1590 */
1591 XFS_WANT_CORRUPTED_GOTO(ibtrec->ir_freecount == 1, error);
1592
1593 error = xfs_inobt_insert_rec(cur, ibtrec->ir_freecount,
1594 ibtrec->ir_free, &i);
1595 if (error)
1596 goto error;
1597 ASSERT(i == 1);
1598
1599 goto out;
1600 }
1601
1602 /*
1603 * Read and update the existing record. We could just copy the ibtrec
1604 * across here, but that would defeat the purpose of having redundant
1605 * metadata. By making the modifications independently, we can catch
1606 * corruptions that we wouldn't see if we just copied from one record
1607 * to another.
1608 */
1609 error = xfs_inobt_get_rec(cur, &rec, &i);
1610 if (error)
1611 goto error;
1612 XFS_WANT_CORRUPTED_GOTO(i == 1, error);
1613
1614 rec.ir_free |= XFS_INOBT_MASK(offset);
1615 rec.ir_freecount++;
1616
1617 XFS_WANT_CORRUPTED_GOTO((rec.ir_free == ibtrec->ir_free) &&
1618 (rec.ir_freecount == ibtrec->ir_freecount),
1619 error);
1620
1621 /*
1622 * The content of inobt records should always match between the inobt
1623 * and finobt. The lifecycle of records in the finobt is different from
1624 * the inobt in that the finobt only tracks records with at least one
1625 * free inode. Hence, if all of the inodes are free and we aren't
1626 * keeping inode chunks permanently on disk, remove the record.
1627 * Otherwise, update the record with the new information.
1628 */
1629 if (rec.ir_freecount == mp->m_ialloc_inos &&
1630 !(mp->m_flags & XFS_MOUNT_IKEEP)) {
1631 error = xfs_btree_delete(cur, &i);
1632 if (error)
1633 goto error;
1634 ASSERT(i == 1);
1635 } else {
1636 error = xfs_inobt_update(cur, &rec);
1637 if (error)
1638 goto error;
1639 }
1640
1641out:
1642 error = xfs_check_agi_freecount(cur, agi);
1643 if (error)
1644 goto error;
1645
1646 xfs_btree_del_cursor(cur, XFS_BTREE_NOERROR);
1647 return 0;
1648
1649error:
1650 xfs_btree_del_cursor(cur, XFS_BTREE_ERROR);
1651 return error;
1652}
1653
1654/*
1562 * Free disk inode. Carefully avoids touching the incore inode, all 1655 * Free disk inode. Carefully avoids touching the incore inode, all
1563 * manipulations incore are the caller's responsibility. 1656 * manipulations incore are the caller's responsibility.
1564 * The on-disk inode is not changed by this operation, only the 1657 * The on-disk inode is not changed by this operation, only the
@@ -1626,6 +1719,15 @@ xfs_difree(
1626 if (error) 1719 if (error)
1627 goto error0; 1720 goto error0;
1628 1721
1722 /*
1723 * Fix up the free inode btree.
1724 */
1725 if (xfs_sb_version_hasfinobt(&mp->m_sb)) {
1726 error = xfs_difree_finobt(mp, tp, agbp, agino, &rec);
1727 if (error)
1728 goto error0;
1729 }
1730
1629 return 0; 1731 return 0;
1630 1732
1631error0: 1733error0: