aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2014-04-24 02:00:53 -0400
committerDave Chinner <david@fromorbit.com>2014-04-24 02:00:53 -0400
commit3efa4ffd58a04f859713daaf910f1f1ff8ef647f (patch)
treeb103ea8df040f239429d9a29d7ae5876933c8cae
parent2b64ee5cdc106704b5c0f8954a52aa598eee25eb (diff)
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: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
-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: