Browse Source

mount: let filer handle chunk deletion decision (#7900)

* mount: let filer handle chunk deletion decision

Remove chunk deletion decision from FUSE mount's Unlink operation.
Previously, the mount decided whether to delete chunks based on
its locally cached entry's HardLinkCounter, which could be stale.

Now always pass isDeleteData=true and let the filer make the
authoritative decision based on its own data. This prevents
potential inconsistencies when:
- The FUSE mount's cached entry is stale
- Race conditions occur between multiple mounts
- Direct filer operations change hard link counts

* filer: check hard link counter before deleting chunks

When deleting an entry, only delete the underlying chunks if:
1. It is not a hard link
2. OR it is the last hard link (counter <= 1)

This protects against data loss when a client (like FUSE mount)
requests chunk deletion for a file that has multiple hard links.
dependabot/go_modules/modernc.org/sqlite-1.42.2
Chris Lu 1 day ago
committed by GitHub
parent
commit
288ba5fec8
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 6
      weed/filer/filer_delete_entry.go
  2. 5
      weed/mount/weedfs_file_mkrm.go

6
weed/filer/filer_delete_entry.go

@ -53,7 +53,11 @@ func (f *Filer) DeleteEntryMetaAndData(ctx context.Context, p util.FullPath, isR
} }
if shouldDeleteChunks && !isDeleteCollection { if shouldDeleteChunks && !isDeleteCollection {
f.DeleteChunks(ctx, p, entry.GetChunks())
if len(entry.HardLinkId) != 0 && entry.HardLinkCounter > 1 {
// if the file is a hard link and there are other hard links, do not delete the chunks
} else {
f.DeleteChunks(ctx, p, entry.GetChunks())
}
} }
if isDeleteCollection { if isDeleteCollection {

5
weed/mount/weedfs_file_mkrm.go

@ -140,8 +140,9 @@ func (wfs *WFS) Unlink(cancel <-chan struct{}, header *fuse.InHeader, name strin
// first, ensure the filer store can correctly delete // first, ensure the filer store can correctly delete
glog.V(3).Infof("remove file: %v", entryFullPath) glog.V(3).Infof("remove file: %v", entryFullPath)
isDeleteData := entry != nil && entry.HardLinkCounter <= 1
err := filer_pb.Remove(context.Background(), wfs, string(dirFullPath), name, isDeleteData, false, false, false, []int32{wfs.signature})
// Always let the filer decide whether to delete chunks based on its authoritative data.
// The filer has the correct hard link count and will only delete chunks when appropriate.
err := filer_pb.Remove(context.Background(), wfs, string(dirFullPath), name, true, false, false, false, []int32{wfs.signature})
if err != nil { if err != nil {
glog.V(0).Infof("remove %s: %v", entryFullPath, err) glog.V(0).Infof("remove %s: %v", entryFullPath, err)
return fuse.OK return fuse.OK

Loading…
Cancel
Save