Page MenuHomeFreeBSD

loader: do not try to mount currdev for TFTP
ClosedPublic

Authored by sjg on Jul 20 2025, 11:06 PM.
Tags
None
Referenced Files
Unknown Object (File)
Fri, Oct 10, 12:07 AM
Unknown Object (File)
Fri, Oct 10, 12:07 AM
Unknown Object (File)
Fri, Oct 10, 12:07 AM
Unknown Object (File)
Fri, Oct 10, 12:06 AM
Unknown Object (File)
Thu, Oct 9, 8:07 PM
Unknown Object (File)
Thu, Oct 2, 4:59 AM
Unknown Object (File)
Fri, Sep 26, 12:42 AM
Unknown Object (File)
Tue, Sep 23, 9:57 PM
Subscribers

Details

Summary

Mounting net0:/ via TFTP does not work, and depending
on the tftp server the attempt can add significant delays to boot.
Unless netproto is NET_NFS skip mount currdir for net0:

Sponsored by: Juniper Networks, Inc.

Diff Detail

Repository
rG FreeBSD src repository
Lint
Lint Not Applicable
Unit
Tests Not Applicable

Event Timeline

sjg requested review of this revision.Jul 20 2025, 11:06 PM
stand/common/misc.c
206 ↗(On Diff #158844)

I don't know that this extra check is worthwhile, in all the scenarios I've tested (when we want to skip the mount attempt) netproto==0 ie NET_NONE

Rework to avoid opening dirs via TFTP while not breaking diskless
boot with nfs.

I do like this better...

But what we're trying to avoid is setting currdir to tftp://1.2.3.4/mumble and having lots of tftp traffic go as we try to open it a bunch of times to see if each of the filesystems can cope... Can you confirm that's the top of this rabbit hole?

So let me look at that. part of the problem is how mount was implemented, and we also have an n^2 thing going on where we try to mount all the filesystems, and to do that we try to open the filesystem mountpoint, but we try all the filesystems to open that... And that just seems wrong... We already have a NULL fo_mount for tftp, and that should be enough... It seems like this indicates a problem more fundamental... If I can't find a better path forward, we'll fix this up and go from there.

You don't, by chance, have a good way to reproduce this with qemu, do you?

stand/libsa/mount.c
95

if (is_tftp()) return (0); here would be better than the code below. It's the same since the break leaves rc==-1 which is converted to 0.

But I think the real issue is this weird recursive thing to take a device, try and open it with a given filesystem, and many of the FS don't say 'am I trying to do this on a disk, no get out'. But I'm not completely sure of that so I need to think.

In D51447#1175667, @imp wrote:

I do like this better...

But what we're trying to avoid is setting currdir to tftp://1.2.3.4/mumble and having lots of tftp traffic go as we try to open it a bunch of times to see if each of the filesystems can cope... Can you confirm that's the top of this rabbit hole?

Actually in the problem case it is just the 1st attempt to open "/" via tftp that takes forever if you have the Linux tftp server.
I don't see any comparable impact with FreeBSD's tftp server.
So the goal of this patch is to detect is_tftp as early as possible, and skip trying to opendir - let alone mount neither of which serve any purpose.

So let me look at that. part of the problem is how mount was implemented, and we also have an n^2 thing going on where we try to mount all the filesystems, and to do that we try to open the filesystem mountpoint, but we try all the filesystems to open that... And that just seems wrong... We already have a NULL fo_mount for tftp, and that should be enough... It seems like this indicates a problem more fundamental... If I can't find a better path forward, we'll fix this up and go from there.

It would probably be easier to fix this if the devopen() wasn't hidden behind open() but that's likely a rather substantial change.

You don't, by chance, have a good way to reproduce this with qemu, do you?

I'm testing using bhyve mostly with FreeBSD's tftp server, if I see tftpd log an attempt to open a dir I know we have an issue.
For the arm64 platform I need to use real h/w and finding one that will load an unsigned loader is a pain - hence I test what I can on amd64 and vm, and just confirm results on the real h/w

Note: I checked that booting diskless with root-path via nfs still works

stand/libsa/mount.c
95

if (is_tftp()) return (0); here would be better than the code below. It's the same since the break leaves rc==-1 which is converted to 0.

But I think the real issue is this weird recursive thing to take a device, try and open it with a given filesystem, and many of the FS don't say 'am I trying to do this on a disk, no get out'. But I'm not completely sure of that so I need to think.

We can't do that, as it isn't until we've done one of the open's via the calls below that we discover that we are tftp.

Any way you slice it this is currently a very twisty maze

This revision was not accepted when it landed; it landed in state Needs Review.Aug 20 2025, 10:48 PM
This revision was automatically updated to reflect the committed changes.

This commit seems to break the build (even on a clean build) with the following error:

ld: error: undefined symbol: is_tftp
>>> referenced by mount.c:112 (/home/siva/src/freebsd-src/stand/libsa/mount.c:112)
>>>               mount.o:(mount) in archive /home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/stand/libsa/libsa.a
>>> referenced by open.c:191 (/home/siva/src/freebsd-src/stand/libsa/open.c:191)
>>>               open.o:(open) in archive /home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/stand/libsa/libsa.a
cc: error: linker command failed with exit code 1 (use -v to see invocation)
*** [loader.kboot] Error code 1

make[6]: stopped making "all" in /home/siva/src/freebsd-src/stand/kboot/kboot
.ERROR_TARGET='loader.kboot'
.ERROR_META_FILE='/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/stand/kboot/kboot/loader.kboot.meta'
.MAKE.LEVEL='6'
MAKEFILE=''
.MAKE.MODE='meta missing-filemon=yes missing-meta=yes silent=yes verbose'
_ERROR_CMD='cc -target x86_64-unknown-freebsd15.0 --sysroot=/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/tmp -B/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/tmp/usr/bin -O2 -pipe -fno-common -I/home/siva/src/freebsd-src/stand/kboot/include -I/home/siva/src/freebsd-src/stand/kboot/include/arch/amd64 -nostdinc -I/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/stand/libsa -I/home/siva/src/freebsd-src/stand/libsa -D_STANDALONE -I/home/siva/src/freebsd-src/sys -Ddouble=jagged-little-pill -Dfloat=floaty-mcfloatface -ffunction-sections -fdata-sections -DLOADER_GELI_SUPPORT -I/home/siva/src/freebsd-src/stand/libsa/geli -DLOADER_DISK_SUPPORT -ffreestanding -mno-mmx -mno-sse -mno-avx -mno-avx2 -msoft-float -fPIC -mno-red-zone -mno-relax -I. -Iinclude -I/home/siva/src/freebsd-src/stand/libsa/zfs -I/home/siva/src/freebsd-src/sys/contrib/openzfs/include -I/home/siva/src/freebsd-src/sys/contrib/openzfs/include/os/freebsd/zfs -I/home/siva/src/freebsd-src/sys/contrib/dev/acpica/include -I/home/siva/src/freebsd-src/stand/common -I/home/siva/src/freebsd-src/contrib/lua/src -I/home/siva/src/freebsd-src/stand/common -I/home/siva/src/freebsd-src/stand/liblua -DLOADER_CD9660_SUPPORT -DLOADER_EXT2FS_SUPPORT -DLOADER_UFS_SUPPORT -DLOADER_GPT_SUPPORT -DLOADER_MBR_SUPPORT -DLOADER_ZFS_SUPPORT -I/home/siva/src/freebsd-src/stand/libsa/zfs -I/home/siva/src/freebsd-src/sys/cddl/boot/zfs -I/home/siva/src/freebsd-src/sys/cddl/contrib/opensolaris/uts/common -DHELP_FILENAME=\"loader.help.kboot\" -I/home/siva/src/freebsd-src/stand/kboot/kboot -I/home/siva/src/freebsd-src/stand/kboot/kboot/arch/amd64 -Wall -std=gnu17 -Wno-format-zero-length -Wsystem-headers -Werror -Wno-pointer-sign -Wdate-time -Wno-empty-body -Wno-string-plus-int -Wno-unused-const-variable -Wno-error=unused-but-set-parameter -Wno-error=cast-function-type-mismatch -Wno-tautological-compare -Wno-unused-value -Wno-parentheses-equality -Wno-unused-function -Wno-enum-conversion -Wno-unused-local-typedef -Wno-address-of-packed-member -Wno-switch -Wno-switch-enum -Wno-knr-promoted-parameter -Wno-parentheses -Oz -Qunused-arguments -nostdlib -static -T /home/siva/src/freebsd-src/stand/kboot/kboot/arch/amd64/amd64.ldscript -Wl,-zrelro    -o loader.kboot bootinfo.o conf.o hostcons.o hostdisk.o hostfs.o init.o main.o vers.o amd64_tramp.o elf64_freebsd.o load_addr.o fdt_arch.o boot.o commands.o console.o devopen.o interp.o interp_backslash.o interp_parse.o ls.o misc.o modinfo.o module.o nvstore.o pnglite.o tslog.o load_elf32.o load_elf32_obj.o reloc_elf32.o load_elf64.o load_elf64_obj.o reloc_elf64.o disk.o part.o vdisk.o interp_lua.o zfs_cmd.o lua_bindings.o  /home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/stand/liblua/liblua.a   /home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/stand/libsa/libsa.a /home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/stand/kboot/libkboot/libkboot.a ;'
.CURDIR='/home/siva/src/freebsd-src/stand/kboot/kboot'
.MAKE='make'
.OBJDIR='/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/stand/kboot/kboot'
.TARGETS='all'
CPUTYPE=''
DESTDIR='/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/tmp'
LD_LIBRARY_PATH=''
MACHINE='amd64'
MACHINE_ARCH='amd64'
MACHINE_CPUARCH='amd64'
MAKEOBJDIRPREFIX=''
MAKESYSPATH='/home/siva/src/freebsd-src/share/mk'
MAKE_VERSION='20250804'
PATH='/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/tmp/bin:/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/tmp/usr/sbin:/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/tmp/usr/bin:/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/tmp/legacy/usr/sbin:/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/tmp/legacy/usr/bin:/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/tmp/legacy/bin:/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64/tmp/legacy/usr/libexec::/sbin:/bin:/usr/sbin:/usr/bin'
SRCTOP='/home/siva/src/freebsd-src'
OBJTOP='/home/siva/.cache/obj/myfreebsd/dev/home/siva/src/freebsd-src/amd64.amd64'
.MAKE.MAKEFILES='/home/siva/src/freebsd-src/share/mk/sys.mk /home/siva/src/freebsd-src/share/mk/local.sys.env.mk /home/siva/src/freebsd-src/share/mk/src.sys.env.mk /home/siva/src/mypoudriere/dev/src-env.conf /home/siva/src/freebsd-src/share/mk/bsd.mkopt.mk /home/siva/src/freebsd-src/share/mk/src.sys.obj.mk /home/siva/src/freebsd-src/share/mk/local.sys.machine.mk /home/siva/src/freebsd-src/share/mk/meta.sys.mk /home/siva/src/freebsd-src/share/mk/local.meta.sys.env.mk /home/siva/src/freebsd-src/share/mk/auto.obj.mk /home/siva/src/freebsd-src/share/mk/bsd.suffixes.mk /home/siva/src/mypoudriere/dev/make.conf /home/siva/src/freebsd-src/share/mk/local.sys.mk /home/siva/src/freebsd-src/share/mk/src.sys.mk /home/siva/src/mypoudriere/dev/src.conf /home/siva/src/freebsd-src/stand/kboot/kboot/Makefile /home/siva/src/freebsd-src/share/mk/bsd.init.mk /home/siva/src/freebsd-src/share/mk/bsd.opts.mk /home/siva/src/freebsd-src/share/mk/bsd.cpu.mk /home/siva/src/freebsd-src/share/mk/local.init.mk /home/siva/src/freebsd-src/share/mk/src.init.mk /home/siva/src/freebsd-src/stand/kboot/kboot/../Makefile.inc /home/siva/src/freebsd-src/stand/kboot/kboot/../../Makefile.inc /home/siva/src/freebsd-src/stand/kboot/kboot/../../defs.mk /home/siva/src/freebsd-src/share/mk/src.opts.mk /home/siva/src/freebsd-src/share/mk/bsd.own.mk /home/siva/src/freebsd-src/share/mk/bsd.compiler.mk /home/siva/src/freebsd-src/share/mk/bsd.endian.mk /home/siva/src/freebsd-src/share/mk/bsd.linker.mk /home/siva/src/freebsd-src/stand/veriexec.mk /home/siva/src/freebsd-src/stand/fdt.mk /home/siva/src/freebsd-src/stand/kboot/kboot/arch/amd64/Makefile.inc /home/siva/src/freebsd-src/stand/loader.mk /home/siva/src/freebsd-src/stand/lua.mk /home/siva/src/freebsd-src/share/mk/bsd.prog.mk /home/siva/src/freebsd-src/share/mk/bsd.suffixes-extra.mk /home/siva/src/freebsd-src/share/mk/bsd.sanitizer.mk /home/siva/src/freebsd-src/share/mk/bsd.libnames.mk /home/siva/src/freebsd-src/share/mk/src.libnames.mk /home/siva/src/freebsd-src/share/mk/bsd.nls.mk /home/siva/src/freebsd-src/share/mk/bsd.confs.mk /home/siva/src/freebsd-src/share/mk/bsd.files.mk /home/siva/src/freebsd-src/share/mk/bsd.dirs.mk /home/siva/src/freebsd-src/share/mk/bsd.incs.mk /home/siva/src/freebsd-src/share/mk/bsd.links.mk /home/siva/src/freebsd-src/share/mk/bsd.man.mk /home/siva/src/freebsd-src/share/mk/bsd.dep.mk /home/siva/src/freebsd-src/share/mk/bsd.clang-analyze.mk /home/siva/src/freebsd-src/share/mk/bsd.obj.mk /home/siva/src/freebsd-src/share/mk/bsd.subdir.mk /home/siva/src/freebsd-src/share/mk/bsd.sys.mk /dev/null'
.PATH='. /home/siva/src/freebsd-src/stand/kboot/kboot /home/siva/src/freebsd-src/stand/efi/loader /home/siva/src/freebsd-src/stand/kboot/kboot/arch/amd64 /home/siva/src/freebsd-src/stand/common /home/siva/src/freebsd-src/stand/libsa /home/siva/src/freebsd-src/contrib/pnglite'
make[6]: 1 error

Is anyone else able to reproduce this?