Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 1 May 2018 18:26:35 +0200
From:      Stefano Duo <duostefano93@gmail.com>
To:        freebsd-net@freebsd.org
Cc:        Vincenzo Maffione <v.maffione@gmail.com>
Subject:   Page fault inside ifunit_ref() FreeBSD12.0-CURRENT
Message-ID:  <CALkzoBv8rPXVwerJfGHt_69k2D9OUnYON6d3%2BTgrd6vAiGTWWw@mail.gmail.com>

next in thread | raw e-mail | index | archive | help
Hi,
I am a GSoC student working on netmap.

I am trying to get a kernel module to call nm_vi_create(), which creates a
persistent VALE port.
Internally, nm_vi_create() calls ifunit_ref() to check if an interface with
the specified name already exists.
The system panics inside ifunit_ref() due to a page fault while accessing
V_ifnet.
This happens using FreeBSD12.0-CURRENT.

To better understand what is going on, I have written a dummy module, that
only calls ifunit_ref(), here you can find the source code
https://github.com/StefanoDuo/ifunit_ref_test.
This is what I have found.

FreeBSD11.1-STABLE:
The module works correctly, either if loaded through kldload or compiled
with the kernel.

FreeBSD12.0-CURRENT:
Calling ifunit_ref() inside the module loader function does not cause a
page fault, while calling it inside a write() or ioctl() causes a page
fault. This happens either if the module is loaded through kldload or
compiled with the kernel.

Following Vincenzo's advice (he's one of my mentors), i tried enclosing the
call to ifunit_ref() between CURVNET_SET() and CURVNET_RESTORE().
This solves the problem on FreeBSD12.0-CURRENT, but only if the module is
compiled with the kernel, if loaded through kldload, i still get a page
fault.

The problem seems related to the virtualization of the network stack, and
therefore the of the V_ifnet variable.
It seems that inside the module loader function i have a struct vnet
selected, instead inside a write() or ioctl() call i do not.
This though, doesn't explain (at least to me) why adding CURVNET_SET() and
CURVNET_RESTORE(), doesn't solve the problem for modules loaded through
kldload.

I don't know if i'm doing something wrong (or not doing something needed),
or if it's a bug introduced in FreeBSD12.0-CURRENT.

Does anyone have a better idea of what's happening?


Here is the panic message i get after writing to the device (causing a call
to ifunit_ref).

[root@freebsd ~/repos/ifunit_ref_test/sys/modules/foo_module]# echo "test"
>/dev/FOO_DEV
Kernel page fault with the following non-sleepable locks held:
shared rw ifnet_rw (ifnet_rw) r = 0 (0xffffffff820474e8) locked @
/usr/src/sys/net/if.c:2379
stack backtrace:
#0 0xffffffff80ba5cd3 at witness_debugger+0x73
#1 0xffffffff80ba70b1 at witness_warn+0x461
#2 0xffffffff80ffe2d3 at trap_pfault+0x53
#3 0xffffffff80ffdad2 at trap+0x2f2
#4 0xffffffff80fd9d9c at calltrap+0x8
#5 0xffffffff8261d10e at foo_write+0x1e
#6 0xffffffff80a0a8c0 at devfs_write_f+0xf0
#7 0xffffffff80baad77 at dofilewrite+0xa7
#8 0xffffffff80baa968 at kern_writev+0x68
#9 0xffffffff80baa8f6 at sys_write+0x86
#10 0xffffffff80fff0cb at amd64_syscall+0x79b
#11 0xffffffff80fda5ed at fast_syscall_common+0x101


Fatal trap 12: page fault while in kernel mode
cpuid = 0; apic id = 00
fault virtual address   = 0x28
fault code              = supervisor read data, page not present
instruction pointer     = 0x20:0xffffffff80c3e2f2
stack pointer           = 0x28:0xfffffe00005c0950
frame pointer           = 0x28:0xfffffe00005c0960
code segment            = base 0x0, limit 0xfffff, type 0x1b
                        = DPL 0, pres 1, long 1, def32 0, gran 1
processor eflags        = interrupt enabled, resume, IOPL = 0
current process         = 700 (bash)
[ thread pid 700 tid 100087 ]
Stopped at      ifunit_ref+0x32:        movq    ll+0x7(%rax),%rax


And here you can find the backtrace taken from the dump.

(kgdb) l *0xffffffff80c3e2f2
0xffffffff80c3e2f2 is in ifunit_ref (/usr/src/sys/net/if.c:2380).
2375    ifunit_ref(const char *name)
2376    {
2377            struct ifnet *ifp;
2378
2379            IFNET_RLOCK_NOSLEEP();
2380            TAILQ_FOREACH(ifp, &V_ifnet, if_link) {
2381                    if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0 &&
2382                        !(ifp->if_flags & IFF_DYING))
2383                            break;
2384            }
(kgdb) bt
#0  __curthread () at ./machine/pcpu.h:230
#1  doadump (textdump=0) at /usr/src/sys/kern/kern_shutdown.c:361
#2  0xffffffff8040ac9b in db_dump (dummy=<optimized out>,
dummy2=<unavailable>,
    dummy3=<unavailable>, dummy4=<unavailable>) at
/usr/src/sys/ddb/db_command.c:574
#3  0xffffffff8040aa69 in db_command (last_cmdp=<optimized out>,
cmd_table=<optimized out>,
    dopager=<optimized out>) at /usr/src/sys/ddb/db_command.c:481
#4  0xffffffff8040a7e4 in db_command_loop () at
/usr/src/sys/ddb/db_command.c:534
#5  0xffffffff8040da0f in db_trap (type=<optimized out>, code=<optimized
out>)
    at /usr/src/sys/ddb/db_main.c:250
#6  0xffffffff80b85603 in kdb_trap (type=12, code=0, tf=<optimized out>)
    at /usr/src/sys/kern/subr_kdb.c:697
#7  0xffffffff80ffe1d0 in trap_fatal (frame=0xfffffe00005c0890, eva=40)
    at /usr/src/sys/amd64/amd64/trap.c:815
#8  0xffffffff80ffe2e2 in trap_pfault (frame=0xfffffe00005c0890,
usermode=<optimized out>)
    at /usr/src/sys/amd64/amd64/trap.c:664
#9  0xffffffff80ffdad2 in trap (frame=0xfffffe00005c0890) at
/usr/src/sys/amd64/amd64/trap.c:413
#10 <signal handler called>
#11 0xffffffff80c3e2f2 in ifunit_ref (name=0xffffffff8261d174 "FOO") at
/usr/src/sys/net/if.c:2380
#12 0xffffffff8261d10e in foo_write (dev=<optimized out>, uio=<optimized
out>,
    ioflag=<optimized out>)
    at
/root/repos/ifunit_ref_test/sys/modules/foo_module/../../dev/foo_module/foo_module.c:50
#13 0xffffffff80a0a8c0 in devfs_write_f (fp=<optimized out>,
uio=0xfffffe00005c0a80,
    cred=0xfffff80003fb0000, flags=0, td=<optimized out>) at
/usr/src/sys/fs/devfs/devfs_vnops.c:1784
#14 0xffffffff80baad77 in fo_write (fp=<optimized out>, uio=<optimized
out>, active_cred=0x1,
    flags=<optimized out>, td=<optimized out>) at
/usr/src/sys/sys/file.h:309
#15 dofilewrite (td=0xfffff80003fb0000, fd=1, fp=0xfffff8000401c820,
auio=0xfffffe00005c0a80,
    offset=<optimized out>, flags=0) at /usr/src/sys/kern/sys_generic.c:593
#16 0xffffffff80baa968 in kern_writev (td=0xfffff80003fb0000, fd=1,
auio=0xfffffe00005c0a80)
    at /usr/src/sys/kern/sys_generic.c:507
#17 0xffffffff80baa8f6 in sys_write (td=0x0, uap=<optimized out>)
    at /usr/src/sys/kern/sys_generic.c:421
#18 0xffffffff80fff0cb in syscallenter (td=0xfffff80003fb0000)
    at /usr/src/sys/amd64/amd64/../../kern/subr_syscall.c:134
#19 amd64_syscall (td=0xfffff80003fb0000, traced=0) at
/usr/src/sys/amd64/amd64/trap.c:936
#20 <signal handler called>
#21 0x0000000800b7baca in ?? ()
Backtrace stopped: Cannot access memory at address 0x7fffffffe808


Thanks,
Stefano.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CALkzoBv8rPXVwerJfGHt_69k2D9OUnYON6d3%2BTgrd6vAiGTWWw>