Re: 14.1 NFS / mountd : -alldirs not working as expected
Date: Tue, 26 Nov 2024 16:01:45 UTC
On Mon, Nov 25, 2024 at 3:57 PM Rick Macklem <rick.macklem@gmail.com> wrote: > > On Mon, Nov 25, 2024 at 2:55 PM Rick Macklem <rick.macklem@gmail.com> wrote: > > > > On Wed, Nov 20, 2024 at 8:01 PM Michael Proto <mike@jellydonut.org> wrote: > > > > > > Hello all, > > > > > > Running into an issue with a 14.1 server that I think is a bug, though > > > it may be me not interpreting documentation correctly so I wanted to > > > ask here. > > > > > > Using NFSv3, with FreeBSD 14.1 as the NFS server. Based on what I see > > > in exports(5), if I want to export conditional mounts (IE filesystem > > > paths that are intermittently mounted locally on server) I should use > > > -alldirs and specify the mount-point as the export. Per the manpage, > > > this export should only be accessible when the exported directory is > > > actually the root of a mounted filesystem. Currently if mountd is > > > HUPed while the export isn't a filesystem mount I get the warning > > > about exporting the filesystem "below" the export (root-FS in this > > > case) and I can actually mount the root-FS from the client, instead of > > > getting an error as I would expect. Using the specific example for a > > > sometimes-mounted /cdrom in exports(5) can demonstrate this behavior. > Just fyi, I also plan on coming up with a patch for exports(5) to make the > correct semantics of -alldirs clearer. It only explains that -alldirs > is only supposed > to work on mount points in the examples section. It took me a couple of > passes through it before I spotted it and realized this is a bug. I dug into the git repository and, believe it or not, it looks like this was broken between releng1.0 and releng2.0 (there doesn't seem to be an exact commit). Basically, for releng1.0 the path provided by the exports line was passed into mount(2), which would fail if the path was not a mount point. This was how "not at a mount point" was detected for -alldirs. For releng2.0, it passes f_mntonname to mount(2), which is the mount point. This broke the check for "is a mount point". To be honest, the while() loop calling nmount(2) is mostly (if not entirely useless), because its purpose was to climb the path to the mount point and this should never now happen. I do have a patch that detects "not a mount point" using a strcmp() between f_mntoname and the path in the exports line. That should be sufficient, since symbolic links should not be in the path in exports(5). Michael, once you create a bugzilla bug report (bugs.freebsd.org), I will attach the patch and work on getting it committed. rick > > rick > > > > > > > /etc/rc.conf : > > > nfs_server_enable="YES" > > > rpcbind_enable="YES" > > > rpc_statd_enable="YES" > > > rpc_lockd_enable="YES" > > > mountd_enable="YES" > > > > > > /etc/exports : > > > /cdrom -alldirs,quiet,ro -network=10.0.0.0/24 > > > > > > (at this time /cdrom exists as a directory but is not currently a > > > filesystem mount point) > > > on the server: > > > root@zfstest1:~ # killall -HUP mountd > > > > > > /var/log/messages: > > > Nov 20 22:34:56 zfstest1 mountd[27724]: Warning: exporting /cdrom > > > exports entire / file system > > I took a closer look and this is a bug. It appears that -alldirs is supposed > > to fail when a non-mountpoint is exported. > > > > It appears to have been introduced to the system long ago, although I > > haven't yet tracked down the commit. > > > > mountd.c assumes that nmount(8) will fail when the directory path > > is not a mount point, however for MNT_UPDATE (which is what is > > used to export file systems) this is not the case. > > > > Please create a bugzilla bug report for this and I will work on a patch. > > > > Btw, quiet is also broken in the sense that it will cause any nmount(8) > > failure to fail. However, since nmount(8) does not fail for this case, > > it hardly matters. I will come up with a patch for this too, since it is > > easy to fix. > > > > Thanks for reporting this, rick > > > > > > > > root@zfstest1:~ # showmount -e > > > Exports list on localhost: > > > /cdrom 10.0.0.0 > > > > > > > > > on a client, I can now mount "/" from my server zfstest1: > > > > > > root@client1:~ # mount -r -t nfs zfstest1:/ /mnt > > > root@client1:~ # mount | tail -n1 > > > zfstest1:/ on /mnt (nfs, read-only) > > > > > > The root-FS of zfstest1 is indeed visible in /mnt on client1 > > > > > > From what I see in /usr/src/usr.sbin/mountd/mountd.c this isn't > > > supposed to happen (I'm no C programmer but this did read something > > > like I should receive an export error from mountd when I send a HUP): > > > ... > > > } else if (!strcmp(cpopt, "alldirs")) { > > > opt_flags |= OP_ALLDIRS; > > > ... > > > if (opt_flags & OP_ALLDIRS) { > > > if (errno == EINVAL) > > > syslog(LOG_ERR, > > > "-alldirs requested but %s is not a filesystem mountpoint", > > > dirp); > > > else > > > syslog(LOG_ERR, > > > "could not remount %s: %m", > > > dirp); > > > ret = 1; > > > goto error_exit; > > > } > > > > > > I suspect this code path isn't being hit since I'm getting the mountd > > > warning I referenced above instead of this error. This appears to be a > > > possible recurrence of a very old bug that depicts similar behavior : > > > https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=170413 > > > While it appears the "-sec" issue referenced in that bug is fixed in > > > the listed PRs I didn't see anything on this -alldirs issue that's > > > also mentioned there, maybe that's why I'm running into this now? > > > > > > I'd be totally unsurprised if my /etc/exports file isn't configured > > > correctly, but I reduced my setup to just the example in the exports > > > man page and I'm struggling to determine how to interpret that > > > information differently. I also tried an export of /cdrom with only > > > "-alldirs" as an option and I get the same behavior. Ideas? > > > > > > > > > Thanks, > > > Michael Proto > > >