aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorchrislu <chris.lu@gmail.com>2022-08-23 01:52:32 -0700
committerchrislu <chris.lu@gmail.com>2022-08-23 01:52:32 -0700
commit21a933c9329f80bb7bfe5dbfb09e5b4f1a736f29 (patch)
tree5ef423da46d87463c464b5bb667dc8e0137bc913
parentf0b4a7659a85d98121e4455b41e858fb6526a23f (diff)
parentcda8cc22bcd2cea397ee833f39bd1bad0b4b4ea0 (diff)
downloadseaweedfs-21a933c9329f80bb7bfe5dbfb09e5b4f1a736f29.tar.xz
seaweedfs-21a933c9329f80bb7bfe5dbfb09e5b4f1a736f29.zip
Merge branch 'master' of https://github.com/seaweedfs/seaweedfs
-rw-r--r--weed/mount/weedfs_file_lseek.go110
-rw-r--r--weed/mount/weedfs_unsupported.go7
2 files changed, 110 insertions, 7 deletions
diff --git a/weed/mount/weedfs_file_lseek.go b/weed/mount/weedfs_file_lseek.go
new file mode 100644
index 000000000..ed495f5b5
--- /dev/null
+++ b/weed/mount/weedfs_file_lseek.go
@@ -0,0 +1,110 @@
+package mount
+
+import (
+ "syscall"
+
+ "github.com/hanwen/go-fuse/v2/fuse"
+
+ "github.com/seaweedfs/seaweedfs/weed/filer"
+ "github.com/seaweedfs/seaweedfs/weed/glog"
+)
+
+// These are non-POSIX extensions
+const (
+ SEEK_DATA uint32 = 3 // seek to next data after the offset
+ SEEK_HOLE uint32 = 4 // seek to next hole after the offset
+ ENXIO = fuse.Status(syscall.ENXIO)
+)
+
+// Lseek finds next data or hole segments after the specified offset
+// See https://man7.org/linux/man-pages/man2/lseek.2.html
+func (wfs *WFS) Lseek(cancel <-chan struct{}, in *fuse.LseekIn, out *fuse.LseekOut) fuse.Status {
+ // not a documented feature
+ if in.Padding != 0 {
+ return fuse.EINVAL
+ }
+
+ if in.Whence != SEEK_DATA && in.Whence != SEEK_HOLE {
+ return fuse.EINVAL
+ }
+
+ // file must exist
+ fh := wfs.GetHandle(FileHandleId(in.Fh))
+ if fh == nil {
+ return fuse.EBADF
+ }
+
+ // lock the file until the proper offset was calculated
+ fh.Lock()
+ defer fh.Unlock()
+ fh.entryLock.Lock()
+ defer fh.entryLock.Unlock()
+
+ fileSize := int64(filer.FileSize(fh.entry))
+ offset := max(int64(in.Offset), 0)
+
+ glog.V(4).Infof(
+ "Lseek %s fh %d in [%d,%d], whence %d",
+ fh.FullPath(), fh.fh, offset, fileSize, in.Whence,
+ )
+
+ // can neither seek beyond file nor seek to a hole at the end of the file with SEEK_DATA
+ if offset > fileSize {
+ return ENXIO
+ } else if in.Whence == SEEK_DATA && offset == fileSize {
+ return ENXIO
+ }
+
+ // refresh view cache if necessary
+ if fh.entryViewCache == nil {
+ var err error
+ fh.entryViewCache, err = filer.NonOverlappingVisibleIntervals(fh.wfs.LookupFn(), fh.entry.Chunks, 0, fileSize)
+ if err != nil {
+ return fuse.EIO
+ }
+ }
+
+ // search chunks for the offset
+ found, offset := searchChunks(fh, offset, fileSize, in.Whence)
+ if found {
+ out.Offset = uint64(offset)
+ return fuse.OK
+ }
+
+ // in case we found no exact matches, we return the recommended fallbacks, that is:
+ // original offset for SEEK_DATA or end of file for an implicit hole
+ if in.Whence == SEEK_DATA {
+ out.Offset = in.Offset
+ } else {
+ out.Offset = uint64(fileSize)
+ }
+
+ return fuse.OK
+}
+
+// searchChunks goes through all chunks to find the correct offset
+func searchChunks(fh *FileHandle, offset, fileSize int64, whence uint32) (found bool, out int64) {
+ chunkViews := filer.ViewFromVisibleIntervals(fh.entryViewCache, offset, fileSize)
+
+ for _, chunkView := range chunkViews {
+ if offset < chunkView.LogicOffset {
+ if whence == SEEK_HOLE {
+ out = offset
+ } else {
+ out = chunkView.LogicOffset
+ }
+
+ return true, out
+ }
+
+ if offset >= chunkView.LogicOffset && offset < chunkView.Offset+int64(chunkView.Size) && whence == SEEK_DATA {
+ out = offset
+
+ return true, out
+ }
+
+ offset += int64(chunkView.Size)
+ }
+
+ return
+}
diff --git a/weed/mount/weedfs_unsupported.go b/weed/mount/weedfs_unsupported.go
index 08347aec1..a8342a2fc 100644
--- a/weed/mount/weedfs_unsupported.go
+++ b/weed/mount/weedfs_unsupported.go
@@ -16,13 +16,6 @@ func (wfs *WFS) Fallocate(cancel <-chan struct{}, in *fuse.FallocateIn) (code fu
return fuse.ENOSYS
}
-/**
- * Find next data or hole after the specified offset
- */
-func (wfs *WFS) Lseek(cancel <-chan struct{}, in *fuse.LseekIn, out *fuse.LseekOut) fuse.Status {
- return fuse.ENOSYS
-}
-
func (wfs *WFS) GetLk(cancel <-chan struct{}, in *fuse.LkIn, out *fuse.LkOut) (code fuse.Status) {
return fuse.ENOSYS
}