summaryrefslogtreecommitdiff
path: root/internal/openfiletable
diff options
context:
space:
mode:
authorJakob Unterwurzacher2018-07-22 22:29:22 +0200
committerJakob Unterwurzacher2018-07-22 22:29:22 +0200
commitf316f1b2df47dca651174e574ab072f6b46c0b01 (patch)
tree16176cb053718ba6b2815d08df44040f75d3fdae /internal/openfiletable
parentc70df522d2a78f3152fa61511bed9fafa7c495a3 (diff)
fusefronted: disallow writes running concurrently with reads
As uncovered by xfstests generic/465, concurrent reads and writes could lead to this, doRead 3015532: corrupt block #1039: stupidgcm: message authentication failed, as the read could pick up a block that has not yet been completely written - write() is not atomic! Now writes take ContentLock exclusively, while reads take it shared, meaning that multiple reads can run in parallel with each other, but not with a write. This also simplifies the file header locking.
Diffstat (limited to 'internal/openfiletable')
-rw-r--r--internal/openfiletable/open_file_table.go18
1 files changed, 8 insertions, 10 deletions
diff --git a/internal/openfiletable/open_file_table.go b/internal/openfiletable/open_file_table.go
index d70bcfa..e21c96d 100644
--- a/internal/openfiletable/open_file_table.go
+++ b/internal/openfiletable/open_file_table.go
@@ -57,18 +57,16 @@ type table struct {
// Entry is an entry in the open file table
type Entry struct {
- // Reference count
+ // Reference count. Protected by the table lock.
refCount int
- // ContentLock guards the file content from concurrent writes. Every writer
+ // ContentLock protects on-disk content from concurrent writes. Every writer
// must take this lock before modifying the file content.
ContentLock countingMutex
- // HeaderLock guards the file ID (in this struct) and the file header (on
- // disk). Take HeaderLock.RLock() to make sure the file ID does not change
- // behind your back. If you modify the file ID, you must take
- // HeaderLock.Lock().
- HeaderLock sync.RWMutex
// ID is the file ID in the file header.
ID []byte
+ // IDLock must be taken before reading or writing the ID field in this struct,
+ // unless you have an exclusive lock on ContentLock.
+ IDLock sync.Mutex
}
// Register creates an open file table entry for "qi" (or incrementes the
@@ -101,15 +99,15 @@ func Unregister(qi QIno) {
// countingMutex incrementes t.writeLockCount on each Lock() call.
type countingMutex struct {
- sync.Mutex
+ sync.RWMutex
}
func (c *countingMutex) Lock() {
- c.Mutex.Lock()
+ c.RWMutex.Lock()
atomic.AddUint64(&t.writeOpCount, 1)
}
-// WriteOpCount returns the write lock counter value. This value is encremented
+// WriteOpCount returns the write lock counter value. This value is incremented
// each time writeLock.Lock() on a file table entry is called.
func WriteOpCount() uint64 {
return atomic.LoadUint64(&t.writeOpCount)