worm grace period and retention time support (#6404)

Signed-off-by: lou <alex1988@outlook.com>
This commit is contained in:
Guang Jiong Lou
2025-01-01 10:41:43 +08:00
committed by GitHub
parent 0e8e6122d5
commit 3b1ac77e1f
14 changed files with 831 additions and 707 deletions

View File

@@ -3,12 +3,14 @@ package mount
import (
"errors"
"fmt"
"path/filepath"
"time"
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/mount/meta_cache"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
"github.com/seaweedfs/seaweedfs/weed/util"
"path/filepath"
)
func (wfs *WFS) subscribeFilerConfEvents() (*meta_cache.MetadataFollower, error) {
@@ -73,18 +75,32 @@ func (wfs *WFS) subscribeFilerConfEvents() (*meta_cache.MetadataFollower, error)
}, nil
}
func (wfs *WFS) wormEnabledForEntry(path util.FullPath, entry *filer_pb.Entry) bool {
if entry == nil || entry.Attributes == nil {
return false
}
if wfs.FilerConf == nil {
return false
func (wfs *WFS) wormEnforcedForEntry(path util.FullPath, entry *filer_pb.Entry) (wormEnforced, wormEnabled bool) {
if entry == nil || wfs.FilerConf == nil {
return false, false
}
rule := wfs.FilerConf.MatchStorageRule(string(path))
if !rule.Worm {
return false
return false, false
}
return entry.Attributes.FileSize > 0 || entry.Attributes.Crtime != entry.Attributes.Mtime
// worm is not enforced
if entry.WormEnforcedAtTsNs == 0 {
return false, true
}
// worm will never expire
if rule.WormRetentionTimeSeconds == 0 {
return true, true
}
enforcedAt := time.Unix(0, entry.WormEnforcedAtTsNs)
// worm is expired
if time.Now().Sub(enforcedAt).Seconds() >= float64(rule.WormRetentionTimeSeconds) {
return false, true
}
return true, true
}

View File

@@ -1,13 +1,14 @@
package mount
import (
"os"
"syscall"
"time"
"github.com/hanwen/go-fuse/v2/fuse"
"github.com/seaweedfs/seaweedfs/weed/filer"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
"os"
"syscall"
"time"
)
func (wfs *WFS) GetAttr(cancel <-chan struct{}, input *fuse.GetAttrIn, out *fuse.AttrOut) (code fuse.Status) {
@@ -42,7 +43,7 @@ func (wfs *WFS) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse
}
path, fh, entry, status := wfs.maybeReadEntry(input.NodeId)
if status != fuse.OK {
if status != fuse.OK || entry == nil {
return status
}
if fh != nil {
@@ -50,7 +51,12 @@ func (wfs *WFS) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse
defer fh.entryLock.Unlock()
}
if size, ok := input.GetSize(); ok && entry != nil {
wormEnforced, wormEnabled := wfs.wormEnforcedForEntry(path, entry)
if wormEnforced {
return fuse.EPERM
}
if size, ok := input.GetSize(); ok {
glog.V(4).Infof("%v setattr set size=%v chunks=%d", path, size, len(entry.GetChunks()))
if size < filer.FileSize(entry) {
// fmt.Printf("truncate %v \n", fullPath)
@@ -85,6 +91,11 @@ func (wfs *WFS) SetAttr(cancel <-chan struct{}, input *fuse.SetAttrIn, out *fuse
}
if mode, ok := input.GetMode(); ok {
// commit the file to worm when it is set to readonly at the first time
if entry.WormEnforcedAtTsNs == 0 && wormEnabled && !hasWritePermission(mode) {
entry.WormEnforcedAtTsNs = time.Now().UnixNano()
}
// glog.V(4).Infof("setAttr mode %o", mode)
entry.Attributes.FileMode = chmod(entry.Attributes.FileMode, mode)
if input.NodeId == 1 {
@@ -216,6 +227,14 @@ func chmod(existing uint32, mode uint32) uint32 {
return existing&^07777 | mode&07777
}
const ownerWrite = 0o200
const groupWrite = 0o020
const otherWrite = 0o002
func hasWritePermission(mode uint32) bool {
return (mode&ownerWrite != 0) || (mode&groupWrite != 0) || (mode&otherWrite != 0)
}
func toSyscallMode(mode os.FileMode) uint32 {
return toSyscallType(mode) | uint32(mode)
}

View File

@@ -130,7 +130,7 @@ func (wfs *WFS) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name strin
return code
}
if wfs.wormEnabledForEntry(entryFullPath, entry) {
if wormEnforced, _ := wfs.wormEnforcedForEntry(entryFullPath, entry); wormEnforced {
return fuse.EPERM
}

View File

@@ -11,7 +11,7 @@ func (wfs *WFS) AcquireHandle(inode uint64, flags, uid, gid uint32) (fileHandle
var path util.FullPath
path, _, entry, status = wfs.maybeReadEntry(inode)
if status == fuse.OK {
if wfs.wormEnabledForEntry(path, entry) && flags&fuse.O_ANYWRITE != 0 {
if wormEnforced, _ := wfs.wormEnforcedForEntry(path, entry); wormEnforced && flags&fuse.O_ANYWRITE != 0 {
return nil, fuse.EPERM
}
// need to AcquireFileHandle again to ensure correct handle counter

View File

@@ -49,7 +49,7 @@ func (wfs *WFS) Link(cancel <-chan struct{}, in *fuse.LinkIn, name string, out *
}
// hardlink is not allowed in WORM mode
if wfs.wormEnabledForEntry(oldEntryPath, oldEntry) {
if wormEnforced, _ := wfs.wormEnforcedForEntry(oldEntryPath, oldEntry); wormEnforced {
return fuse.EPERM
}

View File

@@ -161,11 +161,13 @@ func (wfs *WFS) Rename(cancel <-chan struct{}, in *fuse.RenameIn, oldName string
}
newPath := newDir.Child(newName)
if wfs.FilerConf != nil {
rule := wfs.FilerConf.MatchStorageRule(string(oldPath))
if rule.Worm {
return fuse.EPERM
}
oldEntry, status := wfs.maybeLoadEntry(oldPath)
if status != fuse.OK {
return status
}
if wormEnforced, _ := wfs.wormEnforcedForEntry(oldPath, oldEntry); wormEnforced {
return fuse.EPERM
}
glog.V(4).Infof("dir Rename %s => %s", oldPath, newPath)