mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-08-24 16:17:08 +00:00
filer: revalidate WORM under the commit lock
WORM was checked before the entry lock was acquired, so a concurrent writer could enable it while an ingest, repack, or plain HTTP overwrite waited, and the commit then replaced a protected entry. Repack now checks under its lock, and ingest and saveMetaData recheck at commit time.
This commit is contained in:
@@ -206,6 +206,16 @@ func (fs *FilerServer) formatIngest(ctx context.Context, w http.ResponseWriter,
|
||||
// serialize with gRPC writers, renames, and repack
|
||||
pathLock := fs.entryLockTable.AcquireLock("formatIngest", entry.FullPath, util.ExclusiveLock)
|
||||
defer fs.entryLockTable.ReleaseLock(entry.FullPath, pathLock)
|
||||
// recheck under the lock: WORM may have been enabled during the upload
|
||||
if enforced, wormErr := fs.wormEnforcedForEntry(ctx, r.URL.Path); wormErr != nil {
|
||||
cleanup()
|
||||
writeJsonError(w, r, http.StatusInternalServerError, wormErr)
|
||||
return
|
||||
} else if enforced {
|
||||
cleanup()
|
||||
writeJsonError(w, r, http.StatusForbidden, errors.New("cannot replace WORM-enforced entry"))
|
||||
return
|
||||
}
|
||||
if err := fs.filer.CreateEntry(context.WithoutCancel(ctx), entry, nil, false, false, nil, skipCheckParentDirEntry(r), so.MaxFileNameLength); err != nil {
|
||||
cleanup()
|
||||
writeJsonError(w, r, http.StatusInternalServerError, err)
|
||||
@@ -230,6 +240,13 @@ func (fs *FilerServer) formatRepack(ctx context.Context, w http.ResponseWriter,
|
||||
return
|
||||
}
|
||||
fullPath := util.FullPath(r.URL.Path)
|
||||
// Serializes gRPC writers, renames, and this filer's HTTP overwrites;
|
||||
// cross-filer serialization needs owner routing.
|
||||
pathLock := fs.entryLockTable.AcquireLock("formatRepack", fullPath, util.ExclusiveLock)
|
||||
defer fs.entryLockTable.ReleaseLock(fullPath, pathLock)
|
||||
|
||||
// checked under the lock so a concurrent WORM enable cannot land between
|
||||
// validation and the entry swap
|
||||
if enforced, err := fs.wormEnforcedForEntry(ctx, r.URL.Path); err != nil {
|
||||
writeJsonError(w, r, http.StatusInternalServerError, err)
|
||||
return
|
||||
@@ -238,11 +255,6 @@ func (fs *FilerServer) formatRepack(ctx context.Context, w http.ResponseWriter,
|
||||
return
|
||||
}
|
||||
|
||||
// The lock covers gRPC writers and renames; plain HTTP overwrites do not
|
||||
// take it, so repack targets should be quiescent.
|
||||
pathLock := fs.entryLockTable.AcquireLock("formatRepack", fullPath, util.ExclusiveLock)
|
||||
defer fs.entryLockTable.ReleaseLock(fullPath, pathLock)
|
||||
|
||||
entry, err := fs.filer.FindEntry(ctx, fullPath)
|
||||
if err != nil {
|
||||
if errors.Is(err, filer_pb.ErrNotFound) {
|
||||
|
||||
@@ -247,11 +247,19 @@ func (fs *FilerServer) saveMetaData(ctx context.Context, r *http.Request, fileNa
|
||||
path := fs.fixFilePath(ctx, r, fileName)
|
||||
|
||||
// Commit under the entry lock so plain HTTP overwrites serialize with
|
||||
// gRPC writers, renames, and format repack.
|
||||
// gRPC writers, renames, and format repack on this filer; cross-filer
|
||||
// serialization needs owner routing.
|
||||
fullPath := util.FullPath(path)
|
||||
pathLock := fs.entryLockTable.AcquireLock("saveMetaData", fullPath, util.ExclusiveLock)
|
||||
defer fs.entryLockTable.ReleaseLock(fullPath, pathLock)
|
||||
|
||||
// recheck under the lock: WORM may have been enabled during the upload
|
||||
if enforced, wormErr := fs.wormEnforcedForEntry(ctx, path); wormErr != nil {
|
||||
return nil, wormErr
|
||||
} else if enforced {
|
||||
return nil, errors.New(constants.ErrMsgOperationNotPermitted)
|
||||
}
|
||||
|
||||
var entry *filer.Entry
|
||||
var newChunks []*filer_pb.FileChunk
|
||||
var mergedChunks []*filer_pb.FileChunk
|
||||
|
||||
Reference in New Issue
Block a user