diff options
| -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: |
