]> xenbits.xensource.com Git - people/royger/freebsd.git/commit
Fix NFS exports of FUSE file systems for big directories
authorAlan Somers <asomers@FreeBSD.org>
Sun, 2 Jan 2022 17:18:47 +0000 (10:18 -0700)
committerAlan Somers <asomers@FreeBSD.org>
Wed, 2 Mar 2022 23:35:33 +0000 (16:35 -0700)
commit3d721de049be0f073306c8109499fbbbe945c3b3
tree28e5a0828ec1573dc3ce3ac6f1091d5e9eac43c2
parent1e40fc6fa9c4e394195fd2972c8831526c684f5e
Fix NFS exports of FUSE file systems for big directories

The FUSE protocol does not require that a directory entry's d_off field
outlive the lifetime of its directory's file handle.  Since the NFS
server must reopen the directory on every VOP_READDIR call, that means
it can't pass uio->uio_offset down to the FUSE server.  Instead, it must
read the directory from 0 each time.  It may need to issue multiple
FUSE_READDIR operations until it finds the d_off field that it's looking
for.  That was the intention behind SVN r348209 and r297887, but a logic
bug prevented subsequent FUSE_READDIR operations from ever being issued,
rendering large directories incompletely browseable.

Reviewed by: rmacklem

(cherry picked from commit d088dc76e1a62ecb6c05bd2b14ee48a9f9a7e2bd)

fusefs: optimize NFS readdir for FUSE_NO_OPENDIR_SUPPORT

In its lowest common denominator, FUSE does not require that a directory
entry's d_off field is valid outside of the lifetime of the directory's
FUSE file handle.  But since NFS is stateless, it must reopen the
directory on every call to VOP_READDIR.  That means reading the
directory all the way from the first entry.  Not only does this create
an O(n^2) condition for large directories, but it can also result in
incorrect behavior if either:

* The file system _does_ change the d_off field for the last directory
  entry previously seen by NFS, or
* The file system deletes the last directory entry previously seen by
  NFS.

Handily, for file systems that set FUSE_NO_OPENDIR_SUPPORT d_off is
guaranteed to be valid for the lifetime of the directory entry, there is
no need to read the directory from the start.

Reviewed by: rmacklem

(cherry picked from commit 4a6526d84a56f398732bff491e63aa42f796a27d)

fusefs: require FUSE_NO_OPENDIR_SUPPORT for NFS exporting

FUSE file systems that do not set FUSE_NO_OPENDIR_SUPPORT do not
guarantee that d_off will be valid after closing and reopening a
directory.  That conflicts with NFS's statelessness, that results in
unresolvable bugs when NFS reads large directories, if:

* The file system _does_ change the d_off field for the last directory
  entry previously returned by VOP_READDIR, or
* The file system deletes the last directory entry previously seen by
  NFS.

Rather than doing a poor job of exporting such file systems, it's better
just to refuse.

Even though this is technically a breaking change, 13.0-RELEASE's
NFS-FUSE support was bad enough that an MFC should be allowed.

Reviewed by: rmacklem
Differential Revision: https://reviews.freebsd.org/D33726

(cherry picked from commit 00134a07898fa807b8a1fcb2596f0e3644143f69)

fusefs: fix the build without INVARIANTS after 00134a07898

MFC with: 00134a07898fa807b8a1fcb2596f0e3644143f69
Reported by: se

(cherry picked from commit 18ed2ce77a254f365a4687d6afe8eeba2aad2e13)
sys/fs/fuse/fuse_internal.c
sys/fs/fuse/fuse_internal.h
sys/fs/fuse/fuse_vnops.c