Repository navigation
Expand file tree
/
Copy pathnextbsd-e14-tickets.html
More file actions
1452 lines (1261 loc) · 98.4 KB
/
Copy pathnextbsd-e14-tickets.html
File metadata and controls
1452 lines (1261 loc) · 98.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>E14 ticket drafts — VM, paging and filesystems</title>
<style>
:root {
--bg: #fbfbf8;
--fg: #1a1a1a;
--muted: #555;
--accent: #b03000;
--accent2: #0a4d68;
--ok: #1f7a1f;
--warn: #b06800;
--bad: #b00020;
--code-bg: #f0ece4;
--rule: #d6cfc0;
--card: #fff;
}
html { -webkit-text-size-adjust: 100%; }
body { margin: 0 auto; max-width: 1080px; padding: 2.5rem 1.5rem 6rem;
font: 16px/1.55 -apple-system, BlinkMacSystemFont, "SF Pro Text", system-ui, sans-serif;
color: var(--fg); background: var(--bg); }
h1 { font-size: 2rem; line-height: 1.2; margin: 0 0 .25rem; }
h2 { font-size: 1.4rem; margin: 2.5rem 0 .75rem; padding-bottom: .25rem; border-bottom: 2px solid var(--rule); }
h3 { font-size: 1.15rem; margin: 1.75rem 0 .5rem; color: var(--accent2); }
h4 { margin: 1.25rem 0 .35rem; }
.subtitle { color: var(--muted); font-size: 1.05rem; margin: 0 0 2rem; }
code, pre, kbd { font-family: "SF Mono", Menlo, Consolas, monospace; }
code { background: var(--code-bg); padding: 1px 5px; border-radius: 3px; font-size: .9em; }
pre { background: var(--code-bg); padding: .85rem 1rem; border-radius: 6px;
overflow-x: auto; font-size: .82rem; line-height: 1.45;
border-left: 3px solid var(--accent2); }
pre code { background: none; padding: 0; }
pre.shell { border-left-color: var(--ok); }
pre.c { border-left-color: var(--accent); }
a { color: var(--accent2); }
a:hover { color: var(--accent); }
.tldr { background: var(--card); border: 1px solid var(--rule); border-left: 4px solid var(--accent2);
padding: 1rem 1.25rem; border-radius: 6px; margin-bottom: 2rem; }
.tldr h3 { margin-top: 0; color: var(--accent2); }
.pill { display: inline-block; font-size: .72rem; padding: 1px 8px; border-radius: 999px;
background: #eee; color: #333; margin-left: .35rem; vertical-align: middle;
font-weight: 600; letter-spacing: .02em; }
.pill.ok { background: #d8efd8; color: var(--ok); }
.pill.warn { background: #f6e4cb; color: var(--warn); }
.pill.bad { background: #f5d0d6; color: var(--bad); }
.pill.info { background: #d6e6f3; color: var(--accent2); }
table { border-collapse: collapse; width: 100%; margin: 1rem 0; font-size: .92rem; }
th, td { text-align: left; padding: .5rem .65rem; border-bottom: 1px solid var(--rule); vertical-align: top; }
th { background: #eee5d6; }
tr:nth-child(even) td { background: #faf6ed; }
table.compact td, table.compact th { padding: .35rem .55rem; font-size: .88rem; }
.nav { position: sticky; top: 0; background: var(--bg); margin: -2.5rem -1.5rem 2rem;
padding: .75rem 1.5rem; border-bottom: 1px solid var(--rule);
font-size: .88rem; z-index: 10; }
.nav a { margin-right: .9rem; text-decoration: none; }
.gap { background: #fff5f5; border-left: 4px solid var(--bad); padding: .8rem 1rem; margin: 1rem 0; border-radius: 0 6px 6px 0; }
.gap strong { color: var(--bad); }
.resolved { background: #ecf7ec; border-left: 4px solid var(--ok); padding: .8rem 1rem; margin: 1rem 0; border-radius: 0 6px 6px 0; }
.resolved strong { color: var(--ok); }
.open-q { background: #fff8d6; border: 1px solid #e5d76b; padding: .8rem 1rem; margin: 1rem 0; border-radius: 6px; font-size: .92rem; }
.open-q strong { color: #7a5e00; }
.risk { background: #fff5f5; border: 1px solid #e7b8bf; border-left: 4px solid var(--bad); padding: .8rem 1rem; margin: 1rem 0; border-radius: 6px; font-size: .93rem; }
.risk strong { color: var(--bad); }
.ascii-diagram { font-family: "SF Mono", Menlo, Consolas, monospace; font-size: .82rem; line-height: 1.3; white-space: pre; background: var(--code-bg); padding: 1rem; border-radius: 6px; overflow-x: auto; }
.rec { background: #eef4f8; border: 1px solid #bcd4e2; border-left: 4px solid var(--accent2); padding: 1rem 1.25rem; margin: 1.25rem 0; border-radius: 6px; }
.rec strong { color: var(--accent2); }
.yesno { font-weight: 600; }
.yesno.yes { color: var(--ok); }
.yesno.no { color: var(--bad); }
.yesno.partial { color: var(--warn); }
</style>
<style>
.tk { background: var(--card); border: 1px solid var(--rule); border-left: 4px solid var(--accent2); border-radius: 6px; padding: .9rem 1.1rem .4rem; margin: 1.25rem 0; }
.tk h3 { margin-top: .1rem; }
.tk .meta { font-size: .88rem; margin: .25rem 0 .6rem; border-collapse: collapse; }
.tk .meta td { padding: .15rem .8rem .15rem 0; vertical-align: top; }
.tk .meta td:first-child { color: var(--muted); white-space: nowrap; }
.tk pre { white-space: pre-wrap; word-wrap: break-word; }
.tk-epic { border-left-color: var(--accent); }
</style>
</head><body>
<nav class="nav">
<a href="#tldr">TL;DR</a>
<a href="#before">Preconditions</a>
<a href="#label">Label</a>
<a href="#epic">Epic</a>
<a href="#index">Index</a>
<a href="#tickets">Tickets</a>
<a href="#existing">Existing issues</a>
<a href="#recreate">Recreating</a>
</nav>
<h1>E14 ticket drafts — VM, paging and filesystems <span class="pill ok">Filed 2026-09-20</span></h1>
<p class="subtitle"><strong>Every issue for EPIC E14, written out in full — and now filed.</strong> This page is the companion to <a href="nextbsd-swap-vm-plan.html">NextBSD swap and paging without a partition</a>. It records the epic, the new <code>area:vm</code> label, all 23 child tickets and one migration: title, target repo, labels, dependencies, and the exact Markdown body for each. <strong>Filed on 2026-09-20</strong> as epic <a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a> and 23 child issues, attached to it as GitHub sub-issues. The bodies below are exactly what was filed; each issue also carries a footer naming its parent, its dependencies by issue number, and a link back here. The plan's ticket map is generated from the same source as this page, so the two cannot drift apart.</p>
<section id="tldr" class="tldr">
<h3>TL;DR</h3>
<ul>
<li><strong>23 child tickets</strong> across four repos, plus the epic <a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a> and the <code>area:vm</code> label, created in all four repos.</li>
<li><strong>Tracks:</strong> K = kernel swap pager and dumper · Z = ZFS swapify · P = platform dump paths · U = userland · S/X = spike and upstream report.</li>
<li><strong>All preconditions are done</strong> — Q3, R7 and the labels; see <a href="#before">Preconditions</a>. R7 added two pin-time requirements to K1 (<a href="https://github.com/nextbsd/nextbsd-kernel/issues/214">nextbsd-kernel#214</a>).</li>
<li><strong>Order:</strong> K1 -> K2 / K3 / K4 / K7 -> K5 / K6 -> U1 -> U2. Z0 first for everything ZFS, then Z2 and Z1 (after K6) in parallel, then Z3 -> Z4. K8, Z5, S1 follow K1. U4 after Z0 and U2, once its design is refined. P2, U3 and X1 are independent.</li>
<li><strong>Machine-readable:</strong> every field on this page is also embedded as JSON (<code><script id="e14-data"></code>), so the issues can be recreated by script as well as by hand.</li>
</ul>
</section>
<h2 id="before">Preconditions</h2>
<div class="resolved"><strong>1. Q3 — done 2026-09-20: no local changes.</strong> none of the 50 patches in <code>nextbsd-kernel</code> (at <code>ddad2c1</code>) touch <code>sys/vm/</code>, <code>sys/dev/md/</code>, UFS/FFS, the VFS layer, GEOM, <code>kern_shutdown.c</code> or the bundled OpenZFS, and <code>src-overlay/</code> only adds new files. The kernel builds from <code>releng/15.1</code> (<code>FREEBSD_BRANCH</code> in <code>.github/workflows/build.yml</code>), where the <code>VFCF_NETWORK</code> test K1 relaxes is at <code>swap_pager.c:2680</code>. K1 is unchanged.</div>
<div class="resolved"><strong>2. R7 — done 2026-09-20: soft-updates cannot see bypass writes.</strong> On <code>releng/15.1</code>, soft-updates' write hook (<code>buf_start</code> on a buffer's <code>b_dep</code>) and UFS snapshot copy-on-write (<code>ffs_copyonwrite</code>, called only at <code>ffs_vfsops.c:2366</code> and <code>:2378</code>) both live in <code>ffs_geom_strategy</code> (<code>ffs_vfsops.c:2334</code>), so they run only for writes through the buffer cache; a bypass bio has no buffer and no dependency list. <code>fsync(MNT_WAIT)</code> flushes every inode dependency, every dirty buffer and then <code>softdep_fsync</code>, looping until nothing is dirty or in flight (<code>ffs_vnops.c:226-258</code>), and SU+J takes the same path (<code>DOINGSOFTDEP</code>). Two requirements follow, now in K1: <code>fsync(MNT_WAIT)</code> then <code>vinvalbuf()</code> at pin time, and documenting that UFS snapshots hold live swap contents for the swapfile.</div>
<div class="resolved"><strong>3. Labels — done 2026-09-20.</strong> <code>area:vm</code> was created in all four repos, including <code>nextbsd-freebsd-compat</code>, which previously had no <code>area:*</code> labels at all.</div>
<h2 id="label">Label</h2>
<table class="compact">
<tr><td>Name</td><td><code>area:vm</code></td></tr>
<tr><td>Description</td><td>Virtual memory, swap, paging, memory pressure, crash dumps, and the filesystems they back</td></tr>
<tr><td>Colour</td><td><code>#5319e7</code></td></tr>
<tr><td>Create in</td><td><a href="https://github.com/nextbsd/nextbsd">nextbsd</a>, <a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a>, <a href="https://github.com/nextbsd/nextbsd-userland">nextbsd-userland</a>, <a href="https://github.com/nextbsd/nextbsd-freebsd-compat">nextbsd-freebsd-compat</a></td></tr>
</table>
<h2 id="epic">Epic</h2>
<div class="tk tk-epic" id="e14">
<h3>EPIC: E14 VM, paging & filesystems</h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd">nextbsd</a></td></tr>
<tr><td>Labels</td><td><code>epic</code> <code>area:vm</code></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
Swap and crash dumps for NextBSD with **no swap partition and no dump partition**, on both UFS and ZFS.
One primitive serves both: pin an object's blocks, extract a physical extent map once, and bypass the filesystem at I/O time. After `swapon` the filesystem is off the write path, so swapfiles perform like a partition and cannot deadlock the way `md(4)`'s `VOP_WRITE` path does.
**Read first:** https://pkgdemon.github.io/nextbsd-swap-vm-plan.html
**Ticket drafts:** https://pkgdemon.github.io/nextbsd-e14-tickets.html
## Why
- NextBSD ships **zero swap** today; `build.sh` calls `/cow` "swap-backed", which is false.
- #326: live ISO OOM-kills daemons (`/cow` 97% of 7 GB, `7032M Laundry`, `swapctl -l` empty).
- nextbsd-userland#171: launchd runs no `rc.d`, so a swap entry in fstab is inert.
## Tracks
- **K** -- kernel: extent-map swap pager, `VV_SWAP`, file-backed dumper
- **Z** -- ZFS: restore illumos dumpify as "swapify"
- **P** -- platform: polled dump paths, CI harness
- **U** -- userland: `swapd`, installer, `vm_stat`
- **S/X** -- research spike and upstream report
## Children
Replace IDs with issue numbers once filed.
- [ ] K1 Extent-map swap pager
- [ ] K2 `VV_SWAP` immutability guard
- [ ] K3 `swapon(8)` drops the md detour
- [ ] K4 File-backed kernel dumper
- [ ] K5 `dumpon`/`savecore` file mode
- [ ] K6 `g_part` kerneldump on non-swap partitions
- [ ] K7 Swap low-space event
- [ ] K8 Defence-in-depth VM privileges
- [ ] Z1 `vdev_op_dumpio`
- [ ] Z2 Reinstate `dmu_prealloc()`
- [ ] Z3 Swapify
- [ ] Z4 DSL guards
- [ ] Z5 Pager-level swap encryption
- [ ] P1 NVMe polled dump on Pi 500+
- [ ] P2 `dwmmc` dumping path
- [ ] P3 virtio-blk dump CI harness
- [ ] U1 `swapd`
- [ ] U2 installer creates `/private/var/vm`
- [ ] U3 `vm_stat` real numbers
- [ ] S1 Spike: decouple reclaim from swap-I/O completion
- [ ] X1 Upstream report: `zfs_putpages` exposure
- [ ] #393 (migrated)
## Linked, not migrated
#326, #329 (E8) - nextbsd-userland#171, nextbsd-userland#54 (E13) - #410 (E2)</code></pre>
</div>
<h2 id="index">Index</h2>
<table class="compact">
<tr><th>ID</th><th>Ticket</th><th>Repo</th><th>Depends on</th><th>Issue</th></tr>
<tr><td><a href="#k1"><strong>K1</strong></a></td><td>Extent-map swap pager: accept local VREG swapon on filesystems with a real VOP_BMAP</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td>—</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/214">nextbsd-kernel#214</a></td></tr>
<tr><td><a href="#k2"><strong>K2</strong></a></td><td>VV_SWAP: refuse write, truncate and unlink on a pinned swap or dump file</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td><a href="#k1">K1</a></td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/215">nextbsd-kernel#215</a></td></tr>
<tr><td><a href="#k3"><strong>K3</strong></a></td><td>swapon(8): stop creating an md(4) device for local swapfiles</td><td><a href="https://github.com/nextbsd/nextbsd-freebsd-compat">nextbsd-freebsd-compat</a></td><td><a href="#k1">K1</a></td><td><a href="https://github.com/nextbsd/nextbsd-freebsd-compat/issues/51">nextbsd-freebsd-compat#51</a></td></tr>
<tr><td><a href="#k4"><strong>K4</strong></a></td><td>File-backed kernel dumper: write crash dumps through a pinned file's extent map</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td><a href="#k1">K1</a></td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/216">nextbsd-kernel#216</a></td></tr>
<tr><td><a href="#k5"><strong>K5</strong></a></td><td>dumpon(8)/savecore(8): regular-file mode</td><td><a href="https://github.com/nextbsd/nextbsd-freebsd-compat">nextbsd-freebsd-compat</a></td><td><a href="#k4">K4</a></td><td><a href="https://github.com/nextbsd/nextbsd-freebsd-compat/issues/52">nextbsd-freebsd-compat#52</a></td></tr>
<tr><td><a href="#k6"><strong>K6</strong></a></td><td>g_part: allow GEOM::kerneldump on freebsd-ufs/freebsd-zfs partitions for the file dumper</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td><a href="#k4">K4</a></td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/217">nextbsd-kernel#217</a></td></tr>
<tr><td><a href="#k7"><strong>K7</strong></a></td><td>Swap low-space event: surface swp_sizecheck transitions to userland via devctl</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td>—</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/218">nextbsd-kernel#218</a></td></tr>
<tr><td><a href="#k8"><strong>K8</strong></a></td><td>Defence-in-depth VM privileges: TDP_VMPRIV, sync dispatch for swap objects, ARC pageout throttle</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td><a href="#k1">K1</a></td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/219">nextbsd-kernel#219</a></td></tr>
<tr><td><a href="#z0"><strong>Z0</strong></a></td><td>kernel: compile ZFS into NEXTBSD (options ZFS, no module tree) and ship the ZFS userland</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td>—</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/230">nextbsd-kernel#230</a></td></tr>
<tr><td><a href="#z1"><strong>Z1</strong></a></td><td>vdev_op_dumpio for vdev_geom, mirror and raidz</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td><a href="#k6">K6</a></td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/220">nextbsd-kernel#220</a></td></tr>
<tr><td><a href="#z2"><strong>Z2</strong></a></td><td>Reinstate dmu_prealloc()</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td>—</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/221">nextbsd-kernel#221</a></td></tr>
<tr><td><a href="#z3"><strong>Z3</strong></a></td><td>Swapify: pin a ZFS file object -- property freeze, preallocation, DVA extent walk, DMU bypass</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td><a href="#z1">Z1</a>, <a href="#z2">Z2</a></td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/222">nextbsd-kernel#222</a></td></tr>
<tr><td><a href="#z4"><strong>Z4</strong></a></td><td>DSL guards for pinned objects -- and skip, not fail, them in recursive snapshot/send</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td><a href="#z3">Z3</a></td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/223">nextbsd-kernel#223</a></td></tr>
<tr><td><a href="#z5"><strong>Z5</strong></a></td><td>Pager-level swap encryption (geli cannot cover a sub-range of a provider)</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td><a href="#k1">K1</a></td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/224">nextbsd-kernel#224</a></td></tr>
<tr><td><a href="#p1"><strong>P1</strong></a></td><td>rpi5: verify NVMe polled crash dump on the Pi 500+</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td><a href="#k4">K4</a></td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/225">nextbsd-kernel#225</a></td></tr>
<tr><td><a href="#p2"><strong>P2</strong></a></td><td>dwmmc: add a dumping path so d_dump does not hang</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td>—</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/226">nextbsd-kernel#226</a></td></tr>
<tr><td><a href="#p3"><strong>P3</strong></a></td><td>CI: virtio-blk crash-dump harness so the dump path is tested before hardware</td><td><a href="https://github.com/nextbsd/nextbsd">nextbsd</a></td><td><a href="#k4">K4</a></td><td><a href="https://github.com/nextbsd/nextbsd/issues/469">nextbsd#469</a></td></tr>
<tr><td><a href="#u1"><strong>U1</strong></a></td><td>swapd: grow and reclaim swapfiles under memory pressure</td><td><a href="https://github.com/nextbsd/nextbsd-userland">nextbsd-userland</a></td><td><a href="#k1">K1</a>, <a href="#k7">K7</a></td><td><a href="https://github.com/nextbsd/nextbsd-userland/issues/178">nextbsd-userland#178</a></td></tr>
<tr><td><a href="#u2"><strong>U2</strong></a></td><td>installer: create /private/var/vm (ZFS: zroot/private/var/vm) -- no partition, no sizing</td><td><a href="https://github.com/nextbsd/nextbsd-userland">nextbsd-userland</a></td><td><a href="#u1">U1</a></td><td><a href="https://github.com/nextbsd/nextbsd-userland/issues/179">nextbsd-userland#179</a></td></tr>
<tr><td><a href="#u3"><strong>U3</strong></a></td><td>vm_stat / pagesize report real numbers from vm.stats instead of the 'feature not available' stub</td><td><a href="https://github.com/nextbsd/nextbsd-userland">nextbsd-userland</a></td><td>—</td><td><a href="https://github.com/nextbsd/nextbsd-userland/issues/180">nextbsd-userland#180</a></td></tr>
<tr><td><a href="#u4"><strong>U4</strong></a></td><td>installer: ZFS install path -- F8 on the disk picker, pool layout, options and review (preliminary design)</td><td><a href="https://github.com/nextbsd/nextbsd-userland">nextbsd-userland</a></td><td><a href="#z0">Z0</a>, <a href="#u2">U2</a></td><td><a href="https://github.com/nextbsd/nextbsd-userland/issues/201">nextbsd-userland#201</a></td></tr>
<tr><td><a href="#s1"><strong>S1</strong></a></td><td>Spike: decouple page reclaim from swap-I/O completion (compressor-style staging)</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td><td><a href="#k1">K1</a></td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/227">nextbsd-kernel#227</a></td></tr>
<tr><td><a href="#x1"><strong>X1</strong></a></td><td>Report upstream: zfs_putpages calls dmu_tx_assign(DMU_TX_WAIT) in pageout context</td><td><a href="https://github.com/nextbsd/nextbsd">nextbsd</a></td><td>—</td><td><a href="https://github.com/nextbsd/nextbsd/issues/470">nextbsd#470</a></td></tr>
</table>
<h2 id="tickets">Tickets</h2>
<div class="tk" id="k1">
<h3>K1 · Extent-map swap pager: accept local VREG swapon on filesystems with a real VOP_BMAP <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td>—</td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/214">nextbsd-kernel#214</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
FreeBSD refuses `swapon(2)` on a local regular file. `sys_swapon()` accepts `VREG` only when the mount is `VFCF_NETWORK` (NFS), so local swapfiles go through `md(4)`, whose vnode path deadlocks under memory pressure.
Add a swapfile backend that resolves the file to a physical extent map **at swapon time** and writes raw bios to the underlying GEOM provider. After `swapon`, the filesystem is not on the I/O path.
## Why
Today's path: `mdstart_vnode` -> `vn_start_write` -> `vn_lock` -> `VOP_WRITE` -> `ffs_write` -> `getblk`/`allocbuf` -> `vm_wait`. The md kthread is not `pageproc`, so it gets no reserve and sleeps behind the pagedaemon, which is waiting on this very bio.
## Design
- `sys/vm/swap_pager.c:2680` (`releng/15.1`, the NextBSD kernel base) -- relax the `VFCF_NETWORK` test for filesystems that return a full, hole-free block map.
- At swapon, walk `VOP_BMAP` (UFS: `ufs_bmaparray`) as Linux's `generic_swapfile_activate()` does. Reject holes.
- Store the extents in `struct swdevt`.
- New `sw_strategy_t swapfile_strategy()`: translate `bp->b_blkno` through the extent table, `g_new_bio()` (non-sleeping), `g_io_request()` on a GEOM consumer of the mount's provider (`VFSTOUFS(mp)->um_cp` for UFS).
- Everything upstream in `swap_pager_putpages()` is already allocation-free: `blist` bitmap, preallocated `swwbuf` pbuf, `M_NOWAIT` metadata. **Only `sw_strategy` changes.**
- **At pin time** (from R7): `VOP_FSYNC(vp, MNT_WAIT)` after preallocation, then `vinvalbuf(vp, 0, ...)` before building the extent map. The fsync leaves no soft-updates dependency pending; the invalidate drops the file's cached buffers *and* pages (`bufobj_invalbuf` calls `vm_object_page_remove`), so no stale cached copy can mask blocks the bypass writes. `VV_SWAP` (K2) then stops new dirty buffers appearing
- **UFS snapshots** (from R7): bypass writes skip `ffs_copyonwrite`, so a snapshot's image of the swapfile holds live swap contents instead of what it held when the snapshot was taken. That is harmless -- nothing that uses snapshots (`dump -L`, background `fsck`) interprets swap or dump data -- so document it rather than refuse `swapon` while a snapshot exists
## Scope
~500-800 LOC. Low risk: the same device path swap partitions use today.
## Before starting
- [x] **Q3:** done 2026-09-20 -- no patch in `nextbsd-kernel` touches `swap_pager.c`, `md.c`, UFS/FFS, VFS, GEOM or OpenZFS, so this ticket is written against stock `releng/15.1`
- [x] **R7:** done 2026-09-20 -- soft-updates cannot see bypass writes, and nothing is left pending on a synced file. On `releng/15.1`, soft-updates' write hook (`buf_start` on a buffer's `b_dep`) and UFS snapshot copy-on-write (`ffs_copyonwrite`, called only at `ffs_vfsops.c:2366` and `:2378`) both live in `ffs_geom_strategy` (`ffs_vfsops.c:2334`), the strategy routine for FFS's device vnode -- so they run only for writes that go through the buffer cache. A bypass bio has no buffer and no dependency list. `fsync(MNT_WAIT)` flushes every inode dependency (`softdep_sync_metadata`), every dirty buffer, then `softdep_fsync`, and loops until nothing is dirty or in flight (`ffs_vnops.c:226-258`); the guard is `DOINGSOFTDEP`, so SU+J takes the same path
## Acceptance
- [ ] `swapon /private/var/vm/swapfile0` on UFS succeeds with no `mdconfig`
- [ ] `swapinfo` lists the file
- [ ] a larger-than-RAM allocation test pages out through the file without hanging
- [ ] the same test on a soft-updates root with an active UFS snapshot; `fsck` is clean afterwards
- [ ] `swapon` rejects a file with holes
## Refs
Plan sections 2, 3. `sys/vm/swap_pager.c:2680` on `releng/15.1`.</code></pre>
</div>
<div class="tk" id="k2">
<h3>K2 · VV_SWAP: refuse write, truncate and unlink on a pinned swap or dump file <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#k1">K1</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/215">nextbsd-kernel#215</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
Once a file is pinned, its extents must never move or be freed -- the kernel holds raw block addresses. Add a vnode flag `VV_SWAP` (in `v_vflag`), set at swapon/pin time.
## Design
With `VV_SWAP` set, return `ETXTBSY` from:
- `ffs_write`
- `ffs_truncate` / `VOP_SETATTR(va_size)`
- `ufs_remove`, rename
- `vop_allocate` / `vop_deallocate`
Mirrors xnu `VSWAP` (`bsd/sys/vnode_internal.h:301`) and Linux `S_SWAPFILE` (`-ETXTBSY` in `fs/read_write.c`, `fs/open.c`).
Note: `ffs_reallocblks` only relocates *dirty, not-yet-written* clusters, so a fully synced file does not move.
## Acceptance
- [ ] write, truncate and unlink on a pinned file fail with `ETXTBSY`
- [ ] after `swapoff` / unpin they succeed again</code></pre>
</div>
<div class="tk" id="k3">
<h3>K3 · swapon(8): stop creating an md(4) device for local swapfiles <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-freebsd-compat">nextbsd-freebsd-compat</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#k1">K1</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-freebsd-compat/issues/51">nextbsd-freebsd-compat#51</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
`swapon(8)` currently runs `mdconfig -a -t vnode -f` for file entries (`sbin/swapon/swapon.c:417`, `swap_on_off_md`; fstab form `md none swap sw,file=...`). With K1 in place, call `swapon(2)` on the path directly.
`sbin/swapon` is currently **DEFER** in the srclist ("no swap configured"). This ticket brings it into the build.
## Acceptance
- [ ] `swapon /private/var/vm/swapfile0` activates the file directly, with no md device. Test it this way rather than through `/etc/fstab`: E15 stops shipping fstab (A1, nextbsd/nextbsd-overlays#4), and `swapd` (nextbsd/nextbsd-userland#178) is the activation path
- [ ] `mdconfig -l` is empty afterwards
## Note
This repo has **no `area:*` labels**. Create `area:vm` here before filing.</code></pre>
</div>
<div class="tk" id="k4">
<h3>K4 · File-backed kernel dumper: write crash dumps through a pinned file's extent map <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#k1">K1</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/216">nextbsd-kernel#216</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
Crash dumps without a dump device. **No `struct dumperinfo` change is needed**: netdump already registers `mediaoffset = 0`, `mediasize = 0` and ignores offsets entirely (`sys/netinet/netdump/netdump_client.c:584` and `:745`).
## Design
New `sys/kern/kern_dumpfile.c` (~400 LOC):
- obtain the leaf `dumperinfo` plus `extent[]` through a new `VOP_DUMPCTL(PIN|UNPIN)` (illumos analogue)
- register a wrapper with `dumper_insert(&di, "file:<path>", kda)`: `mediaoffset = 0`, `mediasize` = file length, `blocksize = 4096`, `maxiosize` = min leaf `d_maxsize`
- the `dumper` callback locates the extent and **splits at extent boundaries** -- mandatory, because arm64 `minidump_machdep.c` writes unaligned chunks via `blk_write` -- then calls the leaf `d_dump` with `leaf.mediaoffset + phys`
- the `(NULL, 0, 0)` flush fans out to every leaf
- unregister on unmount
EKCD encryption and zstd compression layer above `dump_write` and need no changes.
## Acceptance
- [ ] `dumpon /private/var/vm/kernelcore` registers
- [ ] a panic in a VM (`sysctl debug.kdb.panic=1`) followed by `savecore` (K5) recovers a valid vmcore
## Refs
Apple reference design: `kern_open_file_for_direct_io()` in `bsd/kern/kern_symfile.c`.</code></pre>
</div>
<div class="tk" id="k5">
<h3>K5 · dumpon(8)/savecore(8): regular-file mode <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-freebsd-compat">nextbsd-freebsd-compat</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#k4">K4</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-freebsd-compat/issues/52">nextbsd-freebsd-compat#52</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
`savecore` requires `DIOCGMEDIASIZE`/`DIOCGSECTORSIZE` (`sbin/savecore/savecore.c:975-977`) and reads the trailing header at `mediasize - sectorsize`. Add a regular-file mode to both tools.
`dumpon` is **DEFER** and `savecore` is **DROP** in the srclist -- this brings both back.
## Design
- `savecore`: `fstat()` for `st_size`; fixed 4096-byte sector size for `S_ISREG`; extract to `/private/var/crash` (~150 LOC)
- `dumpon`: an `S_ISREG` path routes `DIOCSKERNELDUMP` through `VOP_IOCTL` (~100 LOC)
- `savecore -c` clear-write must land in place: UFS `write(2)` is in place; ZFS must take the raw path (Z3)
## Acceptance
- [ ] full panic -> `savecore` round trip on a UFS VM
## Note
This repo has **no `area:*` labels**. Create `area:vm` here before filing.</code></pre>
</div>
<div class="tk" id="k6">
<h3>K6 · g_part: allow GEOM::kerneldump on freebsd-ufs/freebsd-zfs partitions for the file dumper <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#k4">K4</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/217">nextbsd-kernel#217</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
`sys/geom/part/g_part.c:2295-2316` refuses `GEOM::kerneldump` unless `G_PART_DUMPTO` passes, and `g_part_gpt_dumpto` (`g_part_gpt.c:803-811`) returns 1 only for swap-type GUIDs. The file dumper (K4) and ZFS dumpio (Z1) need the leaf `dumperinfo` of the partition that holds the root filesystem.
## Design
~15 LOC: permit the attribute when the requester is the file-dumper facility.
## Acceptance
- [ ] K4 registers on a `freebsd-ufs` partition
- [ ] Z1 caches a leaf `dumperinfo` on a `freebsd-zfs` partition</code></pre>
</div>
<div class="tk" id="k7">
<h3>K7 · Swap low-space event: surface swp_sizecheck transitions to userland via devctl <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td>—</td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/218">nextbsd-kernel#218</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
`swp_sizecheck()` flips `swap_pager_almost_full` at `nswap_lowat` (128 pages) / `nswap_hiwat` (512 pages) and only `printf`s -- there is **no userland event**. Without one, `swapd` (U1) must poll.
## Design
- `EVENTHANDLER_DECLARE(swap_lowspace, ...)`, invoked on `swp_sizecheck()` transitions
- deliver via `devctl_notify("VM", "swap", "LOWSPACE", ...)` (devd-consumable)
- make `nswap_lowat` / `nswap_hiwat` sysctls
- optional, Darwin-faithful: have `mach.ko` carry a `default_pager_space_alert`-shaped message to a registered port
## Scope
Days. Phase 3 (Grow) of the plan depends on it.
## Acceptance
- [ ] `devd` receives `LOWSPACE` when free swap crosses `nswap_lowat`</code></pre>
</div>
<div class="tk" id="k8">
<h3>K8 · Defence-in-depth VM privileges: TDP_VMPRIV, sync dispatch for swap objects, ARC pageout throttle <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#k1">K1</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/219">nextbsd-kernel#219</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
The cheap parts of the memory-reserve route, taken as **defence in depth only** -- not as the correctness argument. The bypass design (K1, Z3) is what makes swap safe.
## Why only the cheap parts
illumos built the full reserve design (`NOMEMWAIT()`, `KM_PUSHPAGE`, a ZFS-sized `pageout_reserve`, the ARC throttle) and still ships `pageout_deadman`, which panics after 90 s of stuck pageout. On FreeBSD it is weaker again:
- `KM_PUSHPAGE` is `#define`d to `M_WAITOK` (`include/os/freebsd/spl/sys/kmem.h:49`)
- `arc_memory_throttle()` is `return (0);` (`module/os/freebsd/zfs/arc_os.c:124`)
## Design
- `TDP_VMPRIV` bit in `td_pflags` plus a `vm_thread_privileged()` inline (`curproc == pageproc || (td->td_pflags & TDP_VMPRIV)`) at the ~10 existing `curproc == pageproc` sites (~300-500 LOC in `sys/vm`)
- synchronous dispatch for swap objects (no taskq hop)
- the `arc_memory_throttle` pageout branch, as Linux and illumos have
## Acceptance
- [ ] a thread marked `TDP_VMPRIV` allocates at `VM_ALLOC_SYSTEM` and waits pageproc-style</code></pre>
</div>
<div class="tk" id="z0">
<h3>Z0 · kernel: compile ZFS into NEXTBSD (options ZFS, no module tree) and ship the ZFS userland <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code> <code>area:storage</code></td></tr>
<tr><td>Depends on</td><td>—</td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/230">nextbsd-kernel#230</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
NextBSD cannot use ZFS at all today. `config/NEXTBSD` has no `options ZFS`, stock FreeBSD builds ZFS only as `zfs.ko`, and NextBSD ships no module tree -- the same situation E15's C7 describes for UDF and LIBICONV. Compile ZFS into the kernel, and ship the userland that drives it.
## Why
Every ZFS ticket in E14 (Z1-Z5), the ZFS path of U2 (nextbsd/nextbsd-userland#179), and the installer's ZFS option need a kernel that can create and import a pool. Nothing ZFS works without this.
## Kernel
- add `options ZFS` to `config/NEXTBSD`. On `releng/15.1` it is defined at `sys/conf/options:279`, and **222 sources in `sys/conf/files` are `optional zfs`** (216 plain, 5 `optional zfs | dtrace`, 1 `optional zfs zstdio`)
- `ZSTDIO` is already enabled through `std.arm64`, which covers the one `zfs zstdio` source
- crypto acceleration for native encryption: check whether ZFS's ICP uses `armv8crypto` (arm64) / `aesni` (amd64) or its own implementations
- record the kernel size delta
## Boot
- the kernel mounts the root dataset from `vfs.root.mountfrom=zfs:zroot/ROOT/default`
- confirm NextBSD's loader can read ZFS on both layouts: gpt, and the Pi's mbr-fat. FreeBSD builds `loader.efi` with ZFS support by default; verify for NextBSD's boot chain rather than assume it
## Userland (lands in nextbsd-freebsd-compat)
The image does not ship ZFS userland today. The srclist keeps `zfs`/`zpool`/`zdb` **only inside the `/rescue` crunchgen**, and marks `sbin/zfsbootcfg` **DROP -- "UFS-only boot"**. Bring in `sbin/zfs`, `sbin/zpool`, `zdb`, `libzfs` and its dependencies, and reverse the `zfsbootcfg` decision.
## Not in this ticket
Importing pools and mounting their datasets at boot under launchd, with no `/etc/fstab` -- that is E15, nextbsd/nextbsd-userland#200.
## Acceptance
- [ ] NEXTBSD builds with `options ZFS` on arm64 and amd64 in CI
- [ ] `zpool create` / `zpool import` / `zfs create` work on a virtio disk in the CI VM
- [ ] a system boots from a ZFS root (`zroot/ROOT/default`) on the gpt layout
- [ ] the mbr-fat (Pi) result is recorded, supported or not
- [ ] kernel size delta recorded</code></pre>
</div>
<div class="tk" id="z1">
<h3>Z1 · vdev_op_dumpio for vdev_geom, mirror and raidz <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#k6">K6</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/220">nextbsd-kernel#220</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
OpenZFS removed the illumos dump I/O operation -- there is no `vdev_op_dumpio` in `include/sys/vdev_impl.h`. Restore it; it is the raw-I/O leaf that both swap (Z3) and dumps use.
## Design
- add `vdev_op_dumpio_t` to `vdev_ops_t`, `NULL` in every initializer (~40 LOC)
- `vdev_geom_dumpio` in `module/os/freebsd/zfs/vdev_geom.c` (~150 LOC): cache the leaf `dumperinfo` via `g_io_getattr("GEOM::kerneldump")` at open (needs K6); add `VDEV_LABEL_START_SIZE`; at panic call the cached `di.dumper` directly (`g_up`/`g_down` are not running), otherwise `vdev_geom_io()`
- mirror: port illumos `vdev_mirror.c:786-813` (~40 LOC)
- raidz: port illumos `vdev_raidz.c:1680-1769` onto `raidz_row_t`, refuse during expansion (~120-200 LOC). **Can be deferred** -- single disk and mirror first.
- dRAID: unsupported
## Acceptance
- [ ] dumpio round trip on a single-disk pool and a mirror pool in a VM</code></pre>
</div>
<div class="tk" id="z2">
<h3>Z2 · Reinstate dmu_prealloc() <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td>—</td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/221">nextbsd-kernel#221</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
~20 LOC, from illumos `dmu.c:1251-1269`: `dmu_buf_hold_array` plus `dmu_buf_will_not_fill()` on each dbuf. Allocates real DVAs **without writing data** (DB_NOFILL).
## Why it is safe to restore
The primitive is live code in OpenZFS, not a vestige:
- `dmu_buf_will_not_fill()` at `module/zfs/dbuf.c:2973`, called internally at 3153 and 3194
- the DB_NOFILL write path at `dbuf.c:5500-5501` still asserts `zp_checksum == ZIO_CHECKSUM_OFF || zp_checksum == ZIO_CHECKSUM_NOPARITY`
## Acceptance
- [ ] preallocating a 1 GiB object on a `checksum=off` dataset yields fully allocated, non-gang level-0 blocks</code></pre>
</div>
<div class="tk" id="z3">
<h3>Z3 · Swapify: pin a ZFS file object -- property freeze, preallocation, DVA extent walk, DMU bypass <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#z1">Z1</a>, <a href="#z2">Z2</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/222">nextbsd-kernel#222</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
Port illumos dumpify to a ZPL file object, in a new `module/zfs/zfs_dump.c` (~600-800 LOC). This one mechanism feeds **both** K1 (swap) and K4 (dumps) on ZFS.
## How illumos handles copy-on-write
It does not make ZFS COW-safe; it makes COW irrelevant. While pinned, **every** read and write takes the dumpio bypass, so nothing ever dirties the object through the DMU, so no block pointer is rewritten, so the captured DVAs stay valid.
## Design
Port from `usr/src/uts/common/fs/zfs/zvol.c`:
| illumos | lines |
|---|---|
| `zvol_dump_init` | 1908-2064 |
| `zvol_dumpify` | 2067-2120 |
| `zvol_get_lbas` | 315-334 |
| `zvol_map_block` | 261-301 |
| `zvol_dumpio` | 1134-1170 |
- `ZVOL_OBJ` becomes `zp->z_id`
- require dataset `zroot/private/var/vm` with `checksum=off compression=off dedup=off copies=1 recordsize=128K`, no encryption
- `traverse_dataset` filtered on `zb_object`; coalesce adjacent DVAs; **reject `BP_IS_GANG`** (`EFRAGS`)
- all I/O while pinned goes through dumpio -- no DMU, tx, ARC or ZIL -- which keeps the ARC coherent
- extent array preallocated: no allocation at panic
- rebuild the map every boot; never cache it across boots
## Acceptance
- [ ] `swapon` and `dumpon` a file in `zroot/private/var/vm`
- [ ] larger-than-RAM paging test completes
- [ ] VM panic round trip recovers a vmcore</code></pre>
</div>
<div class="tk" id="z4">
<h3>Z4 · DSL guards for pinned objects -- and skip, not fail, them in recursive snapshot/send <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#z3">Z3</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/223">nextbsd-kernel#223</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
Operations that would move, share or reinterpret a pinned object's blocks must be refused while it is pinned.
## Refuse, with a clear error
- a snapshot aimed **directly** at the pinned dataset
- clone
- device removal (indirect vdevs remap DVAs)
- raidz expansion (relocates data)
- block cloning / BRT (`FICLONE` on the pinned file)
- `zfs destroy` of the dataset
## Skip, do not fail
`zfs snapshot -r` is atomic. If a pinned child refused, the **whole** recursive snapshot would fail -- silently breaking backup scripts, `sanoid` and `zfs-auto-snapshot`. So pinned datasets are **skipped** in recursive snapshot and `send -R`. Also set `com.sun:auto-snapshot=false` (the OpenZFS FAQ already recommends it for swap).
## Open
- **R4:** how resilver is ordered against concurrent bypass writes is unverified
## Acceptance
- [ ] each refused operation returns a clear error
- [ ] `zfs snapshot -r zroot/private@x` succeeds and excludes `vm`</code></pre>
</div>
<div class="tk" id="z5">
<h3>Z5 · Pager-level swap encryption (geli cannot cover a sub-range of a provider) <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#k1">K1</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/224">nextbsd-kernel#224</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
The usual FreeBSD encrypted-swap answer -- `geli onetime` on the swap device -- does not apply: geli cannot cover a sub-range of a provider, and an extent-mapped file is a set of sub-ranges. ZFS dataset encryption is incompatible with the bypass.
## Design
Encrypt in the pager, as xnu does (per-segment AES, `vm_swap_encrypt`): `crypto(9)` with an ephemeral per-boot key that is never persisted.
## Open
Plan Q2: port xnu's approach, or accept unencrypted swap initially?
## Acceptance
- [ ] swap blocks on disk are ciphertext
- [ ] the key does not survive reboot</code></pre>
</div>
<div class="tk" id="p1">
<h3>P1 · rpi5: verify NVMe polled crash dump on the Pi 500+ <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>area:vm</code> <code>area:rpi5</code> <code>needs-hardware</code></td></tr>
<tr><td>Depends on</td><td><a href="#k4">K4</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/225">nextbsd-kernel#225</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
`ndadump()` (`sys/cam/nvme/nvme_da.c:583`, installed as `d_dump` at `:1011`) polls through `cam_periph_runccb` when `dumping` (`cam_periph.c:1273-1300`) -> `nvme_sim_poll` -> `nvme_ctrlr_poll`. The Pi 500+ boots from NVMe over PCIe -> RP1.
Confirm the PCIe/RP1 path needs no interrupts at panic time and that a K4 dump completes.
## Acceptance
- [ ] a panic on the Pi 500+ produces a recoverable vmcore</code></pre>
</div>
<div class="tk" id="p2">
<h3>P2 · dwmmc: add a dumping path so d_dump does not hang <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>bug</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td>—</td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/226">nextbsd-kernel#226</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
`dwmmc_request()` (`sys/dev/mmc/host/dwmmc.c:1237`, `msleep` at `:1279`) has no `dumping` path and would hang at panic. `sdhci` already spins when `dumping` (`sys/dev/sdhci/sdhci.c:2159-2164`). Mirror that.
## Scope
~30 LOC.
## Acceptance
- [ ] an `mmcsd` dump completes on a dwmmc host</code></pre>
</div>
<div class="tk" id="p3">
<h3>P3 · CI: virtio-blk crash-dump harness so the dump path is tested before hardware <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd">nextbsd</a></td></tr>
<tr><td>Labels</td><td><code>area:vm</code> <code>area:ci</code></td></tr>
<tr><td>Depends on</td><td><a href="#k4">K4</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd/issues/469">nextbsd#469</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
`vtblk_dump` (`sys/dev/virtio/block/virtio_blk.c:644-667`) supports polled dumps, so the whole design can be exercised in the CI VM.
Add a stage: induce a panic, reboot, assert `savecore` recovers a vmcore. Pairs with #428 (iso-test/img-test declare PASS at the login prompt).
## Acceptance
- [ ] CI fails if a panic does not produce a recoverable dump</code></pre>
</div>
<div class="tk" id="u1">
<h3>U1 · swapd: grow and reclaim swapfiles under memory pressure <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-userland">nextbsd-userland</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td><a href="#k1">K1</a>, <a href="#k7">K7</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-userland/issues/178">nextbsd-userland#178</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
A launchd daemon that owns `/private/var/vm`. It is also the **activation path**: nothing under launchd runs `swapon -a` (#171).
## Design
- **Boot:** pin existing files; pin the corefile and register it with `dumpon`
- **Grow:** on `devctl` `VM/swap/LOWSPACE` (K7), create the next file on xnu's ladder, 256 MiB -> 1 GiB; back off 15 s on `ENOSPC`; refuse past `vm.swap_maxpages / 2` (4x RAM) unless `kern.maxswzone` was raised
- **Reclaim:** free swap above a high-water mark for N minutes -> `swapoff(2)` the newest file (handle `ENOMEM`; **never** default to `SWAPOFF_FORCE`) -> unlink
- `mlock` itself, and keep one pre-created file of headroom so growth is never on the critical path
## Known weakness
`swapd` must open and preallocate at exactly the moment memory is short. xnu's real answer is in-kernel creation (`vm_swapfile_create_thread`) -- see S1.
## Acceptance
- [ ] a WebKit-scale build on a 4 GB VM grows swap under pressure and reclaims it afterwards</code></pre>
</div>
<div class="tk" id="u2">
<h3>U2 · installer: create /private/var/vm (ZFS: zroot/private/var/vm) -- no partition, no sizing <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-userland">nextbsd-userland</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code> <code>area:live-media</code></td></tr>
<tr><td>Depends on</td><td><a href="#u1">U1</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-userland/issues/179">nextbsd-userland#179</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
`src/nextbsd-installer/engine/do-install.sh`. No `freebsd-swap` partition and no size decision.
## UFS
`mkdir /private/var/vm`
## ZFS
```
zroot/private mountpoint=/private canmount=off
zroot/private/var canmount=off
zroot/private/var/vm checksum=off compression=off dedup=off copies=1
recordsize=128K com.sun:auto-snapshot=false
zroot/private/var/crash exec=off setuid=off
```
The `canmount=off` parents keep `/private/etc` and most of `/private/var` inside `zroot/ROOT/default`, so they roll back with the boot environment.
**Create these early**, while the pool is unfragmented -- gang blocks are fatal to the extent walk.
Must work under both the mbr-fat (Pi) and gpt layouts.
## Acceptance
- [ ] a fresh install has the directory / datasets with the right properties
- [ ] `gpart show` contains no swap partition</code></pre>
</div>
<div class="tk" id="u3">
<h3>U3 · vm_stat / pagesize report real numbers from vm.stats instead of the 'feature not available' stub <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-userland">nextbsd-userland</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:vm</code> <code>good first issue</code></td></tr>
<tr><td>Depends on</td><td>—</td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-userland/issues/180">nextbsd-userland#180</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
freebsd-apple-userland-cmds v3 stubs the Mach VM introspection family. `vm_stat`'s columns map cleanly onto `sysctl vm.stats.vm.*` and `vm.swap_*`. Ship a FreeBSD backend for `vm_stat` and `pagesize`; keep the graceful stub only for jetsam-only fields.
## Acceptance
- [ ] `vm_stat` on the live ISO matches `top` / `sysctl` within one sample interval</code></pre>
</div>
<div class="tk" id="u4">
<h3>U4 · installer: ZFS install path -- F8 on the disk picker, pool layout, options and review (preliminary design) <span class="pill warn">design to refine</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-userland">nextbsd-userland</a></td></tr>
<tr><td>Labels</td><td><code>enhancement</code> <code>area:live-media</code> <code>area:storage</code></td></tr>
<tr><td>Depends on</td><td><a href="#z0">Z0</a>, <a href="#u2">U2</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-userland/issues/201">nextbsd-userland#201</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>> **Preliminary design -- not final.** The linked draft is a starting point and will be refined before implementation begins. Treat its screens, keys and defaults as proposals, not a spec.
**Design draft:** https://pkgdemon.github.io/nextbsd-installer-zfs-design.html
## Summary
Add a ZFS install path to `nextbsd-installer`. On the disk picker, **F8** switches from the single-disk UFS install to a multi-disk ZFS one. The marked disks are arranged into vdevs on a two-pane layout screen, followed by pool options and a review screen that shows exactly what will be erased before anything is written.
## Where the installer is today
- `src/screen_disk.cpp` is a 76-line single-select FTXUI `Menu` that handles only Return and Escape, and the engine holds a single `disk_index`. ZFS needs multi-select and a new layout screen -- it is more than a toggle.
- F8 is unused.
## Scope, per the draft
- **F8** toggles UFS / ZFS on the disk picker; **Space** marks disks in ZFS mode
- **Pool Layout**: <- -> move disks into and out of vdevs, **T** cycles single / mirror / raidz1 / raidz2 / raidz3, **N** adds a vdev, **D** deletes one; usable size and failure tolerance update live
- **Validation**: mirror needs 2 disks, raidzN needs N+1 (`vdev_raidz_open()`, and `zpool`'s `is_grouping()` sets `mindev = nparity + 1`); no mixed replication levels; every marked disk placed before Continue
- **Pool Options**: name, ashift (auto from the disks), compression, and encryption of **user data only** -- FreeBSD's loader can open a pool that uses encryption but cannot decrypt a dataset, so an encrypted root would not boot
- **Review**: pool, partitions (EFI + `freebsd-zfs` on each disk, **no swap partition**), the E14 dataset tree, and every volume that will be destroyed
- **Engine**: `gpart`, `zpool create`, and the datasets under `zroot/private` with `canmount=off` parents, so the boot environment stays intact
- ZFS stays disabled on the Pi's mbr-fat layout until Z0 records whether its boot chain can read ZFS
## Open decisions (draft section 7)
- Space: mark disks, or keep it for "toggle details"?
- home location: `/Users` or `/home` (`do-install.sh:264` preserves both)
- compression default: lz4 or zstd
- an EFI partition on every disk, so any mirror member can boot
## Depends on
- Z0 nextbsd/nextbsd-kernel#230 -- ZFS in the kernel, and `zfs`/`zpool` in the image
- A6 nextbsd/nextbsd-userland#200 -- mounting the datasets at boot, and prompting for the user-data passphrase
- U2 nextbsd/nextbsd-userland#179 -- the dataset layout
## Acceptance
- [ ] the design is refined and signed off **before** implementation starts
- [ ] a mirror install and a raidz install each boot in a VM
- [ ] the review screen lists every volume on every marked disk before erasing
- [ ] UFS installs are unchanged</code></pre>
</div>
<div class="tk" id="s1">
<h3>S1 · Spike: decouple page reclaim from swap-I/O completion (compressor-style staging) <span class="pill info">spike</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd-kernel">nextbsd-kernel</a></td></tr>
<tr><td>Labels</td><td><code>area:vm</code> <code>area:research</code></td></tr>
<tr><td>Depends on</td><td><a href="#k1">K1</a></td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd-kernel/issues/227">nextbsd-kernel#227</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
xnu's pageout stays robust independent of everything else because reclaim does not wait on swap writes: pages are freed by compressing them, and `vm_swapout_thread` drains already-compressed segments asynchronously (`vm_swap_put`). A stalled swap write slows the system rather than wedging the pagedaemon.
## Questions
- what would compressor-style staging look like on FreeBSD's VM?
- could in-kernel swapfile creation (`vm_swapfile_create_thread`) replace U1's userland growth, closing its known weakness?
## Deliverable
A design note with scope and a recommendation.</code></pre>
</div>
<div class="tk" id="x1">
<h3>X1 · Report upstream: zfs_putpages calls dmu_tx_assign(DMU_TX_WAIT) in pageout context <span class="pill ok">ready</span></h3>
<table class="meta">
<tr><td>Repo</td><td><a href="https://github.com/nextbsd/nextbsd">nextbsd</a></td></tr>
<tr><td>Labels</td><td><code>bug</code> <code>area:vm</code></td></tr>
<tr><td>Depends on</td><td>—</td></tr>
<tr><td>Filed as</td><td><a href="https://github.com/nextbsd/nextbsd/issues/470">nextbsd#470</a></td></tr>
<tr><td>Parent</td><td><a href="https://github.com/nextbsd/nextbsd/issues/468">nextbsd#468</a></td></tr>
</table>
<pre><code>## Summary
`module/os/freebsd/zfs/zfs_vnops_os.c` `zfs_putpages` takes `zfs_rangelock_enter` and **then** calls `dmu_tx_assign(tx, DMU_TX_WAIT)` in pageproc context, for dirty mmap'd pages. The file's own header comment (lines 131-155) documents exactly this as the deadlock pattern.
This exists on **every ZFS-root system today, with no swap involved**.
Compounding factors on FreeBSD:
- `KM_PUSHPAGE` is `#define`d to `M_WAITOK` (`include/os/freebsd/spl/sys/kmem.h:49`)
- `arc_memory_throttle()` returns 0 (`module/os/freebsd/zfs/arc_os.c:124`)
## Action
Decide whether to file with OpenZFS (plan Q4), and with what reproduction.</code></pre>
</div>
<h2 id="existing">Existing issues</h2>
<h3>Moved under E14</h3>
<table class="compact">
<tr><th>Issue</th><th>Title</th><th>Action</th></tr>
<tr><td><a href="https://github.com/nextbsd/nextbsd/issues/393">nextbsd#393</a></td><td>Wired memory usage (696 MB at idle)</td><td>Moved under E14 on 2026-09-20, from E11 (#444). It is a VM measurement task. area:desktop was removed and area:vm kept, because the Roadmap mirrors each issue's Epic as its area:* label. E11's body now notes where it went.</td></tr>
</table>
<h3>Link, do not migrate</h3>
<p>These stay in their current epics. Cross-link them from E14 and add <code>area:vm</code> where it applies.</p>
<table class="compact">
<tr><th>Issue</th><th>Epic</th><th>Why it relates</th></tr>
<tr><td><a href="https://github.com/nextbsd/nextbsd/issues/326">nextbsd#326</a></td><td>E8</td><td>Live ISO tmpfs overlay is swapless -- the measured OOM failure</td></tr>
<tr><td><a href="https://github.com/nextbsd/nextbsd/issues/329">nextbsd#329</a></td><td>E8</td><td>Cap the tmpfs overlay at ~50% of RAM</td></tr>
<tr><td><a href="https://github.com/nextbsd/nextbsd-userland/issues/171">nextbsd-userland#171</a></td><td>E13</td><td>launchd never runs mount -a -- the activation gap</td></tr>
<tr><td><a href="https://github.com/nextbsd/nextbsd-userland/issues/54">nextbsd-userland#54</a></td><td>E13</td><td>Who mounts the Linux ABI filesystems -- constrains the activation design</td></tr>
<tr><td><a href="https://github.com/nextbsd/nextbsd/issues/410">nextbsd#410</a></td><td>E2</td><td>Friendly kernel panic screen -- pairs with K4</td></tr>
<tr><td><a href="https://github.com/nextbsd/nextbsd/issues/428">nextbsd#428</a></td><td>E10</td><td>Test gates pass at the login prompt -- pairs with P3</td></tr>
<tr><td><a href="https://github.com/nextbsd/nextbsd/issues/66">nextbsd#66</a></td><td>E1</td><td>OOL receive VM fix -- nearest existing Mach-VM-on-FreeBSD work</td></tr>
<tr><td><a href="https://github.com/nextbsd/nextbsd/issues/350">nextbsd#350</a></td><td>E13</td><td>ext4/btrfs -- the filesystems half of the epic title</td></tr>
</table>
<h2 id="recreate">Recreating in GitHub</h2>
<p>Everything is filed; these commands are kept in case the issues ever need recreating. File the epic first, so that each child can name its parent, then the children in dependency order.</p>
<pre class="shell"><code># 1. the label, in all four repos
gh label create area:vm --color 5319e7 \
--description "Virtual memory, swap, paging, memory pressure, crash dumps, and the filesystems they back" \
--repo nextbsd/nextbsd-freebsd-compat # repeat for each repo
# 2. any single ticket: copy its body from this page into a file
gh issue create --repo nextbsd/nextbsd-kernel \
--title "..." --label enhancement,area:vm --body-file K1.md
# 3. or all of them, from the embedded JSON
curl -s https://pkgdemon.github.io/nextbsd-e14-tickets.html | python3 -c '
import sys, re, json
page = sys.stdin.read()
m = re.search(r"<script type=\"application/json\" id=\"e14-data\">(.*?)</script>", page, re.S)
print(json.dumps(json.loads(m.group(1)), indent=1))' > e14.json</code></pre>
<p>A script working from <code>e14.json</code> needs only the fields shown on this page: <code>id</code>, <code>title</code>, <code>repo</code>, <code>labels</code>, <code>depends</code>, <code>body</code>.</p>
<script type="application/json" id="e14-data">{
"generated": "2026-09-20",
"filed": {
"E14": {
"repo": "nextbsd/nextbsd",
"number": 468,
"url": "https://github.com/nextbsd/nextbsd/issues/468"
},
"K1": {
"repo": "nextbsd/nextbsd-kernel",
"number": 214,
"url": "https://github.com/nextbsd/nextbsd-kernel/issues/214"
},
"K2": {
"repo": "nextbsd/nextbsd-kernel",
"number": 215,
"url": "https://github.com/nextbsd/nextbsd-kernel/issues/215"
},
"K3": {
"repo": "nextbsd/nextbsd-freebsd-compat",
"number": 51,
"url": "https://github.com/nextbsd/nextbsd-freebsd-compat/issues/51"
},
"K4": {
"repo": "nextbsd/nextbsd-kernel",
"number": 216,
"url": "https://github.com/nextbsd/nextbsd-kernel/issues/216"
},
"K5": {
"repo": "nextbsd/nextbsd-freebsd-compat",
"number": 52,
"url": "https://github.com/nextbsd/nextbsd-freebsd-compat/issues/52"
},
"K6": {
"repo": "nextbsd/nextbsd-kernel",
"number": 217,
"url": "https://github.com/nextbsd/nextbsd-kernel/issues/217"
},
"K7": {
"repo": "nextbsd/nextbsd-kernel",
"number": 218,
"url": "https://github.com/nextbsd/nextbsd-kernel/issues/218"
},
"K8": {
"repo": "nextbsd/nextbsd-kernel",
"number": 219,
"url": "https://github.com/nextbsd/nextbsd-kernel/issues/219"
},
"Z1": {
"repo": "nextbsd/nextbsd-kernel",
"number": 220,
"url": "https://github.com/nextbsd/nextbsd-kernel/issues/220"
},
"Z2": {
"repo": "nextbsd/nextbsd-kernel",
"number": 221,
"url": "https://github.com/nextbsd/nextbsd-kernel/issues/221"
},
"Z3": {
"repo": "nextbsd/nextbsd-kernel",
"number": 222,
"url": "https://github.com/nextbsd/nextbsd-kernel/issues/222"
},
"Z4": {
"repo": "nextbsd/nextbsd-kernel",
"number": 223,