| 1603 | } |
| 1604 | |
| 1605 | void |
| 1606 | dnode_rele_and_unlock(dnode_t *dn, void *tag, boolean_t evicting) |
| 1607 | { |
| 1608 | uint64_t refs; |
| 1609 | /* Get while the hold prevents the dnode from moving. */ |
| 1610 | dmu_buf_impl_t *db = dn->dn_dbuf; |
| 1611 | dnode_handle_t *dnh = dn->dn_handle; |
| 1612 | |
| 1613 | refs = zfs_refcount_remove(&dn->dn_holds, tag); |
| 1614 | if (refs == 0) |
| 1615 | cv_broadcast(&dn->dn_nodnholds); |
| 1616 | mutex_exit(&dn->dn_mtx); |
| 1617 | /* dnode could get destroyed at this point, so don't use it anymore */ |
| 1618 | |
| 1619 | /* |
| 1620 | * It's unsafe to release the last hold on a dnode by dnode_rele() or |
| 1621 | * indirectly by dbuf_rele() while relying on the dnode handle to |
| 1622 | * prevent the dnode from moving, since releasing the last hold could |
| 1623 | * result in the dnode's parent dbuf evicting its dnode handles. For |
| 1624 | * that reason anyone calling dnode_rele() or dbuf_rele() without some |
| 1625 | * other direct or indirect hold on the dnode must first drop the dnode |
| 1626 | * handle. |
| 1627 | */ |
| 1628 | ASSERT(refs > 0 || dnh->dnh_zrlock.zr_owner != curthread); |
| 1629 | |
| 1630 | /* NOTE: the DNODE_DNODE does not have a dn_dbuf */ |
| 1631 | if (refs == 0 && db != NULL) { |
| 1632 | /* |
| 1633 | * Another thread could add a hold to the dnode handle in |
| 1634 | * dnode_hold_impl() while holding the parent dbuf. Since the |
| 1635 | * hold on the parent dbuf prevents the handle from being |
| 1636 | * destroyed, the hold on the handle is OK. We can't yet assert |
| 1637 | * that the handle has zero references, but that will be |
| 1638 | * asserted anyway when the handle gets destroyed. |
| 1639 | */ |
| 1640 | mutex_enter(&db->db_mtx); |
| 1641 | dbuf_rele_and_unlock(db, dnh, evicting); |
| 1642 | } |
| 1643 | } |
| 1644 | |
| 1645 | /* |
| 1646 | * Test whether we can create a dnode at the specified location. |
no test coverage detected