|
68 | 68 | #include <sys/zio_compress.h>
|
69 | 69 | #include <zfs_fletcher.h>
|
70 | 70 | #include <sys/zio_checksum.h>
|
| 71 | +#include <sys/brt.h> |
71 | 72 |
|
72 | 73 | /*
|
73 | 74 | * The SPA supports block sizes up to 16MB. However, very large blocks
|
@@ -289,18 +290,41 @@ dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
|
289 | 290 | if (BP_GET_LOGICAL_BIRTH(bp) > dsl_dataset_phys(ds)->ds_prev_snap_txg) {
|
290 | 291 | int64_t delta;
|
291 | 292 |
|
292 |
| - dprintf_bp(bp, "freeing ds=%llu", (u_longlong_t)ds->ds_object); |
293 |
| - dsl_free(tx->tx_pool, tx->tx_txg, bp); |
| 293 | + /* |
| 294 | + * Put blocks that would create IO on the pool's deadlist for |
| 295 | + * dsl_process_async_destroys() to find. This is to prevent |
| 296 | + * zio_free() from creating a ZIO_TYPE_FREE IO for them, which |
| 297 | + * are very heavy and can lead to out-of-memory conditions if |
| 298 | + * something tries to free millions of blocks on the same txg. |
| 299 | + */ |
| 300 | + boolean_t defer = spa_version(spa) >= SPA_VERSION_DEADLISTS && |
| 301 | + (BP_IS_GANG(bp) || BP_GET_DEDUP(bp) || |
| 302 | + brt_maybe_exists(spa, bp)); |
| 303 | + |
| 304 | + if (defer) { |
| 305 | + dprintf_bp(bp, "putting on free list: %s", ""); |
| 306 | + bpobj_enqueue(&ds->ds_dir->dd_pool->dp_free_bpobj, |
| 307 | + bp, B_FALSE, tx); |
| 308 | + } else { |
| 309 | + dprintf_bp(bp, "freeing ds=%llu", |
| 310 | + (u_longlong_t)ds->ds_object); |
| 311 | + dsl_free(tx->tx_pool, tx->tx_txg, bp); |
| 312 | + } |
294 | 313 |
|
295 | 314 | mutex_enter(&ds->ds_lock);
|
296 | 315 | ASSERT(dsl_dataset_phys(ds)->ds_unique_bytes >= used ||
|
297 | 316 | !DS_UNIQUE_IS_ACCURATE(ds));
|
298 | 317 | delta = parent_delta(ds, -used);
|
299 | 318 | dsl_dataset_phys(ds)->ds_unique_bytes -= used;
|
300 | 319 | mutex_exit(&ds->ds_lock);
|
| 320 | + |
301 | 321 | dsl_dir_diduse_transfer_space(ds->ds_dir,
|
302 | 322 | delta, -compressed, -uncompressed, -used,
|
303 | 323 | DD_USED_REFRSRV, DD_USED_HEAD, tx);
|
| 324 | + |
| 325 | + if (defer) |
| 326 | + dsl_dir_diduse_space(tx->tx_pool->dp_free_dir, |
| 327 | + DD_USED_HEAD, used, compressed, uncompressed, tx); |
304 | 328 | } else {
|
305 | 329 | dprintf_bp(bp, "putting on dead list: %s", "");
|
306 | 330 | if (async) {
|
|
0 commit comments