Fix race condition when registering files
This commit is contained in:
parent
985d852343
commit
9e98192442
85
file.go
85
file.go
@ -38,20 +38,21 @@ func mangleOpenFlags(flags uint32) (newFlags int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (volume *Volume) registerFileHandle(fd int, cName, path string) int {
|
func (volume *Volume) registerFileHandle(fd int, cName, path string) int {
|
||||||
handleID := -1
|
volume.handlesLock.Lock()
|
||||||
c := 0
|
c := 0
|
||||||
for handleID == -1 {
|
for {
|
||||||
_, ok := volume.file_handles.Load(c)
|
_, ok := volume.fileHandles[c]
|
||||||
if !ok {
|
if !ok {
|
||||||
handleID = c
|
break
|
||||||
}
|
}
|
||||||
c++
|
c++
|
||||||
}
|
}
|
||||||
volume.file_handles.Store(handleID, &File {
|
volume.fileHandles[c] = &File {
|
||||||
fd: os.NewFile(uintptr(fd), cName),
|
fd: os.NewFile(uintptr(fd), cName),
|
||||||
path: string([]byte(path[:])),
|
path: string([]byte(path[:])),
|
||||||
})
|
}
|
||||||
return handleID
|
volume.handlesLock.Unlock()
|
||||||
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
// readFileID loads the file header from disk and extracts the file ID.
|
// readFileID loads the file header from disk and extracts the file ID.
|
||||||
@ -102,12 +103,7 @@ func createHeader(fd *os.File) (fileID []byte, err error) {
|
|||||||
//
|
//
|
||||||
// Called by Read() for normal reading,
|
// Called by Read() for normal reading,
|
||||||
// by Write() and Truncate() via doWrite() for Read-Modify-Write.
|
// by Write() and Truncate() via doWrite() for Read-Modify-Write.
|
||||||
func (volume *Volume) doRead(handleID int, dst []byte, off uint64, length uint64) ([]byte, bool) {
|
func (volume *Volume) doRead(f *File, dst []byte, off uint64, length uint64) ([]byte, bool) {
|
||||||
value, ok := volume.file_handles.Load(handleID)
|
|
||||||
if !ok {
|
|
||||||
return nil, false
|
|
||||||
}
|
|
||||||
f := value.(*File)
|
|
||||||
fd := f.fd
|
fd := f.fd
|
||||||
// Get the file ID, either from the open file table, or from disk.
|
// Get the file ID, either from the open file table, or from disk.
|
||||||
var fileID []byte
|
var fileID []byte
|
||||||
@ -183,11 +179,9 @@ func (volume *Volume) doRead(handleID int, dst []byte, off uint64, length uint64
|
|||||||
//
|
//
|
||||||
// Empty writes do nothing and are allowed.
|
// Empty writes do nothing and are allowed.
|
||||||
func (volume *Volume) doWrite(handleID int, data []byte, off uint64) (uint32, bool) {
|
func (volume *Volume) doWrite(handleID int, data []byte, off uint64) (uint32, bool) {
|
||||||
value, ok := volume.file_handles.Load(handleID)
|
volume.handlesLock.RLock()
|
||||||
if !ok {
|
f := volume.fileHandles[handleID]
|
||||||
return 0, false
|
volume.handlesLock.RUnlock()
|
||||||
}
|
|
||||||
f := value.(*File)
|
|
||||||
fd := f.fd
|
fd := f.fd
|
||||||
fileWasEmpty := false
|
fileWasEmpty := false
|
||||||
var fileID []byte
|
var fileID []byte
|
||||||
@ -216,7 +210,7 @@ func (volume *Volume) doWrite(handleID int, data []byte, off uint64) (uint32, bo
|
|||||||
// Incomplete block -> Read-Modify-Write
|
// Incomplete block -> Read-Modify-Write
|
||||||
if b.IsPartial() {
|
if b.IsPartial() {
|
||||||
// Read
|
// Read
|
||||||
oldData, success := volume.doRead(handleID, nil, b.BlockPlainOff(), volume.contentEnc.PlainBS())
|
oldData, success := volume.doRead(f, nil, b.BlockPlainOff(), volume.contentEnc.PlainBS())
|
||||||
if !success {
|
if !success {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
@ -299,11 +293,9 @@ func (volume *Volume) truncateGrowFile(handleID int, oldPlainSz uint64, newPlain
|
|||||||
// The new size is block-aligned. In this case we can do everything ourselves
|
// The new size is block-aligned. In this case we can do everything ourselves
|
||||||
// and avoid the call to doWrite.
|
// and avoid the call to doWrite.
|
||||||
if newPlainSz%volume.contentEnc.PlainBS() == 0 {
|
if newPlainSz%volume.contentEnc.PlainBS() == 0 {
|
||||||
value, ok := volume.file_handles.Load(handleID)
|
volume.handlesLock.RLock()
|
||||||
if !ok {
|
f := volume.fileHandles[handleID]
|
||||||
return false
|
volume.handlesLock.RUnlock()
|
||||||
}
|
|
||||||
f := value.(*File)
|
|
||||||
// The file was empty, so it did not have a header. Create one.
|
// The file was empty, so it did not have a header. Create one.
|
||||||
if oldPlainSz == 0 {
|
if oldPlainSz == 0 {
|
||||||
id, err := createHeader(f.fd)
|
id, err := createHeader(f.fd)
|
||||||
@ -324,11 +316,9 @@ func (volume *Volume) truncateGrowFile(handleID int, oldPlainSz uint64, newPlain
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (volume *Volume) truncate(handleID int, newSize uint64) bool {
|
func (volume *Volume) truncate(handleID int, newSize uint64) bool {
|
||||||
value, ok := volume.file_handles.Load(handleID)
|
volume.handlesLock.RLock()
|
||||||
if !ok {
|
f := volume.fileHandles[handleID]
|
||||||
return false
|
volume.handlesLock.RUnlock()
|
||||||
}
|
|
||||||
f := value.(*File)
|
|
||||||
fileFD := int(f.fd.Fd())
|
fileFD := int(f.fd.Fd())
|
||||||
var err error
|
var err error
|
||||||
// Common case first: Truncate to zero
|
// Common case first: Truncate to zero
|
||||||
@ -359,7 +349,7 @@ func (volume *Volume) truncate(handleID int, newSize uint64) bool {
|
|||||||
lastBlockLen := newSize - plainOff
|
lastBlockLen := newSize - plainOff
|
||||||
var data []byte
|
var data []byte
|
||||||
if lastBlockLen > 0 {
|
if lastBlockLen > 0 {
|
||||||
data, success = volume.doRead(handleID, nil, plainOff, lastBlockLen)
|
data, success = volume.doRead(f, nil, plainOff, lastBlockLen)
|
||||||
if !success {
|
if !success {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -459,16 +449,14 @@ func gcf_read_file(sessionID, handleID int, offset uint64, dst_buff []byte) uint
|
|||||||
}
|
}
|
||||||
volume := value.(*Volume)
|
volume := value.(*Volume)
|
||||||
|
|
||||||
value, ok = volume.file_handles.Load(handleID)
|
volume.handlesLock.RLock()
|
||||||
if !ok {
|
f := volume.fileHandles[handleID]
|
||||||
return 0
|
volume.handlesLock.RUnlock()
|
||||||
}
|
|
||||||
f := value.(*File)
|
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
f.contentLock.RLock()
|
f.contentLock.RLock()
|
||||||
defer f.contentLock.RUnlock()
|
defer f.contentLock.RUnlock()
|
||||||
out, success := volume.doRead(handleID, dst_buff[:0], offset, uint64(length))
|
out, success := volume.doRead(f, dst_buff[:0], offset, uint64(length))
|
||||||
if !success {
|
if !success {
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
@ -490,13 +478,11 @@ func gcf_write_file(sessionID, handleID int, offset uint64, data []byte) uint32
|
|||||||
}
|
}
|
||||||
volume := value.(*Volume)
|
volume := value.(*Volume)
|
||||||
|
|
||||||
value, ok = volume.file_handles.Load(handleID)
|
volume.handlesLock.RLock()
|
||||||
if !ok {
|
f := volume.fileHandles[handleID]
|
||||||
return 0
|
volume.handlesLock.RUnlock()
|
||||||
}
|
|
||||||
f := value.(*File)
|
|
||||||
f.fdLock.RLock()
|
f.fdLock.RLock()
|
||||||
defer f.fdLock.RUnlock()
|
defer f.fdLock.RUnlock()
|
||||||
f.contentLock.Lock()
|
f.contentLock.Lock()
|
||||||
defer f.contentLock.Unlock()
|
defer f.contentLock.Unlock()
|
||||||
n, _ := volume.doWrite(handleID, data, offset)
|
n, _ := volume.doWrite(handleID, data, offset)
|
||||||
@ -510,14 +496,13 @@ func gcf_close_file(sessionID, handleID int) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
volume := value.(*Volume)
|
volume := value.(*Volume)
|
||||||
value, ok = volume.file_handles.Load(handleID)
|
volume.handlesLock.Lock()
|
||||||
if ok {
|
f := volume.fileHandles[handleID]
|
||||||
f := value.(*File)
|
f.fdLock.Lock()
|
||||||
f.fdLock.Lock()
|
f.fd.Close()
|
||||||
f.fd.Close()
|
delete(volume.fileHandles, handleID)
|
||||||
volume.file_handles.Delete(handleID)
|
volume.handlesLock.Unlock()
|
||||||
f.fdLock.Unlock()
|
f.fdLock.Unlock()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//export gcf_remove_file
|
//export gcf_remove_file
|
||||||
|
17
volume.go
17
volume.go
@ -44,7 +44,8 @@ type Volume struct {
|
|||||||
cryptoCore *cryptocore.CryptoCore
|
cryptoCore *cryptocore.CryptoCore
|
||||||
contentEnc *contentenc.ContentEnc
|
contentEnc *contentenc.ContentEnc
|
||||||
dirCache dirCache
|
dirCache dirCache
|
||||||
file_handles sync.Map
|
handlesLock sync.RWMutex
|
||||||
|
fileHandles map[int]*File
|
||||||
}
|
}
|
||||||
|
|
||||||
var OpenedVolumes sync.Map
|
var OpenedVolumes sync.Map
|
||||||
@ -93,6 +94,7 @@ func registerNewVolume(rootCipherDir string, masterkey []byte, cf *configfile.Co
|
|||||||
ivLen = 0
|
ivLen = 0
|
||||||
}
|
}
|
||||||
newVolume.dirCache = dirCache{ivLen: ivLen}
|
newVolume.dirCache = dirCache{ivLen: ivLen}
|
||||||
|
newVolume.fileHandles = make(map[int]*File)
|
||||||
|
|
||||||
//find unused volumeID
|
//find unused volumeID
|
||||||
volumeID := -1
|
volumeID := -1
|
||||||
@ -130,10 +132,15 @@ func gcf_close(volumeID int) {
|
|||||||
}
|
}
|
||||||
volume := value.(*Volume)
|
volume := value.(*Volume)
|
||||||
volume.cryptoCore.Wipe()
|
volume.cryptoCore.Wipe()
|
||||||
volume.file_handles.Range(func (handleID, _ interface {}) bool {
|
volume.handlesLock.RLock()
|
||||||
gcf_close_file(volumeID, handleID.(int))
|
fileHandles := make([]int, 0, len(volume.fileHandles))
|
||||||
return true
|
for i := range volume.fileHandles {
|
||||||
})
|
fileHandles = append(fileHandles, i)
|
||||||
|
}
|
||||||
|
volume.handlesLock.RUnlock()
|
||||||
|
for i := range fileHandles {
|
||||||
|
gcf_close_file(volumeID, i)
|
||||||
|
}
|
||||||
volume.dirCache.Clear()
|
volume.dirCache.Clear()
|
||||||
OpenedVolumes.Delete(volumeID)
|
OpenedVolumes.Delete(volumeID)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user