* Try to change the block size for the indicated dnode. This can only * succeed if there are no blocks allocated or dirty beyond first block */
| 1737 | * succeed if there are no blocks allocated or dirty beyond first block |
| 1738 | */ |
| 1739 | int |
| 1740 | dnode_set_blksz(dnode_t *dn, uint64_t size, int ibs, dmu_tx_t *tx) |
| 1741 | { |
| 1742 | dmu_buf_impl_t *db; |
| 1743 | int err; |
| 1744 | |
| 1745 | ASSERT3U(size, <=, spa_maxblocksize(dmu_objset_spa(dn->dn_objset))); |
| 1746 | if (size == 0) |
| 1747 | size = SPA_MINBLOCKSIZE; |
| 1748 | else |
| 1749 | size = P2ROUNDUP(size, SPA_MINBLOCKSIZE); |
| 1750 | |
| 1751 | if (ibs == dn->dn_indblkshift) |
| 1752 | ibs = 0; |
| 1753 | |
| 1754 | if (size >> SPA_MINBLOCKSHIFT == dn->dn_datablkszsec && ibs == 0) |
| 1755 | return (0); |
| 1756 | |
| 1757 | rw_enter(&dn->dn_struct_rwlock, RW_WRITER); |
| 1758 | |
| 1759 | /* Check for any allocated blocks beyond the first */ |
| 1760 | if (dn->dn_maxblkid != 0) |
| 1761 | goto fail; |
| 1762 | |
| 1763 | mutex_enter(&dn->dn_dbufs_mtx); |
| 1764 | for (db = avl_first(&dn->dn_dbufs); db != NULL; |
| 1765 | db = AVL_NEXT(&dn->dn_dbufs, db)) { |
| 1766 | if (db->db_blkid != 0 && db->db_blkid != DMU_BONUS_BLKID && |
| 1767 | db->db_blkid != DMU_SPILL_BLKID) { |
| 1768 | mutex_exit(&dn->dn_dbufs_mtx); |
| 1769 | goto fail; |
| 1770 | } |
| 1771 | } |
| 1772 | mutex_exit(&dn->dn_dbufs_mtx); |
| 1773 | |
| 1774 | if (ibs && dn->dn_nlevels != 1) |
| 1775 | goto fail; |
| 1776 | |
| 1777 | /* resize the old block */ |
| 1778 | err = dbuf_hold_impl(dn, 0, 0, TRUE, FALSE, FTAG, &db); |
| 1779 | if (err == 0) { |
| 1780 | dbuf_new_size(db, size, tx); |
| 1781 | } else if (err != ENOENT) { |
| 1782 | goto fail; |
| 1783 | } |
| 1784 | |
| 1785 | dnode_setdblksz(dn, size); |
| 1786 | dnode_setdirty(dn, tx); |
| 1787 | dn->dn_next_blksz[tx->tx_txg&TXG_MASK] = size; |
| 1788 | if (ibs) { |
| 1789 | dn->dn_indblkshift = ibs; |
| 1790 | dn->dn_next_indblkshift[tx->tx_txg&TXG_MASK] = ibs; |
| 1791 | } |
| 1792 | /* release after we have fixed the blocksize in the dnode */ |
| 1793 | if (db) |
| 1794 | dbuf_rele(db, FTAG); |
| 1795 | |
| 1796 | rw_exit(&dn->dn_struct_rwlock); |
no test coverage detected