dsl_dataset: put IO-inducing frees on the pool deadlist
commit46c4f2ce0baafe161c726a72a38573354228fe10
authorRob Norris <rob.norris@klarasystems.com>
Wed, 13 Nov 2024 15:38:42 +0000 (14 02:38 +1100)
committerGitHub <noreply@github.com>
Wed, 13 Nov 2024 15:38:42 +0000 (13 07:38 -0800)
treef31a7e87953e1a9246cb2861a8375229b3e9939a
parenta60ed3822b61d6a1cb10d634051e0ab70dcac802
dsl_dataset: put IO-inducing frees on the pool deadlist

dsl_free() calls zio_free() to free the block. For most blocks, this
simply calls metaslab_free() without doing any IO or putting anything on
the IO pipeline.

Some blocks however require additional IO to free. This at least
includes gang, dedup and cloned blocks. For those, zio_free() will issue
a ZIO_TYPE_FREE IO and return.

If a huge number of blocks are being freed all at once, it's possible
for dsl_dataset_block_kill() to be called millions of time on a single
transaction (eg a 2T object of 128K blocks is 16M blocks). If those are
all IO-inducing frees, that then becomes 16M FREE IOs placed on the
pipeline. At time of writing, a zio_t is 1280 bytes, so for just one 2T
object that requires a 20G allocation of resident memory from the
zio_cache. If that can't be satisfied by the kernel, an out-of-memory
condition is raised.

This would be better handled by improving the cases that the
dmu_tx_assign() throttle will handle, or by reducing the overheads
required by the IO pipeline, or with a better central facility for
freeing blocks.

For now, we simply check for the cases that would cause zio_free() to
create a FREE IO, and instead put the block on the pool's freelist. This
is the same place that blocks from destroyed datasets go, and the async
destroy machinery will automatically see them and trickle them out as
normal.

Sponsored-by: Klara, Inc.
Sponsored-by: Wasabi Technology, Inc.
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
Closes #6783
Closes #16708
Closes #16722
Closes #16697
module/zfs/dsl_dataset.c