From 0c45e1b4d72d13b0fba02d247a535b73a7c9c9b4 Mon Sep 17 00:00:00 2001 From: Matthew Macy Date: Tue, 13 Oct 2020 21:03:36 -0700 Subject: [PATCH] dmu_zfetch: don't leak unreferenced stream when zfetch is freed Currently streams are only freed when: - They have no referencing zfetch and and their I/O references go to zero. - They are more than 2s old and a new I/O request comes in on the same zfetch. This means that we will leak unreferenced streams when their zfetch structure is freed. This change checks the reference count on a stream at zfetch free time. If it is zero we free it immediately. If it has remaining references we allow the prefetch callback to free it at I/O completion time. Reviewed-by: Brian Behlendorf Reviewed-by: Adam Moss Reviewed-by: Ryan Moeller Signed-off-by: Matt Macy Closes #11052 --- module/zfs/dmu_zfetch.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/module/zfs/dmu_zfetch.c b/module/zfs/dmu_zfetch.c index fa43fe4fcefd..5d061fe3813e 100644 --- a/module/zfs/dmu_zfetch.c +++ b/module/zfs/dmu_zfetch.c @@ -161,8 +161,12 @@ dmu_zfetch_fini(zfetch_t *zf) zstream_t *zs; mutex_enter(&zf->zf_lock); - while ((zs = list_head(&zf->zf_stream)) != NULL) - dmu_zfetch_stream_orphan(zf, zs); + while ((zs = list_head(&zf->zf_stream)) != NULL) { + if (zfs_refcount_count(&zs->zs_blocks) != 0) + dmu_zfetch_stream_orphan(zf, zs); + else + dmu_zfetch_stream_remove(zf, zs); + } mutex_exit(&zf->zf_lock); list_destroy(&zf->zf_stream); mutex_destroy(&zf->zf_lock);