Re: [PATCH V4 0/2] ndctl: Add daxctl support for the new "famfs" mode of devdax

Alison Schofield
2026-02-09T23:13:18Z

On Sun, Jan 18, 2026 at 10:36:02PM +0000, John Groves wrote:
> From: John Groves <john@groves.net>
>
> No change since V2 - re-sending due to technical challenges.
>
> No change since V1 - reposting as V2 to keep this with the related
> kernel (dax and fuse) patches and libfuse patches.
>
> This short series adds support and tests to daxctl for famfs[1]. The
> famfs kernel patch series, under the same "compound cover" as this
> series, adds a new 'fsdev_dax' driver for devdax. When that driver
> is bound (instead of device_dax), the device is in 'famfs' mode rather
> than 'devdax' mode.
>

Hi John,

I fired this all up and ran it. It got through all but it's last test
case before failing.

Three things appended:
1) the diff I applied to daxctl-famfs.sh to run the test
2) testlog.txt output of the test
3) RIP: 0010:is_free_buddy_page+0x39/0x60 kernel log

1) Diff I applied to execute the test:

diff --git a/test/daxctl-famfs.sh b/test/daxctl-famfs.sh
index 12fbfefa3144..a4e8d87b9762 100755
--- a/test/daxctl-famfs.sh
+++ b/test/daxctl-famfs.sh
@@ -9,6 +9,17 @@ rc=77

trap 'cleanup $LINENO' ERR

+# Use cxl-test module to get the DAX device of the CXL auto region,
+# which also makes this test NON destructive.
+#
+# The $CXL list below is a delay because find_daxdev() was not
+# finding the DAX region without it.
+#
+modprobe -r cxl-test
+modprobe cxl-test
+$CXL list
+
+
daxdev=""
original_mode=""

2) Log of Meson test suite run on 2026-02-09T14:52:40.498801

1/1 ndctl:dax / daxctl-famfs.sh INTERRUPT 230.60s killed by signal 15 SIGTERM
22:52:40 MALLOC_PERTURB_=233 LC_ALL=C TEST_PATH=/root/ndctl/build/test NDCTL=/root/ndctl/build/ndctl/ndctl DAXCTL=/root/ndctl/build/daxctl/daxctl DATA_PATH=/root/ndctl/test CXL=/root/ndctl/build/cxl/cxl /root/ndctl/test/daxctl-famfs.sh
----------------------------------- output -----------------------------------
stdout:

Found dax device: dax6.0 (current mode: system-ram)

=== Testing famfs mode transitions ===
Device is in system-ram mode, attempting to convert to devdax...
[
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"devdax"
}
]
Initial mode: devdax - OK
Testing devdax -> famfs... [
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"famfs"
}
]
OK
Testing famfs -> famfs (re-enable)... [
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"famfs"
}
]
OK
Testing famfs -> devdax... [
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"devdax"
}
]
OK
Testing devdax -> devdax (re-enable)... [
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"devdax"
}
]
OK

=== Testing JSON output for mode field ===
Testing JSON output for devdax mode... OK
[
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"famfs"
}
]
Testing JSON output for famfs mode... OK
[
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"devdax"
}
]

=== Testing error handling ===
[
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"famfs"
}
]
Testing invalid mode rejection... OK (correctly rejected)
[
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"devdax"
}
]

=== Testing system-ram transitions with famfs ===
Testing devdax -> system-ram... [
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"system-ram",
"online_memblocks":0,
"total_memblocks":4
}
]
OK
Testing system-ram -> famfs (should fail)... OK (correctly rejected)
Testing system-ram -> devdax -> famfs... [
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"devdax"
}
]
[
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"famfs"
}
]
OK
[
{
"chardev":"dax6.0",
"size":536870912,
"target_node":0,
"align":2097152,
"mode":"devdax"
}
]

Restoring device to original mode: system-ram
Error at line 255
stderr:
+ rc=77
++ dirname /root/ndctl/test/daxctl-famfs.sh
+ . /root/ndctl/test/common
+++ basename /root/ndctl/test/daxctl-famfs.sh
++ test_basename=daxctl-famfs.sh
++ '[' -z /root/ndctl/build/ndctl/ndctl ']'
++ '[' -z /root/ndctl/build/daxctl/daxctl ']'
++ '[' -z /root/ndctl/build/cxl/cxl ']'
++ '[' -z /root/ndctl/build/test ']'
++ NFIT_TEST_BUS0=nfit_test.0
++ NFIT_TEST_BUS1=nfit_test.1
++ CXL_TEST_BUS=cxl_test
++ ACPI_BUS=ACPI.NFIT
++ E820_BUS=e820
++ CXL_TEST_QOS_CLASS=42
+ trap 'cleanup $LINENO' ERR
+ modprobe -r cxl-test
+ modprobe cxl-test
+ /root/ndctl/build/cxl/cxl list
+ daxdev=
+ original_mode=
+ main
+ check_fsdev_dax
+ modinfo fsdev_dax
+ return 0
+ find_daxdev
++ /root/ndctl/build/daxctl/daxctl list
++ jq -er '.[0].chardev // empty'
+ daxdev=dax6.0
+ [[ ! -n dax6.0 ]]
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ original_mode=system-ram
+ printf 'Found dax device: %s (current mode: %s)\n' dax6.0 system-ram
+ rc=1
+ test_famfs_mode_transitions
+ printf '\n=== Testing famfs mode transitions ===\n'
+ ensure_devdax_mode
+ local mode
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ mode=system-ram
+ [[ system-ram == \d\e\v\d\a\x ]]
+ [[ system-ram == \s\y\s\t\e\m\-\r\a\m ]]
+ printf 'Device is in system-ram mode, attempting to convert to devdax...\n'
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -f -m devdax dax6.0
dax6.0: all memory sections (4) already offline
reconfigured 1 device
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ [[ devdax == \d\e\v\d\a\x ]]
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ [[ devdax == \d\e\v\d\a\x ]]
+ printf 'Initial mode: devdax - OK\n'
+ printf 'Testing devdax -> famfs... '
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m famfs dax6.0
reconfigured 1 device
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ [[ famfs == \f\a\m\f\s ]]
+ printf 'OK\n'
+ printf 'Testing famfs -> famfs (re-enable)... '
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m famfs dax6.0
reconfigured 1 device
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ [[ famfs == \f\a\m\f\s ]]
+ printf 'OK\n'
+ printf 'Testing famfs -> devdax... '
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m devdax dax6.0
reconfigured 1 device
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ [[ devdax == \d\e\v\d\a\x ]]
+ printf 'OK\n'
+ printf 'Testing devdax -> devdax (re-enable)... '
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m devdax dax6.0
reconfigured 1 device
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ [[ devdax == \d\e\v\d\a\x ]]
+ printf 'OK\n'
+ test_json_output
+ printf '\n=== Testing JSON output for mode field ===\n'
+ ensure_devdax_mode
+ local mode
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ mode=devdax
+ [[ devdax == \d\e\v\d\a\x ]]
+ return 0
+ printf 'Testing JSON output for devdax mode... '
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ mode=devdax
+ [[ devdax == \d\e\v\d\a\x ]]
+ printf 'OK\n'
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m famfs dax6.0
reconfigured 1 device
+ printf 'Testing JSON output for famfs mode... '
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ mode=famfs
+ [[ famfs == \f\a\m\f\s ]]
+ printf 'OK\n'
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m devdax dax6.0
reconfigured 1 device
+ test_error_handling
+ printf '\n=== Testing error handling ===\n'
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m famfs dax6.0
reconfigured 1 device
+ printf 'Testing invalid mode rejection... '
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m invalidmode dax6.0
+ printf 'OK (correctly rejected)\n'
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m devdax dax6.0
reconfigured 1 device
+ check_kmem
+ modinfo kmem
+ return 0
++ cat /sys/devices/system/memory/auto_online_blocks
+ saved_policy=offline
+ echo offline
+ test_system_ram_transitions
+ printf '\n=== Testing system-ram transitions with famfs ===\n'
+ ensure_devdax_mode
+ local mode
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ mode=devdax
+ [[ devdax == \d\e\v\d\a\x ]]
+ return 0
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ [[ devdax == \d\e\v\d\a\x ]]
+ printf 'Testing devdax -> system-ram... '
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -N -m system-ram dax6.0
reconfigured 1 device
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ [[ system-ram == \s\y\s\t\e\m\-\r\a\m ]]
+ printf 'OK\n'
+ printf 'Testing system-ram -> famfs (should fail)... '
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m famfs dax6.0
+ printf 'OK (correctly rejected)\n'
+ printf 'Testing system-ram -> devdax -> famfs... '
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -f -m devdax dax6.0
dax6.0: all memory sections (4) already offline
reconfigured 1 device
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ [[ devdax == \d\e\v\d\a\x ]]
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m famfs dax6.0
reconfigured 1 device
++ daxctl_get_mode dax6.0
++ /root/ndctl/build/daxctl/daxctl list -d dax6.0
++ jq -er '.[].mode'
+ [[ famfs == \f\a\m\f\s ]]
+ printf 'OK\n'
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -m devdax dax6.0
reconfigured 1 device
+ echo offline
+ printf '\nRestoring device to original mode: %s\n' system-ram
+ /root/ndctl/build/daxctl/daxctl reconfigure-device -f -m system-ram dax6.0
/root/ndctl/test/daxctl-famfs.sh: line 231: 1266 Killed "$DAXCTL" reconfigure-device -f -m "$original_mode" "$daxdev"
++ cleanup 255
++ printf 'Error at line %d\n' 255
++ [[ -n dax6.0 ]]
++ [[ -n system-ram ]]
++ /root/ndctl/build/daxctl/daxctl reconfigure-device -f -m system-ram dax6.0
------------------------------------------------------------------------------

Summary of Failures:

1/1 ndctl:dax / daxctl-famfs.sh INTERRUPT 230.60s killed by signal 15 SIGTERM

Ok: 0
Expected Fail: 0
Fail: 1
Unexpected Pass: 0
Skipped: 0
Timeout: 0

3) BUG: unable to handle page fault for address: ffffc9000f508033
[ 343.806681] #PF: supervisor read access in kernel mode
[ 343.808158] #PF: error_code(0x0000) - not-present page
[ 343.809635] PGD 80a067 P4D 80a067 PUD 1936067 PMD 12eeb9067 PTE 0
[ 343.811357] Oops: Oops: 0000 [#1] SMP NOPTI
[ 343.812634] CPU: 4 UID: 0 PID: 1266 Comm: daxctl Tainted: G O 6.19.0-rc5+ #106 PREEMPT(voluntary)
[ 343.815263] Tainted: [O]=OOT_MODULE
[ 343.816423] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015
[ 343.818507] RIP: 0010:is_free_buddy_page+0x39/0x60
[ 343.819466] Code: 00 00 00 48 c1 fe 06 eb 0a 48 83 c1 01 48 83 f9 0b 74 30 44 89 c0 48 89 fa d3 e0 83 e8 01 48 98 48 21 f0 48 c1 e0 06 48 29 c2 <80> 7a 33 f0 75 d9 48 8b 42 28 48 39 c8 72 d0 b8 01 00 00 00 c3 cc
[ 343.822668] RSP: 0018:ffffc9000f50f828 EFLAGS: 00010286
[ 343.823719] RAX: 0000000000007a80 RBX: ffffc9000f50f8a0 RCX: 0000000000000009
[ 343.825021] RDX: ffffc9000f508000 RSI: ffffff7c003d43ea RDI: ffffc9000f50fa80
[ 343.826343] RBP: ffffc9000f50f838 R08: 0000000000000001 R09: 00000000ffefffff
[ 343.827651] R10: ffffc9000f50fa38 R11: ffff888376ffe000 R12: ffffc9000f50fa80
[ 343.828834] R13: ffffc9000f50f9a0 R14: 0000000000000006 R15: 0000000000000001
[ 343.829725] FS: 00007f0f83e087c0(0000) GS:ffff8881fa8f8000(0000) knlGS:0000000000000000
[ 343.830765] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 343.831581] CR2: ffffc9000f508033 CR3: 000000012dec6003 CR4: 0000000000370ef0
[ 343.832517] Call Trace:
[ 343.832964] <TASK>
[ 343.833385] ? set_ps_flags.constprop.0+0x3c/0x70
[ 343.834099] snapshot_page+0x2ca/0x330
[ 343.834679] __dump_page+0x2e/0x380
[ 343.835260] ? up+0x5a/0x90
[ 343.835757] dump_page+0x16/0x50
[ 343.836324] ? dump_page+0x16/0x50
[ 343.836861] __get_pfnblock_flags_mask+0x6f/0xd0
[ 343.837520] get_pfnblock_migratetype+0xe/0x30
[ 343.838192] __dump_page+0x15b/0x380
[ 343.838692] dump_page+0x16/0x50
[ 343.839111] ? dump_page+0x16/0x50
[ 343.839504] __set_pfnblock_flags_mask.constprop.0+0x6f/0xf0
[ 343.840093] init_pageblock_migratetype+0x39/0x60
[ 343.840589] memmap_init_range+0x165/0x290
[ 343.841069] move_pfn_range_to_zone+0xed/0x200
[ 343.841548] mhp_init_memmap_on_memory+0x23/0xb0
[ 343.842062] memory_subsys_online+0x127/0x1a0
[ 343.842542] device_online+0x4d/0x90
[ 343.842986] state_store+0x96/0xa0
[ 343.843393] dev_attr_store+0x12/0x30
[ 343.843809] sysfs_kf_write+0x48/0x70
[ 343.844231] kernfs_fop_write_iter+0x160/0x210
[ 343.844714] vfs_write+0x261/0x500
[ 343.845185] ksys_write+0x5c/0xf0
[ 343.845584] __x64_sys_write+0x14/0x20
[ 343.846040] x64_sys_call+0x1fbc/0x1ff0
[ 343.846480] do_syscall_64+0x67/0x370
[ 343.846905] entry_SYSCALL_64_after_hwframe+0x71/0x79
[ 343.847432] RIP: 0033:0x7f0f83d01c37
[ 343.847838] Code: 0f 00 f7 d8 64 89 02 48 c7 c0 ff ff ff ff eb b7 0f 1f 00 f3 0f 1e fa 64 8b 04 25 18 00 00 00 85 c0 75 10 b8 01 00 00 00 0f 05 <48> 3d 00 f0 ff ff 77 51 c3 48 83 ec 28 48 89 54 24 18 48 89 74 24
[ 343.849536] RSP: 002b:00007ffe63e1f148 EFLAGS: 00000246 ORIG_RAX: 0000000000000001
[ 343.850282] RAX: ffffffffffffffda RBX: 00007ffe63e1f708 RCX: 00007f0f83d01c37
[ 343.850997] RDX: 000000000000000f RSI: 00007f0f83ef543e RDI: 0000000000000004
[ 343.851692] RBP: 00007ffe63e1f180 R08: 0000000000000000 R09: 0000000000000073
[ 343.852405] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
[ 343.853112] R13: 00007ffe63e1f740 R14: 0000000000414da0 R15: 00007f0f83f3b000
[ 343.853789] </TASK>
[ 343.854109] Modules linked in: cxl_test(O) cxl_mem(O) cxl_pmem(O) cxl_acpi(O) cxl_port(O) cxl_mock(O) device_dax(O) fsdev_dax kmem dax_cxl cxl_mock_mem(O) cxl_core(O) dax_pmem(O) nd_pmem(O) nd_btt(O) nfit(O) nd_e820(O) libnvdimm(O) nfit_test_iomap(O) [last unloaded: cxl_mock(O)]
[ 343.856252] CR2: ffffc9000f508033
[ 343.856656] ---[ end trace 0000000000000000 ]---
[ 343.857172] RIP: 0010:is_free_buddy_page+0x39/0x60
[ 343.857678] Code: 00 00 00 48 c1 fe 06 eb 0a 48 83 c1 01 48 83 f9 0b 74 30 44 89 c0 48 89 fa d3 e0 83 e8 01 48 98 48 21 f0 48 c1 e0 06 48 29 c2 <80> 7a 33 f0 75 d9 48 8b 42 28 48 39 c8 72 d0 b8 01 00 00 00 c3 cc
[ 343.859395] RSP: 0018:ffffc9000f50f828 EFLAGS: 00010286
[ 343.859929] RAX: 0000000000007a80 RBX: ffffc9000f50f8a0 RCX: 0000000000000009
[ 343.860614] RDX: ffffc9000f508000 RSI: ffffff7c003d43ea RDI: ffffc9000f50fa80
[ 343.861333] RBP: ffffc9000f50f838 R08: 0000000000000001 R09: 00000000ffefffff
[ 343.862076] R10: ffffc9000f50fa38 R11: ffff888376ffe000 R12: ffffc9000f50fa80
[ 343.862753] R13: ffffc9000f50f9a0 R14: 0000000000000006 R15: 0000000000000001
[ 343.863477] FS: 00007f0f83e087c0(0000) GS:ffff8881fa8f8000(0000) knlGS:0000000000000000
[ 343.864268] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[ 343.864855] CR2: ffffc9000f508033 CR3: 000000012dec6003 CR4: 0000000000370ef0
[ 343.865542] note: daxctl[1266] exited with irqs disabled