@@ -26,6 +26,7 @@ import (
2626 "strconv"
2727 "strings"
2828
29+ "github.com/owncloud/reva/v2/pkg/appctx"
2930 "github.com/owncloud/reva/v2/pkg/storage/cache"
3031 "github.com/owncloud/reva/v2/pkg/storage/utils/decomposedfs/metadata/prefixes"
3132 "github.com/owncloud/reva/v2/pkg/storage/utils/filelocks"
@@ -82,12 +83,32 @@ func (b XattrsBackend) List(ctx context.Context, filePath string) (attribs []str
8283 return b .list (ctx , filePath , true )
8384}
8485
86+ const listMaxRetries = 10
87+
8588func (b XattrsBackend ) list (ctx context.Context , filePath string , acquireLock bool ) (attribs []string , err error ) {
8689 attrs , err := xattr .List (filePath )
8790 if err == nil {
8891 return attrs , nil
8992 }
9093
94+ // ERANGE means a concurrent writer (e.g. the posix inotify assimilate worker)
95+ // mutated the attribute set mid-read. It is transient and self-clearing: retry
96+ // until the set stabilises.
97+ if IsErrRange (err ) {
98+ for attempt := 1 ; attempt <= listMaxRetries ; attempt ++ {
99+ appctx .GetLogger (ctx ).Debug ().Err (err ).Str ("path" , filePath ).Int ("attempt" , attempt ).Msg ("xattr.List ERANGE, retrying" )
100+ attrs , err = xattr .List (filePath )
101+ if err == nil {
102+ appctx .GetLogger (ctx ).Debug ().Str ("path" , filePath ).Int ("attempt" , attempt ).Msg ("xattr.List ERANGE recovered after retry" )
103+ return attrs , nil
104+ }
105+ if ! IsErrRange (err ) {
106+ break
107+ }
108+ }
109+ appctx .GetLogger (ctx ).Error ().Err (err ).Str ("path" , filePath ).Msg ("xattr.List still failing after ERANGE retries" )
110+ }
111+
91112 // listing xattrs failed, try again, either with lock or without
92113 if acquireLock {
93114 f , err := lockedfile .OpenFile (filePath + filelocks .LockFileSuffix , os .O_CREATE | os .O_WRONLY , 0600 )
0 commit comments