From 6fdbe7e375a02d409689f5f10b5ecfb1b4720bd4 Mon Sep 17 00:00:00 2001 From: Brian Behlendorf Date: Fri, 22 Aug 2025 18:21:08 -0700 Subject: [PATCH] panic in zfs arc_release during zfs send of encrypted dataset Authored by: Paul Zuchowski Reviewed by: Jerry Jelinek Reviewed by: Gordon Ross Reviewed by: Toomas Soome Approved by: Robert Mustacchi Illumos-issue: https://www.illumos.org/issues/14003 Illumos-commit: illumos/illumos-gate@b541cf35 Porting Notes: The b_cv was removed in #15340 preventing us from adopting this change without modification. Instead, we adopt the approach taken in #15340 to wait for any in progress IO. Additionally, update trace_arc.h on Linux to include the new dtrace probe. While not required I opted to keep it. Signed-off-by: Brian Behlendorf Issue #13479 --- include/os/linux/zfs/sys/trace_arc.h | 2 ++ module/zfs/arc.c | 33 ++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/include/os/linux/zfs/sys/trace_arc.h b/include/os/linux/zfs/sys/trace_arc.h index 39d75fbc4426..f1201acf6a50 100644 --- a/include/os/linux/zfs/sys/trace_arc.h +++ b/include/os/linux/zfs/sys/trace_arc.h @@ -105,6 +105,7 @@ DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__hit); DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__iohit); DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__evict); DEFINE_ARC_BUF_HDR_EVENT(zfs_arc__delete); +DEFINE_ARC_BUF_HDR_EVENT(zfs_arc_release__io); DEFINE_ARC_BUF_HDR_EVENT(zfs_new_state__mru); DEFINE_ARC_BUF_HDR_EVENT(zfs_new_state__mfu); DEFINE_ARC_BUF_HDR_EVENT(zfs_new_state__uncached); @@ -388,6 +389,7 @@ DEFINE_DTRACE_PROBE1(arc__hit); DEFINE_DTRACE_PROBE1(arc__iohit); DEFINE_DTRACE_PROBE1(arc__evict); DEFINE_DTRACE_PROBE1(arc__delete); +DEFINE_DTRACE_PROBE1(arc_release__io); DEFINE_DTRACE_PROBE1(new_state__mru); DEFINE_DTRACE_PROBE1(new_state__mfu); DEFINE_DTRACE_PROBE1(new_state__uncached); diff --git a/module/zfs/arc.c b/module/zfs/arc.c index df41e3b49204..656e45026879 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -6623,6 +6623,39 @@ arc_release(arc_buf_t *buf, const void *tag) kmutex_t *hash_lock = HDR_LOCK(hdr); mutex_enter(hash_lock); + /* + * Wait for any other IO for this hdr, as additional + * buf(s) could be about to appear, in which case + * we would not want to transition hdr to arc_anon. + */ + while (HDR_IO_IN_PROGRESS(hdr)) { + arc_callback_t *acb; + + DTRACE_PROBE1(arc_release__io, arc_buf_hdr_t *, hdr); + + acb = kmem_zalloc(sizeof (arc_callback_t), KM_SLEEP); + acb->acb_wait = B_TRUE; + mutex_init(&acb->acb_wait_lock, NULL, MUTEX_DEFAULT, NULL); + cv_init(&acb->acb_wait_cv, NULL, CV_DEFAULT, NULL); + + acb->acb_zio_head = hdr->b_l1hdr.b_acb->acb_zio_head; + acb->acb_next = hdr->b_l1hdr.b_acb; + hdr->b_l1hdr.b_acb->acb_prev = acb; + hdr->b_l1hdr.b_acb = acb; + + mutex_exit(hash_lock); + mutex_enter(&acb->acb_wait_lock); + while (acb->acb_wait) + cv_wait(&acb->acb_wait_cv, &acb->acb_wait_lock); + + mutex_exit(&acb->acb_wait_lock); + mutex_destroy(&acb->acb_wait_lock); + cv_destroy(&acb->acb_wait_cv); + kmem_free(acb, sizeof (arc_callback_t)); + + mutex_enter(hash_lock); + } + /* * This assignment is only valid as long as the hash_lock is * held, we must be careful not to reference state or the