mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-19 21:12:35 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4378325188 | ||
|
|
f409c2588f | ||
|
|
74b323cc3b | ||
|
|
43a4ca4680 | ||
|
|
bff851e48d | ||
|
|
b2e53d8035 | ||
|
|
e768c45f79 |
@@ -75,6 +75,25 @@ jobs:
|
||||
- name: Build
|
||||
run: cd weed; go build -tags "elastic gocdk sqlite ydb tarantool tikv rclone" -v .
|
||||
|
||||
build-cross:
|
||||
name: Build cross-platform
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v7
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
# Nothing else on a PR compiles these, so per-OS syscall constants creep
|
||||
# back into shared files unnoticed and only a release build catches it.
|
||||
- name: Cross-compile
|
||||
run: |
|
||||
for target in windows/amd64 windows/arm64 freebsd/amd64 darwin/arm64; do
|
||||
echo "== $target"
|
||||
GOOS=${target%/*} GOARCH=${target#*/} go build ./weed/...
|
||||
done
|
||||
|
||||
test:
|
||||
name: Test
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -148,7 +148,7 @@ require (
|
||||
github.com/rdleal/intervalst v1.5.0
|
||||
github.com/redis/go-redis/v9 v9.21.0
|
||||
github.com/schollz/progressbar/v3 v3.19.1
|
||||
github.com/seaweedfs/go-fuse/v2 v2.9.3
|
||||
github.com/seaweedfs/go-fuse/v2 v2.9.4
|
||||
github.com/shirou/gopsutil/v4 v4.26.6
|
||||
github.com/tarantool/go-option v1.1.0
|
||||
github.com/tarantool/go-tarantool/v3 v3.0.0
|
||||
|
||||
@@ -1810,6 +1810,12 @@ github.com/seaweedfs/cockroachdb-parser v0.0.0-20260225204133-2f342c5ea564 h1:Tg
|
||||
github.com/seaweedfs/cockroachdb-parser v0.0.0-20260225204133-2f342c5ea564/go.mod h1:JSKCh6uCHBz91lQYFYHCyTrSVIPge4SUFVn28iwMNB0=
|
||||
github.com/seaweedfs/go-fuse/v2 v2.9.3 h1:rJufGrHImTx7yoGUmetUi+To4LrmTQJROJnBHWt92ic=
|
||||
github.com/seaweedfs/go-fuse/v2 v2.9.3/go.mod h1:zABdmWEa6A0bwaBeEOBUeUkGIZlxUhcdv+V1Dcc/U/I=
|
||||
github.com/seaweedfs/go-fuse/v2 v2.9.4-0.20260803073934-cb95bfebced6 h1:Kn79NPV77uc3bEat4RWi6vpNYNacYfjXcWBLNv3RZ2A=
|
||||
github.com/seaweedfs/go-fuse/v2 v2.9.4-0.20260803073934-cb95bfebced6/go.mod h1:zABdmWEa6A0bwaBeEOBUeUkGIZlxUhcdv+V1Dcc/U/I=
|
||||
github.com/seaweedfs/go-fuse/v2 v2.9.4-0.20260803074752-bd46d45ccb3b h1:ECjScJHzIATk8CTdlP+yfPY4W5bLxeoy1Mma8rd0dRA=
|
||||
github.com/seaweedfs/go-fuse/v2 v2.9.4-0.20260803074752-bd46d45ccb3b/go.mod h1:zABdmWEa6A0bwaBeEOBUeUkGIZlxUhcdv+V1Dcc/U/I=
|
||||
github.com/seaweedfs/go-fuse/v2 v2.9.4 h1:ACyloiuopdhRSjdLLeSWbsVaemMPskORaRF01TY6GyM=
|
||||
github.com/seaweedfs/go-fuse/v2 v2.9.4/go.mod h1:zABdmWEa6A0bwaBeEOBUeUkGIZlxUhcdv+V1Dcc/U/I=
|
||||
github.com/seaweedfs/goexif v1.0.3 h1:ve/OjI7dxPW8X9YQsv3JuVMaxEyF9Rvfd04ouL+Bz30=
|
||||
github.com/seaweedfs/goexif v1.0.3/go.mod h1:Oni780Z236sXpIQzk1XoJlTwqrJ02smEin9zQeff7Fk=
|
||||
github.com/seaweedfs/raft v1.2.0 h1:Ez4Hw9ifBbTT7wg54DvGHBjw1vRlTb4roH0TKl0Oj9Y=
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import (
|
||||
"math"
|
||||
"sort"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/seaweedfs/go-fuse/v2/fuse"
|
||||
)
|
||||
@@ -13,7 +12,7 @@ import (
|
||||
type lockRange struct {
|
||||
Start uint64 // inclusive byte offset
|
||||
End uint64 // inclusive; math.MaxUint64 means "to EOF"
|
||||
Typ uint32 // syscall.F_RDLCK or syscall.F_WRLCK
|
||||
Typ uint32 // f_RDLCK or f_WRLCK
|
||||
Owner uint64 // FUSE lock owner (from LkIn.Owner)
|
||||
Pid uint32 // PID of lock holder (for GetLk reporting)
|
||||
// flock and fcntl locks have different ownership and close semantics.
|
||||
@@ -127,7 +126,7 @@ func findConflict(locks []lockRange, proposed lockRange) (lockRange, bool) {
|
||||
if !rangesOverlap(h.Start, h.End, proposed.Start, proposed.End) {
|
||||
continue
|
||||
}
|
||||
if h.Typ == syscall.F_RDLCK && proposed.Typ == syscall.F_RDLCK {
|
||||
if h.Typ == f_RDLCK && proposed.Typ == f_RDLCK {
|
||||
continue
|
||||
}
|
||||
return h, true
|
||||
@@ -304,7 +303,7 @@ func (plt *PosixLockTable) GetLk(inode uint64, proposed lockRange, out *fuse.LkO
|
||||
for {
|
||||
il := plt.getInodeLocks(inode)
|
||||
if il == nil {
|
||||
out.Lk.Typ = syscall.F_UNLCK
|
||||
out.Lk.Typ = f_UNLCK
|
||||
return
|
||||
}
|
||||
il.mu.Lock()
|
||||
@@ -324,7 +323,7 @@ func (plt *PosixLockTable) GetLk(inode uint64, proposed lockRange, out *fuse.LkO
|
||||
out.Lk.Typ = conflict.Typ
|
||||
out.Lk.Pid = conflict.Pid
|
||||
} else {
|
||||
out.Lk.Typ = syscall.F_UNLCK
|
||||
out.Lk.Typ = f_UNLCK
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -334,7 +333,7 @@ func (plt *PosixLockTable) GetLk(inode uint64, proposed lockRange, out *fuse.LkO
|
||||
// For unlock (F_UNLCK): removes locks in the given range for the owner.
|
||||
// For lock: returns fuse.EAGAIN if a conflict exists, fuse.OK on success.
|
||||
func (plt *PosixLockTable) SetLk(inode uint64, lk lockRange) fuse.Status {
|
||||
if lk.Typ == syscall.F_UNLCK {
|
||||
if lk.Typ == f_UNLCK {
|
||||
il := plt.getInodeLocks(inode)
|
||||
if il == nil {
|
||||
return fuse.OK
|
||||
@@ -376,7 +375,7 @@ func (plt *PosixLockTable) SetLk(inode uint64, lk lockRange) fuse.Status {
|
||||
// SetLkw attempts a blocking lock. It waits until the lock can be acquired
|
||||
// or the cancel channel is closed.
|
||||
func (plt *PosixLockTable) SetLkw(inode uint64, lk lockRange, cancel <-chan struct{}) fuse.Status {
|
||||
if lk.Typ == syscall.F_UNLCK {
|
||||
if lk.Typ == f_UNLCK {
|
||||
return plt.SetLk(inode, lk)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
//go:build !windows
|
||||
|
||||
package mount
|
||||
|
||||
import "syscall"
|
||||
|
||||
const (
|
||||
f_RDLCK = syscall.F_RDLCK
|
||||
f_WRLCK = syscall.F_WRLCK
|
||||
f_UNLCK = syscall.F_UNLCK
|
||||
o_ACCMODE = syscall.O_ACCMODE
|
||||
)
|
||||
@@ -0,0 +1,14 @@
|
||||
package mount
|
||||
|
||||
// Windows has no fcntl lock types and no access-mode mask. The Linux values
|
||||
// stand in: nothing on Windows feeds these, and the lock table only ever
|
||||
// compares them against each other.
|
||||
const (
|
||||
f_RDLCK = 0
|
||||
f_WRLCK = 1
|
||||
f_UNLCK = 2
|
||||
o_ACCMODE = 0x3
|
||||
|
||||
xattr_CREATE = 1
|
||||
xattr_REPLACE = 2
|
||||
)
|
||||
@@ -31,8 +31,6 @@ import (
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/grace"
|
||||
"github.com/seaweedfs/seaweedfs/weed/util/version"
|
||||
"github.com/seaweedfs/seaweedfs/weed/wdclient"
|
||||
|
||||
"github.com/seaweedfs/go-fuse/v2/fs"
|
||||
)
|
||||
|
||||
type Option struct {
|
||||
@@ -136,7 +134,6 @@ type WFS struct {
|
||||
// follow https://github.com/hanwen/go-fuse/blob/master/fuse/api.go
|
||||
fuse.RawFileSystem
|
||||
mount_pb.UnimplementedSeaweedMountServer
|
||||
fs.Inode
|
||||
option *Option
|
||||
metaCache *meta_cache.MetaCache
|
||||
stats statsCache
|
||||
|
||||
@@ -155,7 +155,7 @@ func checkStickyBit(dirMode, dirUid, targetUid, callerUid uint32) fuse.Status {
|
||||
|
||||
// openFlagsToAccessMask converts open(2) flags to an access permission mask.
|
||||
func openFlagsToAccessMask(flags uint32) uint32 {
|
||||
switch flags & uint32(syscall.O_ACCMODE) {
|
||||
switch flags & uint32(o_ACCMODE) {
|
||||
case syscall.O_WRONLY:
|
||||
return fuse.W_OK
|
||||
case syscall.O_RDWR:
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"github.com/seaweedfs/go-fuse/v2/fuse"
|
||||
)
|
||||
|
||||
func setBlksize(out *fuse.Attr, size uint32) {
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
|
||||
"github.com/seaweedfs/go-fuse/v2/fuse"
|
||||
)
|
||||
|
||||
@@ -56,7 +54,7 @@ func (wfs *WFS) SetLkw(cancel <-chan struct{}, in *fuse.LkIn) fuse.Status {
|
||||
Pid: in.Lk.Pid,
|
||||
IsFlock: in.LkFlags&fuse.FUSE_LK_FLOCK != 0,
|
||||
}
|
||||
if lk.Typ == syscall.F_UNLCK {
|
||||
if lk.Typ == f_UNLCK {
|
||||
return wfs.posixLocks.SetLk(in.NodeId, lk)
|
||||
}
|
||||
return wfs.posixLocks.SetLkw(in.NodeId, lk, cancel)
|
||||
|
||||
@@ -6,7 +6,6 @@ import (
|
||||
"encoding/hex"
|
||||
"math/rand/v2"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/seaweedfs/go-fuse/v2/fuse"
|
||||
@@ -103,9 +102,9 @@ func (wfs *WFS) posixLockKeyForInode(inode uint64) (string, bool) {
|
||||
|
||||
func posixLockTypeToWire(typ uint32) uint32 {
|
||||
switch typ {
|
||||
case syscall.F_RDLCK:
|
||||
case f_RDLCK:
|
||||
return posixlock.Read
|
||||
case syscall.F_WRLCK:
|
||||
case f_WRLCK:
|
||||
return posixlock.Write
|
||||
default:
|
||||
return posixlock.Unlock
|
||||
@@ -115,11 +114,11 @@ func posixLockTypeToWire(typ uint32) uint32 {
|
||||
func posixLockTypeFromWire(typ uint32) uint32 {
|
||||
switch typ {
|
||||
case posixlock.Read:
|
||||
return syscall.F_RDLCK
|
||||
return f_RDLCK
|
||||
case posixlock.Write:
|
||||
return syscall.F_WRLCK
|
||||
return f_WRLCK
|
||||
default:
|
||||
return syscall.F_UNLCK
|
||||
return f_UNLCK
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,7 +185,7 @@ func (wfs *WFS) routedGetLk(cancel <-chan struct{}, in *fuse.LkIn, out *fuse.LkO
|
||||
out.Lk.Start, out.Lk.End, out.Lk.Pid = c.GetStart(), c.GetEnd(), c.GetPid()
|
||||
out.Lk.Typ = posixLockTypeFromWire(c.GetType())
|
||||
} else {
|
||||
out.Lk.Typ = syscall.F_UNLCK
|
||||
out.Lk.Typ = f_UNLCK
|
||||
}
|
||||
return fuse.OK
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
"github.com/seaweedfs/go-fuse/v2/fs"
|
||||
"github.com/seaweedfs/go-fuse/v2/fuse"
|
||||
"github.com/seaweedfs/seaweedfs/weed/cluster/lock_manager"
|
||||
"github.com/seaweedfs/seaweedfs/weed/glog"
|
||||
@@ -160,7 +159,7 @@ renameat2()
|
||||
const (
|
||||
RenameEmptyFlag = 0
|
||||
RenameNoReplace = 1
|
||||
RenameExchange = fs.RENAME_EXCHANGE
|
||||
RenameExchange = 2
|
||||
RenameWhiteout = 3
|
||||
)
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/seaweedfs/go-fuse/v2/fuse"
|
||||
sys "golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -123,11 +122,11 @@ func (wfs *WFS) SetXAttr(cancel <-chan struct{}, input *fuse.SetXAttrIn, attr st
|
||||
}
|
||||
_, exists := entry.Extended[XATTR_PREFIX+attr]
|
||||
switch input.Flags {
|
||||
case sys.XATTR_CREATE:
|
||||
case xattr_CREATE:
|
||||
if exists {
|
||||
return fuse.Status(syscall.EEXIST)
|
||||
}
|
||||
case sys.XATTR_REPLACE:
|
||||
case xattr_REPLACE:
|
||||
if !exists {
|
||||
return fuse.ENODATA
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
//go:build !windows && !freebsd
|
||||
|
||||
package mount
|
||||
|
||||
import sys "golang.org/x/sys/unix"
|
||||
|
||||
const (
|
||||
xattr_CREATE = sys.XATTR_CREATE
|
||||
xattr_REPLACE = sys.XATTR_REPLACE
|
||||
)
|
||||
Reference in New Issue
Block a user