| 2042 | } |
| 2043 | |
| 2044 | void |
| 2045 | dnode_free_range(dnode_t *dn, uint64_t off, uint64_t len, dmu_tx_t *tx) |
| 2046 | { |
| 2047 | dmu_buf_impl_t *db; |
| 2048 | uint64_t blkoff, blkid, nblks; |
| 2049 | int blksz, blkshift, head, tail; |
| 2050 | int trunc = FALSE; |
| 2051 | int epbs; |
| 2052 | |
| 2053 | blksz = dn->dn_datablksz; |
| 2054 | blkshift = dn->dn_datablkshift; |
| 2055 | epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT; |
| 2056 | |
| 2057 | if (len == DMU_OBJECT_END) { |
| 2058 | len = UINT64_MAX - off; |
| 2059 | trunc = TRUE; |
| 2060 | } |
| 2061 | |
| 2062 | /* |
| 2063 | * First, block align the region to free: |
| 2064 | */ |
| 2065 | if (ISP2(blksz)) { |
| 2066 | head = P2NPHASE(off, blksz); |
| 2067 | blkoff = P2PHASE(off, blksz); |
| 2068 | if ((off >> blkshift) > dn->dn_maxblkid) |
| 2069 | return; |
| 2070 | } else { |
| 2071 | ASSERT(dn->dn_maxblkid == 0); |
| 2072 | if (off == 0 && len >= blksz) { |
| 2073 | /* |
| 2074 | * Freeing the whole block; fast-track this request. |
| 2075 | */ |
| 2076 | blkid = 0; |
| 2077 | nblks = 1; |
| 2078 | if (dn->dn_nlevels > 1) { |
| 2079 | rw_enter(&dn->dn_struct_rwlock, RW_WRITER); |
| 2080 | dnode_dirty_l1(dn, 0, tx); |
| 2081 | rw_exit(&dn->dn_struct_rwlock); |
| 2082 | } |
| 2083 | goto done; |
| 2084 | } else if (off >= blksz) { |
| 2085 | /* Freeing past end-of-data */ |
| 2086 | return; |
| 2087 | } else { |
| 2088 | /* Freeing part of the block. */ |
| 2089 | head = blksz - off; |
| 2090 | ASSERT3U(head, >, 0); |
| 2091 | } |
| 2092 | blkoff = off; |
| 2093 | } |
| 2094 | /* zero out any partial block data at the start of the range */ |
| 2095 | if (head) { |
| 2096 | int res; |
| 2097 | ASSERT3U(blkoff + head, ==, blksz); |
| 2098 | if (len < head) |
| 2099 | head = len; |
| 2100 | rw_enter(&dn->dn_struct_rwlock, RW_READER); |
| 2101 | res = dbuf_hold_impl(dn, 0, dbuf_whichblock(dn, 0, off), |
no test coverage detected