]> git.proxmox.com Git - zfsonlinux.git/blobdiff - debian/patches/0022-abd_iter_page-don-t-use-compound-heads-on-Linux-4.5.patch
backport 2.2.4 staging for better 6.8 support
[zfsonlinux.git] / debian / patches / 0022-abd_iter_page-don-t-use-compound-heads-on-Linux-4.5.patch
diff --git a/debian/patches/0022-abd_iter_page-don-t-use-compound-heads-on-Linux-4.5.patch b/debian/patches/0022-abd_iter_page-don-t-use-compound-heads-on-Linux-4.5.patch
new file mode 100644 (file)
index 0000000..28dbbf9
--- /dev/null
@@ -0,0 +1,96 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Rob Norris <rob.norris@klarasystems.com>
+Date: Thu, 14 Mar 2024 10:57:30 +1100
+Subject: [PATCH] abd_iter_page: don't use compound heads on Linux <4.5
+
+Before 4.5 (specifically, torvalds/linux@ddc58f2), head and tail pages
+in a compound page were refcounted separately. This means that using the
+head page without taking a reference to it could see it cleaned up later
+before we're finished with it. Specifically, bio_add_page() would take a
+reference, and drop its reference after the bio completion callback
+returns.
+
+If the zio is executed immediately from the completion callback, this is
+usually ok, as any data is referenced through the tail page referenced
+by the ABD, and so becomes "live" that way. If there's a delay in zio
+execution (high load, error injection), then the head page can be freed,
+along with any dirty flags or other indicators that the underlying
+memory is used. Later, when the zio completes and that memory is
+accessed, its either unmapped and an unhandled fault takes down the
+entire system, or it is mapped and we end up messing around in someone
+else's memory. Both of these are very bad.
+
+The solution on these older kernels is to take a reference to the head
+page when we use it, and release it when we're done. There's not really
+a sensible way under our current structure to do this; the "best" would
+be to keep a list of head page references in the ABD, and release them
+when the ABD is freed.
+
+Since this additional overhead is totally unnecessary on 4.5+, where
+head and tail pages share refcounts, I've opted to simply not use the
+compound head in ABD page iteration there. This is theoretically less
+efficient (though cleaning up head page references would add overhead),
+but its safe, and we still get the other benefits of not mapping pages
+before adding them to a bio and not mis-splitting pages.
+
+There doesn't appear to be an obvious symbol name or config option we
+can match on to discover this behaviour in configure (and the mm/page
+APIs have changed a lot since then anyway), so I've gone with a simple
+version check.
+
+Reviewed-by: Alexander Motin <mav@FreeBSD.org>
+Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
+Signed-off-by: Rob Norris <rob.norris@klarasystems.com>
+Sponsored-by: Klara, Inc.
+Sponsored-by: Wasabi Technology, Inc.
+Closes #15533
+Closes #15588
+(cherry picked from commit c6be6ce1755a3d9a3cbe70256cd8958ef83d8542)
+---
+ module/os/linux/zfs/abd_os.c | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/module/os/linux/zfs/abd_os.c b/module/os/linux/zfs/abd_os.c
+index 3fe01c0b7..d3255dcbc 100644
+--- a/module/os/linux/zfs/abd_os.c
++++ b/module/os/linux/zfs/abd_os.c
+@@ -62,6 +62,7 @@
+ #include <linux/kmap_compat.h>
+ #include <linux/mm_compat.h>
+ #include <linux/scatterlist.h>
++#include <linux/version.h>
+ #endif
+ #ifdef _KERNEL
+@@ -1061,6 +1062,7 @@ abd_iter_page(struct abd_iter *aiter)
+       }
+       ASSERT(page);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
+       if (PageTail(page)) {
+               /*
+                * This page is part of a "compound page", which is a group of
+@@ -1082,11 +1084,23 @@ abd_iter_page(struct abd_iter *aiter)
+                * To do this, we need to adjust the offset to be counted from
+                * the head page. struct page for compound pages are stored
+                * contiguously, so we can just adjust by a simple offset.
++               *
++               * Before kernel 4.5, compound page heads were refcounted
++               * separately, such that moving back to the head page would
++               * require us to take a reference to it and releasing it once
++               * we're completely finished with it. In practice, that means
++               * when our caller is done with the ABD, which we have no
++               * insight into from here. Rather than contort this API to
++               * track head page references on such ancient kernels, we just
++               * compile this block out and use the tail pages directly. This
++               * is slightly less efficient, but makes everything far
++               * simpler.
+                */
+               struct page *head = compound_head(page);
+               doff += ((page - head) * PAGESIZE);
+               page = head;
+       }
++#endif
+       /* final page and position within it */
+       aiter->iter_page = page;