Skip to content

Commit c234f20

Browse files
committed
Update Getxattr and Removexattr methods to return ENODATA for non-existent attributes
This commit modifies the Getxattr and Removexattr methods in the OrcasNode to return ENODATA when attributes are not found, improving clarity in the response for cache hits and preventing infinite loops during removals. Debug logging is enhanced to reflect these changes, ensuring better traceability of attribute handling within the VFS.
1 parent 5bcab0a commit c234f20

2 files changed

Lines changed: 30 additions & 10 deletions

File tree

vfs/fs.go

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4517,8 +4517,8 @@ func (n *OrcasNode) Getxattr(ctx context.Context, attr string, dest []byte) (uin
45174517
if exists {
45184518
// Check if this is a "not found" sentinel (nil)
45194519
if value == nil {
4520-
DebugLog("[VFS Getxattr] Cache hit (sentinel): objID=%d, attr=%s, returning 0", n.objID, attr)
4521-
return 0, 0
4520+
DebugLog("[VFS Getxattr] Cache hit (sentinel): objID=%d, attr=%s, returning ENODATA", n.objID, attr)
4521+
return 0, syscall.ENODATA
45224522
}
45234523
if len(value) > len(dest) {
45244524
DebugLog("[VFS Getxattr] Cache hit but buffer too small: objID=%d, attr=%s, valueLen=%d, destLen=%d, returning ERANGE", n.objID, attr, len(value), len(dest))
@@ -4572,7 +4572,7 @@ func (n *OrcasNode) Getxattr(ctx context.Context, attr string, dest []byte) (uin
45724572
entry.attrs[attr] = nil // Use nil as sentinel
45734573
entry.mu.Unlock()
45744574
attrCache.Put(cacheKey, entry)
4575-
return 0, 0
4575+
return 0, syscall.ENODATA
45764576
}
45774577
// For other errors (database errors, etc.), return EIO instead of ENODATA
45784578
DebugLog("[VFS Getxattr] ERROR: Failed to get attribute: objID=%d, attr=%s, error=%v", n.objID, attr, err)
@@ -4678,14 +4678,29 @@ func (n *OrcasNode) Removexattr(ctx context.Context, attr string) syscall.Errno
46784678
if lh, ok := n.fs.h.(*core.LocalHandler); ok {
46794679
ma := lh.MetadataAdapter()
46804680
if ma != nil {
4681+
// Check cache first to see if attribute already doesn't exist
4682+
cacheKey := n.objID
4683+
if cached, ok := attrCache.Get(cacheKey); ok {
4684+
if entry, ok := cached.(*attrCacheEntry); ok && entry != nil {
4685+
entry.mu.RLock()
4686+
value, exists := entry.attrs[attr]
4687+
entry.mu.RUnlock()
4688+
if exists && value == nil {
4689+
// Cache already has sentinel (attribute doesn't exist)
4690+
// Return ENODATA to prevent infinite loop
4691+
DebugLog("[VFS Removexattr] Attribute already marked as non-existent in cache: objID=%d, attr=%s, returning ENODATA", n.objID, attr)
4692+
return syscall.ENODATA
4693+
}
4694+
}
4695+
}
4696+
46814697
DebugLog("[VFS Removexattr] Removing attribute from database: objID=%d, attr=%s", n.objID, attr)
46824698
err := ma.RemoveAttr(n.fs.c, n.fs.bktID, n.objID, attr)
46834699
if err != nil {
46844700
// Check if this is a "not found" error (attribute doesn't exist)
46854701
if strings.Contains(err.Error(), "attribute not found") || strings.Contains(err.Error(), "not found") {
46864702
DebugLog("[VFS Removexattr] Attribute not found: objID=%d, attr=%s, setting sentinel in cache", n.objID, attr)
46874703
// Attribute doesn't exist, set sentinel in cache to prevent repeated queries
4688-
cacheKey := n.objID
46894704
var entry *attrCacheEntry
46904705
if cached, ok := attrCache.Get(cacheKey); ok {
46914706
if e, ok := cached.(*attrCacheEntry); ok && e != nil {
@@ -4701,15 +4716,16 @@ func (n *OrcasNode) Removexattr(ctx context.Context, attr string) syscall.Errno
47014716
entry.attrs[attr] = nil // Set sentinel to indicate attribute doesn't exist
47024717
entry.mu.Unlock()
47034718
attrCache.Put(cacheKey, entry)
4704-
return 0
4719+
// Return ENODATA to indicate attribute doesn't exist and prevent infinite loop
4720+
return syscall.ENODATA
47054721
}
47064722
// For other errors (database errors, etc.), return EIO
47074723
DebugLog("[VFS Removexattr] ERROR: Failed to remove attribute: objID=%d, attr=%s, error=%v", n.objID, attr, err)
47084724
return syscall.EIO
47094725
}
47104726

47114727
// Update cache: set sentinel (nil) to indicate attribute doesn't exist
4712-
cacheKey := n.objID
4728+
// cacheKey is already defined above
47134729
var entry *attrCacheEntry
47144730
if cached, ok := attrCache.Get(cacheKey); ok {
47154731
if e, ok := cached.(*attrCacheEntry); ok && e != nil {

vfs/vfs_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4319,13 +4319,17 @@ func TestXattrSetGetRemove(t *testing.T) {
43194319
errno = fileNode.Removexattr(ctx, attrName)
43204320
So(errno, ShouldEqual, syscall.Errno(0))
43214321

4322-
// Get attribute again - should not exist (return 0, 0)
4323-
// This is the key test: after removal, Getxattr should return 0, 0
4324-
// instead of ENODATA, indicating the attribute doesn't exist
4322+
// Get attribute again - should not exist (return ENODATA)
4323+
// This is the key test: after removal, Getxattr should return ENODATA
4324+
// indicating the attribute doesn't exist
43254325
dest2 := make([]byte, 1024)
43264326
size2, errno2 := fileNode.Getxattr(ctx, attrName, dest2)
4327-
So(errno2, ShouldEqual, syscall.Errno(0))
4327+
So(errno2, ShouldEqual, syscall.ENODATA)
43284328
So(size2, ShouldEqual, uint32(0))
4329+
4330+
// Try to remove again - should return ENODATA to prevent infinite loop
4331+
errno3 := fileNode.Removexattr(ctx, attrName)
4332+
So(errno3, ShouldEqual, syscall.ENODATA)
43294333
})
43304334
})
43314335
}

0 commit comments

Comments
 (0)