diff --git a/weed/mount/dir_sink.go b/weed/mount/dir_sink.go new file mode 100644 index 000000000..81cb6cd3a --- /dev/null +++ b/weed/mount/dir_sink.go @@ -0,0 +1,37 @@ +package mount + +import ( + "github.com/seaweedfs/go-fuse/v2/fuse" +) + +// DirEntrySink receives the entries a readdir produces. The FUSE server packs +// them straight into the kernel's reply buffer; a front end that is not the +// kernel reads them out instead of re-parsing that wire format. +type DirEntrySink interface { + // AddEntry reports one entry, returning false once the sink is full. A + // full sink ends the batch; the client resumes from the entry's Off. + AddEntry(entry fuse.DirEntry) bool + + // AddEntryPlus is AddEntry for readdirplus, returning the attribute block + // to fill in, or nil once the sink is full. + AddEntryPlus(entry fuse.DirEntry) *fuse.EntryOut +} + +// fuseDirEntryList adapts the kernel reply buffer to DirEntrySink. +type fuseDirEntryList struct { + *fuse.DirEntryList +} + +func (l fuseDirEntryList) AddEntry(entry fuse.DirEntry) bool { + return l.AddDirEntry(entry) +} + +func (l fuseDirEntryList) AddEntryPlus(entry fuse.DirEntry) *fuse.EntryOut { + return l.AddDirLookupEntry(entry) +} + +// ReadDirectoryInto runs a readdir against sink. ReadDir and ReadDirPlus are +// this with the kernel reply buffer as the sink. +func (wfs *WFS) ReadDirectoryInto(input *fuse.ReadIn, sink DirEntrySink, isPlusMode bool) fuse.Status { + return wfs.doReadDirectory(input, sink, isPlusMode) +} diff --git a/weed/mount/weedfs_dir_read.go b/weed/mount/weedfs_dir_read.go index 488a69f38..dbdba0e97 100644 --- a/weed/mount/weedfs_dir_read.go +++ b/weed/mount/weedfs_dir_read.go @@ -139,14 +139,14 @@ func (wfs *WFS) FsyncDir(cancel <-chan struct{}, input *fuse.FsyncIn) (code fuse * '1'. */ func (wfs *WFS) ReadDir(cancel <-chan struct{}, input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) { - return wfs.doReadDirectory(input, out, false) + return wfs.doReadDirectory(input, fuseDirEntryList{out}, false) } func (wfs *WFS) ReadDirPlus(cancel <-chan struct{}, input *fuse.ReadIn, out *fuse.DirEntryList) (code fuse.Status) { - return wfs.doReadDirectory(input, out, true) + return wfs.doReadDirectory(input, fuseDirEntryList{out}, true) } -func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPlusMode bool) fuse.Status { +func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out DirEntrySink, isPlusMode bool) fuse.Status { // Get the directory handle and lock it for the duration of this operation. // This serializes concurrent readdir calls on the same handle, fixing the // race condition that caused hangs with NFS-Ganesha. @@ -182,11 +182,11 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPl dirEntry.Off = dh.entryStreamOffset + uint64(index) + 1 if !isPlusMode { - if !out.AddDirEntry(dirEntry) { + if !out.AddEntry(dirEntry) { return false } } else { - entryOut := out.AddDirLookupEntry(dirEntry) + entryOut := out.AddEntryPlus(dirEntry) if entryOut == nil { return false } @@ -203,14 +203,14 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPl if input.Offset < directoryStreamBaseOffset { if !isPlusMode { if input.Offset == 0 { - out.AddDirEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".", Off: 1}) + out.AddEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".", Off: 1}) } - out.AddDirEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "..", Off: 2}) + out.AddEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "..", Off: 2}) } else { if input.Offset == 0 { - out.AddDirLookupEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".", Off: 1}) + out.AddEntryPlus(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: ".", Off: 1}) } - out.AddDirLookupEntry(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "..", Off: 2}) + out.AddEntryPlus(fuse.DirEntry{Mode: fuse.S_IFDIR, Name: "..", Off: 2}) } input.Offset = directoryStreamBaseOffset } @@ -296,7 +296,7 @@ func (wfs *WFS) doReadDirectory(input *fuse.ReadIn, out *fuse.DirEntryList, isPl return fuse.OK } -func (wfs *WFS) readDirectoryDirect(input *fuse.ReadIn, out *fuse.DirEntryList, dh *DirectoryHandle, dirPath util.FullPath, processEachEntryFn func(entry *filer.Entry, index int64) bool) fuse.Status { +func (wfs *WFS) readDirectoryDirect(input *fuse.ReadIn, out DirEntrySink, dh *DirectoryHandle, dirPath util.FullPath, processEachEntryFn func(entry *filer.Entry, index int64) bool) fuse.Status { var lastEntryName string if input.Offset >= dh.entryStreamOffset {