Gentoo Archives: gentoo-commits

From: Sam James <sam@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] repo/gentoo:master commit in: sys-fs/zfs-kmod/files/, sys-fs/zfs-kmod/
Date: Mon, 08 Nov 2021 06:09:15
Message-Id: 1636351633.9fb275f656de639e25acc9497b70b4cae593d35d.sam@gentoo
1 commit: 9fb275f656de639e25acc9497b70b4cae593d35d
2 Author: Sam James <sam <AT> gentoo <DOT> org>
3 AuthorDate: Mon Nov 8 06:07:13 2021 +0000
4 Commit: Sam James <sam <AT> gentoo <DOT> org>
5 CommitDate: Mon Nov 8 06:07:13 2021 +0000
6 URL: https://gitweb.gentoo.org/repo/gentoo.git/commit/?id=9fb275f6
7
8 sys-fs/zfs-kmod: yank SEEK_HOLE patch for now
9
10 Preliminary investigation suggests this patch (and earlier iterations)
11 may introduce regressions. Let's yank it for now while we continue
12 the investigation with upstream.
13
14 Bug: https://bugs.gentoo.org/815469
15 See: https://github.com/openzfs/zfs/issues/11900
16 Signed-off-by: Sam James <sam <AT> gentoo.org>
17
18 sys-fs/zfs-kmod/files/2.1.1-fix-lseek-mmap.patch | 594 ---------------------
19 ...od-2.1.1-r1.ebuild => zfs-kmod-2.1.1-r2.ebuild} | 2 -
20 2 files changed, 596 deletions(-)
21
22 diff --git a/sys-fs/zfs-kmod/files/2.1.1-fix-lseek-mmap.patch b/sys-fs/zfs-kmod/files/2.1.1-fix-lseek-mmap.patch
23 deleted file mode 100644
24 index 2c3a66a97bf..00000000000
25 --- a/sys-fs/zfs-kmod/files/2.1.1-fix-lseek-mmap.patch
26 +++ /dev/null
27 @@ -1,594 +0,0 @@
28 -From de198f2d9507b6dcf3d0d8f037ba33940208733e Mon Sep 17 00:00:00 2001
29 -From: Brian Behlendorf <behlendorf1@××××.gov>
30 -Date: Sun, 7 Nov 2021 13:27:44 -0800
31 -Subject: [PATCH] Fix lseek(SEEK_DATA/SEEK_HOLE) mmap consistency
32 -
33 -When using lseek(2) to report data/holes memory mapped regions of
34 -the file were ignored. This could result in incorrect results.
35 -To handle this zfs_holey_common() was updated to asynchronously
36 -writeback any dirty mmap(2) regions prior to reporting holes.
37 -
38 -Additionally, while not strictly required, the dn_struct_rwlock is
39 -now held over the dirty check to prevent the dnode structure from
40 -changing. This ensures that a clean dnode can't be dirtied before
41 -the data/hole is located. The range lock is now also taken to
42 -ensure the call cannot race with zfs_write().
43 -
44 -Furthermore, the code was refactored to provide a dnode_is_dirty()
45 -helper function which checks the dnode for any dirty records to
46 -determine its dirtiness.
47 -
48 -Reviewed-by: Matthew Ahrens <mahrens@×××××××.com>
49 -Reviewed-by: Tony Hutter <hutter2@××××.gov>
50 -Reviewed-by: Rich Ercolani <rincebrain@×××××.com>
51 -Signed-off-by: Brian Behlendorf <behlendorf1@××××.gov>
52 -Issue #11900
53 -Closes #12724
54 ----
55 - configure.ac | 1 +
56 - include/os/freebsd/spl/sys/vnode.h | 18 +++
57 - include/os/freebsd/zfs/sys/zfs_znode_impl.h | 3 +-
58 - include/os/linux/zfs/sys/zfs_znode_impl.h | 1 +
59 - include/sys/dnode.h | 1 +
60 - man/man4/zfs.4 | 2 +-
61 - module/zfs/dmu.c | 53 ++++---
62 - module/zfs/dnode.c | 20 +++
63 - module/zfs/zfs_vnops.c | 9 +-
64 - tests/runfiles/common.run | 2 +-
65 - tests/zfs-tests/cmd/Makefile.am | 1 +
66 - tests/zfs-tests/cmd/mmap_seek/.gitignore | 1 +
67 - tests/zfs-tests/cmd/mmap_seek/Makefile.am | 6 +
68 - tests/zfs-tests/cmd/mmap_seek/mmap_seek.c | 147 ++++++++++++++++++
69 - tests/zfs-tests/include/commands.cfg | 1 +
70 - tests/zfs-tests/include/tunables.cfg | 1 +
71 - .../tests/functional/mmap/Makefile.am | 3 +-
72 - .../functional/mmap/mmap_seek_001_pos.ksh | 67 ++++++++
73 - 18 files changed, 305 insertions(+), 32 deletions(-)
74 - create mode 100644 tests/zfs-tests/cmd/mmap_seek/.gitignore
75 - create mode 100644 tests/zfs-tests/cmd/mmap_seek/Makefile.am
76 - create mode 100644 tests/zfs-tests/cmd/mmap_seek/mmap_seek.c
77 - create mode 100755 tests/zfs-tests/tests/functional/mmap/mmap_seek_001_pos.ksh
78 -
79 -diff --git a/configure.ac b/configure.ac
80 -index 6f34b210d2b..ebc7b276a64 100644
81 ---- a/configure.ac
82 -+++ b/configure.ac
83 -@@ -221,6 +221,7 @@ AC_CONFIG_FILES([
84 - tests/zfs-tests/cmd/mktree/Makefile
85 - tests/zfs-tests/cmd/mmap_exec/Makefile
86 - tests/zfs-tests/cmd/mmap_libaio/Makefile
87 -+ tests/zfs-tests/cmd/mmap_seek/Makefile
88 - tests/zfs-tests/cmd/mmapwrite/Makefile
89 - tests/zfs-tests/cmd/nvlist_to_lua/Makefile
90 - tests/zfs-tests/cmd/randfree_file/Makefile
91 -diff --git a/include/os/freebsd/spl/sys/vnode.h b/include/os/freebsd/spl/sys/vnode.h
92 -index 3670712a045..3bc8a18eeb7 100644
93 ---- a/include/os/freebsd/spl/sys/vnode.h
94 -+++ b/include/os/freebsd/spl/sys/vnode.h
95 -@@ -59,6 +59,8 @@ enum symfollow { NO_FOLLOW = NOFOLLOW };
96 - #include <sys/file.h>
97 - #include <sys/filedesc.h>
98 - #include <sys/syscallsubr.h>
99 -+#include <sys/vm.h>
100 -+#include <vm/vm_object.h>
101 -
102 - typedef struct vop_vector vnodeops_t;
103 - #define VOP_FID VOP_VPTOFH
104 -@@ -83,6 +85,22 @@ vn_is_readonly(vnode_t *vp)
105 - #define vn_has_cached_data(vp) \
106 - ((vp)->v_object != NULL && \
107 - (vp)->v_object->resident_page_count > 0)
108 -+
109 -+static __inline void
110 -+vn_flush_cached_data(vnode_t *vp, boolean_t sync)
111 -+{
112 -+#if __FreeBSD_version > 1300054
113 -+ if (vm_object_mightbedirty(vp->v_object)) {
114 -+#else
115 -+ if (vp->v_object->flags & OBJ_MIGHTBEDIRTY) {
116 -+#endif
117 -+ int flags = sync ? OBJPC_SYNC : 0;
118 -+ zfs_vmobject_wlock(vp->v_object);
119 -+ vm_object_page_clean(vp->v_object, 0, 0, flags);
120 -+ zfs_vmobject_wunlock(vp->v_object);
121 -+ }
122 -+}
123 -+
124 - #define vn_exists(vp) do { } while (0)
125 - #define vn_invalid(vp) do { } while (0)
126 - #define vn_renamepath(tdvp, svp, tnm, lentnm) do { } while (0)
127 -diff --git a/include/os/freebsd/zfs/sys/zfs_znode_impl.h b/include/os/freebsd/zfs/sys/zfs_znode_impl.h
128 -index 7d28bddbf51..4456046e6e4 100644
129 ---- a/include/os/freebsd/zfs/sys/zfs_znode_impl.h
130 -+++ b/include/os/freebsd/zfs/sys/zfs_znode_impl.h
131 -@@ -116,7 +116,8 @@ typedef struct zfs_soft_state {
132 - #define Z_ISLNK(type) ((type) == VLNK)
133 - #define Z_ISDIR(type) ((type) == VDIR)
134 -
135 --#define zn_has_cached_data(zp) vn_has_cached_data(ZTOV(zp))
136 -+#define zn_has_cached_data(zp) vn_has_cached_data(ZTOV(zp))
137 -+#define zn_flush_cached_data(zp, sync) vn_flush_cached_data(ZTOV(zp), sync)
138 - #define zn_rlimit_fsize(zp, uio) \
139 - vn_rlimit_fsize(ZTOV(zp), GET_UIO_STRUCT(uio), zfs_uio_td(uio))
140 -
141 -diff --git a/include/os/linux/zfs/sys/zfs_znode_impl.h b/include/os/linux/zfs/sys/zfs_znode_impl.h
142 -index 0a6273442b7..de46fc8f2bd 100644
143 ---- a/include/os/linux/zfs/sys/zfs_znode_impl.h
144 -+++ b/include/os/linux/zfs/sys/zfs_znode_impl.h
145 -@@ -71,6 +71,7 @@ extern "C" {
146 - #define Z_ISDIR(type) S_ISDIR(type)
147 -
148 - #define zn_has_cached_data(zp) ((zp)->z_is_mapped)
149 -+#define zn_flush_cached_data(zp, sync) write_inode_now(ZTOI(zp), sync)
150 - #define zn_rlimit_fsize(zp, uio) (0)
151 -
152 - /*
153 -diff --git a/include/sys/dnode.h b/include/sys/dnode.h
154 -index e7cccd044ab..3f5fcc958c3 100644
155 ---- a/include/sys/dnode.h
156 -+++ b/include/sys/dnode.h
157 -@@ -425,6 +425,7 @@ boolean_t dnode_add_ref(dnode_t *dn, void *ref);
158 - void dnode_rele(dnode_t *dn, void *ref);
159 - void dnode_rele_and_unlock(dnode_t *dn, void *tag, boolean_t evicting);
160 - int dnode_try_claim(objset_t *os, uint64_t object, int slots);
161 -+boolean_t dnode_is_dirty(dnode_t *dn);
162 - void dnode_setdirty(dnode_t *dn, dmu_tx_t *tx);
163 - void dnode_set_dirtyctx(dnode_t *dn, dmu_tx_t *tx, void *tag);
164 - void dnode_sync(dnode_t *dn, dmu_tx_t *tx);
165 -diff --git a/man/man4/zfs.4 b/man/man4/zfs.4
166 -index d7fc31bfde1..a136690c76e 100644
167 ---- a/man/man4/zfs.4
168 -+++ b/man/man4/zfs.4
169 -@@ -1586,7 +1586,7 @@ Allow no-operation writes.
170 - The occurrence of nopwrites will further depend on other pool properties
171 - .Pq i.a. the checksumming and compression algorithms .
172 - .
173 --.It Sy zfs_dmu_offset_next_sync Ns = Ns Sy 0 Ns | ns 1 Pq int
174 -+.It Sy zfs_dmu_offset_next_sync Ns = Ns Sy 0 Ns | Ns 1 Pq int
175 - Enable forcing TXG sync to find holes.
176 - When enabled forces ZFS to act like prior versions when
177 - .Sy SEEK_HOLE No or Sy SEEK_DATA
178 -diff --git a/module/zfs/dmu.c b/module/zfs/dmu.c
179 -index b29d82fd793..f12c5eda8b5 100644
180 ---- a/module/zfs/dmu.c
181 -+++ b/module/zfs/dmu.c
182 -@@ -2093,42 +2093,41 @@ int
183 - dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole, uint64_t *off)
184 - {
185 - dnode_t *dn;
186 -- int i, err;
187 -- boolean_t clean = B_TRUE;
188 -+ int err;
189 -
190 -+restart:
191 - err = dnode_hold(os, object, FTAG, &dn);
192 - if (err)
193 - return (err);
194 -
195 -- /*
196 -- * Check if dnode is dirty
197 -- */
198 -- for (i = 0; i < TXG_SIZE; i++) {
199 -- if (multilist_link_active(&dn->dn_dirty_link[i])) {
200 -- clean = B_FALSE;
201 -- break;
202 -- }
203 -- }
204 -+ rw_enter(&dn->dn_struct_rwlock, RW_READER);
205 -
206 -- /*
207 -- * If compatibility option is on, sync any current changes before
208 -- * we go trundling through the block pointers.
209 -- */
210 -- if (!clean && zfs_dmu_offset_next_sync) {
211 -- clean = B_TRUE;
212 -- dnode_rele(dn, FTAG);
213 -- txg_wait_synced(dmu_objset_pool(os), 0);
214 -- err = dnode_hold(os, object, FTAG, &dn);
215 -- if (err)
216 -- return (err);
217 -- }
218 -+ if (dnode_is_dirty(dn)) {
219 -+ /*
220 -+ * If the zfs_dmu_offset_next_sync module option is enabled
221 -+ * then strict hole reporting has been requested. Dirty
222 -+ * dnodes must be synced to disk to accurately report all
223 -+ * holes. When disabled (the default) dirty dnodes are
224 -+ * reported to not have any holes which is always safe.
225 -+ *
226 -+ * When called by zfs_holey_common() the zp->z_rangelock
227 -+ * is held to prevent zfs_write() and mmap writeback from
228 -+ * re-dirtying the dnode after txg_wait_synced().
229 -+ */
230 -+ if (zfs_dmu_offset_next_sync) {
231 -+ rw_exit(&dn->dn_struct_rwlock);
232 -+ dnode_rele(dn, FTAG);
233 -+ txg_wait_synced(dmu_objset_pool(os), 0);
234 -+ goto restart;
235 -+ }
236 -
237 -- if (clean)
238 -- err = dnode_next_offset(dn,
239 -- (hole ? DNODE_FIND_HOLE : 0), off, 1, 1, 0);
240 -- else
241 - err = SET_ERROR(EBUSY);
242 -+ } else {
243 -+ err = dnode_next_offset(dn, DNODE_FIND_HAVELOCK |
244 -+ (hole ? DNODE_FIND_HOLE : 0), off, 1, 1, 0);
245 -+ }
246 -
247 -+ rw_exit(&dn->dn_struct_rwlock);
248 - dnode_rele(dn, FTAG);
249 -
250 - return (err);
251 -diff --git a/module/zfs/dnode.c b/module/zfs/dnode.c
252 -index 900240479c7..6f87f49f89f 100644
253 ---- a/module/zfs/dnode.c
254 -+++ b/module/zfs/dnode.c
255 -@@ -1648,6 +1648,26 @@ dnode_try_claim(objset_t *os, uint64_t object, int slots)
256 - slots, NULL, NULL));
257 - }
258 -
259 -+/*
260 -+ * Checks if the dnode contains any uncommitted dirty records.
261 -+ */
262 -+boolean_t
263 -+dnode_is_dirty(dnode_t *dn)
264 -+{
265 -+ mutex_enter(&dn->dn_mtx);
266 -+
267 -+ for (int i = 0; i < TXG_SIZE; i++) {
268 -+ if (list_head(&dn->dn_dirty_records[i]) != NULL) {
269 -+ mutex_exit(&dn->dn_mtx);
270 -+ return (B_TRUE);
271 -+ }
272 -+ }
273 -+
274 -+ mutex_exit(&dn->dn_mtx);
275 -+
276 -+ return (B_FALSE);
277 -+}
278 -+
279 - void
280 - dnode_setdirty(dnode_t *dn, dmu_tx_t *tx)
281 - {
282 -diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c
283 -index a83f0b02ab5..7cbb70f499a 100644
284 ---- a/module/zfs/zfs_vnops.c
285 -+++ b/module/zfs/zfs_vnops.c
286 -@@ -85,6 +85,7 @@ zfs_fsync(znode_t *zp, int syncflag, cred_t *cr)
287 - static int
288 - zfs_holey_common(znode_t *zp, ulong_t cmd, loff_t *off)
289 - {
290 -+ zfs_locked_range_t *lr;
291 - uint64_t noff = (uint64_t)*off; /* new offset */
292 - uint64_t file_sz;
293 - int error;
294 -@@ -100,12 +101,18 @@ zfs_holey_common(znode_t *zp, ulong_t cmd, loff_t *off)
295 - else
296 - hole = B_FALSE;
297 -
298 -+ /* Flush any mmap()'d data to disk */
299 -+ if (zn_has_cached_data(zp))
300 -+ zn_flush_cached_data(zp, B_FALSE);
301 -+
302 -+ lr = zfs_rangelock_enter(&zp->z_rangelock, 0, file_sz, RL_READER);
303 - error = dmu_offset_next(ZTOZSB(zp)->z_os, zp->z_id, hole, &noff);
304 -+ zfs_rangelock_exit(lr);
305 -
306 - if (error == ESRCH)
307 - return (SET_ERROR(ENXIO));
308 -
309 -- /* file was dirty, so fall back to using generic logic */
310 -+ /* File was dirty, so fall back to using generic logic */
311 - if (error == EBUSY) {
312 - if (hole)
313 - *off = file_sz;
314 -diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run
315 -index 7f7d161be35..9f181b53e15 100644
316 ---- a/tests/runfiles/common.run
317 -+++ b/tests/runfiles/common.run
318 -@@ -675,7 +675,7 @@ tests = ['migration_001_pos', 'migration_002_pos', 'migration_003_pos',
319 - tags = ['functional', 'migration']
320 -
321 - [tests/functional/mmap]
322 --tests = ['mmap_write_001_pos', 'mmap_read_001_pos']
323 -+tests = ['mmap_write_001_pos', 'mmap_read_001_pos', 'mmap_seek_001_pos']
324 - tags = ['functional', 'mmap']
325 -
326 - [tests/functional/mount]
327 -diff --git a/tests/zfs-tests/cmd/Makefile.am b/tests/zfs-tests/cmd/Makefile.am
328 -index 2b965ca7000..d1c29fcd1c6 100644
329 ---- a/tests/zfs-tests/cmd/Makefile.am
330 -+++ b/tests/zfs-tests/cmd/Makefile.am
331 -@@ -19,6 +19,7 @@ SUBDIRS = \
332 - mktree \
333 - mmap_exec \
334 - mmap_libaio \
335 -+ mmap_seek \
336 - mmapwrite \
337 - nvlist_to_lua \
338 - randwritecomp \
339 -diff --git a/tests/zfs-tests/cmd/mmap_seek/.gitignore b/tests/zfs-tests/cmd/mmap_seek/.gitignore
340 -new file mode 100644
341 -index 00000000000..6b05a791750
342 ---- /dev/null
343 -+++ b/tests/zfs-tests/cmd/mmap_seek/.gitignore
344 -@@ -0,0 +1 @@
345 -+/mmap_seek
346 -diff --git a/tests/zfs-tests/cmd/mmap_seek/Makefile.am b/tests/zfs-tests/cmd/mmap_seek/Makefile.am
347 -new file mode 100644
348 -index 00000000000..b938931125f
349 ---- /dev/null
350 -+++ b/tests/zfs-tests/cmd/mmap_seek/Makefile.am
351 -@@ -0,0 +1,6 @@
352 -+include $(top_srcdir)/config/Rules.am
353 -+
354 -+pkgexecdir = $(datadir)/@PACKAGE@/zfs-tests/bin
355 -+
356 -+pkgexec_PROGRAMS = mmap_seek
357 -+mmap_seek_SOURCES = mmap_seek.c
358 -diff --git a/tests/zfs-tests/cmd/mmap_seek/mmap_seek.c b/tests/zfs-tests/cmd/mmap_seek/mmap_seek.c
359 -new file mode 100644
360 -index 00000000000..f476e1dba9a
361 ---- /dev/null
362 -+++ b/tests/zfs-tests/cmd/mmap_seek/mmap_seek.c
363 -@@ -0,0 +1,147 @@
364 -+/*
365 -+ * CDDL HEADER START
366 -+ *
367 -+ * The contents of this file are subject to the terms of the
368 -+ * Common Development and Distribution License (the "License").
369 -+ * You may not use this file except in compliance with the License.
370 -+ *
371 -+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
372 -+ * or http://www.opensolaris.org/os/licensing.
373 -+ * See the License for the specific language governing permissions
374 -+ * and limitations under the License.
375 -+ *
376 -+ * When distributing Covered Code, include this CDDL HEADER in each
377 -+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
378 -+ * If applicable, add the following below this CDDL HEADER, with the
379 -+ * fields enclosed by brackets "[]" replaced with your own identifying
380 -+ * information: Portions Copyright [yyyy] [name of copyright owner]
381 -+ *
382 -+ * CDDL HEADER END
383 -+ */
384 -+
385 -+/*
386 -+ * Copyright (c) 2021 by Lawrence Livermore National Security, LLC.
387 -+ */
388 -+
389 -+#include <unistd.h>
390 -+#include <fcntl.h>
391 -+#include <stdio.h>
392 -+#include <stdlib.h>
393 -+#include <string.h>
394 -+#include <sys/mman.h>
395 -+#include <errno.h>
396 -+
397 -+static void
398 -+seek_data(int fd, off_t offset, off_t expected)
399 -+{
400 -+ off_t data_offset = lseek(fd, offset, SEEK_DATA);
401 -+ if (data_offset != expected) {
402 -+ fprintf(stderr, "lseek(fd, %d, SEEK_DATA) = %d (expected %d)\n",
403 -+ (int)offset, (int)data_offset, (int)expected);
404 -+ exit(2);
405 -+ }
406 -+}
407 -+
408 -+static void
409 -+seek_hole(int fd, off_t offset, off_t expected)
410 -+{
411 -+ off_t hole_offset = lseek(fd, offset, SEEK_HOLE);
412 -+ if (hole_offset != expected) {
413 -+ fprintf(stderr, "lseek(fd, %d, SEEK_HOLE) = %d (expected %d)\n",
414 -+ (int)offset, (int)hole_offset, (int)expected);
415 -+ exit(2);
416 -+ }
417 -+}
418 -+
419 -+int
420 -+main(int argc, char **argv)
421 -+{
422 -+ char *execname = argv[0];
423 -+ char *file_path = argv[1];
424 -+ char *buf = NULL;
425 -+ int err;
426 -+
427 -+ if (argc != 4) {
428 -+ (void) printf("usage: %s <file name> <file size> "
429 -+ "<block size>\n", argv[0]);
430 -+ exit(1);
431 -+ }
432 -+
433 -+ int fd = open(file_path, O_RDWR | O_CREAT, 0666);
434 -+ if (fd == -1) {
435 -+ (void) fprintf(stderr, "%s: %s: ", execname, file_path);
436 -+ perror("open");
437 -+ exit(2);
438 -+ }
439 -+
440 -+ off_t file_size = atoi(argv[2]);
441 -+ off_t block_size = atoi(argv[3]);
442 -+
443 -+ if (block_size * 2 > file_size) {
444 -+ (void) fprintf(stderr, "file size must be at least "
445 -+ "double the block size\n");
446 -+ exit(2);
447 -+ }
448 -+
449 -+ err = ftruncate(fd, file_size);
450 -+ if (err == -1) {
451 -+ perror("ftruncate");
452 -+ exit(2);
453 -+ }
454 -+
455 -+ if ((buf = mmap(NULL, file_size, PROT_READ | PROT_WRITE,
456 -+ MAP_SHARED, fd, 0)) == MAP_FAILED) {
457 -+ perror("mmap");
458 -+ exit(2);
459 -+ }
460 -+
461 -+ /* Verify the file is sparse and reports no data. */
462 -+ seek_data(fd, 0, -1);
463 -+
464 -+ /* Verify the file is reported as a hole. */
465 -+ seek_hole(fd, 0, 0);
466 -+
467 -+ /* Verify search beyond end of file is an error. */
468 -+ seek_data(fd, 2 * file_size, -1);
469 -+ seek_hole(fd, 2 * file_size, -1);
470 -+
471 -+ /* Dirty the first byte. */
472 -+ memset(buf, 'a', 1);
473 -+ seek_data(fd, 0, 0);
474 -+ seek_data(fd, block_size, -1);
475 -+ seek_hole(fd, 0, block_size);
476 -+ seek_hole(fd, block_size, block_size);
477 -+
478 -+ /* Dirty the first half of the file. */
479 -+ memset(buf, 'b', file_size / 2);
480 -+ seek_data(fd, 0, 0);
481 -+ seek_data(fd, block_size, block_size);
482 -+ seek_hole(fd, 0, P2ROUNDUP(file_size / 2, block_size));
483 -+ seek_hole(fd, block_size, P2ROUNDUP(file_size / 2, block_size));
484 -+
485 -+ /* Dirty the whole file. */
486 -+ memset(buf, 'c', file_size);
487 -+ seek_data(fd, 0, 0);
488 -+ seek_data(fd, file_size * 3 / 4,
489 -+ P2ROUNDUP(file_size * 3 / 4, block_size));
490 -+ seek_hole(fd, 0, file_size);
491 -+ seek_hole(fd, file_size / 2, file_size);
492 -+
493 -+ /* Punch a hole (required compression be enabled). */
494 -+ memset(buf + block_size, 0, block_size);
495 -+ seek_data(fd, 0, 0);
496 -+ seek_data(fd, block_size, 2 * block_size);
497 -+ seek_hole(fd, 0, block_size);
498 -+ seek_hole(fd, block_size, block_size);
499 -+ seek_hole(fd, 2 * block_size, file_size);
500 -+
501 -+ err = munmap(buf, file_size);
502 -+ if (err == -1) {
503 -+ perror("munmap");
504 -+ exit(2);
505 -+ }
506 -+
507 -+ close(fd);
508 -+
509 -+ return (0);
510 -+}
511 -diff --git a/tests/zfs-tests/include/commands.cfg b/tests/zfs-tests/include/commands.cfg
512 -index 1ec73f25bae..4497a6248b4 100644
513 ---- a/tests/zfs-tests/include/commands.cfg
514 -+++ b/tests/zfs-tests/include/commands.cfg
515 -@@ -209,6 +209,7 @@ export ZFSTEST_FILES='badsend
516 - mktree
517 - mmap_exec
518 - mmap_libaio
519 -+ mmap_seek
520 - mmapwrite
521 - nvlist_to_lua
522 - randfree_file
523 -diff --git a/tests/zfs-tests/include/tunables.cfg b/tests/zfs-tests/include/tunables.cfg
524 -index 56d430a3987..fff43e46916 100644
525 ---- a/tests/zfs-tests/include/tunables.cfg
526 -+++ b/tests/zfs-tests/include/tunables.cfg
527 -@@ -33,6 +33,7 @@ DEADMAN_FAILMODE deadman.failmode zfs_deadman_failmode
528 - DEADMAN_SYNCTIME_MS deadman.synctime_ms zfs_deadman_synctime_ms
529 - DEADMAN_ZIOTIME_MS deadman.ziotime_ms zfs_deadman_ziotime_ms
530 - DISABLE_IVSET_GUID_CHECK disable_ivset_guid_check zfs_disable_ivset_guid_check
531 -+DMU_OFFSET_NEXT_SYNC dmu_offset_next_sync zfs_dmu_offset_next_sync
532 - INITIALIZE_CHUNK_SIZE initialize_chunk_size zfs_initialize_chunk_size
533 - INITIALIZE_VALUE initialize_value zfs_initialize_value
534 - KEEP_LOG_SPACEMAPS_AT_EXPORT keep_log_spacemaps_at_export zfs_keep_log_spacemaps_at_export
535 -diff --git a/tests/zfs-tests/tests/functional/mmap/Makefile.am b/tests/zfs-tests/tests/functional/mmap/Makefile.am
536 -index 2adc398b8c0..b26791ee7ce 100644
537 ---- a/tests/zfs-tests/tests/functional/mmap/Makefile.am
538 -+++ b/tests/zfs-tests/tests/functional/mmap/Makefile.am
539 -@@ -4,7 +4,8 @@ dist_pkgdata_SCRIPTS = \
540 - cleanup.ksh \
541 - mmap_read_001_pos.ksh \
542 - mmap_write_001_pos.ksh \
543 -- mmap_libaio_001_pos.ksh
544 -+ mmap_libaio_001_pos.ksh \
545 -+ mmap_seek_001_pos.ksh
546 -
547 - dist_pkgdata_DATA = \
548 - mmap.cfg
549 -diff --git a/tests/zfs-tests/tests/functional/mmap/mmap_seek_001_pos.ksh b/tests/zfs-tests/tests/functional/mmap/mmap_seek_001_pos.ksh
550 -new file mode 100755
551 -index 00000000000..6188549ad8d
552 ---- /dev/null
553 -+++ b/tests/zfs-tests/tests/functional/mmap/mmap_seek_001_pos.ksh
554 -@@ -0,0 +1,67 @@
555 -+#!/bin/ksh -p
556 -+#
557 -+# CDDL HEADER START
558 -+#
559 -+# The contents of this file are subject to the terms of the
560 -+# Common Development and Distribution License (the "License").
561 -+# You may not use this file except in compliance with the License.
562 -+#
563 -+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
564 -+# or http://www.opensolaris.org/os/licensing.
565 -+# See the License for the specific language governing permissions
566 -+# and limitations under the License.
567 -+#
568 -+# When distributing Covered Code, include this CDDL HEADER in each
569 -+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
570 -+# If applicable, add the following below this CDDL HEADER, with the
571 -+# fields enclosed by brackets "[]" replaced with your own identifying
572 -+# information: Portions Copyright [yyyy] [name of copyright owner]
573 -+#
574 -+# CDDL HEADER END
575 -+#
576 -+
577 -+#
578 -+# Copyright (c) 2021 by Lawrence Livermore National Security, LLC.
579 -+#
580 -+
581 -+. $STF_SUITE/include/libtest.shlib
582 -+. $STF_SUITE/tests/functional/mmap/mmap.cfg
583 -+
584 -+#
585 -+# DESCRIPTION:
586 -+# lseek() data/holes for an mmap()'d file.
587 -+#
588 -+# STRATEGY:
589 -+# 1. Enable compression and hole reporting for dirty files.
590 -+# 2. Call mmap_seek binary test case for various record sizes.
591 -+#
592 -+
593 -+verify_runnable "global"
594 -+
595 -+function cleanup
596 -+{
597 -+ log_must zfs set compression=off $TESTPOOL/$TESTFS
598 -+ log_must zfs set recordsize=128k $TESTPOOL/$TESTFS
599 -+ log_must rm -f $TESTDIR/test-mmap-file
600 -+ log_must set_tunable64 DMU_OFFSET_NEXT_SYNC $dmu_offset_next_sync
601 -+}
602 -+
603 -+log_assert "lseek() data/holes for an mmap()'d file."
604 -+
605 -+log_onexit cleanup
606 -+
607 -+# Enable hole reporting for dirty files.
608 -+typeset dmu_offset_next_sync=$(get_tunable DMU_OFFSET_NEXT_SYNC)
609 -+log_must set_tunable64 DMU_OFFSET_NEXT_SYNC 1
610 -+
611 -+# Compression must be enabled to convert zero'd blocks to holes.
612 -+# This behavior is checked by the mmap_seek test.
613 -+log_must zfs set compression=on $TESTPOOL/$TESTFS
614 -+
615 -+for bs in 4096 8192 16384 32768 65536 131072; do
616 -+ log_must zfs set recordsize=$bs $TESTPOOL/$TESTFS
617 -+ log_must mmap_seek $TESTDIR/test-mmap-file $((1024*1024)) $bs
618 -+ log_must rm $TESTDIR/test-mmap-file
619 -+done
620 -+
621 -+log_pass "lseek() data/holes for an mmap()'d file succeeded."
622
623 diff --git a/sys-fs/zfs-kmod/zfs-kmod-2.1.1-r1.ebuild b/sys-fs/zfs-kmod/zfs-kmod-2.1.1-r2.ebuild
624 similarity index 98%
625 rename from sys-fs/zfs-kmod/zfs-kmod-2.1.1-r1.ebuild
626 rename to sys-fs/zfs-kmod/zfs-kmod-2.1.1-r2.ebuild
627 index 5939b99e648..1f2473e7964 100644
628 --- a/sys-fs/zfs-kmod/zfs-kmod-2.1.1-r1.ebuild
629 +++ b/sys-fs/zfs-kmod/zfs-kmod-2.1.1-r2.ebuild
630 @@ -62,8 +62,6 @@ RESTRICT="debug? ( strip ) test"
631
632 DOCS=( AUTHORS COPYRIGHT META README.md )
633
634 -PATCHES=( "${FILESDIR}/2.1.1-fix-lseek-mmap.patch" )
635 -
636 pkg_pretend() {
637 use rootfs || return 0