@@ -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 {
0 commit comments