diff options
Diffstat (limited to 'internal/fusefrontend/open_file_table.go')
-rw-r--r-- | internal/fusefrontend/open_file_table.go | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/internal/fusefrontend/open_file_table.go b/internal/fusefrontend/open_file_table.go new file mode 100644 index 0000000..053298d --- /dev/null +++ b/internal/fusefrontend/open_file_table.go @@ -0,0 +1,101 @@ +package fusefrontend + +import ( + "sync" + "sync/atomic" + "syscall" +) + +// DevInoStruct uniquely identifies a backing file through device number and +// inode number. +type DevInoStruct struct { + dev uint64 + ino uint64 +} + +// DevInoFromStat fills a new DevInoStruct with the passed Stat_t info +func DevInoFromStat(st *syscall.Stat_t) DevInoStruct { + // Explicit cast to uint64 to prevent build problems on 32-bit platforms + return DevInoStruct{ + dev: uint64(st.Dev), + ino: uint64(st.Ino), + } +} + +func init() { + openFileMap.entries = make(map[DevInoStruct]*openFileEntryT) +} + +// wlock - serializes write accesses to each file (identified by inode number) +// Writing partial blocks means we have to do read-modify-write cycles. We +// really don't want concurrent writes there. +// Concurrent full-block writes could actually be allowed, but are not to +// keep the locking simple. +var openFileMap openFileMapT + +// wlockMap - usage: +// 1) register +// 2) lock ... unlock ... +// 3) unregister +type openFileMapT struct { + // opCount counts writeLock.Lock() calls. As every operation that modifies a file should + // call it, this effectively serves as a write-operation counter. + // The variable is accessed without holding any locks so atomic operations + // must be used. It must be the first element of the struct to guarantee + // 64-bit alignment. + opCount uint64 + // Protects map access + sync.Mutex + entries map[DevInoStruct]*openFileEntryT +} + +type opCountMutex struct { + sync.Mutex + // Points to the opCount variable of the parent openFileMapT + opCount *uint64 +} + +func (o *opCountMutex) Lock() { + o.Mutex.Lock() + atomic.AddUint64(o.opCount, 1) +} + +// refCntMutex - mutex with reference count +type openFileEntryT struct { + // Reference count + refCnt int + // Write lock for this inode + writeLock *opCountMutex + // ID is the file ID in the file header. + ID []byte + IDLock sync.RWMutex +} + +// register creates an entry for "ino", or incrementes the reference count +// if the entry already exists. +func (w *openFileMapT) register(di DevInoStruct) *openFileEntryT { + w.Lock() + defer w.Unlock() + + r := w.entries[di] + if r == nil { + o := opCountMutex{opCount: &w.opCount} + r = &openFileEntryT{writeLock: &o} + w.entries[di] = r + } + r.refCnt++ + return r +} + +// unregister decrements the reference count for "di" and deletes the entry if +// the reference count has reached 0. +func (w *openFileMapT) unregister(di DevInoStruct) { + w.Lock() + defer w.Unlock() + + r := w.entries[di] + r.refCnt-- + if r.refCnt == 0 { + delete(w.entries, di) + } +} |