diff options
Diffstat (limited to 'fs/xfs/xfs_ialloc.c')
-rw-r--r-- | fs/xfs/xfs_ialloc.c | 102 |
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 | */ | ||
1564 | STATIC int | ||
1565 | xfs_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 | |||
1641 | out: | ||
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 | |||
1649 | error: | ||
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 | ||
1631 | error0: | 1733 | error0: |