This commit is contained in:
+23
-13
@@ -48,25 +48,35 @@ type fskey struct {
|
|||||||
// their cache every now and then.
|
// their cache every now and then.
|
||||||
type caseFilesystemRegistry struct {
|
type caseFilesystemRegistry struct {
|
||||||
fss map[fskey]*caseFilesystem
|
fss map[fskey]*caseFilesystem
|
||||||
mut sync.Mutex
|
mut sync.RWMutex
|
||||||
startCleaner sync.Once
|
startCleaner sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *caseFilesystemRegistry) get(fs Filesystem) Filesystem {
|
func (r *caseFilesystemRegistry) get(fs Filesystem) Filesystem {
|
||||||
r.mut.Lock()
|
|
||||||
defer r.mut.Unlock()
|
|
||||||
|
|
||||||
k := fskey{fs.Type(), fs.URI()}
|
k := fskey{fs.Type(), fs.URI()}
|
||||||
|
|
||||||
|
// Use double locking when getting a caseFs. In the common case it will
|
||||||
|
// already exist and we take the read lock fast path. If it doesn't, we
|
||||||
|
// take a write lock and try again.
|
||||||
|
|
||||||
|
r.mut.RLock()
|
||||||
caseFs, ok := r.fss[k]
|
caseFs, ok := r.fss[k]
|
||||||
|
r.mut.RUnlock()
|
||||||
|
|
||||||
if !ok {
|
if !ok {
|
||||||
caseFs = &caseFilesystem{
|
r.mut.Lock()
|
||||||
Filesystem: fs,
|
caseFs, ok = r.fss[k]
|
||||||
realCaser: newDefaultRealCaser(fs),
|
if !ok {
|
||||||
|
caseFs = &caseFilesystem{
|
||||||
|
Filesystem: fs,
|
||||||
|
realCaser: newDefaultRealCaser(fs),
|
||||||
|
}
|
||||||
|
r.fss[k] = caseFs
|
||||||
|
r.startCleaner.Do(func() {
|
||||||
|
go r.cleaner()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
r.fss[k] = caseFs
|
r.mut.Unlock()
|
||||||
r.startCleaner.Do(func() {
|
|
||||||
go r.cleaner()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return caseFs
|
return caseFs
|
||||||
@@ -74,11 +84,11 @@ func (r *caseFilesystemRegistry) get(fs Filesystem) Filesystem {
|
|||||||
|
|
||||||
func (r *caseFilesystemRegistry) cleaner() {
|
func (r *caseFilesystemRegistry) cleaner() {
|
||||||
for range time.NewTicker(time.Minute).C {
|
for range time.NewTicker(time.Minute).C {
|
||||||
r.mut.Lock()
|
r.mut.RLock()
|
||||||
for _, caseFs := range r.fss {
|
for _, caseFs := range r.fss {
|
||||||
caseFs.dropCache()
|
caseFs.dropCache()
|
||||||
}
|
}
|
||||||
r.mut.Unlock()
|
r.mut.RUnlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-7
@@ -1790,13 +1790,6 @@ func (m *model) Request(deviceID protocol.DeviceID, folder, name string, blockNo
|
|||||||
return nil, protocol.ErrInvalid
|
return nil, protocol.ErrInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
folderFs := folderCfg.Filesystem()
|
|
||||||
|
|
||||||
if err := osutil.TraversesSymlink(folderFs, filepath.Dir(name)); err != nil {
|
|
||||||
l.Debugf("%v REQ(in) traversal check: %s - %s: %q / %q o=%d s=%d", m, err, deviceID, folder, name, offset, size)
|
|
||||||
return nil, protocol.ErrNoSuchFile
|
|
||||||
}
|
|
||||||
|
|
||||||
// Restrict parallel requests by connection/device
|
// Restrict parallel requests by connection/device
|
||||||
|
|
||||||
m.pmut.RLock()
|
m.pmut.RLock()
|
||||||
@@ -1814,6 +1807,16 @@ func (m *model) Request(deviceID protocol.DeviceID, folder, name string, blockNo
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// Grab the FS after limiting, as it causes I/O and we want to minimize
|
||||||
|
// the race time between the symlink check and the read.
|
||||||
|
|
||||||
|
folderFs := folderCfg.Filesystem()
|
||||||
|
|
||||||
|
if err := osutil.TraversesSymlink(folderFs, filepath.Dir(name)); err != nil {
|
||||||
|
l.Debugf("%v REQ(in) traversal check: %s - %s: %q / %q o=%d s=%d", m, err, deviceID, folder, name, offset, size)
|
||||||
|
return nil, protocol.ErrNoSuchFile
|
||||||
|
}
|
||||||
|
|
||||||
// Only check temp files if the flag is set, and if we are set to advertise
|
// Only check temp files if the flag is set, and if we are set to advertise
|
||||||
// the temp indexes.
|
// the temp indexes.
|
||||||
if fromTemporary && !folderCfg.DisableTempIndexes {
|
if fromTemporary && !folderCfg.DisableTempIndexes {
|
||||||
|
|||||||
Reference in New Issue
Block a user