fix(filer): update hard link ctime when nlink changes on unlink (#9018)

* fix(filer): update hard link ctime when nlink changes on unlink

When a hard link is unlinked, POSIX requires that the remaining links'
ctime is updated because the inode's nlink count changed. The filer's
DeleteHardLink() decremented the counter in the KV store but did not
update the ctime field.

Set ctime to time.Now() on the KV entry before writing it back when
the hard link counter is decremented but still > 0.

Remove tests/unlink/00.t from known_failures.txt (all 112 subtests
now pass).

* style: use time.Now().UTC() for ctime in DeleteHardLink
This commit is contained in:
Chris Lu
2026-04-10 11:23:52 -07:00
committed by GitHub
parent 2b8c16160f
commit 3f36846642
2 changed files with 5 additions and 4 deletions
+1 -4
View File
@@ -38,12 +38,9 @@ tests/unlink/02.t
tests/unlink/03.t
# ── Hard link nlink/ctime tracking (requires filer changes) ────────────
# The filer does not update ctime on remaining hard link entries when one
# link is removed, and nlink counts are not correctly maintained across
# rename operations.
# nlink counts are not correctly maintained across rename operations.
tests/rename/23.t
tests/rename/24.t
tests/unlink/00.t
# ── Parent directory mtime/ctime on deferred file create ───────────────
# When file creation is deferred (not flushed to filer immediately),
+4
View File
@@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
"time"
"github.com/seaweedfs/seaweedfs/weed/glog"
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
@@ -113,6 +114,9 @@ func (fsw *FilerStoreWrapper) DeleteHardLink(ctx context.Context, hardLinkId Har
return fsw.KvDelete(ctx, key)
}
// POSIX: update ctime when nlink changes (a hard link was removed).
entry.Attr.Ctime = time.Now().UTC()
newBlob, encodeErr := entry.EncodeAttributesAndChunks()
if encodeErr != nil {
return encodeErr