aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Tetlow <gordon@FreeBSD.org>2024-04-24 20:25:48 +0000
committerGordon Tetlow <gordon@FreeBSD.org>2024-04-24 20:25:48 +0000
commitf5973f2e90e430ed97d65de8dd5230f6c4405f0d (patch)
tree1004d110511596be050254b466e795c2c839ae46
parent46373512563e22ddcbc134fe8015bab9675afa45 (diff)
downloaddoc-f5973f2e90e430ed97d65de8dd5230f6c4405f0d.tar.gz
doc-f5973f2e90e430ed97d65de8dd5230f6c4405f0d.zip
Add EN-24:09.
Approved by: so
-rw-r--r--website/data/security/errata.toml4
-rw-r--r--website/static/security/advisories/FreeBSD-EN-24:09.zfs.asc144
-rw-r--r--website/static/security/patches/EN-24:09/zfs.patch316
-rw-r--r--website/static/security/patches/EN-24:09/zfs.patch.asc16
4 files changed, 480 insertions, 0 deletions
diff --git a/website/data/security/errata.toml b/website/data/security/errata.toml
index 50d0a89e3a..702576a943 100644
--- a/website/data/security/errata.toml
+++ b/website/data/security/errata.toml
@@ -2,6 +2,10 @@
# $FreeBSD$
[[notices]]
+name = "FreeBSD-EN-24:09.zfs"
+date = "2024-04-24"
+
+[[notices]]
name = "FreeBSD-EN-24:08.kerberos"
date = "2024-03-28"
diff --git a/website/static/security/advisories/FreeBSD-EN-24:09.zfs.asc b/website/static/security/advisories/FreeBSD-EN-24:09.zfs.asc
new file mode 100644
index 0000000000..3a3b203d3a
--- /dev/null
+++ b/website/static/security/advisories/FreeBSD-EN-24:09.zfs.asc
@@ -0,0 +1,144 @@
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA512
+
+=============================================================================
+FreeBSD-EN-24:09.zfs Errata Notice
+ The FreeBSD Project
+
+Topic: High CPU usage by kernel threads related to ZFS
+
+Category: contrib
+Module: zfs
+Announced: 2024-04-24
+Affects: FreeBSD 13.3
+Corrected: 2024-04-12 13:00:11 UTC (stable/13, 13-STABLE)
+ 2024-04-24 20:21:10 UTC (releng/13.3, 13.3-RELEASE-p2)
+
+For general information regarding FreeBSD Errata Notices and Security
+Advisories, including descriptions of the fields above, security
+branches, and the following sections, please visit
+<URL:https://security.FreeBSD.org/>.
+
+I. Background
+
+ZFS is an advanced and scalable file system originally developed by Sun
+Microsystems for its Solaris operating system. ZFS was integrated as part of
+the FreeBSD starting with FreeBSD 7.0, and it has since become a prominent
+and preferred choice for storage management.
+
+II. Problem Description
+
+Because ZFS may consume large amounts of RAM to cache various types of
+filesystem objects, it continuously monitors system RAM available to decide
+whether to shrink its caches. Some caches are shrunk using a dedicated
+thread, to which work is dispatched asynchronously.
+
+In some cases, the cache shrinking logic may dispatch excessive amounts of
+work to the "ARC pruning" thread, causing it to continue attempting to shrink
+caches even after resource shortages are resolved.
+
+III. Impact
+
+The bug manifests as a kernel thread, "arc_prune", consuming 100% of a CPU core
+for indefinite periods, even while the system is otherwise idle. This behavior
+also impacts workloads running on the system, by reducing available CPU
+resources and by triggering lock contention in the kernel, in particular with
+the "vnlru" process whose function is to recycle vnodes (structures representing
+files, whether opened or cached), a mechanism frequently triggered by intensive
+filesystem workloads.
+
+IV. Workaround
+
+No workaround is available. Systems not using ZFS are unaffected.
+
+V. Solution
+
+Upgrade your system to a supported FreeBSD stable or release / security branch
+(releng) dated after the correction date. A reboot is required following the
+upgrade.
+
+Perform one of the following:
+
+1) To update your system via a binary patch:
+
+Systems running a RELEASE version of FreeBSD on the amd64 or arm64 platforms,
+or the i386 platform on FreeBSD 13 and earlier, can be updated via
+the freebsd-update(8) utility:
+
+# freebsd-update fetch
+# freebsd-update install
+# reboot
+
+2) To update your system via a source code patch:
+
+The following patches have been verified to apply to the applicable
+FreeBSD release branches.
+
+a) Download the relevant patch from the location below, and verify the
+detached PGP signature using your PGP utility.
+
+# fetch https://security.FreeBSD.org/patches/EN-24:09/zfs.patch
+# fetch https://security.FreeBSD.org/patches/EN-24:09/zfs.patch.asc
+# gpg --verify zfs.patch.asc
+
+b) Apply the patch. Execute the following commands as root:
+
+# cd /usr/src
+# patch < /path/to/patch
+
+c) Recompile your kernel as described in
+<URL:https://www.FreeBSD.org/handbook/kernelconfig.html> and reboot the
+system.
+
+VI. Correction details
+
+This issue is corrected as of the corresponding Git commit hash or Subversion
+revision number in the following stable and release branches:
+
+Branch/path Hash Revision
+- -------------------------------------------------------------------------
+stable/13/ 330954bdb822 stable/13-n257698
+releng/13.3/ 266b3bd3f26d releng/13.3-n257432
+- -------------------------------------------------------------------------
+
+Run the following command to see which files were modified by a
+particular commit:
+
+# git show --stat <commit hash>
+
+Or visit the following URL, replacing NNNNNN with the hash:
+
+<URL:https://cgit.freebsd.org/src/commit/?id=NNNNNN>
+
+To determine the commit count in a working tree (for comparison against
+nNNNNNN in the table above), run:
+
+# git rev-list --count --first-parent HEAD
+
+VII. References
+
+See problem reports
+<URL:https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=274698> and
+<URL:https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=275594>.
+
+See also the previous, similar errata notice issued for FreeBSD 14.0:
+<URL:https://security.FreeBSD.org/advisories/FreeBSD-EN-23:18.openzfs.asc>.
+
+The latest revision of this advisory is available at
+<URL:https://security.FreeBSD.org/advisories/FreeBSD-EN-24:09.zfs.asc>
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAEBCgAdFiEEthUnfoEIffdcgYM7bljekB8AGu8FAmYpapQACgkQbljekB8A
+Gu8gBxAAiuUNqeGaKNQ1XbV0kSucwnae5uOrQmthHQBY98PJJKUZpm1RTt/FnBB7
+qPxEY5vFRcGgZ43GVlnmfmH/EmqOg6WPpsgKfdq1XTy/ERU815JOsD+wKUWa/9Ia
+g67pnl8HPMSF5eZ1FreWfzNsWmxakiDLg2VXtFx7x3+qocifD/WwGvDTjdDBzzyK
++cIrBqvTlbOCRdHzl49wmNLz46ha5bmxTb7MzXB3jIQ1v+PZ71biyQxBZTrZgR6S
+La8oVe4Kj2lJTJw5S2xvsoyo5PzqmPCyD1m22fzgKTyaAUCXiioUUQDuFTxu9rhW
+I3lSvqdIRw28yRFjGslxlq9x1vShQTw3ILcH31ucxKUNow7hlDz4Ow2NzqXhSjxN
+RMGamxLTA5BcNCR4/DexAjfeh6OKnCG7n0ntlhxI0LWGr4ceT3/ySck7xhCNCSm1
+Ze/Gf9/j4+zR2jyauRANkITPkVHUV79/Sgjn1IlcMDLpzegH+QfQsX6CosG5uSWS
+UlpK2hhCv2g3lE7XuBItz7E/8i5Nx9RZgnh047Nj3ZB/6dCauAeUYKnY5X3xJa5X
+OKJWIGyJAyrCoFIg+LdBS47ggg8wswyyb1XBF2rZgZNqVmzZrJd7lBV/sjDaEC1H
+13lHhIIwtpTagDAT1Nbji++IT+2DatjhLZnMQwvALno0tIE19mg=
+=IgLQ
+-----END PGP SIGNATURE-----
diff --git a/website/static/security/patches/EN-24:09/zfs.patch b/website/static/security/patches/EN-24:09/zfs.patch
new file mode 100644
index 0000000000..48e3e06a44
--- /dev/null
+++ b/website/static/security/patches/EN-24:09/zfs.patch
@@ -0,0 +1,316 @@
+--- sys/contrib/openzfs/include/os/linux/zfs/sys/zpl.h.orig
++++ sys/contrib/openzfs/include/os/linux/zfs/sys/zpl.h
+@@ -52,7 +52,7 @@
+ extern const struct file_operations zpl_dir_file_operations;
+
+ /* zpl_super.c */
+-extern void zpl_prune_sb(int64_t nr_to_scan, void *arg);
++extern void zpl_prune_sb(uint64_t nr_to_scan, void *arg);
+
+ extern const struct super_operations zpl_super_operations;
+ extern const struct export_operations zpl_export_operations;
+--- sys/contrib/openzfs/include/sys/arc.h.orig
++++ sys/contrib/openzfs/include/sys/arc.h
+@@ -81,7 +81,7 @@
+ typedef void arc_read_done_func_t(zio_t *zio, const zbookmark_phys_t *zb,
+ const blkptr_t *bp, arc_buf_t *buf, void *priv);
+ typedef void arc_write_done_func_t(zio_t *zio, arc_buf_t *buf, void *priv);
+-typedef void arc_prune_func_t(int64_t bytes, void *priv);
++typedef void arc_prune_func_t(uint64_t bytes, void *priv);
+
+ /* Shared module parameters */
+ extern int zfs_arc_average_blocksize;
+--- sys/contrib/openzfs/include/sys/arc_impl.h.orig
++++ sys/contrib/openzfs/include/sys/arc_impl.h
+@@ -994,7 +994,6 @@
+
+ extern void arc_lowmem_init(void);
+ extern void arc_lowmem_fini(void);
+-extern void arc_prune_async(int64_t);
+ extern int arc_memory_throttle(spa_t *spa, uint64_t reserve, uint64_t txg);
+ extern uint64_t arc_free_memory(void);
+ extern int64_t arc_available_memory(void);
+--- sys/contrib/openzfs/module/os/freebsd/zfs/arc_os.c.orig
++++ sys/contrib/openzfs/module/os/freebsd/zfs/arc_os.c
+@@ -51,11 +51,6 @@
+ #include <sys/vm.h>
+ #include <sys/vmmeter.h>
+
+-#if __FreeBSD_version >= 1300139
+-static struct sx arc_vnlru_lock;
+-static struct vnode *arc_vnlru_marker;
+-#endif
+-
+ extern struct vfsops zfs_vfsops;
+
+ uint_t zfs_arc_free_target = 0;
+@@ -151,53 +146,6 @@
+ return (MAX(allmem * 5 / 8, size));
+ }
+
+-/*
+- * Helper function for arc_prune_async() it is responsible for safely
+- * handling the execution of a registered arc_prune_func_t.
+- */
+-static void
+-arc_prune_task(void *arg)
+-{
+- int64_t nr_scan = (intptr_t)arg;
+-
+-#ifndef __ILP32__
+- if (nr_scan > INT_MAX)
+- nr_scan = INT_MAX;
+-#endif
+-
+-#if __FreeBSD_version >= 1300139
+- sx_xlock(&arc_vnlru_lock);
+- vnlru_free_vfsops(nr_scan, &zfs_vfsops, arc_vnlru_marker);
+- sx_xunlock(&arc_vnlru_lock);
+-#else
+- vnlru_free(nr_scan, &zfs_vfsops);
+-#endif
+-}
+-
+-/*
+- * Notify registered consumers they must drop holds on a portion of the ARC
+- * buffered they reference. This provides a mechanism to ensure the ARC can
+- * honor the arc_meta_limit and reclaim otherwise pinned ARC buffers. This
+- * is analogous to dnlc_reduce_cache() but more generic.
+- *
+- * This operation is performed asynchronously so it may be safely called
+- * in the context of the arc_reclaim_thread(). A reference is taken here
+- * for each registered arc_prune_t and the arc_prune_task() is responsible
+- * for releasing it once the registered arc_prune_func_t has completed.
+- */
+-void
+-arc_prune_async(int64_t adjust)
+-{
+-
+-#ifndef __LP64__
+- if (adjust > INTPTR_MAX)
+- adjust = INTPTR_MAX;
+-#endif
+- taskq_dispatch(arc_prune_taskq, arc_prune_task,
+- (void *)(intptr_t)adjust, TQ_SLEEP);
+- ARCSTAT_BUMP(arcstat_prune);
+-}
+-
+ uint64_t
+ arc_all_memory(void)
+ {
+@@ -248,10 +196,6 @@
+ {
+ arc_event_lowmem = EVENTHANDLER_REGISTER(vm_lowmem, arc_lowmem, NULL,
+ EVENTHANDLER_PRI_FIRST);
+-#if __FreeBSD_version >= 1300139
+- arc_vnlru_marker = vnlru_alloc_marker();
+- sx_init(&arc_vnlru_lock, "arc vnlru lock");
+-#endif
+ }
+
+ void
+@@ -259,12 +203,6 @@
+ {
+ if (arc_event_lowmem != NULL)
+ EVENTHANDLER_DEREGISTER(vm_lowmem, arc_event_lowmem);
+-#if __FreeBSD_version >= 1300139
+- if (arc_vnlru_marker != NULL) {
+- vnlru_free_marker(arc_vnlru_marker);
+- sx_destroy(&arc_vnlru_lock);
+- }
+-#endif
+ }
+
+ void
+--- sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c.orig
++++ sys/contrib/openzfs/module/os/freebsd/zfs/zfs_vfsops.c
+@@ -2097,6 +2097,26 @@
+ #endif
+ }
+
++#if __FreeBSD_version >= 1300139
++static struct sx zfs_vnlru_lock;
++static struct vnode *zfs_vnlru_marker;
++#endif
++static arc_prune_t *zfs_prune;
++
++static void
++zfs_prune_task(uint64_t nr_to_scan, void *arg __unused)
++{
++ if (nr_to_scan > INT_MAX)
++ nr_to_scan = INT_MAX;
++#if __FreeBSD_version >= 1300139
++ sx_xlock(&zfs_vnlru_lock);
++ vnlru_free_vfsops(nr_to_scan, &zfs_vfsops, zfs_vnlru_marker);
++ sx_xunlock(&zfs_vnlru_lock);
++#else
++ vnlru_free(nr_to_scan, &zfs_vfsops);
++#endif
++}
++
+ void
+ zfs_init(void)
+ {
+@@ -2123,11 +2143,23 @@
+ dmu_objset_register_type(DMU_OST_ZFS, zpl_get_file_info);
+
+ zfsvfs_taskq = taskq_create("zfsvfs", 1, minclsyspri, 0, 0, 0);
++
++#if __FreeBSD_version >= 1300139
++ zfs_vnlru_marker = vnlru_alloc_marker();
++ sx_init(&zfs_vnlru_lock, "zfs vnlru lock");
++#endif
++ zfs_prune = arc_add_prune_callback(zfs_prune_task, NULL);
+ }
+
+ void
+ zfs_fini(void)
+ {
++ arc_remove_prune_callback(zfs_prune);
++#if __FreeBSD_version >= 1300139
++ vnlru_free_marker(zfs_vnlru_marker);
++ sx_destroy(&zfs_vnlru_lock);
++#endif
++
+ taskq_destroy(zfsvfs_taskq);
+ zfsctl_fini();
+ zfs_znode_fini();
+--- sys/contrib/openzfs/module/os/linux/zfs/arc_os.c.orig
++++ sys/contrib/openzfs/module/os/linux/zfs/arc_os.c
+@@ -491,57 +491,6 @@
+ }
+ #endif /* _KERNEL */
+
+-/*
+- * Helper function for arc_prune_async() it is responsible for safely
+- * handling the execution of a registered arc_prune_func_t.
+- */
+-static void
+-arc_prune_task(void *ptr)
+-{
+- arc_prune_t *ap = (arc_prune_t *)ptr;
+- arc_prune_func_t *func = ap->p_pfunc;
+-
+- if (func != NULL)
+- func(ap->p_adjust, ap->p_private);
+-
+- zfs_refcount_remove(&ap->p_refcnt, func);
+-}
+-
+-/*
+- * Notify registered consumers they must drop holds on a portion of the ARC
+- * buffered they reference. This provides a mechanism to ensure the ARC can
+- * honor the arc_meta_limit and reclaim otherwise pinned ARC buffers. This
+- * is analogous to dnlc_reduce_cache() but more generic.
+- *
+- * This operation is performed asynchronously so it may be safely called
+- * in the context of the arc_reclaim_thread(). A reference is taken here
+- * for each registered arc_prune_t and the arc_prune_task() is responsible
+- * for releasing it once the registered arc_prune_func_t has completed.
+- */
+-void
+-arc_prune_async(int64_t adjust)
+-{
+- arc_prune_t *ap;
+-
+- mutex_enter(&arc_prune_mtx);
+- for (ap = list_head(&arc_prune_list); ap != NULL;
+- ap = list_next(&arc_prune_list, ap)) {
+-
+- if (zfs_refcount_count(&ap->p_refcnt) >= 2)
+- continue;
+-
+- zfs_refcount_add(&ap->p_refcnt, ap->p_pfunc);
+- ap->p_adjust = adjust;
+- if (taskq_dispatch(arc_prune_taskq, arc_prune_task,
+- ap, TQ_SLEEP) == TASKQID_INVALID) {
+- zfs_refcount_remove(&ap->p_refcnt, ap->p_pfunc);
+- continue;
+- }
+- ARCSTAT_BUMP(arcstat_prune);
+- }
+- mutex_exit(&arc_prune_mtx);
+-}
+-
+ /* BEGIN CSTYLED */
+ ZFS_MODULE_PARAM(zfs_arc, zfs_arc_, shrinker_limit, INT, ZMOD_RW,
+ "Limit on number of pages that ARC shrinker can reclaim at once");
+--- sys/contrib/openzfs/module/os/linux/zfs/zpl_super.c.orig
++++ sys/contrib/openzfs/module/os/linux/zfs/zpl_super.c
+@@ -334,7 +334,7 @@
+ }
+
+ void
+-zpl_prune_sb(int64_t nr_to_scan, void *arg)
++zpl_prune_sb(uint64_t nr_to_scan, void *arg)
+ {
+ struct super_block *sb = (struct super_block *)arg;
+ int objects = 0;
+--- sys/contrib/openzfs/module/zfs/arc.c.orig
++++ sys/contrib/openzfs/module/zfs/arc.c
+@@ -868,6 +868,8 @@
+ static void l2arc_hdr_arcstats_update(arc_buf_hdr_t *hdr, boolean_t incr,
+ boolean_t state_only);
+
++static void arc_prune_async(uint64_t adjust);
++
+ #define l2arc_hdr_arcstats_increment(hdr) \
+ l2arc_hdr_arcstats_update((hdr), B_TRUE, B_FALSE)
+ #define l2arc_hdr_arcstats_decrement(hdr) \
+@@ -6521,6 +6523,56 @@
+ kmem_free(p, sizeof (*p));
+ }
+
++/*
++ * Helper function for arc_prune_async() it is responsible for safely
++ * handling the execution of a registered arc_prune_func_t.
++ */
++static void
++arc_prune_task(void *ptr)
++{
++ arc_prune_t *ap = (arc_prune_t *)ptr;
++ arc_prune_func_t *func = ap->p_pfunc;
++
++ if (func != NULL)
++ func(ap->p_adjust, ap->p_private);
++
++ zfs_refcount_remove(&ap->p_refcnt, func);
++}
++
++/*
++ * Notify registered consumers they must drop holds on a portion of the ARC
++ * buffers they reference. This provides a mechanism to ensure the ARC can
++ * honor the metadata limit and reclaim otherwise pinned ARC buffers.
++ *
++ * This operation is performed asynchronously so it may be safely called
++ * in the context of the arc_reclaim_thread(). A reference is taken here
++ * for each registered arc_prune_t and the arc_prune_task() is responsible
++ * for releasing it once the registered arc_prune_func_t has completed.
++ */
++static void
++arc_prune_async(uint64_t adjust)
++{
++ arc_prune_t *ap;
++
++ mutex_enter(&arc_prune_mtx);
++ for (ap = list_head(&arc_prune_list); ap != NULL;
++ ap = list_next(&arc_prune_list, ap)) {
++
++ if (zfs_refcount_count(&ap->p_refcnt) >= 2)
++ continue;
++
++ zfs_refcount_add(&ap->p_refcnt, ap->p_pfunc);
++ ap->p_adjust = adjust;
++ if (taskq_dispatch(arc_prune_taskq, arc_prune_task,
++ ap, TQ_SLEEP) == TASKQID_INVALID) {
++ zfs_refcount_remove(&ap->p_refcnt, ap->p_pfunc);
++ continue;
++ }
++ ARCSTAT_BUMP(arcstat_prune);
++ }
++ mutex_exit(&arc_prune_mtx);
++}
++
+ /*
+ * Notify the arc that a block was freed, and thus will never be used again.
+ */
diff --git a/website/static/security/patches/EN-24:09/zfs.patch.asc b/website/static/security/patches/EN-24:09/zfs.patch.asc
new file mode 100644
index 0000000000..52cdb325ff
--- /dev/null
+++ b/website/static/security/patches/EN-24:09/zfs.patch.asc
@@ -0,0 +1,16 @@
+-----BEGIN PGP SIGNATURE-----
+
+iQIzBAABCgAdFiEEthUnfoEIffdcgYM7bljekB8AGu8FAmYpapUACgkQbljekB8A
+Gu+L3BAA1EBD3O+tAqKg9W8MvPihcNkHCVX5gDvY9p/xiN6nmo7JQsdNmoycZVjF
+R07XpgAtuQ0mfw4fy/FvgAy4EK1q/SjQC/ON3zu78Hph610F2wabGW5p6qbotYl2
+P/msYGFPDqUgtw1SjVzXHKYRYjQnhQqbr2SIpH7ekOej65TiWuQSsRcl0YIQrjia
+RfeH6faIXUyjNnDrlu2L71GY9XxiWR3FGXTfnXWbguz17kuWctCxT8UMfVGRoLa+
+yxzPX1cVgEW86lDtlvlnPbymR4rohGPrGlmLdHJdwY0H855ff0kQrreQzcfNYf7Y
+xu/yxj51CF+ima7o8auDGPxGFzy3zkD5GQsLw2QoXG+Ad4EY4ZiaKYryqK7zug6Q
+V8Im3PPx2CXHXXs3FmVYA+RVMHJo79zlDEwE450bRfTaj/NzRUlO62v6jqpUjayr
+2pFVYwIyECm/qNddKY/4j/hMCjp11/H1co5uqFvXDWUfyVQB3iXHl5wjjyTdO8xw
+DS9dRtNAUiCxgOHgz6k0U9C6gi6Xh8NNLE9QSU3CWpFWuTgrzIwAXYoCryg/c7J+
+17M6DnK0NN9z3ScehrVT4QgPPzxp5ziLhY84ZJ8qpCPsYV7ZR/rU9Yc/+mT5N3SE
+QcJehAsEQUJjHL7EhkML61emj8i/avXau95AkCrcmHI5eLy1F+g=
+=Q5E+
+-----END PGP SIGNATURE-----